aboutsummaryrefslogtreecommitdiffstats
path: root/system_cmds
diff options
context:
space:
mode:
Diffstat (limited to 'system_cmds')
-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
253 files changed, 73278 insertions, 0 deletions
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,
+}))