diff options
author | Cameron Katri <me@cameronkatri.com> | 2021-05-09 14:20:58 -0400 |
---|---|---|
committer | Cameron Katri <me@cameronkatri.com> | 2021-05-09 14:20:58 -0400 |
commit | 5fd83771641d15c418f747bd343ba6738d3875f7 (patch) | |
tree | 5abf0f78f680d9837dbd93d4d4c3933bb7509599 /adv_cmds | |
download | apple_cmds-5fd83771641d15c418f747bd343ba6738d3875f7.tar.gz apple_cmds-5fd83771641d15c418f747bd343ba6738d3875f7.tar.zst apple_cmds-5fd83771641d15c418f747bd343ba6738d3875f7.zip |
Import macOS userland
adv_cmds-176
basic_cmds-55
bootstrap_cmds-116.100.1
developer_cmds-66
diskdev_cmds-667.40.1
doc_cmds-53.60.1
file_cmds-321.40.3
mail_cmds-35
misc_cmds-34
network_cmds-606.40.1
patch_cmds-17
remote_cmds-63
shell_cmds-216.60.1
system_cmds-880.60.2
text_cmds-106
Diffstat (limited to 'adv_cmds')
74 files changed, 21915 insertions, 0 deletions
diff --git a/adv_cmds/.upstream_base_commits b/adv_cmds/.upstream_base_commits new file mode 100644 index 0000000..2e37ca8 --- /dev/null +++ b/adv_cmds/.upstream_base_commits @@ -0,0 +1,3 @@ +#freebsd = https://github.com/freebsd/freebsd.git +usr.bin/whois/whois.c freebsd whois/whois.c 872b698bd4a1bfc0bf008c09228e6fd238809c75 +usr.bin/whois/whois.1 freebsd whois/whois.1 7e6cabd06e6caa6a02eeb86308dc0cb3f27e10da diff --git a/adv_cmds/adv_cmds.xcodeproj/project.pbxproj b/adv_cmds/adv_cmds.xcodeproj/project.pbxproj new file mode 100644 index 0000000..d1eda3c --- /dev/null +++ b/adv_cmds/adv_cmds.xcodeproj/project.pbxproj @@ -0,0 +1,1806 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXAggregateTarget section */ + FD0D7F98108FE550004F2A1C /* localedef */ = { + isa = PBXAggregateTarget; + buildConfigurationList = FD0D7FA2108FE56E004F2A1C /* Build configuration list for PBXAggregateTarget "localedef" */; + buildPhases = ( + FD0D7F97108FE550004F2A1C /* ShellScript */, + FD0D7FA5108FE5AA004F2A1C /* Install man1 */, + ); + dependencies = ( + ); + name = localedef; + productName = localedef2; + }; + FD201DCD14369D0C00906237 /* pgrep */ = { + isa = PBXAggregateTarget; + buildConfigurationList = FD201DCE14369D0C00906237 /* Build configuration list for PBXAggregateTarget "pgrep" */; + buildPhases = ( + FD201DD014369D1000906237 /* ShellScript */, + ); + dependencies = ( + FD201DD214369D5C00906237 /* PBXTargetDependency */, + ); + name = pgrep; + productName = pgrep; + }; + FDF2764E0FC60ECD00D7A3C6 /* Embedded */ = { + isa = PBXAggregateTarget; + buildConfigurationList = FDF276580FC60EE600D7A3C6 /* Build configuration list for PBXAggregateTarget "Embedded" */; + buildPhases = ( + ); + dependencies = ( + FD201DD614369D6700906237 /* PBXTargetDependency */, + FD201DBF14369B1700906237 /* PBXTargetDependency */, + FDF2766D0FC60F0D00D7A3C6 /* PBXTargetDependency */, + FDF2766B0FC60F0D00D7A3C6 /* PBXTargetDependency */, + ); + name = Embedded; + productName = Embedded; + }; + FDF276500FC60EDA00D7A3C6 /* Desktop */ = { + isa = PBXAggregateTarget; + buildConfigurationList = FDF276570FC60EE600D7A3C6 /* Build configuration list for PBXAggregateTarget "Desktop" */; + buildPhases = ( + ); + dependencies = ( + FDF277670FC6102600D7A3C6 /* PBXTargetDependency */, + FDF277650FC6102600D7A3C6 /* PBXTargetDependency */, + FDF277630FC6102600D7A3C6 /* PBXTargetDependency */, + FDF2775F0FC6102600D7A3C6 /* PBXTargetDependency */, + FDF2775D0FC6102600D7A3C6 /* PBXTargetDependency */, + FDF2775B0FC6102600D7A3C6 /* PBXTargetDependency */, + FD0D7FA9108FE5C3004F2A1C /* PBXTargetDependency */, + FDF277570FC6102600D7A3C6 /* PBXTargetDependency */, + FDF277530FC6102600D7A3C6 /* PBXTargetDependency */, + FD201DD414369D6300906237 /* PBXTargetDependency */, + FD201DC114369B1D00906237 /* PBXTargetDependency */, + FDF2766F0FC60F0F00D7A3C6 /* PBXTargetDependency */, + FDF276710FC60F1300D7A3C6 /* PBXTargetDependency */, + FDF2776D0FC6102B00D7A3C6 /* PBXTargetDependency */, + FDF2776B0FC6102B00D7A3C6 /* PBXTargetDependency */, + FDF277690FC6102B00D7A3C6 /* PBXTargetDependency */, + ); + name = Desktop; + productName = Desktop; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + FD0D7FA4108FE58C004F2A1C /* localedef.1 in Install man1 */ = {isa = PBXBuildFile; fileRef = FDF277140FC60FDF00D7A3C6 /* localedef.1 */; }; + FD201DC214369B4200906237 /* pkill.c in Sources */ = {isa = PBXBuildFile; fileRef = FD201DB014369AD000906237 /* pkill.c */; }; + FD201DC314369B4600906237 /* pkill.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FD201DAF14369AD000906237 /* pkill.1 */; }; + FDCD383B143BC63000AB81C6 /* libsysmon.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = FDCD383A143BC63000AB81C6 /* libsysmon.dylib */; }; + FDF2774B0FC6100400D7A3C6 /* cap_mkdb.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF276DE0FC60FDF00D7A3C6 /* cap_mkdb.c */; }; + FDF277730FC6105F00D7A3C6 /* cap_mkdb.1 in Install man1 */ = {isa = PBXBuildFile; fileRef = FDF276DD0FC60FDF00D7A3C6 /* cap_mkdb.1 */; }; + FDF277790FC610EC00D7A3C6 /* finger.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF276EC0FC60FDF00D7A3C6 /* finger.c */; }; + FDF2777A0FC610EC00D7A3C6 /* lprint.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF276EF0FC60FDF00D7A3C6 /* lprint.c */; }; + FDF2777B0FC610EC00D7A3C6 /* net.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF276F10FC60FDF00D7A3C6 /* net.c */; }; + FDF2777C0FC610EC00D7A3C6 /* sprint.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF276F30FC60FDF00D7A3C6 /* sprint.c */; }; + FDF2777D0FC610EC00D7A3C6 /* util.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF276F40FC60FDF00D7A3C6 /* util.c */; }; + FDF2779D0FC611B800D7A3C6 /* finger.conf.5 in Install man5 */ = {isa = PBXBuildFile; fileRef = FDF276ED0FC60FDF00D7A3C6 /* finger.conf.5 */; }; + FDF2779E0FC611BA00D7A3C6 /* finger.1 in Install man1 */ = {isa = PBXBuildFile; fileRef = FDF276EB0FC60FDF00D7A3C6 /* finger.1 */; }; + FDF277BE0FC612B000D7A3C6 /* whois.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF277490FC60FDF00D7A3C6 /* whois.c */; }; + FDF277C20FC612C800D7A3C6 /* whois.1 in Install man1 */ = {isa = PBXBuildFile; fileRef = FDF277480FC60FDF00D7A3C6 /* whois.1 */; }; + FDF277C40FC6133400D7A3C6 /* tty.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF277450FC60FDF00D7A3C6 /* tty.c */; }; + FDF277C70FC6137B00D7A3C6 /* tty.1 in Install man1 */ = {isa = PBXBuildFile; fileRef = FDF277440FC60FDF00D7A3C6 /* tty.1 */; }; + FDF277D70FC613F500D7A3C6 /* tabs.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF277410FC60FDF00D7A3C6 /* tabs.c */; }; + FDF277D90FC6140400D7A3C6 /* tabs.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FDF277400FC60FDF00D7A3C6 /* tabs.1 */; }; + FDF277E80FC6144400D7A3C6 /* libtermcap.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = FDF277E70FC6144400D7A3C6 /* libtermcap.dylib */; }; + FDF277EE0FC6148500D7A3C6 /* cchar.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF277330FC60FDF00D7A3C6 /* cchar.c */; }; + FDF277EF0FC6148500D7A3C6 /* gfmt.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF277350FC60FDF00D7A3C6 /* gfmt.c */; }; + FDF277F00FC6148500D7A3C6 /* key.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF277360FC60FDF00D7A3C6 /* key.c */; }; + FDF277F10FC6148500D7A3C6 /* modes.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF277380FC60FDF00D7A3C6 /* modes.c */; }; + FDF277F20FC6148500D7A3C6 /* print.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF277390FC60FDF00D7A3C6 /* print.c */; }; + FDF277F30FC6148500D7A3C6 /* stty.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF2773B0FC60FDF00D7A3C6 /* stty.c */; }; + FDF277F40FC6148500D7A3C6 /* util.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF2773D0FC60FDF00D7A3C6 /* util.c */; }; + FDF277F80FC614A300D7A3C6 /* stty.1 in Install man1 */ = {isa = PBXBuildFile; fileRef = FDF2773A0FC60FDF00D7A3C6 /* stty.1 */; }; + FDF278060FC6151E00D7A3C6 /* fmt.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF277290FC60FDF00D7A3C6 /* fmt.c */; }; + FDF278070FC6151E00D7A3C6 /* keyword.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF2772A0FC60FDF00D7A3C6 /* keyword.c */; }; + FDF278080FC6151E00D7A3C6 /* nlist.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF2772C0FC60FDF00D7A3C6 /* nlist.c */; }; + FDF278090FC6151E00D7A3C6 /* print.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF2772D0FC60FDF00D7A3C6 /* print.c */; }; + FDF2780A0FC6151E00D7A3C6 /* ps.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF2772F0FC60FDF00D7A3C6 /* ps.c */; }; + FDF2780B0FC6151E00D7A3C6 /* tasks.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF277310FC60FDF00D7A3C6 /* tasks.c */; }; + FDF278280FC615F900D7A3C6 /* ps.1 in Install man1 */ = {isa = PBXBuildFile; fileRef = FDF2772E0FC60FDF00D7A3C6 /* ps.1 */; }; + FDF278370FC6167800D7A3C6 /* lex.l in Sources */ = {isa = PBXBuildFile; fileRef = FDF277220FC60FDF00D7A3C6 /* lex.l */; }; + FDF278380FC6167800D7A3C6 /* yacc.y in Sources */ = {isa = PBXBuildFile; fileRef = FDF277260FC60FDF00D7A3C6 /* yacc.y */; }; + FDF278A30FC61D8900D7A3C6 /* mklocale.1 in Install man1 */ = {isa = PBXBuildFile; fileRef = FDF277240FC60FDF00D7A3C6 /* mklocale.1 */; }; + FDF278C60FC61FDF00D7A3C6 /* lsvfs.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF277180FC60FDF00D7A3C6 /* lsvfs.c */; }; + FDF278CA0FC61FFD00D7A3C6 /* lsvfs.1 in Install man1 */ = {isa = PBXBuildFile; fileRef = FDF277170FC60FDF00D7A3C6 /* lsvfs.1 */; }; + FDF278D60FC6204E00D7A3C6 /* locale.cc in Sources */ = {isa = PBXBuildFile; fileRef = FDF2770A0FC60FDF00D7A3C6 /* locale.cc */; }; + FDF278DA0FC6206500D7A3C6 /* locale.1 in Install man1 */ = {isa = PBXBuildFile; fileRef = FDF277090FC60FDF00D7A3C6 /* locale.1 */; }; + FDF278DB0FC6208600D7A3C6 /* last.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF277060FC60FDF00D7A3C6 /* last.c */; }; + FDF278E00FC620A000D7A3C6 /* last.1 in Install man1 */ = {isa = PBXBuildFile; fileRef = FDF277050FC60FDF00D7A3C6 /* last.1 */; }; + FDF278F50FC623D300D7A3C6 /* gencat.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF276FE0FC60FDF00D7A3C6 /* gencat.c */; }; + FDF278F60FC623D300D7A3C6 /* genlib.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF277000FC60FDF00D7A3C6 /* genlib.c */; }; + FDF2792D0FC625B800D7A3C6 /* gencat.1 in Install man1 */ = {isa = PBXBuildFile; fileRef = FDF276FD0FC60FDF00D7A3C6 /* gencat.1 */; }; + FDF279390FC6263E00D7A3C6 /* parse.y in Sources */ = {isa = PBXBuildFile; fileRef = FDF276E70FC60FDF00D7A3C6 /* parse.y */; }; + FDF2793A0FC6263E00D7A3C6 /* scan.l in Sources */ = {isa = PBXBuildFile; fileRef = FDF276E80FC60FDF00D7A3C6 /* scan.l */; }; + FDF2795E0FC6272500D7A3C6 /* libl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FDF2795D0FC6272500D7A3C6 /* libl.a */; }; + FDF2798F0FC62B0800D7A3C6 /* colldef.1 in Install man1 */ = {isa = PBXBuildFile; fileRef = FDF276E10FC60FDF00D7A3C6 /* colldef.1 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + FD0D7FA8108FE5C3004F2A1C /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */; + proxyType = 1; + remoteGlobalIDString = FD0D7F98108FE550004F2A1C; + remoteInfo = localedef; + }; + FD201DBE14369B1700906237 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */; + proxyType = 1; + remoteGlobalIDString = FD201DB414369B0300906237; + remoteInfo = pkill; + }; + FD201DC014369B1D00906237 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */; + proxyType = 1; + remoteGlobalIDString = FD201DB414369B0300906237; + remoteInfo = pkill; + }; + FD201DD114369D5C00906237 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */; + proxyType = 1; + remoteGlobalIDString = FD201DB414369B0300906237; + remoteInfo = pkill; + }; + FD201DD314369D6300906237 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */; + proxyType = 1; + remoteGlobalIDString = FD201DCD14369D0C00906237; + remoteInfo = pgrep; + }; + FD201DD514369D6700906237 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */; + proxyType = 1; + remoteGlobalIDString = FD201DCD14369D0C00906237; + remoteInfo = pgrep; + }; + FDF2766A0FC60F0D00D7A3C6 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */; + proxyType = 1; + remoteGlobalIDString = FDF276630FC60EFD00D7A3C6; + remoteInfo = stty; + }; + FDF2766C0FC60F0D00D7A3C6 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */; + proxyType = 1; + remoteGlobalIDString = FDF2765B0FC60EF600D7A3C6; + remoteInfo = ps; + }; + FDF2766E0FC60F0F00D7A3C6 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */; + proxyType = 1; + remoteGlobalIDString = FDF2765B0FC60EF600D7A3C6; + remoteInfo = ps; + }; + FDF276700FC60F1300D7A3C6 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */; + proxyType = 1; + remoteGlobalIDString = FDF276630FC60EFD00D7A3C6; + remoteInfo = stty; + }; + FDF277520FC6102600D7A3C6 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */; + proxyType = 1; + remoteGlobalIDString = FDF276B00FC60F7600D7A3C6; + remoteInfo = mklocale; + }; + FDF277560FC6102600D7A3C6 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */; + proxyType = 1; + remoteGlobalIDString = FDF276A40FC60F5E00D7A3C6; + remoteInfo = lsvfs; + }; + FDF2775A0FC6102600D7A3C6 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */; + proxyType = 1; + remoteGlobalIDString = FDF276980FC60F5000D7A3C6; + remoteInfo = locale; + }; + FDF2775C0FC6102600D7A3C6 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */; + proxyType = 1; + remoteGlobalIDString = FDF276920FC60F4B00D7A3C6; + remoteInfo = last; + }; + FDF2775E0FC6102600D7A3C6 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */; + proxyType = 1; + remoteGlobalIDString = FDF2768C0FC60F3D00D7A3C6; + remoteInfo = gencat; + }; + FDF277620FC6102600D7A3C6 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */; + proxyType = 1; + remoteGlobalIDString = FDF276800FC60F3100D7A3C6; + remoteInfo = finger; + }; + FDF277640FC6102600D7A3C6 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */; + proxyType = 1; + remoteGlobalIDString = FDF2767A0FC60F2A00D7A3C6; + remoteInfo = colldef; + }; + FDF277660FC6102600D7A3C6 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */; + proxyType = 1; + remoteGlobalIDString = FDF276740FC60F2100D7A3C6; + remoteInfo = cap_mkdb; + }; + FDF277680FC6102B00D7A3C6 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */; + proxyType = 1; + remoteGlobalIDString = FDF276C20FC60F8A00D7A3C6; + remoteInfo = whois; + }; + FDF2776A0FC6102B00D7A3C6 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */; + proxyType = 1; + remoteGlobalIDString = FDF276BC0FC60F8400D7A3C6; + remoteInfo = tty; + }; + FDF2776C0FC6102B00D7A3C6 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */; + proxyType = 1; + remoteGlobalIDString = FDF276B60FC60F7F00D7A3C6; + remoteInfo = tabs; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + FD0D7FA5108FE5AA004F2A1C /* Install man1 */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /usr/share/man/man1; + dstSubfolderSpec = 0; + files = ( + FD0D7FA4108FE58C004F2A1C /* localedef.1 in Install man1 */, + ); + name = "Install man1"; + runOnlyForDeploymentPostprocessing = 1; + }; + FD201DB314369B0300906237 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + FD201DC314369B4600906237 /* pkill.1 in CopyFiles */, + ); + runOnlyForDeploymentPostprocessing = 1; + }; + FDF277780FC610A400D7A3C6 /* Install man1 */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /usr/share/man/man1; + dstSubfolderSpec = 0; + files = ( + FDF277730FC6105F00D7A3C6 /* cap_mkdb.1 in Install man1 */, + ); + name = "Install man1"; + runOnlyForDeploymentPostprocessing = 1; + }; + FDF277A10FC611D800D7A3C6 /* Install man1 */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /usr/share/man/man1; + dstSubfolderSpec = 0; + files = ( + FDF2779E0FC611BA00D7A3C6 /* finger.1 in Install man1 */, + ); + name = "Install man1"; + runOnlyForDeploymentPostprocessing = 1; + }; + FDF277A20FC611D800D7A3C6 /* Install man5 */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /usr/share/man/man5; + dstSubfolderSpec = 0; + files = ( + FDF2779D0FC611B800D7A3C6 /* finger.conf.5 in Install man5 */, + ); + name = "Install man5"; + runOnlyForDeploymentPostprocessing = 1; + }; + FDF277C30FC612D900D7A3C6 /* Install man1 */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /usr/share/man/man1; + dstSubfolderSpec = 0; + files = ( + FDF277C20FC612C800D7A3C6 /* whois.1 in Install man1 */, + ); + name = "Install man1"; + runOnlyForDeploymentPostprocessing = 1; + }; + FDF277C60FC6135D00D7A3C6 /* Install man1 */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /usr/share/man/man1; + dstSubfolderSpec = 0; + files = ( + FDF277C70FC6137B00D7A3C6 /* tty.1 in Install man1 */, + ); + name = "Install man1"; + runOnlyForDeploymentPostprocessing = 1; + }; + FDF277E60FC6143000D7A3C6 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /usr/share/man/man1; + dstSubfolderSpec = 0; + files = ( + FDF277D90FC6140400D7A3C6 /* tabs.1 in CopyFiles */, + ); + runOnlyForDeploymentPostprocessing = 1; + }; + FDF278030FC614B900D7A3C6 /* Install man1 */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /usr/share/man/man1; + dstSubfolderSpec = 0; + files = ( + FDF277F80FC614A300D7A3C6 /* stty.1 in Install man1 */, + ); + name = "Install man1"; + runOnlyForDeploymentPostprocessing = 1; + }; + FDF278300FC6160800D7A3C6 /* Install man1 */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /usr/share/man/man1; + dstSubfolderSpec = 0; + files = ( + FDF278280FC615F900D7A3C6 /* ps.1 in Install man1 */, + ); + name = "Install man1"; + runOnlyForDeploymentPostprocessing = 1; + }; + FDF278A40FC61D9600D7A3C6 /* Install man1 */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /usr/share/man/man1; + dstSubfolderSpec = 0; + files = ( + FDF278A30FC61D8900D7A3C6 /* mklocale.1 in Install man1 */, + ); + name = "Install man1"; + runOnlyForDeploymentPostprocessing = 1; + }; + FDF278D50FC6201600D7A3C6 /* Install man1 */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /usr/share/man/man1; + dstSubfolderSpec = 0; + files = ( + FDF278CA0FC61FFD00D7A3C6 /* lsvfs.1 in Install man1 */, + ); + name = "Install man1"; + runOnlyForDeploymentPostprocessing = 1; + }; + FDF278E70FC620B600D7A3C6 /* Install man1 */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /usr/share/man/man1; + dstSubfolderSpec = 0; + files = ( + FDF278E00FC620A000D7A3C6 /* last.1 in Install man1 */, + ); + name = "Install man1"; + runOnlyForDeploymentPostprocessing = 1; + }; + FDF278E80FC620B600D7A3C6 /* Install man1 */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /usr/share/man/man1; + dstSubfolderSpec = 0; + files = ( + FDF278DA0FC6206500D7A3C6 /* locale.1 in Install man1 */, + ); + name = "Install man1"; + runOnlyForDeploymentPostprocessing = 1; + }; + FDF279300FC625CB00D7A3C6 /* Install man1 */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /usr/share/man/man1; + dstSubfolderSpec = 0; + files = ( + FDF2792D0FC625B800D7A3C6 /* gencat.1 in Install man1 */, + ); + name = "Install man1"; + runOnlyForDeploymentPostprocessing = 1; + }; + FDF279930FC62B0B00D7A3C6 /* Install man1 */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /usr/share/man/man1; + dstSubfolderSpec = 0; + files = ( + FDF2798F0FC62B0800D7A3C6 /* colldef.1 in Install man1 */, + ); + name = "Install man1"; + runOnlyForDeploymentPostprocessing = 1; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + FD201DAF14369AD000906237 /* pkill.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; name = pkill.1; path = pkill/pkill.1; sourceTree = "<group>"; }; + FD201DB014369AD000906237 /* pkill.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = pkill.c; path = pkill/pkill.c; sourceTree = "<group>"; }; + FD201DB514369B0400906237 /* pkill */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = pkill; sourceTree = BUILT_PRODUCTS_DIR; }; + FDCD383A143BC63000AB81C6 /* libsysmon.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libsysmon.dylib; path = /usr/lib/libsysmon.dylib; sourceTree = "<absolute>"; }; + FDF2765C0FC60EF600D7A3C6 /* ps */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ps; sourceTree = BUILT_PRODUCTS_DIR; }; + FDF276640FC60EFD00D7A3C6 /* stty */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = stty; sourceTree = BUILT_PRODUCTS_DIR; }; + FDF276750FC60F2100D7A3C6 /* cap_mkdb */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = cap_mkdb; sourceTree = BUILT_PRODUCTS_DIR; }; + FDF2767B0FC60F2A00D7A3C6 /* colldef */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = colldef; sourceTree = BUILT_PRODUCTS_DIR; }; + FDF276810FC60F3100D7A3C6 /* finger */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = finger; sourceTree = BUILT_PRODUCTS_DIR; }; + FDF2768D0FC60F3D00D7A3C6 /* gencat */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = gencat; sourceTree = BUILT_PRODUCTS_DIR; }; + FDF276930FC60F4B00D7A3C6 /* last */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = last; sourceTree = BUILT_PRODUCTS_DIR; }; + FDF276990FC60F5000D7A3C6 /* locale */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = locale; sourceTree = BUILT_PRODUCTS_DIR; }; + FDF276A50FC60F5E00D7A3C6 /* lsvfs */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = lsvfs; sourceTree = BUILT_PRODUCTS_DIR; }; + FDF276B10FC60F7600D7A3C6 /* mklocale */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mklocale; sourceTree = BUILT_PRODUCTS_DIR; }; + FDF276B70FC60F7F00D7A3C6 /* tabs */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = tabs; sourceTree = BUILT_PRODUCTS_DIR; }; + FDF276BD0FC60F8400D7A3C6 /* tty */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = tty; sourceTree = BUILT_PRODUCTS_DIR; }; + FDF276C30FC60F8A00D7A3C6 /* whois */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = whois; sourceTree = BUILT_PRODUCTS_DIR; }; + FDF276DD0FC60FDF00D7A3C6 /* cap_mkdb.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = cap_mkdb.1; sourceTree = "<group>"; }; + FDF276DE0FC60FDF00D7A3C6 /* cap_mkdb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cap_mkdb.c; sourceTree = "<group>"; }; + FDF276E10FC60FDF00D7A3C6 /* colldef.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = colldef.1; sourceTree = "<group>"; }; + FDF276E20FC60FDF00D7A3C6 /* common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = common.h; sourceTree = "<group>"; }; + FDF276E50FC60FDF00D7A3C6 /* collate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = collate.h; sourceTree = "<group>"; }; + FDF276E70FC60FDF00D7A3C6 /* parse.y */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.yacc; path = parse.y; sourceTree = "<group>"; }; + FDF276E80FC60FDF00D7A3C6 /* scan.l */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.lex; path = scan.l; sourceTree = "<group>"; }; + FDF276EA0FC60FDF00D7A3C6 /* extern.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = extern.h; sourceTree = "<group>"; }; + FDF276EB0FC60FDF00D7A3C6 /* finger.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = finger.1; sourceTree = "<group>"; }; + FDF276EC0FC60FDF00D7A3C6 /* finger.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = finger.c; sourceTree = "<group>"; }; + FDF276ED0FC60FDF00D7A3C6 /* finger.conf.5 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = finger.conf.5; sourceTree = "<group>"; }; + FDF276EE0FC60FDF00D7A3C6 /* finger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = finger.h; sourceTree = "<group>"; }; + FDF276EF0FC60FDF00D7A3C6 /* lprint.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = lprint.c; sourceTree = "<group>"; }; + FDF276F10FC60FDF00D7A3C6 /* net.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = net.c; sourceTree = "<group>"; }; + FDF276F20FC60FDF00D7A3C6 /* pathnames.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pathnames.h; sourceTree = "<group>"; }; + FDF276F30FC60FDF00D7A3C6 /* sprint.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sprint.c; sourceTree = "<group>"; }; + FDF276F40FC60FDF00D7A3C6 /* util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = util.c; sourceTree = "<group>"; }; + FDF276F60FC60FDF00D7A3C6 /* finger.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = finger.plist; sourceTree = "<group>"; }; + FDF276F70FC60FDF00D7A3C6 /* fingerd.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = fingerd.8; sourceTree = "<group>"; }; + FDF276F80FC60FDF00D7A3C6 /* fingerd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fingerd.c; sourceTree = "<group>"; }; + FDF276FA0FC60FDF00D7A3C6 /* pathnames.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pathnames.h; sourceTree = "<group>"; }; + FDF276FD0FC60FDF00D7A3C6 /* gencat.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = gencat.1; sourceTree = "<group>"; }; + FDF276FE0FC60FDF00D7A3C6 /* gencat.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gencat.c; sourceTree = "<group>"; }; + FDF276FF0FC60FDF00D7A3C6 /* gencat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gencat.h; sourceTree = "<group>"; }; + FDF277000FC60FDF00D7A3C6 /* genlib.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = genlib.c; sourceTree = "<group>"; }; + FDF277050FC60FDF00D7A3C6 /* last.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = last.1; sourceTree = "<group>"; }; + FDF277060FC60FDF00D7A3C6 /* last.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = last.c; sourceTree = "<group>"; }; + FDF277090FC60FDF00D7A3C6 /* locale.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = locale.1; sourceTree = "<group>"; }; + FDF2770A0FC60FDF00D7A3C6 /* locale.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = locale.cc; sourceTree = "<group>"; }; + FDF277140FC60FDF00D7A3C6 /* localedef.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = localedef.1; sourceTree = "<group>"; }; + FDF277170FC60FDF00D7A3C6 /* lsvfs.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = lsvfs.1; sourceTree = "<group>"; }; + FDF277180FC60FDF00D7A3C6 /* lsvfs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = lsvfs.c; sourceTree = "<group>"; }; + FDF2771F0FC60FDF00D7A3C6 /* extern.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = extern.h; sourceTree = "<group>"; }; + FDF277210FC60FDF00D7A3C6 /* ldef.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ldef.h; sourceTree = "<group>"; }; + FDF277220FC60FDF00D7A3C6 /* lex.l */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.lex; path = lex.l; sourceTree = "<group>"; }; + FDF277240FC60FDF00D7A3C6 /* mklocale.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = mklocale.1; sourceTree = "<group>"; }; + FDF277250FC60FDF00D7A3C6 /* runefile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = runefile.h; sourceTree = "<group>"; }; + FDF277260FC60FDF00D7A3C6 /* yacc.y */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.yacc; path = yacc.y; sourceTree = "<group>"; }; + FDF277280FC60FDF00D7A3C6 /* extern.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = extern.h; sourceTree = "<group>"; }; + FDF277290FC60FDF00D7A3C6 /* fmt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fmt.c; sourceTree = "<group>"; }; + FDF2772A0FC60FDF00D7A3C6 /* keyword.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = keyword.c; sourceTree = "<group>"; }; + FDF2772C0FC60FDF00D7A3C6 /* nlist.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nlist.c; sourceTree = "<group>"; }; + FDF2772D0FC60FDF00D7A3C6 /* print.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = print.c; sourceTree = "<group>"; }; + FDF2772E0FC60FDF00D7A3C6 /* ps.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = ps.1; sourceTree = "<group>"; }; + FDF2772F0FC60FDF00D7A3C6 /* ps.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps.c; sourceTree = "<group>"; }; + FDF277300FC60FDF00D7A3C6 /* ps.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ps.h; sourceTree = "<group>"; }; + FDF277310FC60FDF00D7A3C6 /* tasks.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tasks.c; sourceTree = "<group>"; }; + FDF277330FC60FDF00D7A3C6 /* cchar.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cchar.c; sourceTree = "<group>"; }; + FDF277340FC60FDF00D7A3C6 /* extern.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = extern.h; sourceTree = "<group>"; }; + FDF277350FC60FDF00D7A3C6 /* gfmt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gfmt.c; sourceTree = "<group>"; }; + FDF277360FC60FDF00D7A3C6 /* key.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = key.c; sourceTree = "<group>"; }; + FDF277380FC60FDF00D7A3C6 /* modes.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = modes.c; sourceTree = "<group>"; }; + FDF277390FC60FDF00D7A3C6 /* print.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = print.c; sourceTree = "<group>"; }; + FDF2773A0FC60FDF00D7A3C6 /* stty.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = stty.1; sourceTree = "<group>"; }; + FDF2773B0FC60FDF00D7A3C6 /* stty.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = stty.c; sourceTree = "<group>"; }; + FDF2773C0FC60FDF00D7A3C6 /* stty.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = stty.h; sourceTree = "<group>"; }; + FDF2773D0FC60FDF00D7A3C6 /* util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = util.c; sourceTree = "<group>"; }; + FDF277400FC60FDF00D7A3C6 /* tabs.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = tabs.1; sourceTree = "<group>"; }; + FDF277410FC60FDF00D7A3C6 /* tabs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tabs.c; sourceTree = "<group>"; }; + FDF277440FC60FDF00D7A3C6 /* tty.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = tty.1; sourceTree = "<group>"; }; + FDF277450FC60FDF00D7A3C6 /* tty.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tty.c; sourceTree = "<group>"; }; + FDF277480FC60FDF00D7A3C6 /* whois.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = whois.1; sourceTree = "<group>"; }; + FDF277490FC60FDF00D7A3C6 /* whois.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = whois.c; sourceTree = "<group>"; }; + FDF277E70FC6144400D7A3C6 /* libtermcap.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libtermcap.dylib; path = /usr/lib/libtermcap.dylib; sourceTree = "<absolute>"; }; + FDF2795D0FC6272500D7A3C6 /* libl.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libl.a; path = /usr/lib/libl.a; sourceTree = "<absolute>"; }; + FDF279760FC629B100D7A3C6 /* localedef.pl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.perl; path = localedef.pl; sourceTree = "<group>"; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + FD201DB214369B0300906237 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + FDCD383B143BC63000AB81C6 /* libsysmon.dylib in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + FDF2765A0FC60EF600D7A3C6 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + FDF276620FC60EFD00D7A3C6 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + FDF276730FC60F2100D7A3C6 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + FDF276790FC60F2A00D7A3C6 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + FDF2795E0FC6272500D7A3C6 /* libl.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + FDF2767F0FC60F3100D7A3C6 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + FDF2768B0FC60F3D00D7A3C6 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + FDF276910FC60F4B00D7A3C6 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + FDF276970FC60F5000D7A3C6 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + FDF276A30FC60F5E00D7A3C6 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + FDF276AF0FC60F7600D7A3C6 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + FDF276B50FC60F7F00D7A3C6 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + FDF277E80FC6144400D7A3C6 /* libtermcap.dylib in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + FDF276BB0FC60F8400D7A3C6 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + FDF276C10FC60F8A00D7A3C6 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + FD201DAD14369AB300906237 /* pkill */ = { + isa = PBXGroup; + children = ( + FD201DB014369AD000906237 /* pkill.c */, + FD201DAF14369AD000906237 /* pkill.1 */, + ); + name = pkill; + sourceTree = "<group>"; + }; + FDF276410FC60E9000D7A3C6 = { + isa = PBXGroup; + children = ( + FDF276DA0FC60FD800D7A3C6 /* Source */, + FDF2765D0FC60EF600D7A3C6 /* Products */, + FDF277E70FC6144400D7A3C6 /* libtermcap.dylib */, + FDF2795D0FC6272500D7A3C6 /* libl.a */, + FDCD383A143BC63000AB81C6 /* libsysmon.dylib */, + ); + sourceTree = "<group>"; + }; + FDF2765D0FC60EF600D7A3C6 /* Products */ = { + isa = PBXGroup; + children = ( + FDF2765C0FC60EF600D7A3C6 /* ps */, + FDF276640FC60EFD00D7A3C6 /* stty */, + FDF276750FC60F2100D7A3C6 /* cap_mkdb */, + FDF2767B0FC60F2A00D7A3C6 /* colldef */, + FDF276810FC60F3100D7A3C6 /* finger */, + FDF2768D0FC60F3D00D7A3C6 /* gencat */, + FDF276930FC60F4B00D7A3C6 /* last */, + FDF276990FC60F5000D7A3C6 /* locale */, + FDF276A50FC60F5E00D7A3C6 /* lsvfs */, + FDF276B10FC60F7600D7A3C6 /* mklocale */, + FDF276B70FC60F7F00D7A3C6 /* tabs */, + FDF276BD0FC60F8400D7A3C6 /* tty */, + FDF276C30FC60F8A00D7A3C6 /* whois */, + FD201DB514369B0400906237 /* pkill */, + ); + name = Products; + sourceTree = "<group>"; + }; + FDF276DA0FC60FD800D7A3C6 /* Source */ = { + isa = PBXGroup; + children = ( + FDF276DC0FC60FDF00D7A3C6 /* cap_mkdb */, + FDF276E00FC60FDF00D7A3C6 /* colldef */, + FDF276E90FC60FDF00D7A3C6 /* finger */, + FDF276F50FC60FDF00D7A3C6 /* fingerd */, + FDF276FB0FC60FDF00D7A3C6 /* gencat */, + FDF277040FC60FDF00D7A3C6 /* last */, + FDF277080FC60FDF00D7A3C6 /* locale */, + FDF2770C0FC60FDF00D7A3C6 /* localedef */, + FDF277160FC60FDF00D7A3C6 /* lsvfs */, + FDF2771E0FC60FDF00D7A3C6 /* mklocale */, + FD201DAD14369AB300906237 /* pkill */, + FDF277270FC60FDF00D7A3C6 /* ps */, + FDF277320FC60FDF00D7A3C6 /* stty */, + FDF2773E0FC60FDF00D7A3C6 /* tabs */, + FDF277420FC60FDF00D7A3C6 /* tty */, + FDF277460FC60FDF00D7A3C6 /* whois */, + ); + name = Source; + sourceTree = "<group>"; + }; + FDF276DC0FC60FDF00D7A3C6 /* cap_mkdb */ = { + isa = PBXGroup; + children = ( + FDF276DE0FC60FDF00D7A3C6 /* cap_mkdb.c */, + FDF276DD0FC60FDF00D7A3C6 /* cap_mkdb.1 */, + ); + path = cap_mkdb; + sourceTree = "<group>"; + }; + FDF276E00FC60FDF00D7A3C6 /* colldef */ = { + isa = PBXGroup; + children = ( + FDF276E70FC60FDF00D7A3C6 /* parse.y */, + FDF276E80FC60FDF00D7A3C6 /* scan.l */, + FDF276E20FC60FDF00D7A3C6 /* common.h */, + FDF276E40FC60FDF00D7A3C6 /* locale */, + FDF276E10FC60FDF00D7A3C6 /* colldef.1 */, + ); + path = colldef; + sourceTree = "<group>"; + }; + FDF276E40FC60FDF00D7A3C6 /* locale */ = { + isa = PBXGroup; + children = ( + FDF276E50FC60FDF00D7A3C6 /* collate.h */, + ); + path = locale; + sourceTree = "<group>"; + }; + FDF276E90FC60FDF00D7A3C6 /* finger */ = { + isa = PBXGroup; + children = ( + FDF276EC0FC60FDF00D7A3C6 /* finger.c */, + FDF276EF0FC60FDF00D7A3C6 /* lprint.c */, + FDF276F10FC60FDF00D7A3C6 /* net.c */, + FDF276F30FC60FDF00D7A3C6 /* sprint.c */, + FDF276F40FC60FDF00D7A3C6 /* util.c */, + FDF276EA0FC60FDF00D7A3C6 /* extern.h */, + FDF276EE0FC60FDF00D7A3C6 /* finger.h */, + FDF276F20FC60FDF00D7A3C6 /* pathnames.h */, + FDF276EB0FC60FDF00D7A3C6 /* finger.1 */, + FDF276ED0FC60FDF00D7A3C6 /* finger.conf.5 */, + ); + path = finger; + sourceTree = "<group>"; + }; + FDF276F50FC60FDF00D7A3C6 /* fingerd */ = { + isa = PBXGroup; + children = ( + FDF276F80FC60FDF00D7A3C6 /* fingerd.c */, + FDF276FA0FC60FDF00D7A3C6 /* pathnames.h */, + FDF276F70FC60FDF00D7A3C6 /* fingerd.8 */, + FDF276F60FC60FDF00D7A3C6 /* finger.plist */, + ); + path = fingerd; + sourceTree = "<group>"; + }; + FDF276FB0FC60FDF00D7A3C6 /* gencat */ = { + isa = PBXGroup; + children = ( + FDF276FE0FC60FDF00D7A3C6 /* gencat.c */, + FDF277000FC60FDF00D7A3C6 /* genlib.c */, + FDF276FF0FC60FDF00D7A3C6 /* gencat.h */, + FDF276FD0FC60FDF00D7A3C6 /* gencat.1 */, + ); + path = gencat; + sourceTree = "<group>"; + }; + FDF277040FC60FDF00D7A3C6 /* last */ = { + isa = PBXGroup; + children = ( + FDF277050FC60FDF00D7A3C6 /* last.1 */, + FDF277060FC60FDF00D7A3C6 /* last.c */, + ); + path = last; + sourceTree = "<group>"; + }; + FDF277080FC60FDF00D7A3C6 /* locale */ = { + isa = PBXGroup; + children = ( + FDF277090FC60FDF00D7A3C6 /* locale.1 */, + FDF2770A0FC60FDF00D7A3C6 /* locale.cc */, + ); + path = locale; + sourceTree = "<group>"; + }; + FDF2770C0FC60FDF00D7A3C6 /* localedef */ = { + isa = PBXGroup; + children = ( + FDF279760FC629B100D7A3C6 /* localedef.pl */, + FDF277140FC60FDF00D7A3C6 /* localedef.1 */, + ); + path = localedef; + sourceTree = "<group>"; + }; + FDF277160FC60FDF00D7A3C6 /* lsvfs */ = { + isa = PBXGroup; + children = ( + FDF277170FC60FDF00D7A3C6 /* lsvfs.1 */, + FDF277180FC60FDF00D7A3C6 /* lsvfs.c */, + ); + path = lsvfs; + sourceTree = "<group>"; + }; + FDF2771E0FC60FDF00D7A3C6 /* mklocale */ = { + isa = PBXGroup; + children = ( + FDF277220FC60FDF00D7A3C6 /* lex.l */, + FDF277260FC60FDF00D7A3C6 /* yacc.y */, + FDF2771F0FC60FDF00D7A3C6 /* extern.h */, + FDF277210FC60FDF00D7A3C6 /* ldef.h */, + FDF277250FC60FDF00D7A3C6 /* runefile.h */, + FDF277240FC60FDF00D7A3C6 /* mklocale.1 */, + ); + path = mklocale; + sourceTree = "<group>"; + }; + FDF277270FC60FDF00D7A3C6 /* ps */ = { + isa = PBXGroup; + children = ( + FDF277290FC60FDF00D7A3C6 /* fmt.c */, + FDF2772A0FC60FDF00D7A3C6 /* keyword.c */, + FDF2772C0FC60FDF00D7A3C6 /* nlist.c */, + FDF2772D0FC60FDF00D7A3C6 /* print.c */, + FDF2772F0FC60FDF00D7A3C6 /* ps.c */, + FDF277310FC60FDF00D7A3C6 /* tasks.c */, + FDF277300FC60FDF00D7A3C6 /* ps.h */, + FDF277280FC60FDF00D7A3C6 /* extern.h */, + FDF2772E0FC60FDF00D7A3C6 /* ps.1 */, + ); + path = ps; + sourceTree = "<group>"; + }; + FDF277320FC60FDF00D7A3C6 /* stty */ = { + isa = PBXGroup; + children = ( + FDF277330FC60FDF00D7A3C6 /* cchar.c */, + FDF277350FC60FDF00D7A3C6 /* gfmt.c */, + FDF277360FC60FDF00D7A3C6 /* key.c */, + FDF277380FC60FDF00D7A3C6 /* modes.c */, + FDF277390FC60FDF00D7A3C6 /* print.c */, + FDF2773B0FC60FDF00D7A3C6 /* stty.c */, + FDF2773D0FC60FDF00D7A3C6 /* util.c */, + FDF277340FC60FDF00D7A3C6 /* extern.h */, + FDF2773C0FC60FDF00D7A3C6 /* stty.h */, + FDF2773A0FC60FDF00D7A3C6 /* stty.1 */, + ); + path = stty; + sourceTree = "<group>"; + }; + FDF2773E0FC60FDF00D7A3C6 /* tabs */ = { + isa = PBXGroup; + children = ( + FDF277400FC60FDF00D7A3C6 /* tabs.1 */, + FDF277410FC60FDF00D7A3C6 /* tabs.c */, + ); + path = tabs; + sourceTree = "<group>"; + }; + FDF277420FC60FDF00D7A3C6 /* tty */ = { + isa = PBXGroup; + children = ( + FDF277440FC60FDF00D7A3C6 /* tty.1 */, + FDF277450FC60FDF00D7A3C6 /* tty.c */, + ); + path = tty; + sourceTree = "<group>"; + }; + FDF277460FC60FDF00D7A3C6 /* whois */ = { + isa = PBXGroup; + children = ( + FDF277480FC60FDF00D7A3C6 /* whois.1 */, + FDF277490FC60FDF00D7A3C6 /* whois.c */, + ); + path = whois; + sourceTree = "<group>"; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + FD201DB414369B0300906237 /* pkill */ = { + isa = PBXNativeTarget; + buildConfigurationList = FD201DBC14369B0400906237 /* Build configuration list for PBXNativeTarget "pkill" */; + buildPhases = ( + FD201DB114369B0300906237 /* Sources */, + FD201DB214369B0300906237 /* Frameworks */, + FD201DB314369B0300906237 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = pkill; + productName = pkill; + productReference = FD201DB514369B0400906237 /* pkill */; + productType = "com.apple.product-type.tool"; + }; + FDF2765B0FC60EF600D7A3C6 /* ps */ = { + isa = PBXNativeTarget; + buildConfigurationList = FDF276600FC60EF700D7A3C6 /* Build configuration list for PBXNativeTarget "ps" */; + buildPhases = ( + FDF276590FC60EF600D7A3C6 /* Sources */, + FDF2765A0FC60EF600D7A3C6 /* Frameworks */, + FDF278300FC6160800D7A3C6 /* Install man1 */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = ps; + productName = ps; + productReference = FDF2765C0FC60EF600D7A3C6 /* ps */; + productType = "com.apple.product-type.tool"; + }; + FDF276630FC60EFD00D7A3C6 /* stty */ = { + isa = PBXNativeTarget; + buildConfigurationList = FDF276690FC60EFF00D7A3C6 /* Build configuration list for PBXNativeTarget "stty" */; + buildPhases = ( + FDF276610FC60EFD00D7A3C6 /* Sources */, + FDF276620FC60EFD00D7A3C6 /* Frameworks */, + FDF278030FC614B900D7A3C6 /* Install man1 */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = stty; + productName = stty; + productReference = FDF276640FC60EFD00D7A3C6 /* stty */; + productType = "com.apple.product-type.tool"; + }; + FDF276740FC60F2100D7A3C6 /* cap_mkdb */ = { + isa = PBXNativeTarget; + buildConfigurationList = FDF276C80FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "cap_mkdb" */; + buildPhases = ( + FDF276720FC60F2100D7A3C6 /* Sources */, + FDF276730FC60F2100D7A3C6 /* Frameworks */, + FDF277780FC610A400D7A3C6 /* Install man1 */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = cap_mkdb; + productName = cap_mkdb; + productReference = FDF276750FC60F2100D7A3C6 /* cap_mkdb */; + productType = "com.apple.product-type.tool"; + }; + FDF2767A0FC60F2A00D7A3C6 /* colldef */ = { + isa = PBXNativeTarget; + buildConfigurationList = FDF276C90FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "colldef" */; + buildPhases = ( + FDF276780FC60F2A00D7A3C6 /* Sources */, + FDF276790FC60F2A00D7A3C6 /* Frameworks */, + FDF279930FC62B0B00D7A3C6 /* Install man1 */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = colldef; + productName = colldef; + productReference = FDF2767B0FC60F2A00D7A3C6 /* colldef */; + productType = "com.apple.product-type.tool"; + }; + FDF276800FC60F3100D7A3C6 /* finger */ = { + isa = PBXNativeTarget; + buildConfigurationList = FDF276CA0FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "finger" */; + buildPhases = ( + FDF2767E0FC60F3100D7A3C6 /* Sources */, + FDF2767F0FC60F3100D7A3C6 /* Frameworks */, + FDF277A10FC611D800D7A3C6 /* Install man1 */, + FDF277A20FC611D800D7A3C6 /* Install man5 */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = finger; + productName = finger; + productReference = FDF276810FC60F3100D7A3C6 /* finger */; + productType = "com.apple.product-type.tool"; + }; + FDF2768C0FC60F3D00D7A3C6 /* gencat */ = { + isa = PBXNativeTarget; + buildConfigurationList = FDF276CC0FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "gencat" */; + buildPhases = ( + FDF2768A0FC60F3D00D7A3C6 /* Sources */, + FDF2768B0FC60F3D00D7A3C6 /* Frameworks */, + FDF279300FC625CB00D7A3C6 /* Install man1 */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = gencat; + productName = gencat; + productReference = FDF2768D0FC60F3D00D7A3C6 /* gencat */; + productType = "com.apple.product-type.tool"; + }; + FDF276920FC60F4B00D7A3C6 /* last */ = { + isa = PBXNativeTarget; + buildConfigurationList = FDF276CD0FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "last" */; + buildPhases = ( + FDF276900FC60F4B00D7A3C6 /* Sources */, + FDF276910FC60F4B00D7A3C6 /* Frameworks */, + FDF278E70FC620B600D7A3C6 /* Install man1 */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = last; + productName = last; + productReference = FDF276930FC60F4B00D7A3C6 /* last */; + productType = "com.apple.product-type.tool"; + }; + FDF276980FC60F5000D7A3C6 /* locale */ = { + isa = PBXNativeTarget; + buildConfigurationList = FDF276CE0FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "locale" */; + buildPhases = ( + FDF276960FC60F5000D7A3C6 /* Sources */, + FDF276970FC60F5000D7A3C6 /* Frameworks */, + FDF278E80FC620B600D7A3C6 /* Install man1 */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = locale; + productName = locale; + productReference = FDF276990FC60F5000D7A3C6 /* locale */; + productType = "com.apple.product-type.tool"; + }; + FDF276A40FC60F5E00D7A3C6 /* lsvfs */ = { + isa = PBXNativeTarget; + buildConfigurationList = FDF276D00FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "lsvfs" */; + buildPhases = ( + FDF276A20FC60F5E00D7A3C6 /* Sources */, + FDF276A30FC60F5E00D7A3C6 /* Frameworks */, + FDF278D50FC6201600D7A3C6 /* Install man1 */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = lsvfs; + productName = lsvfs; + productReference = FDF276A50FC60F5E00D7A3C6 /* lsvfs */; + productType = "com.apple.product-type.tool"; + }; + FDF276B00FC60F7600D7A3C6 /* mklocale */ = { + isa = PBXNativeTarget; + buildConfigurationList = FDF276D20FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "mklocale" */; + buildPhases = ( + FDF276AE0FC60F7600D7A3C6 /* Sources */, + FDF276AF0FC60F7600D7A3C6 /* Frameworks */, + FDF278A40FC61D9600D7A3C6 /* Install man1 */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = mklocale; + productName = mklocale; + productReference = FDF276B10FC60F7600D7A3C6 /* mklocale */; + productType = "com.apple.product-type.tool"; + }; + FDF276B60FC60F7F00D7A3C6 /* tabs */ = { + isa = PBXNativeTarget; + buildConfigurationList = FDF276D30FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "tabs" */; + buildPhases = ( + FDF276B40FC60F7F00D7A3C6 /* Sources */, + FDF276B50FC60F7F00D7A3C6 /* Frameworks */, + FDF277E60FC6143000D7A3C6 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = tabs; + productName = tabs; + productReference = FDF276B70FC60F7F00D7A3C6 /* tabs */; + productType = "com.apple.product-type.tool"; + }; + FDF276BC0FC60F8400D7A3C6 /* tty */ = { + isa = PBXNativeTarget; + buildConfigurationList = FDF276D40FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "tty" */; + buildPhases = ( + FDF276BA0FC60F8400D7A3C6 /* Sources */, + FDF276BB0FC60F8400D7A3C6 /* Frameworks */, + FDF277C60FC6135D00D7A3C6 /* Install man1 */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = tty; + productName = tty; + productReference = FDF276BD0FC60F8400D7A3C6 /* tty */; + productType = "com.apple.product-type.tool"; + }; + FDF276C20FC60F8A00D7A3C6 /* whois */ = { + isa = PBXNativeTarget; + buildConfigurationList = FDF276D50FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "whois" */; + buildPhases = ( + FDF276C00FC60F8A00D7A3C6 /* Sources */, + FDF276C10FC60F8A00D7A3C6 /* Frameworks */, + FDF277C30FC612D900D7A3C6 /* Install man1 */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = whois; + productName = whois; + productReference = FDF276C30FC60F8A00D7A3C6 /* whois */; + productType = "com.apple.product-type.tool"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + FDF276430FC60E9000D7A3C6 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0820; + }; + buildConfigurationList = FDF276460FC60E9000D7A3C6 /* Build configuration list for PBXProject "adv_cmds" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = FDF276410FC60E9000D7A3C6; + productRefGroup = FDF2765D0FC60EF600D7A3C6 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + FDF276500FC60EDA00D7A3C6 /* Desktop */, + FDF2764E0FC60ECD00D7A3C6 /* Embedded */, + FDF276740FC60F2100D7A3C6 /* cap_mkdb */, + FDF2767A0FC60F2A00D7A3C6 /* colldef */, + FDF276800FC60F3100D7A3C6 /* finger */, + FDF2768C0FC60F3D00D7A3C6 /* gencat */, + FDF276920FC60F4B00D7A3C6 /* last */, + FDF276980FC60F5000D7A3C6 /* locale */, + FD0D7F98108FE550004F2A1C /* localedef */, + FDF276A40FC60F5E00D7A3C6 /* lsvfs */, + FDF276B00FC60F7600D7A3C6 /* mklocale */, + FD201DCD14369D0C00906237 /* pgrep */, + FD201DB414369B0300906237 /* pkill */, + FDF2765B0FC60EF600D7A3C6 /* ps */, + FDF276630FC60EFD00D7A3C6 /* stty */, + FDF276B60FC60F7F00D7A3C6 /* tabs */, + FDF276BC0FC60F8400D7A3C6 /* tty */, + FDF276C20FC60F8A00D7A3C6 /* whois */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXShellScriptBuildPhase section */ + FD0D7F97108FE550004F2A1C /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 8; + files = ( + ); + inputPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 1; + shellPath = /bin/sh; + shellScript = "set -ex\n/usr/bin/install -m ${INSTALL_MODE_FLAG} ${SRCROOT}/localedef/localedef.pl ${INSTALL_DIR}/localedef\n${CHMOD} +x ${INSTALL_DIR}/localedef"; + }; + FD201DD014369D1000906237 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 8; + files = ( + ); + inputPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 1; + shellPath = /bin/sh; + shellScript = ". ${SRCROOT}/xcodescripts/variant_links.sh"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + FD201DB114369B0300906237 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + FD201DC214369B4200906237 /* pkill.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + FDF276590FC60EF600D7A3C6 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + FDF278060FC6151E00D7A3C6 /* fmt.c in Sources */, + FDF278070FC6151E00D7A3C6 /* keyword.c in Sources */, + FDF278080FC6151E00D7A3C6 /* nlist.c in Sources */, + FDF278090FC6151E00D7A3C6 /* print.c in Sources */, + FDF2780A0FC6151E00D7A3C6 /* ps.c in Sources */, + FDF2780B0FC6151E00D7A3C6 /* tasks.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + FDF276610FC60EFD00D7A3C6 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + FDF277EE0FC6148500D7A3C6 /* cchar.c in Sources */, + FDF277EF0FC6148500D7A3C6 /* gfmt.c in Sources */, + FDF277F00FC6148500D7A3C6 /* key.c in Sources */, + FDF277F10FC6148500D7A3C6 /* modes.c in Sources */, + FDF277F20FC6148500D7A3C6 /* print.c in Sources */, + FDF277F30FC6148500D7A3C6 /* stty.c in Sources */, + FDF277F40FC6148500D7A3C6 /* util.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + FDF276720FC60F2100D7A3C6 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + FDF2774B0FC6100400D7A3C6 /* cap_mkdb.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + FDF276780FC60F2A00D7A3C6 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + FDF279390FC6263E00D7A3C6 /* parse.y in Sources */, + FDF2793A0FC6263E00D7A3C6 /* scan.l in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + FDF2767E0FC60F3100D7A3C6 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + FDF277790FC610EC00D7A3C6 /* finger.c in Sources */, + FDF2777A0FC610EC00D7A3C6 /* lprint.c in Sources */, + FDF2777B0FC610EC00D7A3C6 /* net.c in Sources */, + FDF2777C0FC610EC00D7A3C6 /* sprint.c in Sources */, + FDF2777D0FC610EC00D7A3C6 /* util.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + FDF2768A0FC60F3D00D7A3C6 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + FDF278F50FC623D300D7A3C6 /* gencat.c in Sources */, + FDF278F60FC623D300D7A3C6 /* genlib.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + FDF276900FC60F4B00D7A3C6 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + FDF278DB0FC6208600D7A3C6 /* last.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + FDF276960FC60F5000D7A3C6 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + FDF278D60FC6204E00D7A3C6 /* locale.cc in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + FDF276A20FC60F5E00D7A3C6 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + FDF278C60FC61FDF00D7A3C6 /* lsvfs.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + FDF276AE0FC60F7600D7A3C6 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + FDF278380FC6167800D7A3C6 /* yacc.y in Sources */, + FDF278370FC6167800D7A3C6 /* lex.l in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + FDF276B40FC60F7F00D7A3C6 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + FDF277D70FC613F500D7A3C6 /* tabs.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + FDF276BA0FC60F8400D7A3C6 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + FDF277C40FC6133400D7A3C6 /* tty.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + FDF276C00FC60F8A00D7A3C6 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + FDF277BE0FC612B000D7A3C6 /* whois.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + FD0D7FA9108FE5C3004F2A1C /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = FD0D7F98108FE550004F2A1C /* localedef */; + targetProxy = FD0D7FA8108FE5C3004F2A1C /* PBXContainerItemProxy */; + }; + FD201DBF14369B1700906237 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = FD201DB414369B0300906237 /* pkill */; + targetProxy = FD201DBE14369B1700906237 /* PBXContainerItemProxy */; + }; + FD201DC114369B1D00906237 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = FD201DB414369B0300906237 /* pkill */; + targetProxy = FD201DC014369B1D00906237 /* PBXContainerItemProxy */; + }; + FD201DD214369D5C00906237 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = FD201DB414369B0300906237 /* pkill */; + targetProxy = FD201DD114369D5C00906237 /* PBXContainerItemProxy */; + }; + FD201DD414369D6300906237 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = FD201DCD14369D0C00906237 /* pgrep */; + targetProxy = FD201DD314369D6300906237 /* PBXContainerItemProxy */; + }; + FD201DD614369D6700906237 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = FD201DCD14369D0C00906237 /* pgrep */; + targetProxy = FD201DD514369D6700906237 /* PBXContainerItemProxy */; + }; + FDF2766B0FC60F0D00D7A3C6 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = FDF276630FC60EFD00D7A3C6 /* stty */; + targetProxy = FDF2766A0FC60F0D00D7A3C6 /* PBXContainerItemProxy */; + }; + FDF2766D0FC60F0D00D7A3C6 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = FDF2765B0FC60EF600D7A3C6 /* ps */; + targetProxy = FDF2766C0FC60F0D00D7A3C6 /* PBXContainerItemProxy */; + }; + FDF2766F0FC60F0F00D7A3C6 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = FDF2765B0FC60EF600D7A3C6 /* ps */; + targetProxy = FDF2766E0FC60F0F00D7A3C6 /* PBXContainerItemProxy */; + }; + FDF276710FC60F1300D7A3C6 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = FDF276630FC60EFD00D7A3C6 /* stty */; + targetProxy = FDF276700FC60F1300D7A3C6 /* PBXContainerItemProxy */; + }; + FDF277530FC6102600D7A3C6 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = FDF276B00FC60F7600D7A3C6 /* mklocale */; + targetProxy = FDF277520FC6102600D7A3C6 /* PBXContainerItemProxy */; + }; + FDF277570FC6102600D7A3C6 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = FDF276A40FC60F5E00D7A3C6 /* lsvfs */; + targetProxy = FDF277560FC6102600D7A3C6 /* PBXContainerItemProxy */; + }; + FDF2775B0FC6102600D7A3C6 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = FDF276980FC60F5000D7A3C6 /* locale */; + targetProxy = FDF2775A0FC6102600D7A3C6 /* PBXContainerItemProxy */; + }; + FDF2775D0FC6102600D7A3C6 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = FDF276920FC60F4B00D7A3C6 /* last */; + targetProxy = FDF2775C0FC6102600D7A3C6 /* PBXContainerItemProxy */; + }; + FDF2775F0FC6102600D7A3C6 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = FDF2768C0FC60F3D00D7A3C6 /* gencat */; + targetProxy = FDF2775E0FC6102600D7A3C6 /* PBXContainerItemProxy */; + }; + FDF277630FC6102600D7A3C6 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = FDF276800FC60F3100D7A3C6 /* finger */; + targetProxy = FDF277620FC6102600D7A3C6 /* PBXContainerItemProxy */; + }; + FDF277650FC6102600D7A3C6 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = FDF2767A0FC60F2A00D7A3C6 /* colldef */; + targetProxy = FDF277640FC6102600D7A3C6 /* PBXContainerItemProxy */; + }; + FDF277670FC6102600D7A3C6 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = FDF276740FC60F2100D7A3C6 /* cap_mkdb */; + targetProxy = FDF277660FC6102600D7A3C6 /* PBXContainerItemProxy */; + }; + FDF277690FC6102B00D7A3C6 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = FDF276C20FC60F8A00D7A3C6 /* whois */; + targetProxy = FDF277680FC6102B00D7A3C6 /* PBXContainerItemProxy */; + }; + FDF2776B0FC6102B00D7A3C6 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = FDF276BC0FC60F8400D7A3C6 /* tty */; + targetProxy = FDF2776A0FC6102B00D7A3C6 /* PBXContainerItemProxy */; + }; + FDF2776D0FC6102B00D7A3C6 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = FDF276B60FC60F7F00D7A3C6 /* tabs */; + targetProxy = FDF2776C0FC6102B00D7A3C6 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + FD0D7F99108FE550004F2A1C /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + INSTALL_PATH = /usr/bin; + PRODUCT_NAME = localedef; + }; + name = Release; + }; + FD201DBD14369B0400906237 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_ENTITLEMENTS = pkill/entitlements.plist; + INSTALL_PATH = /usr/bin; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; + FD201DCF14369D0C00906237 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; + FDF276450FC60E9000D7A3C6 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = YES; + CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)"; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_MISSING_NEWLINE = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_CHECK_SWITCH_STATEMENTS = YES; + GCC_WARN_MISSING_PARENTHESES = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNKNOWN_PRAGMAS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_LABEL = YES; + GCC_WARN_UNUSED_VALUE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + PREBINDING = NO; + SDKROOT = macosx.internal; + USE_HEADERMAP = NO; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = __; + ZERO_LINK = NO; + }; + name = Release; + }; + FDF2764F0FC60ECD00D7A3C6 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = Embedded; + }; + name = Release; + }; + FDF276510FC60EDA00D7A3C6 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = Desktop; + }; + name = Release; + }; + FDF2765F0FC60EF700D7A3C6 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_ENTITLEMENTS = ps/entitlements.plist; + GCC_PREPROCESSOR_DEFINITIONS = "__FBSDID=__RCSID"; + "INSTALL_MODE_FLAG[sdk=macosx*]" = "u+sw,go-w,a+rX"; + INSTALL_PATH = /bin; + PRODUCT_NAME = ps; + WARNING_CFLAGS = "-Wno-#warnings"; + }; + name = Release; + }; + FDF276660FC60EFD00D7A3C6 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + INSTALL_PATH = /bin; + PRODUCT_NAME = stty; + }; + name = Release; + }; + FDF276770FC60F2100D7A3C6 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + INSTALL_PATH = /usr/bin; + PRODUCT_NAME = cap_mkdb; + }; + name = Release; + }; + FDF2767D0FC60F2A00D7A3C6 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_PREPROCESSOR_DEFINITIONS = ( + "__FBSDID=__RCSID", + COLLATE_DEBUG, + YY_NO_UNPUT, + ); + GCC_WARN_UNUSED_FUNCTION = NO; + GCC_WARN_UNUSED_VARIABLE = NO; + INSTALL_PATH = /usr/bin; + LEXFLAGS = "-8"; + LEX_CASE_INSENSITIVE_SCANNER = YES; + PRODUCT_NAME = colldef; + USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/colldef $(SRCROOT)/colldef/locale"; + }; + name = Release; + }; + FDF276830FC60F3100D7A3C6 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_PREPROCESSOR_DEFINITIONS = "__FBSDID=__RCSID"; + INSTALL_PATH = /usr/bin; + PRODUCT_NAME = finger; + }; + name = Release; + }; + FDF2768F0FC60F3E00D7A3C6 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_PREPROCESSOR_DEFINITIONS = "__FBSDID=__RCSID"; + INSTALL_PATH = /usr/bin; + PRODUCT_NAME = gencat; + }; + name = Release; + }; + FDF276950FC60F4C00D7A3C6 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + INSTALL_PATH = /usr/bin; + PRODUCT_NAME = last; + }; + name = Release; + }; + FDF2769B0FC60F5100D7A3C6 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + INSTALL_PATH = /usr/bin; + PRODUCT_NAME = locale; + }; + name = Release; + }; + FDF276A70FC60F5F00D7A3C6 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + INSTALL_PATH = /usr/bin; + PRODUCT_NAME = lsvfs; + }; + name = Release; + }; + FDF276B30FC60F7700D7A3C6 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_PREPROCESSOR_DEFINITIONS = "__FBSDID=__RCSID"; + INSTALL_PATH = /usr/bin; + PRODUCT_NAME = mklocale; + USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/mklocale"; + }; + name = Release; + }; + FDF276B90FC60F8000D7A3C6 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_PREPROCESSOR_DEFINITIONS = "__FBSDID=__RCSID"; + INSTALL_PATH = /usr/bin; + PRODUCT_NAME = tabs; + }; + name = Release; + }; + FDF276BF0FC60F8500D7A3C6 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_PREPROCESSOR_DEFINITIONS = "__FBSDID=__RCSID"; + INSTALL_PATH = /usr/bin; + PRODUCT_NAME = tty; + }; + name = Release; + }; + FDF276C50FC60F8A00D7A3C6 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + INSTALL_PATH = /usr/bin; + PRODUCT_NAME = whois; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + FD0D7FA2108FE56E004F2A1C /* Build configuration list for PBXAggregateTarget "localedef" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + FD0D7F99108FE550004F2A1C /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + FD201DBC14369B0400906237 /* Build configuration list for PBXNativeTarget "pkill" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + FD201DBD14369B0400906237 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + FD201DCE14369D0C00906237 /* Build configuration list for PBXAggregateTarget "pgrep" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + FD201DCF14369D0C00906237 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + FDF276460FC60E9000D7A3C6 /* Build configuration list for PBXProject "adv_cmds" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + FDF276450FC60E9000D7A3C6 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + FDF276570FC60EE600D7A3C6 /* Build configuration list for PBXAggregateTarget "Desktop" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + FDF276510FC60EDA00D7A3C6 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + FDF276580FC60EE600D7A3C6 /* Build configuration list for PBXAggregateTarget "Embedded" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + FDF2764F0FC60ECD00D7A3C6 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + FDF276600FC60EF700D7A3C6 /* Build configuration list for PBXNativeTarget "ps" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + FDF2765F0FC60EF700D7A3C6 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + FDF276690FC60EFF00D7A3C6 /* Build configuration list for PBXNativeTarget "stty" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + FDF276660FC60EFD00D7A3C6 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + FDF276C80FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "cap_mkdb" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + FDF276770FC60F2100D7A3C6 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + FDF276C90FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "colldef" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + FDF2767D0FC60F2A00D7A3C6 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + FDF276CA0FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "finger" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + FDF276830FC60F3100D7A3C6 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + FDF276CC0FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "gencat" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + FDF2768F0FC60F3E00D7A3C6 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + FDF276CD0FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "last" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + FDF276950FC60F4C00D7A3C6 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + FDF276CE0FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "locale" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + FDF2769B0FC60F5100D7A3C6 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + FDF276D00FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "lsvfs" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + FDF276A70FC60F5F00D7A3C6 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + FDF276D20FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "mklocale" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + FDF276B30FC60F7700D7A3C6 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + FDF276D30FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "tabs" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + FDF276B90FC60F8000D7A3C6 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + FDF276D40FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "tty" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + FDF276BF0FC60F8500D7A3C6 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + FDF276D50FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "whois" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + FDF276C50FC60F8A00D7A3C6 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = FDF276430FC60E9000D7A3C6 /* Project object */; +} diff --git a/adv_cmds/adv_cmds.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/adv_cmds/adv_cmds.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/adv_cmds/adv_cmds.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?> +<Workspace + version = "1.0"> + <FileRef + location = "self:"> + </FileRef> +</Workspace> diff --git a/adv_cmds/cap_mkdb/cap_mkdb.1 b/adv_cmds/cap_mkdb/cap_mkdb.1 new file mode 100644 index 0000000..5bc4674 --- /dev/null +++ b/adv_cmds/cap_mkdb/cap_mkdb.1 @@ -0,0 +1,101 @@ +.\" Copyright (c) 1992, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)cap_mkdb.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd "June 6, 1993" +.Dt CAP_MKDB 1 +.Os +.Sh NAME +.Nm cap_mkdb +.Nd create capability database +.Pp +.Sh SYNOPSIS +.Nm cap_mkdb +.Op Fl v +.Op Fl f Ar outfile +.Ar file1 +.Op Ar file2 ... +.Pp +.Sh DESCRIPTION +.Nm Cap_mkdb +builds a hashed database out of the +.Xr getcap 3 +logical database constructed by the concatenation of the specified +files . +.Pp +The database is named by the basename of the first file argument and +the string +.Dq .db . +The +.Xr getcap 3 +routines can access the database in this form much more quickly +than they can the original text file(s). +.Pp +The ``tc'' capabilities of the records are expanded before the +record is stored into the database. +.Pp +The options as as follows: +.Bl -tag -width XXXXXX +.It Fl f Ar outfile +Specify a different database basename. +.It Fl v +Print out the number of capability records in the database. +.El +.Pp +.Sh FORMAT +Each record is stored in the database using two different types of keys. +.Pp +The first type is a key which consists of the first capability of +the record (not including the trailing colon (``:'')) with a data +field consisting of a special byte followed by the rest of the record. +The special byte is either a 0 or 1, where a 0 means that the record +is okay, and a 1 means that there was a ``tc'' capability in the record +that couldn't be expanded. +.Pp +The second type is a key which consists of one of the names from the +first capability of the record with a data field consisting a special +byte followed by the the first capability of the record. +The special byte is a 2. +.Pp +In normal operation names are looked up in the database, resulting +in a key/data pair of the second type. +The data field of this key/data pair is used to look up a key/data +pair of the first type which has the real data associated with the +name. +.Sh RETURN VALUE +The +.Nm cap_mkdb +utility exits 0 on success and >0 if an error occurs. +.Sh SEE ALSO +.Xr dbopen 3 , +.Xr getcap 3 , +.Xr termcap 5 diff --git a/adv_cmds/cap_mkdb/cap_mkdb.c b/adv_cmds/cap_mkdb/cap_mkdb.c new file mode 100644 index 0000000..9c26d59 --- /dev/null +++ b/adv_cmds/cap_mkdb/cap_mkdb.c @@ -0,0 +1,228 @@ +/* + * Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved + * + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * The NEXTSTEP Software License Agreement specifies the terms + * and conditions for redistribution. + * + * @(#)cap_mkdb.c 8.2 (Berkeley) 4/27/95 + */ + +#include <sys/param.h> +#include <sys/stat.h> + +#include <db.h> +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +void db_build __P((char **)); +void dounlink __P((void)); +void usage __P((void)); + +DB *capdbp; +int verbose; +char *capdb, *capname, buf[8 * 1024]; + +HASHINFO openinfo = { + 4096, /* bsize */ + 16, /* ffactor */ + 256, /* nelem */ + 2048 * 1024, /* cachesize */ + NULL, /* hash() */ + 0 /* lorder */ +}; + +/* + * Mkcapdb creates a capability hash database for quick retrieval of capability + * records. The database contains 2 types of entries: records and references + * marked by the first byte in the data. A record entry contains the actual + * capability record whereas a reference contains the name (key) under which + * the correct record is stored. + */ +int +main(argc, argv) + int argc; + char *argv[]; +{ + int c; + + capname = NULL; + while ((c = getopt(argc, argv, "f:v")) != EOF) { + switch(c) { + case 'f': + capname = optarg; + break; + case 'v': + verbose = 1; + break; + case '?': + default: + usage(); + } + } + argc -= optind; + argv += optind; + + if (*argv == NULL) + usage(); + + /* + * The database file is the first argument if no name is specified. + * Make arrangements to unlink it if exit badly. + */ + (void)snprintf(buf, sizeof(buf), "%s.db", capname ? capname : *argv); + if ((capname = strdup(buf)) == NULL) + err(1, ""); + if ((capdbp = dbopen(capname, O_CREAT | O_TRUNC | O_RDWR, + DEFFILEMODE, DB_HASH, &openinfo)) == NULL) + err(1, "%s", buf); + + if (atexit(dounlink)) + err(1, "atexit"); + + db_build(argv); + + if (capdbp->close(capdbp) < 0) + err(1, "%s", capname); + capname = NULL; + exit(0); +} + +void +dounlink() +{ + if (capname != NULL) + (void)unlink(capname); +} + +/* + * Any changes to these definitions should be made also in the getcap(3) + * library routines. + */ +#define RECOK (char)0 +#define TCERR (char)1 +#define SHADOW (char)2 + +/* + * Db_build() builds the name and capabilty databases according to the + * details above. + */ +void +db_build(ifiles) + char **ifiles; +{ + DBT key, data; + recno_t reccnt; + size_t len, bplen; + int st; + char *bp, *p, *t; + + data.data = NULL; + key.data = NULL; + for (reccnt = 0, bplen = 0; (st = cgetnext(&bp, ifiles)) > 0;) { + + /* + * Allocate enough memory to store record, terminating + * NULL and one extra byte. + */ + len = strlen(bp); + if (bplen <= len + 2) { + bplen += MAX(256, len + 2); + if ((data.data = realloc(data.data, bplen)) == NULL) + err(1, ""); + } + + /* Find the end of the name field. */ + if ((p = strchr(bp, ':')) == NULL) { + warnx("no name field: %.*s", MIN(len, 20), bp); + continue; + } + + /* First byte of stored record indicates status. */ + switch(st) { + case 1: + ((char *)(data.data))[0] = RECOK; + break; + case 2: + ((char *)(data.data))[0] = TCERR; + warnx("Record not tc expanded: %.*s", p - bp, bp); + break; + } + + /* Create the stored record. */ + memmove(&((u_char *)(data.data))[1], bp, len + 1); + data.size = len + 2; + + /* Store the record under the name field. */ + key.data = bp; + key.size = p - bp; + + switch(capdbp->put(capdbp, &key, &data, R_NOOVERWRITE)) { + case -1: + err(1, "put"); + /* NOTREACHED */ + case 1: + warnx("ignored duplicate: %.*s", + key.size, (char *)key.data); + continue; + } + ++reccnt; + + /* If only one name, ignore the rest. */ + if ((p = strchr(bp, '|')) == NULL) + continue; + + /* The rest of the names reference the entire name. */ + ((char *)(data.data))[0] = SHADOW; + memmove(&((u_char *)(data.data))[1], key.data, key.size); + data.size = key.size + 1; + + /* Store references for other names. */ + for (p = t = bp;; ++p) { + if (p > t && (*p == ':' || *p == '|')) { + key.size = p - t; + key.data = t; + switch(capdbp->put(capdbp, + &key, &data, R_NOOVERWRITE)) { + case -1: + err(1, "put"); + /* NOTREACHED */ + case 1: + warnx("ignored duplicate: %.*s", + key.size, (char *)key.data); + } + t = p + 1; + } + if (*p == ':') + break; + } + } + + switch(st) { + case -1: + err(1, "file argument"); + /* NOTREACHED */ + case -2: + errx(1, "potential reference loop detected"); + /* NOTREACHED */ + } + + if (verbose) + (void)printf("cap_mkdb: %d capability records\n", reccnt); +} + +void +usage() +{ + (void)fprintf(stderr, + "usage: cap_mkdb [-v] [-f outfile] file1 [file2 ...]\n"); + exit(1); +} diff --git a/adv_cmds/colldef/colldef.1 b/adv_cmds/colldef/colldef.1 new file mode 100644 index 0000000..f4f875b --- /dev/null +++ b/adv_cmds/colldef/colldef.1 @@ -0,0 +1,274 @@ +.\" Copyright (c) 1995 Alex Tatmanjants <alex@elvisti.kiev.ua> +.\" at Electronni Visti IA, Kiev, Ukraine. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD: src/usr.bin/colldef/colldef.1,v 1.21 2004/05/19 09:45:46 ru Exp $ +.\" +.Dd January 27, 1995 +.Dt COLLDEF 1 +.Os +.Sh NAME +.Nm colldef +.Nd convert collation sequence source definition +.Sh SYNOPSIS +.Nm +.Op Fl I Ar map_dir +.Op Fl o Ar out_file +.Op Ar filename +.Sh DESCRIPTION +The +.Nm +utility converts a collation sequence source definition +into a format usable by the +.Fn strxfrm +and +.Fn strcoll +functions. +It is used to define the many ways in which +strings can be ordered and collated. +The +.Fn strxfrm +function transforms +its first argument and places the result in its second +argument. +The transformed string is such that it can be +correctly ordered with other transformed strings by using +.Fn strcmp , +.Fn strncmp , +or +.Fn memcmp . +The +.Fn strcoll +function transforms its arguments and does a +comparison. +.Pp +The +.Nm +utility reads the collation sequence source definition +from the standard input and stores the converted definition in filename. +The output file produced contains the +database with collating sequence information in a form +usable by system commands and routines. +.Pp +The following options are available: +.Bl -tag -width indent +.It Fl I Ar map_dir +Set directory name where +.Ar charmap +files can be found, current directory by default. +.It Fl o Ar out_file +Set output file name, +.Ar LC_COLLATE +by default. +.El +.Pp +The collation sequence definition specifies a set of collating elements and +the rules defining how strings containing these should be ordered. +This is most useful for different language definitions. +.Pp +The specification file can consist of three statements: +.Ar charmap , +.Ar substitute +and +.Ar order . +.Pp +Of these, only the +.Ar order +statement is required. +When +.Ar charmap +or +.Ar substitute +is +supplied, these statements must be ordered as above. +Any +statements after the order statement are ignored. +.Pp +Lines in the specification file beginning with a +.Ql # +are +treated as comments and are ignored. +Blank lines are also +ignored. +.Pp +.Dl "charmap charmapfile" +.Pp +.Ar Charmap +defines where a mapping of the character +and collating element symbols to the actual +character encoding can be found. +.Pp +The format of +.Ar charmapfile +is shown below. +Symbol +names are separated from their values by TAB or +SPACE characters. +Symbol-value can be specified in +a hexadecimal (\ex\fI??\fR) or octal (\e\fI???\fR) +representation, and can be only one character in length. +.Pp +.Bd -literal -offset indent +symbol-name1 symbol-value1 +symbol-name2 symbol-value2 +\&... +.Ed +.Pp +Symbol names cannot be specified in +.Ar substitute +fields. +.Pp +The +.Ar charmap +statement is optional. +.Pp +.Bd -literal -offset indent +substitute "symbol" with "repl_string" +.Ed +.Pp +The +.Ar substitute +statement substitutes the character +.Ar symbol +with the string +.Ar repl_string . +Symbol names cannot be specified in +.Ar repl_string +field. +The +.Ar substitute +statement is optional. +.Pp +.Dl "order order_list" +.Pp +.Ar Order_list +is a list of symbols, separated by semi colons, that defines the +collating sequence. +The +special symbol +.Ar ... +specifies, in a short-hand +form, symbols that are sequential in machine code +order. +.Pp +An order list element +can be represented in any one of the following +ways: +.Bl -bullet +.It +The symbol itself (for example, +.Ar a +for the lower-case letter +.Ar a ) . +.It +The symbol in octal representation (for example, +.Ar \e141 +for the letter +.Ar a ) . +.It +The symbol in hexadecimal representation (for example, +.Ar \ex61 +for the letter +.Ar a ) . +.It +The symbol name as defined in the +.Ar charmap +file (for example, +.Ar <letterA> +for +.Ar letterA \e023 +record in +.Ar charmapfile ) . +If character map name have +.Ar > +character, it must be escaped as +.Ar /> , +single +.Ar / +must be escaped as +.Ar // . +.It +Symbols +.Ar \ea , +.Ar \eb , +.Ar \ef , +.Ar \en , +.Ar \er , +.Ar \ev +are permitted in its usual C-language meaning. +.It +The symbol chain (for example: +.Ar abc , +.Ar <letterA><letterB>c , +.Ar \exf1b\exf2 ) +.It +The symbol range (for example, +.Ar a;...;z ) . +.It +Comma-separated symbols, ranges and chains enclosed in parenthesis (for example +.Ar \&( +.Ar sym1 , +.Ar sym2 , +.Ar ... +.Ar \&) ) +are assigned the +same primary ordering but different secondary +ordering. +.It +Comma-separated symbols, ranges and chains enclosed in curly brackets (for example +.Ar \&{ +.Ar sym1 , +.Ar sym2 , +.Ar ... +.Ar \&} ) +are assigned the same primary ordering only. +.El +.Pp +The backslash character +.Ar \e +is used for continuation. +In this case, no characters are permitted +after the backslash character. +.Sh DIAGNOSTICS +The +.Nm +utility exits with the following values: +.Bl -tag -width indent +.It Li 0 +No errors were found and the output was successfully created. +.It Li !=0 +Errors were found. +.El +.Sh FILES +.Bl -tag -width indent +.It Pa /usr/share/locale/ Ns Ao Ar language Ac Ns Pa /LC_COLLATE +The standard shared location for collation orders +under the locale +.Aq Ar language . +.El +.Sh SEE ALSO +.Xr mklocale 1 , +.Xr setlocale 3 , +.Xr strcoll 3 , +.Xr strxfrm 3 diff --git a/adv_cmds/colldef/common.h b/adv_cmds/colldef/common.h new file mode 100644 index 0000000..b59c125 --- /dev/null +++ b/adv_cmds/colldef/common.h @@ -0,0 +1,36 @@ +/* + * $FreeBSD: src/usr.bin/colldef/common.h,v 1.2 2001/11/28 09:50:24 ache Exp $ + */ + +#include <sys/types.h> +#include <db.h> +#include <fcntl.h> + +#define CHARMAP_SYMBOL_LEN 64 +#define BUFSIZE 80 + +#define NOTEXISTS 0 +#define EXISTS 1 + +#define SYMBOL_CHAR 0 +#define SYMBOL_CHAIN 1 +#define SYMBOL_SYMBOL 2 +#define SYMBOL_STRING 3 +#define SYMBOL_IGNORE 4 +#define SYMBOL_ELLIPSIS 5 +struct symbol { + int type; + int val; + wchar_t name[CHARMAP_SYMBOL_LEN]; + union { + wchar_t wc; + wchar_t str[STR_LEN]; + } u; +}; + +extern int line_no; + +struct symbol *getsymbol(const wchar_t *, int); +extern char *showwcs(const wchar_t *, int); + +extern char map_name[FILENAME_MAX]; diff --git a/adv_cmds/colldef/locale/collate.h b/adv_cmds/colldef/locale/collate.h new file mode 100644 index 0000000..494e231 --- /dev/null +++ b/adv_cmds/colldef/locale/collate.h @@ -0,0 +1,121 @@ +/*- + * Copyright (c) 1995 Alex Tatmanjants <alex@elvisti.kiev.ua> + * at Electronni Visti IA, Kiev, Ukraine. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libc/locale/collate.h,v 1.14 2002/08/30 20:26:02 ache Exp $ + */ + +#ifndef _COLLATE_H_ +#define _COLLATE_H_ + +#include <sys/cdefs.h> +#ifndef __LIBC__ +#include <sys/types.h> +#endif /* !__LIBC__ */ +#include <limits.h> + +#define STR_LEN 10 +#define TABLE_SIZE 100 +#define COLLATE_VERSION "1.0\n" +#define COLLATE_VERSION1_1 "1.1\n" +#define COLLATE_VERSION1_1A "1.1A\n" +/* see discussion in string/FreeBSD/strxfrm for this value */ +#define COLLATE_MAX_PRIORITY ((1 << 24) - 1) + +#define DIRECTIVE_UNDEF 0x00 +#define DIRECTIVE_FORWARD 0x01 +#define DIRECTIVE_BACKWARD 0x02 +#define DIRECTIVE_POSITION 0x04 + +#define DIRECTIVE_DIRECTION_MASK (DIRECTIVE_FORWARD | DIRECTIVE_BACKWARD) + +#define COLLATE_SUBST_DUP 0x0001 + +#define IGNORE_EQUIV_CLASS 1 + +struct __collate_st_info { + __uint8_t directive[COLL_WEIGHTS_MAX]; + __uint8_t flags; +#if __DARWIN_BYTE_ORDER == __DARWIN_LITTLE_ENDIAN + __uint8_t directive_count:4; + __uint8_t chain_max_len:4; +#else + __uint8_t chain_max_len:4; + __uint8_t directive_count:4; +#endif + __int32_t undef_pri[COLL_WEIGHTS_MAX]; + __int32_t subst_count[COLL_WEIGHTS_MAX]; + __int32_t chain_count; + __int32_t large_pri_count; +}; + +struct __collate_st_char_pri { + __int32_t pri[COLL_WEIGHTS_MAX]; +}; +struct __collate_st_chain_pri { + __darwin_wchar_t str[STR_LEN]; + __int32_t pri[COLL_WEIGHTS_MAX]; +}; +struct __collate_st_large_char_pri { + __int32_t val; + struct __collate_st_char_pri pri; +}; +struct __collate_st_subst { + __int32_t val; + __darwin_wchar_t str[STR_LEN]; +}; + +#ifndef __LIBC__ +extern int __collate_load_error; +extern int __collate_substitute_nontrivial; +#define __collate_char_pri_table (*__collate_char_pri_table_ptr) +extern struct __collate_st_char_pri __collate_char_pri_table[UCHAR_MAX + 1]; +extern struct __collate_st_chain_pri *__collate_chain_pri_table; +extern __int32_t *__collate_chain_equiv_table; +extern struct __collate_st_info __collate_info; +#endif /* !__LIBC__ */ + +__BEGIN_DECLS +#ifdef __LIBC__ +__darwin_wchar_t *__collate_mbstowcs(const char *, locale_t); +__darwin_wchar_t *__collate_wcsdup(const __darwin_wchar_t *); +__darwin_wchar_t *__collate_substitute(const __darwin_wchar_t *, int, locale_t); +int __collate_load_tables(const char *, locale_t); +void __collate_lookup_l(const __darwin_wchar_t *, int *, int *, int *, locale_t); +void __collate_lookup_which(const __darwin_wchar_t *, int *, int *, int, locale_t); +void __collate_xfrm(const __darwin_wchar_t *, __darwin_wchar_t **, locale_t); +int __collate_range_cmp(__darwin_wchar_t, __darwin_wchar_t, locale_t); +size_t __collate_collating_symbol(__darwin_wchar_t *, size_t, const char *, size_t, __darwin_mbstate_t *, locale_t); +int __collate_equiv_class(const char *, size_t, __darwin_mbstate_t *, locale_t); +size_t __collate_equiv_match(int, __darwin_wchar_t *, size_t, __darwin_wchar_t, const char *, size_t, __darwin_mbstate_t *, size_t *, locale_t); +#else /* !__LIBC__ */ +void __collate_lookup(const unsigned char *, int *, int *, int *); +#endif /* __LIBC__ */ +#ifdef COLLATE_DEBUG +void __collate_print_tables(void); +#endif +__END_DECLS + +#endif /* !_COLLATE_H_ */ diff --git a/adv_cmds/colldef/parse.y b/adv_cmds/colldef/parse.y new file mode 100644 index 0000000..495c2f3 --- /dev/null +++ b/adv_cmds/colldef/parse.y @@ -0,0 +1,1416 @@ +%{ +/*- + * Copyright (c) 1995 Alex Tatmanjants <alex@elvisti.kiev.ua> + * at Electronni Visti IA, Kiev, Ukraine. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD: src/usr.bin/colldef/parse.y,v 1.31 2002/10/16 12:56:22 charnier Exp $"); + +#include <arpa/inet.h> +#include <err.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <wchar.h> +#include <unistd.h> +#include <sysexits.h> +#include <limits.h> +#include "collate.h" +#include "common.h" + +#define PRI_UNDEFINED (-1) +#define PRI_IGNORE 0 +#define LINE_NONE (-1) +#define LINE_NORMAL 0 +#define LINE_ELLIPSIS 1 +#define LINE_UNDEFINED 2 +/* If UNDEFINED is specified with ellipses, we reposition prim_pri to + * UNDEFINED_PRI, leaving gap for undefined characters. */ +#define UNDEFINED_PRI (COLLATE_MAX_PRIORITY - (COLLATE_MAX_PRIORITY >> 2)) + +extern FILE *yyin; +void yyerror(const char *fmt, ...) __printflike(1, 2); +int yyparse(void); +int yylex(void); +static void usage(void); +static void collate_print_tables(void); +static struct __collate_st_char_pri *getpri(int32_t); +static struct __collate_st_char_pri *haspri(int32_t); +static struct __collate_st_chain_pri *getchain(const wchar_t *, int); +static struct symbol *getsymbolbychar(wchar_t); +static struct symbol *hassymbolbychar(wchar_t); +static void setsymbolbychar(struct symbol *); +struct symbol *getstring(const wchar_t *); +static void makeforwardref(int, const struct symbol *, const struct symbol *); +static int charpricompar(const void *, const void *); +static int substcompar(const void *, const void *); +static int chainpricompar(const void *, const void *); +static void putsubst(int32_t, int, const wchar_t *); +static int hassubst(int32_t, int); +static const wchar_t *__collate_wcsnchr(const wchar_t *, wchar_t, int); +static int __collate_wcsnlen(const wchar_t *, int); +char *showwcs(const wchar_t *, int); +static char *charname(wchar_t); +static char *charname2(wchar_t); + +char map_name[FILENAME_MAX] = "."; +wchar_t curr_chain[STR_LEN + 1]; + +char __collate_version[STR_LEN]; +DB *charmapdb; +static DB *charmapdb2; +static DB *largemapdb; +static int nlargemap = 0; +static DB *substdb[COLL_WEIGHTS_MAX]; +static int nsubst[COLL_WEIGHTS_MAX]; +static DB *chaindb; +static int nchain = 0; +static DB *stringdb; +static DB *forward_ref[COLL_WEIGHTS_MAX]; +static struct symbol *prev_weight_table[COLL_WEIGHTS_MAX]; +static struct symbol *prev2_weight_table[COLL_WEIGHTS_MAX]; +static struct symbol *weight_table[COLL_WEIGHTS_MAX]; +static int prev_line = LINE_NONE; +static struct symbol *prev_elem; +static int weight_index = 0; +static int allow_ellipsis = 0; +static struct symbol sym_ellipsis = {SYMBOL_ELLIPSIS, PRI_UNDEFINED}; +static struct symbol sym_ignore = {SYMBOL_IGNORE, PRI_IGNORE}; +static struct symbol sym_undefined = {SYMBOL_CHAR, PRI_UNDEFINED}; +static int order_pass = 0; + +#undef __collate_char_pri_table +struct __collate_st_char_pri __collate_char_pri_table[UCHAR_MAX + 1]; +struct __collate_st_chain_pri *__collate_chain_pri_table; +struct __collate_st_subst *__collate_substitute_table[COLL_WEIGHTS_MAX]; +struct __collate_st_large_char_pri *__collate_large_char_pri_table; + +int prim_pri = 2, sec_pri = 2; +#ifdef COLLATE_DEBUG +int debug; +#endif +struct __collate_st_info info = {{DIRECTIVE_FORWARD, DIRECTIVE_FORWARD}, 0, 0, 0, {PRI_UNDEFINED, PRI_UNDEFINED}}; + +/* Some of the code expects COLL_WEIGHTS_MAX == 2 */ +int directive_count = COLL_WEIGHTS_MAX; + +const char *out_file = "LC_COLLATE"; +%} +%union { + int32_t ch; + wchar_t str[BUFSIZE]; +} +%token SUBSTITUTE WITH +%token START_LC_COLLATE END_LC_COLLATE COLLATING_ELEMENT FROM COLLATING_SYMBOL +%token ELLIPSIS IGNORE UNDEFINED +%token ORDER RANGE ORDER_START ORDER_END ORDER_SECOND_PASS +%token <str> STRING +%token <str> DEFN +%token <str> ELEM +%token <ch> CHAR +%token <ch> ORDER_DIRECTIVE +%% +collate : datafile { + FILE *fp; + int localedef = (stringdb != NULL); + int z; + + if (nchain > 0) { + DBT key, val; + struct __collate_st_chain_pri *t, *v; + wchar_t *wp, *tp; + int flags, i, len; + + if ((__collate_chain_pri_table = (struct __collate_st_chain_pri *)malloc(nchain * sizeof(struct __collate_st_chain_pri))) == NULL) + err(1, "chain malloc"); + flags = R_FIRST; + t = __collate_chain_pri_table; + for(i = 0; i < nchain; i++) { + if (chaindb->seq(chaindb, &key, &val, flags) != 0) + err(1, "Can't retrieve chaindb %d", i); + memcpy(&v, val.data, sizeof(struct __collate_st_chain_pri *)); + *t++ = *v; + if ((len = __collate_wcsnlen(v->str, STR_LEN)) > info.chain_max_len) + info.chain_max_len = len; + flags = R_NEXT; + } + if (chaindb->seq(chaindb, &key, &val, flags) == 0) + err(1, "More in chaindb after retrieving %d", nchain); + qsort(__collate_chain_pri_table, nchain, sizeof(struct __collate_st_chain_pri), chainpricompar); + } + for(z = 0; z < directive_count; z++) { + if (nsubst[z] > 0) { + DBT key, val; + struct __collate_st_subst *t; + wchar_t *wp, *tp; + int flags, i, j; + int32_t cval; + + if ((__collate_substitute_table[z] = (struct __collate_st_subst *)calloc(nsubst[z], sizeof(struct __collate_st_subst))) == NULL) + err(1, "__collate_substitute_table[%d] calloc", z); + flags = R_FIRST; + t = __collate_substitute_table[z]; + for(i = 0; i < nsubst[z]; i++) { + if (substdb[z]->seq(substdb[z], &key, &val, flags) != 0) + err(1, "Can't retrieve substdb[%d]", z); + memcpy(&cval, key.data, sizeof(int32_t)); + /* we don't set the byte order of t->val, since we + * need it for sorting */ + t->val = cval; + for(wp = (wchar_t *)val.data, tp = t->str, j = STR_LEN; *wp && j-- > 0;) + *tp++ = htonl(*wp++); + t++; + flags = R_NEXT; + } + if (substdb[z]->seq(substdb[z], &key, &val, flags) == 0) + err(1, "More in substdb[%d] after retrieving %d", z, nsubst[z]); + qsort(__collate_substitute_table[z], nsubst[z], sizeof(struct __collate_st_subst), substcompar); + } + } + if (nlargemap > 0) { + DBT key, val; + struct __collate_st_large_char_pri *t; + struct __collate_st_char_pri *p; + int flags, i, z; + int32_t cval; + + if ((__collate_large_char_pri_table = (struct __collate_st_large_char_pri *)malloc(nlargemap * sizeof(struct __collate_st_large_char_pri))) == NULL) + err(1, "nlargemap malloc"); + flags = R_FIRST; + t = __collate_large_char_pri_table; + for(i = 0; i < nlargemap; i++) { + if (largemapdb->seq(largemapdb, &key, &val, flags) != 0) + err(1, "Can't retrieve largemapdb %d", i); + memcpy(&cval, key.data, sizeof(int32_t)); + memcpy(&p, val.data, sizeof(struct __collate_st_char_pri *)); + /* we don't set the byte order of t->val, since we + * need it for sorting */ + t->val = cval; + for(z = 0; z < directive_count; z++) + t->pri.pri[z] = htonl(p->pri[z]); + t++; + flags = R_NEXT; + } + if (largemapdb->seq(largemapdb, &key, &val, flags) == 0) + err(1, "More in largemapdb after retrieving %d", nlargemap); + qsort(__collate_large_char_pri_table, nlargemap, sizeof(struct __collate_st_large_char_pri), charpricompar); + } + + if (info.undef_pri[0] == PRI_UNDEFINED) { + int i; + info.undef_pri[0] = prim_pri; + for(i = 1; i < directive_count; i++) + info.undef_pri[i] = -prim_pri; + } + + if (localedef) { + int ch, z, ret; + if (sym_undefined.val == PRI_UNDEFINED) { + int flags = R_FIRST; + DBT key, val; + struct symbol *v; + while((ret = charmapdb->seq(charmapdb, &key, &val, flags)) == 0) { + memcpy(&v, val.data, sizeof(struct symbol *)); + switch(v->type) { + case SYMBOL_CHAR: { + struct __collate_st_char_pri *p = haspri(v->u.wc); + if (!p || p->pri[0] == PRI_UNDEFINED) + warnx("<%s> was not defined", showwcs((const wchar_t *)key.data, key.size / sizeof(wchar_t))); + break; + } + case SYMBOL_CHAIN: { + struct __collate_st_chain_pri *p = getchain(v->u.str, EXISTS); + if (p->pri[0] == PRI_UNDEFINED) + warnx("<%s> was not defined", showwcs((const wchar_t *)key.data, key.size / sizeof(wchar_t))); + break; + } + } + flags = R_NEXT; + } + if (ret < 0) + err(1, "Error retrieving from charmapdb"); + } + for (ch = 1; ch < UCHAR_MAX + 1; ch++) { + for(z = 0; z < directive_count; z++) + if (__collate_char_pri_table[ch].pri[z] == PRI_UNDEFINED) + __collate_char_pri_table[ch].pri[z] = (info.undef_pri[z] >= 0) ? info.undef_pri[z] : (ch - info.undef_pri[z]); + } + for (ch = 0; ch < nlargemap; ch++) { + for(z = 0; z < directive_count; z++) + if (__collate_large_char_pri_table[ch].pri.pri[z] == PRI_UNDEFINED) + __collate_large_char_pri_table[ch].pri.pri[z] = (info.undef_pri[z] >= 0) ? info.undef_pri[z] : (__collate_large_char_pri_table[ch].val - info.undef_pri[z]); + } + } else { + int ch, substed, ordered; + int fatal = 0; + for (ch = 1; ch < UCHAR_MAX + 1; ch++) { + substed = hassubst(ch, 0); + ordered = (__collate_char_pri_table[ch].pri[0] != PRI_UNDEFINED); + if (!ordered && !substed) { + fatal = 1; + warnx("%s not found", charname(ch)); + } + if (substed && ordered) { + fatal = 1; + warnx("%s can't be ordered since substituted", charname(ch)); + } + } + if (fatal) + exit(1); + } + + /* COLLATE_SUBST_DUP depends on COLL_WEIGHTS_MAX == 2 */ + if (localedef) { + if (nsubst[0] == nsubst[1] && (nsubst[0] == 0 || + memcmp(__collate_substitute_table[0], __collate_substitute_table[1], nsubst[0] * sizeof(struct __collate_st_subst)) == 0)) { + info.flags |= COLLATE_SUBST_DUP; + nsubst[1] = 0; + } + } else { + info.flags |= COLLATE_SUBST_DUP; + nsubst[1] = 0; + } + + for(z = 0; z < directive_count; z++) + info.subst_count[z] = nsubst[z]; + + info.directive_count = directive_count; + info.chain_count = nchain; + info.large_pri_count = nlargemap; + + if ((fp = fopen(out_file, "w")) == NULL) + err(EX_UNAVAILABLE, "can't open destination file %s", + out_file); + + strcpy(__collate_version, COLLATE_VERSION1_1A); + if (fwrite(__collate_version, sizeof(__collate_version), 1, fp) != 1) + err(EX_IOERR, + "IO error writting collate version to destination file %s", + out_file); +#if __DARWIN_BYTE_ORDER == __DARWIN_LITTLE_ENDIAN + for(z = 0; z < directive_count; z++) { + info.undef_pri[z] = htonl(info.undef_pri[z]); + info.subst_count[z] = htonl(info.subst_count[z]); + } + info.chain_count = htonl(info.chain_count); + info.large_pri_count = htonl(info.large_pri_count); +#endif /* __DARWIN_BYTE_ORDER == __DARWIN_LITTLE_ENDIAN */ + if (fwrite(&info, sizeof(info), 1, fp) != 1) + err(EX_IOERR, + "IO error writting collate info to destination file %s", + out_file); +#if __DARWIN_BYTE_ORDER == __DARWIN_LITTLE_ENDIAN + { + int i, z; + struct __collate_st_char_pri *p = __collate_char_pri_table; + + for(i = UCHAR_MAX + 1; i-- > 0; p++) { + for(z = 0; z < directive_count; z++) + p->pri[z] = htonl(p->pri[z]); + } + } +#endif /* __DARWIN_BYTE_ORDER == __DARWIN_LITTLE_ENDIAN */ + if (fwrite(__collate_char_pri_table, + sizeof(__collate_char_pri_table), 1, fp) != 1) + err(EX_IOERR, + "IO error writting char table to destination file %s", + out_file); + for(z = 0; z < directive_count; z++) { + if (nsubst[z] > 0) { +#if __DARWIN_BYTE_ORDER == __DARWIN_LITTLE_ENDIAN + struct __collate_st_subst *t = __collate_substitute_table[z]; + int i; + for(i = nsubst[z]; i > 0; i--) { + t->val = htonl(t->val); + t++; + } +#endif /* __DARWIN_BYTE_ORDER == __DARWIN_LITTLE_ENDIAN */ + if (fwrite(__collate_substitute_table[z], sizeof(struct __collate_st_subst), nsubst[z], fp) != nsubst[z]) + err(EX_IOERR, + "IO error writting large substprim table %d to destination file %s", + z, out_file); + } + } + if (nchain > 0) { +#if __DARWIN_BYTE_ORDER == __DARWIN_LITTLE_ENDIAN + int i, j, z; + struct __collate_st_chain_pri *p = __collate_chain_pri_table; + wchar_t *w; + + for(i = nchain; i-- > 0; p++) { + for(j = STR_LEN, w = p->str; *w && j-- > 0; w++) + *w = htonl(*w); + for(z = 0; z < directive_count; z++) + p->pri[z] = htonl(p->pri[z]); + } +#endif /* __DARWIN_BYTE_ORDER == __DARWIN_LITTLE_ENDIAN */ + if (fwrite(__collate_chain_pri_table, + sizeof(*__collate_chain_pri_table), nchain, fp) != + (size_t)nchain) + err(EX_IOERR, + "IO error writting chain table to destination file %s", + out_file); + } + + if (nlargemap > 0) { +#if __DARWIN_BYTE_ORDER == __DARWIN_LITTLE_ENDIAN + struct __collate_st_large_char_pri *t = __collate_large_char_pri_table; + int i; + for(i = 0; i < nlargemap; i++) { + t->val = htonl(t->val); + t++; + } +#endif /* __DARWIN_BYTE_ORDER == __DARWIN_LITTLE_ENDIAN */ + if (fwrite(__collate_large_char_pri_table, sizeof(struct __collate_st_large_char_pri), nlargemap, fp) != nlargemap) + err(EX_IOERR, + "IO error writting large pri tables to destination file %s", + out_file); + } + + if (fclose(fp) != 0) + err(EX_IOERR, "IO error closing destination file %s", + out_file); + +#ifdef COLLATE_DEBUG + if (debug) + collate_print_tables(); +#endif + exit(EX_OK); +} +; +datafile : statment_list + | blank_lines start_localedef localedef_sections blank_lines end_localedef blank_lines +; +statment_list : statment + | statment_list '\n' statment +; +statment : + | charmap + | substitute + | order +; +blank_lines : + | '\n' + | blank_lines '\n' +; +start_localedef : START_LC_COLLATE '\n' { + int i; + if ((stringdb = dbopen(NULL, O_CREAT | O_RDWR, 0600, DB_HASH, NULL)) == NULL) + err(1, "dbopen stringdb"); + directive_count = 0; + for(i = 0; i < COLL_WEIGHTS_MAX; i++) + info.directive[i] = DIRECTIVE_UNDEF; +} +; +end_localedef : END_LC_COLLATE '\n' +; +localedef_sections : localedef_preface localedef_order +; +localedef_preface : localedef_statment '\n' + | localedef_preface localedef_statment '\n' +; +localedef_statment : + | charmap + | collating_element + | collating_symbol +; +collating_element : COLLATING_ELEMENT ELEM FROM STRING { + int len; + struct symbol *s; + if (wcslen($2) > CHARMAP_SYMBOL_LEN) + yyerror("collating-element symbol name '%s' is too long", showwcs($2, CHARMAP_SYMBOL_LEN)); + if ((len = wcslen($4)) > STR_LEN) + yyerror("collating-element string '%s' is too long", showwcs($4, STR_LEN)); + if (len < 2) + yyerror("collating-element string '%s' must be at least two characters", showwcs($4, STR_LEN)); + s = getsymbol($2, NOTEXISTS); + s->val = PRI_UNDEFINED; + s->type = SYMBOL_CHAIN; + wcsncpy(s->u.str, $4, STR_LEN); + getchain($4, NOTEXISTS); +} +; +collating_symbol : COLLATING_SYMBOL ELEM { + struct symbol *s; + if (wcslen($2) > CHARMAP_SYMBOL_LEN) + yyerror("collating-element symbol name '%s' is too long", showwcs($2, CHARMAP_SYMBOL_LEN)); + s = getsymbol($2, NOTEXISTS); + s->val = PRI_UNDEFINED; + s->type = SYMBOL_SYMBOL; +} +; +localedef_order : order_start order_lines1 order_second_pass order_lines2 order_end +; +order_start: ORDER_START order_start_list '\n' +; +order_second_pass: ORDER_SECOND_PASS { + prev_line = LINE_NONE; + prev_elem = NULL; + order_pass++; +} +; +order_start_list : order_start_list_directives { + if (directive_count > 0) + yyerror("Multiple order_start lines not allowed"); + if ((info.directive[0] & DIRECTIVE_DIRECTION_MASK) == 0) + info.directive[0] |= DIRECTIVE_FORWARD; + directive_count++; +} + | order_start_list ';' order_start_list_directives { + if (directive_count >= COLL_WEIGHTS_MAX) + yyerror("only COLL_WEIGHTS_MAX weights allowed"); + if ((info.directive[directive_count] & DIRECTIVE_DIRECTION_MASK) == 0) + info.directive[directive_count] |= DIRECTIVE_FORWARD; + directive_count++; +} +; +order_start_list_directives : ORDER_DIRECTIVE { + info.directive[directive_count] = $1; +} + | order_start_list_directives ',' ORDER_DIRECTIVE { + int direction = ($3 & DIRECTIVE_DIRECTION_MASK); + int prev = (info.directive[directive_count] & DIRECTIVE_DIRECTION_MASK); + if (direction && prev && direction != prev) + yyerror("The forward and backward directives are mutually exclusive"); + info.directive[directive_count] |= $3; +} +; +order_lines1 : order_line1 '\n' + | order_lines1 order_line1 '\n' +; +order_line1 : + | ELEM { + struct symbol *s = getsymbol($1, EXISTS); + if (s->val != PRI_UNDEFINED) + yyerror("<%s> redefined", showwcs($1, CHARMAP_SYMBOL_LEN)); + if (prev_line == LINE_ELLIPSIS) { + struct symbol *m; + wchar_t i; + int v; + switch (s->type) { + case SYMBOL_CHAIN: + yyerror("Chain <%s> can't be endpoints of ellipsis", showwcs($1, CHARMAP_SYMBOL_LEN)); + case SYMBOL_SYMBOL: + yyerror("Collating symbol <%s> can't be endpoints of ellipsis", showwcs($1, CHARMAP_SYMBOL_LEN)); + } + if (s->u.wc <= prev_elem->u.wc) + yyerror("<%s> is before starting point of ellipsis", showwcs($1, CHARMAP_SYMBOL_LEN)); + for(i = prev_elem->u.wc + 1, v = prev_elem->val + 1; i < s->u.wc; i++, v++) { + m = getsymbolbychar(i); + if (m->val != PRI_UNDEFINED) + yyerror("<%s> was previously defined while filling ellipsis symbols", showwcs(m->name, CHARMAP_SYMBOL_LEN)); + m->val = v; + } + s->val = v; + } else + s->val = prim_pri; + prim_pri = s->val + 1; + weight_index = 0; +} weights { + int i; + struct symbol *s = getsymbol($1, EXISTS); + if (s->type == SYMBOL_SYMBOL) { + if (weight_index != 0) + yyerror("Can't specify weights for collating symbol <%s>", showwcs($1, CHARMAP_SYMBOL_LEN)); + } else if (weight_index == 0) { + for(i = 0; i < directive_count; i++) + weight_table[i] = s; + } else if (weight_index != directive_count) + yyerror("Not enough weights specified"); + memcpy(prev_weight_table, weight_table, sizeof(weight_table)); + prev_line = LINE_NORMAL; + prev_elem = s; +} + | ELLIPSIS { weight_index = 0; allow_ellipsis = 1; } weights { + int i; + if (prev_line == LINE_ELLIPSIS) + yyerror("Illegal sequential ellipsis lines"); + if (prev_line == LINE_UNDEFINED) + yyerror("Ellipsis line can not follow UNDEFINED line"); + if (prev_line == LINE_NONE) + yyerror("Ellipsis line must follow a collating identifier lines"); + if (weight_index == 0) { + for(i = 0; i < directive_count; i++) + weight_table[i] = &sym_ellipsis; + } else if (weight_index != directive_count) + yyerror("Not enough weights specified"); + for(i = 0; i < directive_count; i++) { + if (weight_table[i]->type != SYMBOL_ELLIPSIS) + continue; + switch (prev_weight_table[i]->type) { + case SYMBOL_CHAIN: + yyerror("Startpoint of ellipsis can't be a collating element"); + case SYMBOL_IGNORE: + yyerror("Startpoint of ellipsis can't be IGNORE"); + case SYMBOL_SYMBOL: + yyerror("Startpoint of ellipsis can't be a collating symbol"); + case SYMBOL_STRING: + yyerror("Startpoint of ellipsis can't be a string"); + } + } + memcpy(prev2_weight_table, prev_weight_table, sizeof(prev_weight_table)); + memcpy(prev_weight_table, weight_table, sizeof(weight_table)); + prev_line = LINE_ELLIPSIS; + allow_ellipsis = 0; +} + | UNDEFINED { + if (sym_undefined.val != PRI_UNDEFINED) + yyerror("Multiple UNDEFINED lines not allowed"); + sym_undefined.val = prim_pri++; + weight_index = 0; + allow_ellipsis = 1; +} weights { + int i; + if (weight_index == 0) { + weight_table[0] = &sym_undefined; + for(i = 1; i < directive_count; i++) + weight_table[i] = &sym_ellipsis; + } else if (weight_index != directive_count) + yyerror("Not enough weights specified"); + memcpy(prev_weight_table, weight_table, sizeof(weight_table)); + prev_line = LINE_UNDEFINED; +} +; +order_lines2 : order_line2 '\n' + | order_lines2 order_line2 '\n' +; +order_line2 : + | ELEM { weight_index = 0; } weights { + int i; + struct symbol *s = getsymbol($1, EXISTS); + if (s->val == PRI_UNDEFINED) + yyerror("<%s> undefined", showwcs($1, CHARMAP_SYMBOL_LEN)); + if (s->type == SYMBOL_SYMBOL) { + if (weight_index != 0) + yyerror("Can't specify weights for collating symbol <%s>", showwcs($1, CHARMAP_SYMBOL_LEN)); + } else if (weight_index == 0) { + for(i = 0; i < directive_count; i++) + weight_table[i] = s; + } else if (weight_index != directive_count) + yyerror("Not enough weights specified"); + if (prev_line == LINE_ELLIPSIS) { + int w, x; + for(i = 0; i < directive_count; i++) { + switch (prev_weight_table[i]->type) { + case SYMBOL_CHAR: + case SYMBOL_CHAIN: + case SYMBOL_IGNORE: + case SYMBOL_SYMBOL: + for (w = prev_elem->u.wc + 1; w < s->u.wc; w++) { + struct __collate_st_char_pri *p = getpri(w); + if (p->pri[i] != PRI_UNDEFINED) + yyerror("Char 0x02x previously defined", w); + p->pri[i] = prev_weight_table[i]->val; + } + break; + case SYMBOL_ELLIPSIS: + + switch (weight_table[i]->type) { + case SYMBOL_STRING: + yyerror("Strings can't be endpoints of ellipsis"); + case SYMBOL_CHAIN: + yyerror("Chains can't be endpoints of ellipsis"); + case SYMBOL_IGNORE: + yyerror("IGNORE can't be endpoints of ellipsis"); + case SYMBOL_SYMBOL: + yyerror("Collation symbols can't be endpoints of ellipsis"); + } + if (s->val - prev_elem->val != weight_table[i]->val - prev2_weight_table[i]->val) + yyerror("Range mismatch in weight %d", i); + x = prev2_weight_table[i]->val + 1; + for (w = prev_elem->u.wc + 1; w < s->u.wc; w++) { + struct __collate_st_char_pri *p = getpri(w); + if (p->pri[i] != PRI_UNDEFINED) + yyerror("Char 0x02x previously defined", w); + p->pri[i] = x++; + } + break; + case SYMBOL_STRING: + for (w = prev_elem->u.wc + 1; w < s->u.wc; w++) { + struct __collate_st_char_pri *p = getpri(w); + if (p->pri[i] != PRI_UNDEFINED) + yyerror("Char 0x02x previously defined", w); + putsubst(w, i, prev_weight_table[i]->u.str); + p->pri[i] = prev_weight_table[i]->val; + } + break; + } + } + } + switch(s->type) { + case SYMBOL_CHAR: { + struct __collate_st_char_pri *p = getpri(s->u.wc); + for(i = 0; i < directive_count; i++) { + switch (weight_table[i]->type) { + case SYMBOL_CHAR: + case SYMBOL_CHAIN: + case SYMBOL_IGNORE: + case SYMBOL_SYMBOL: + if (p->pri[i] != PRI_UNDEFINED) + yyerror("Char 0x02x previously defined", s->u.wc); + p->pri[i] = weight_table[i]->val; + break; + case SYMBOL_STRING: + if (p->pri[i] != PRI_UNDEFINED) + yyerror("Char 0x02x previously defined", s->u.wc); + putsubst(s->u.wc, i, weight_table[i]->u.str); + p->pri[i] = weight_table[i]->val; + break; + } + } + break; + } + case SYMBOL_CHAIN: { + struct __collate_st_chain_pri *p = getchain(s->u.str, EXISTS); + for(i = 0; i < directive_count; i++) { + switch (weight_table[i]->type) { + case SYMBOL_CHAR: + case SYMBOL_CHAIN: + case SYMBOL_IGNORE: + case SYMBOL_SYMBOL: + if (p->pri[i] != PRI_UNDEFINED) + yyerror("Chain %s previously defined", showwcs(s->u.str, STR_LEN)); + p->pri[i] = weight_table[i]->val; + break; + case SYMBOL_STRING : + if (wcsncmp(s->u.str, weight_table[i]->u.str, STR_LEN) != 0) + yyerror("Chain/string mismatch"); + if (p->pri[i] != PRI_UNDEFINED) + yyerror("Chain %s previously defined", showwcs(s->u.str, STR_LEN)); + /* negative value mean don't substitute + * the chain, but it is in an + * equivalence class */ + p->pri[i] = -weight_table[i]->val; + } + } + break; + } + } + memcpy(prev_weight_table, weight_table, sizeof(weight_table)); + prev_line = LINE_NORMAL; + prev_elem = s; +} + | ELLIPSIS { weight_index = 0; allow_ellipsis = 1; } weights { + int i; + if (prev_line == LINE_ELLIPSIS) + yyerror("Illegal sequential ellipsis lines"); + if (prev_line == LINE_UNDEFINED) + yyerror("Ellipsis line can not follow UNDEFINED line"); + if (prev_line == LINE_NONE) + yyerror("Ellipsis line must follow a collating identifier lines"); + if (weight_index == 0) { + for(i = 0; i < directive_count; i++) + weight_table[i] = &sym_ellipsis; + } else if (weight_index != directive_count) + yyerror("Not enough weights specified"); + for(i = 0; i < directive_count; i++) { + if (weight_table[i]->type != SYMBOL_ELLIPSIS) + continue; + switch (prev_weight_table[i]->type) { + case SYMBOL_CHAIN: + yyerror("Startpoint of ellipsis can't be a collating element"); + case SYMBOL_IGNORE: + yyerror("Startpoint of ellipsis can't be IGNORE"); + case SYMBOL_SYMBOL: + yyerror("Startpoint of ellipsis can't be a collating symbol"); + case SYMBOL_STRING: + yyerror("Startpoint of ellipsis can't be a string"); + } + } + memcpy(prev2_weight_table, prev_weight_table, sizeof(prev_weight_table)); + memcpy(prev_weight_table, weight_table, sizeof(weight_table)); + prev_line = LINE_ELLIPSIS; + allow_ellipsis = 0; +} + | UNDEFINED { weight_index = 0; allow_ellipsis = 1; } weights { + int i; + + if (weight_index == 0) { + weight_table[0] = &sym_undefined; + for(i = 1; i < directive_count; i++) + weight_table[i] = &sym_ellipsis; + } else if (weight_index != directive_count) + yyerror("Not enough weights specified"); + for(i = 0; i < directive_count; i++) { + switch (weight_table[i]->type) { + case SYMBOL_CHAR: + case SYMBOL_CHAIN: + case SYMBOL_IGNORE: + case SYMBOL_SYMBOL: + info.undef_pri[i] = weight_table[i]->val; + break; + case SYMBOL_ELLIPSIS : + /* Negative values mean that the priority is + * relative to the lexical value */ + info.undef_pri[i] = -sym_undefined.val; + prim_pri = UNDEFINED_PRI; + break; + case SYMBOL_STRING : + yyerror("Strings can't be used with UNDEFINED"); + } + } + memcpy(prev_weight_table, weight_table, sizeof(weight_table)); + prev_line = LINE_UNDEFINED; +} +; +weights : + | weight + | weights ';' weight +; +weight : ELEM { + struct symbol *s; + if (weight_index >= directive_count) + yyerror("More weights than specified by order_start"); + s = getsymbol($1, EXISTS); + if (order_pass && s->val == PRI_UNDEFINED) + yyerror("<%s> is undefined", showwcs($1, CHARMAP_SYMBOL_LEN)); + weight_table[weight_index++] = s; +} + | ELLIPSIS { + if (weight_index >= directive_count) + yyerror("More weights than specified by order_start"); + if (!allow_ellipsis) + yyerror("Ellipsis weight not allowed"); + weight_table[weight_index++] = &sym_ellipsis; +} + | IGNORE { + if (weight_index >= directive_count) + yyerror("More weights than specified by order_start"); + weight_table[weight_index++] = &sym_ignore; +} + | STRING { + if (weight_index >= directive_count) + yyerror("More weights than specified by order_start"); + if (wcslen($1) > STR_LEN) + yyerror("String '%s' is too long", showwcs($1, STR_LEN)); + weight_table[weight_index++] = getstring($1); +} +; +order_end : ORDER_END '\n' +; +charmap : DEFN CHAR { + int len = wcslen($1); + struct symbol *s; + if (len > CHARMAP_SYMBOL_LEN) + yyerror("Charmap symbol name '%s' is too long", showwcs($1, CHARMAP_SYMBOL_LEN)); + s = getsymbol($1, NOTEXISTS); + s->type = SYMBOL_CHAR; + s->val = PRI_UNDEFINED; + s->u.wc = $2; + setsymbolbychar(s); +} +; +substitute : SUBSTITUTE CHAR WITH STRING { + if (wcslen($4) + 1 > STR_LEN) + yyerror("%s substitution is too long", charname($2)); + putsubst($2, 0, $4); +} +; +order : ORDER order_list +; +order_list : item + | order_list ';' item +; +chain : CHAR CHAR { + curr_chain[0] = $1; + curr_chain[1] = $2; + if (curr_chain[0] == '\0' || curr_chain[1] == '\0') + yyerror("\\0 can't be chained"); + curr_chain[2] = '\0'; +} + | chain CHAR { + static wchar_t tb[2]; + tb[0] = $2; + if (tb[0] == '\0') + yyerror("\\0 can't be chained"); + if (wcslen(curr_chain) + 1 > STR_LEN) + yyerror("Chain '%s' grows too long", curr_chain); + (void)wcscat(curr_chain, tb); +} +; +item : CHAR { + struct __collate_st_char_pri *p = getpri($1); + if (p->pri[0] >= 0) + yyerror("%s duplicated", charname($1)); + p->pri[0] = p->pri[1] = prim_pri; + sec_pri = ++prim_pri; +} + | chain { + struct __collate_st_chain_pri *c = getchain(curr_chain, NOTEXISTS); + c->pri[0] = c->pri[1] = prim_pri; + sec_pri = ++prim_pri; +} + | CHAR RANGE CHAR { + u_int i; + struct __collate_st_char_pri *p; + + if ($3 <= $1) + yyerror("Illegal range %s -- %s", charname($1), charname2($3)); + + for (i = $1; i <= $3; i++) { + p = getpri(i); + if (p->pri[0] >= 0) + yyerror("%s duplicated", charname(i)); + p->pri[0] = p->pri[1] = prim_pri++; + } + sec_pri = prim_pri; +} + | '{' mixed_order_list '}' { + prim_pri = sec_pri; +} + | '(' sec_order_list ')' { + prim_pri = sec_pri; +} +; +mixed_order_list : mixed_sub_list { + sec_pri++; +} + | mixed_order_list ';' mixed_sub_list { + sec_pri++; +} +; +mixed_sub_list : mixed_sub_item + | mixed_sub_list ',' mixed_sub_item +; +sec_order_list : sec_sub_item + | sec_order_list ',' sec_sub_item +; +mixed_sub_item : CHAR { + struct __collate_st_char_pri *p = getpri($1); + if (p->pri[0] >= 0) + yyerror("%s duplicated", charname($1)); + p->pri[0] = prim_pri; + p->pri[1] = sec_pri; +} + | CHAR RANGE CHAR { + u_int i; + struct __collate_st_char_pri *p; + + if ($3 <= $1) + yyerror("Illegal range %s -- %s", + charname($1), charname2($3)); + + for (i = $1; i <= $3; i++) { + p = getpri(i); + if (p->pri[0] >= 0) + yyerror("%s duplicated", charname(i)); + p->pri[0] = prim_pri; + p->pri[1] = sec_pri; + } +} + | chain { + struct __collate_st_chain_pri *c = getchain(curr_chain, NOTEXISTS); + c->pri[0] = prim_pri; + c->pri[1] = sec_pri; +} +sec_sub_item : CHAR { + struct __collate_st_char_pri *p = getpri($1); + if (p->pri[0] >= 0) + yyerror("%s duplicated", charname($1)); + p->pri[0] = prim_pri; + p->pri[1] = sec_pri++; +} + | CHAR RANGE CHAR { + u_int i; + struct __collate_st_char_pri *p; + + if ($3 <= $1) + yyerror("Illegal range %s -- %s", + charname($1), charname2($3)); + + for (i = $1; i <= $3; i++) { + p = getpri(i); + if (p->pri[0] >= 0) + yyerror("%s duplicated", charname(i)); + p->pri[0] = prim_pri; + p->pri[1] = sec_pri++; + } +} + | chain { + struct __collate_st_chain_pri *c = getchain(curr_chain, NOTEXISTS); + c->pri[0] = prim_pri; + c->pri[1] = sec_pri++; +} +; +%% +int +main(int ac, char **av) +{ + int ch, z; + + if ((charmapdb = dbopen(NULL, O_CREAT | O_RDWR, 0600, DB_HASH, NULL)) == NULL) + err(1, "dbopen charmapdb"); + if ((charmapdb2 = dbopen(NULL, O_CREAT | O_RDWR, 0600, DB_HASH, NULL)) == NULL) + err(1, "dbopen charmapdb"); + if ((largemapdb = dbopen(NULL, O_CREAT | O_RDWR, 0600, DB_HASH, NULL)) == NULL) + err(1, "dbopen largemapdb"); + if ((substdb[0] = dbopen(NULL, O_CREAT | O_RDWR, 0600, DB_HASH, NULL)) == NULL) + err(1, "dbopen substdb[0]"); + if ((chaindb = dbopen(NULL, O_CREAT | O_RDWR, 0600, DB_HASH, NULL)) == NULL) + err(1, "dbopen chaindb"); + /* -1 means an undefined priority, which we adjust after parsing */ + for (ch = 0; ch <= UCHAR_MAX; ch++) + for(z = 0; z < COLL_WEIGHTS_MAX; z++) + __collate_char_pri_table[ch].pri[z] = PRI_UNDEFINED; +#ifdef COLLATE_DEBUG + while((ch = getopt(ac, av, ":do:I:")) != -1) { +#else + while((ch = getopt(ac, av, ":o:I:")) != -1) { +#endif + switch (ch) + { +#ifdef COLLATE_DEBUG + case 'd': + debug++; + break; +#endif + case 'o': + out_file = optarg; + break; + + case 'I': + strlcpy(map_name, optarg, sizeof(map_name)); + break; + + default: + usage(); + } + } + ac -= optind; + av += optind; + if (ac > 0) { + if ((yyin = fopen(*av, "r")) == NULL) + err(EX_UNAVAILABLE, "can't open source file %s", *av); + } + yyparse(); + return 0; +} + +static struct __collate_st_char_pri * +getpri(int32_t c) +{ + DBT key, val; + struct __collate_st_char_pri *p; + int ret; + + if (c <= UCHAR_MAX) + return &__collate_char_pri_table[c]; + key.data = &c; + key.size = sizeof(int32_t); + if ((ret = largemapdb->get(largemapdb, &key, &val, 0)) < 0) + err(1, "getpri: Error getting %s", charname(c)); + if (ret != 0) { + struct __collate_st_char_pri *pn; + int z; + if ((pn = (struct __collate_st_char_pri *)malloc(sizeof(struct __collate_st_char_pri))) == NULL) + err(1, "getpri: malloc"); + for(z = 0; z < COLL_WEIGHTS_MAX; z++) + pn->pri[z] = PRI_UNDEFINED; + val.data = &pn; + val.size = sizeof(struct __collate_st_char_pri *); + if (largemapdb->put(largemapdb, &key, &val, 0) < 0) + err(1, "getpri: Error storing %s", charname(c)); + nlargemap++; + } + memcpy(&p, val.data, sizeof(struct __collate_st_char_pri *)); + return p; +} + +static struct __collate_st_char_pri * +haspri(int32_t c) +{ + DBT key, val; + struct __collate_st_char_pri *p; + int ret; + + if (c <= UCHAR_MAX) + return &__collate_char_pri_table[c]; + key.data = &c; + key.size = sizeof(int32_t); + if ((ret = largemapdb->get(largemapdb, &key, &val, 0)) < 0) + err(1, "haspri: Error getting %s", charname(c)); + if (ret != 0) + return NULL; + memcpy(&p, val.data, sizeof(struct __collate_st_char_pri *)); + return p; +} + +static struct __collate_st_chain_pri * +getchain(const wchar_t *wcs, int exists) +{ + DBT key, val; + struct __collate_st_chain_pri *p; + int ret; + + key.data = (void *)wcs; + key.size = __collate_wcsnlen(wcs, STR_LEN) * sizeof(wchar_t); + if ((ret = chaindb->get(chaindb, &key, &val, 0)) < 0) + err(1, "getchain: Error getting \"%s\"", showwcs(wcs, STR_LEN)); + if (ret != 0) { + struct __collate_st_chain_pri *pn; + int z; + if (exists > 0) + errx(1, "getchain: \"%s\" is not defined", showwcs(wcs, STR_LEN)); + if ((pn = (struct __collate_st_chain_pri *)malloc(sizeof(struct __collate_st_chain_pri))) == NULL) + err(1, "getchain: malloc"); + for(z = 0; z < COLL_WEIGHTS_MAX; z++) + pn->pri[z] = PRI_UNDEFINED; + bzero(pn->str, sizeof(pn->str)); + wcsncpy(pn->str, wcs, STR_LEN); + val.data = &pn; + val.size = sizeof(struct __collate_st_chain_pri *); + if (chaindb->put(chaindb, &key, &val, 0) < 0) + err(1, "getchain: Error storing \"%s\"", showwcs(wcs, STR_LEN)); + nchain++; + } else if (exists == 0) + errx(1, "getchain: \"%s\" already exists", showwcs(wcs, STR_LEN)); + memcpy(&p, val.data, sizeof(struct __collate_st_chain_pri *)); + return p; +} + +struct symbol * +getsymbol(const wchar_t *wcs, int exists) +{ + DBT key, val; + struct symbol *p; + int ret; + + key.data = (void *)wcs; + key.size = wcslen(wcs) * sizeof(wchar_t); + if ((ret = charmapdb->get(charmapdb, &key, &val, 0)) < 0) + err(1, "getsymbol: Error getting \"%s\"", showwcs(wcs, CHARMAP_SYMBOL_LEN)); + if (ret != 0) { + struct symbol *pn; + if (exists > 0) + errx(1, "getsymbol: \"%s\" is not defined", showwcs(wcs, CHARMAP_SYMBOL_LEN)); + if ((pn = (struct symbol *)malloc(sizeof(struct symbol))) == NULL) + err(1, "getsymbol: malloc"); + pn->val = PRI_UNDEFINED; + wcsncpy(pn->name, wcs, CHARMAP_SYMBOL_LEN); + val.data = &pn; + val.size = sizeof(struct symbol *); + if (charmapdb->put(charmapdb, &key, &val, 0) < 0) + err(1, "getsymbol: Error storing \"%s\"", showwcs(wcs, CHARMAP_SYMBOL_LEN)); + } else if (exists == 0) + errx(1, "getsymbol: \"%s\" already exists", showwcs(wcs, CHARMAP_SYMBOL_LEN)); + memcpy(&p, val.data, sizeof(struct symbol *)); + return p; +} + +static struct symbol * +getsymbolbychar(wchar_t wc) +{ + DBT key, val; + struct symbol *p; + int ret; + + key.data = &wc; + key.size = sizeof(wchar_t); + if ((ret = charmapdb2->get(charmapdb2, &key, &val, 0)) < 0) + err(1, "getsymbolbychar: Error getting Char 0x%02x", wc); + if (ret != 0) + errx(1, "getsymbolbychar: Char 0x%02x is not defined", wc); + memcpy(&p, val.data, sizeof(struct symbol *)); + return p; +} + +static struct symbol * +hassymbolbychar(wchar_t wc) +{ + DBT key, val; + struct symbol *p; + int ret; + + key.data = &wc; + key.size = sizeof(wchar_t); + if ((ret = charmapdb2->get(charmapdb2, &key, &val, 0)) < 0) + err(1, "hassymbolbychar: Error getting Char 0x%02x", wc); + if (ret != 0) + return NULL; + memcpy(&p, val.data, sizeof(struct symbol *)); + return p; +} + +static void +setsymbolbychar(struct symbol *s) +{ + DBT key, val; + struct symbol *p; + int ret; + + key.data = &s->u.wc; + key.size = sizeof(wchar_t); + val.data = &s; + val.size = sizeof(struct symbol *); + if (charmapdb2->put(charmapdb2, &key, &val, 0) < 0) + err(1, "setsymbolbychar: Error storing <%s>", showwcs(s->name, CHARMAP_SYMBOL_LEN)); +} + +struct symbol * +getstring(const wchar_t *wcs) +{ + DBT key, val; + struct symbol *p; + int ret; + + key.data = (void *)wcs; + key.size = wcslen(wcs) * sizeof(wchar_t); + if ((ret = stringdb->get(stringdb, &key, &val, 0)) < 0) + err(1, "getstring: Error getting \"%s\"", showwcs(wcs, STR_LEN)); + if (ret != 0) { + struct symbol *pn; + if ((pn = (struct symbol *)malloc(sizeof(struct symbol))) == NULL) + err(1, "getstring: malloc"); + pn->type = SYMBOL_STRING; + pn->val = prim_pri++; + wcsncpy(pn->u.str, wcs, STR_LEN); + val.data = &pn; + val.size = sizeof(struct symbol *); + if (stringdb->put(stringdb, &key, &val, 0) < 0) + err(1, "getstring: Error storing \"%s\"", showwcs(wcs, STR_LEN)); + } + memcpy(&p, val.data, sizeof(struct symbol *)); + return p; +} + +static void +makeforwardref(int i, const struct symbol *from, const struct symbol * to) +{ +} + +static void +putsubst(int32_t c, int i, const wchar_t *str) +{ + DBT key, val; + int ret; + wchar_t clean[STR_LEN]; + + if (!substdb[i]) + if ((substdb[i] = dbopen(NULL, O_CREAT | O_RDWR, 0600, DB_HASH, NULL)) == NULL) + err(1, "dbopen substdb[%d]", i); + key.data = &c; + key.size = sizeof(int32_t); + bzero(clean, sizeof(clean)); + wcsncpy(clean, str, STR_LEN); + val.data = clean; + val.size = sizeof(clean); + if ((ret = substdb[i]->put(substdb[i], &key, &val, R_NOOVERWRITE)) < 0) + err(1, "putsubst: Error on %s", charname(c)); + if (ret != 0) + errx(1, "putsubst: Duplicate substitution of %s", charname(c)); + nsubst[i]++; +} + +static int +hassubst(int32_t c, int i) +{ + DBT key, val; + int ret; + + if (!substdb[i]) + return 0; + key.data = &c; + key.size = sizeof(int32_t); + if ((ret = substdb[i]->get(substdb[i], &key, &val, 0)) < 0) + err(1, "hassubst: Error getting %s", charname(c)); + return (ret == 0); +} + +static int +chainpricompar(const void *a, const void *b) +{ + return wcsncmp(((struct __collate_st_chain_pri *)a)->str, ((struct __collate_st_chain_pri *)b)->str, STR_LEN); +} + +static int +charpricompar(const void *a, const void *b) +{ + return ((struct __collate_st_large_char_pri *)a)->val - ((struct __collate_st_large_char_pri *)b)->val; +} + +static int +substcompar(const void *a, const void *b) +{ + return ((struct __collate_st_subst *)a)->val - ((struct __collate_st_subst *)b)->val; +} + +static const wchar_t * +__collate_wcsnchr(const wchar_t *s, wchar_t c, int len) +{ + while (*s && len > 0) { + if (*s == c) + return s; + s++; + len--; + } + return NULL; +} + +static int +__collate_wcsnlen(const wchar_t *s, int len) +{ + int n = 0; + while (*s && n < len) { + s++; + n++; + } + return n; +} + +static void +usage(void) +{ + fprintf(stderr, "usage: colldef [-o out_file] [-I map_dir] [filename]\n"); + exit(EX_USAGE); +} + +void +yyerror(const char *fmt, ...) +{ + va_list ap; + char msg[128]; + + va_start(ap, fmt); + vsnprintf(msg, sizeof(msg), fmt, ap); + va_end(ap); + errx(EX_UNAVAILABLE, "%s, near line %d", msg, line_no); +} + +char * +showwcs(const wchar_t *t, int len) +{ + static char buf[8* CHARMAP_SYMBOL_LEN]; + char *cp = buf; + + for(; *t && len > 0; len--, t++) { + if (*t >=32 && *t <= 126) + *cp++ = *t; + else { + sprintf(cp, "\\x{%02x}", *t); + cp += strlen(cp); + } + } + *cp = 0; + return buf; +} + +static char * +charname(wchar_t wc) +{ + static char buf[CHARMAP_SYMBOL_LEN + 1]; + struct symbol *s = hassymbolbychar(wc); + + if (s) + strcpy(buf, showwcs(s->name, CHARMAP_SYMBOL_LEN)); + else + sprintf(buf, "Char 0x%02x", wc); + return buf; +} + +static char * +charname2(wchar_t wc) +{ + static char buf[CHARMAP_SYMBOL_LEN + 1]; + struct symbol *s = hassymbolbychar(wc); + + if (s) + strcpy(buf, showwcs(s->name, CHARMAP_SYMBOL_LEN)); + else + sprintf(buf, "Char 0x%02x", wc); + return buf; +} + +#ifdef COLLATE_DEBUG +static char * +show(int c) +{ + static char buf[5]; + + if (c >=32 && c <= 126) + sprintf(buf, "'%c' ", c); + else + sprintf(buf, "\\x{%02x}", c); + return buf; +} + +static void +collate_print_tables(void) +{ + int i, z; + + printf("Info: p=%d s=%d f=0x%02x m=%d dc=%d up=%d us=%d pc=%d sc=%d cc=%d lc=%d\n", + info.directive[0], info.directive[1], + info.flags, info.chain_max_len, + info.directive_count, + info.undef_pri[0], info.undef_pri[1], + info.subst_count[0], info.subst_count[1], + info.chain_count, info.large_pri_count); + for(z = 0; z < info.directive_count; z++) { + if (info.subst_count[z] > 0) { + struct __collate_st_subst *p2 = __collate_substitute_table[z]; + if (z == 0 && (info.flags & COLLATE_SUBST_DUP)) + printf("Both substitute tables:\n"); + else + printf("Substitute table %d:\n", z); + for (i = info.subst_count[z]; i-- > 0; p2++) + printf("\t%s --> \"%s\"\n", + show(p2->val), + showwcs(p2->str, STR_LEN)); + } + } + if (info.chain_count > 0) { + printf("Chain priority table:\n"); + struct __collate_st_chain_pri *p2 = __collate_chain_pri_table; + for (i = info.chain_count; i-- > 0; p2++) { + printf("\t\"%s\" :", showwcs(p2->str, STR_LEN)); + for(z = 0; z < info.directive_count; z++) + printf(" %d", p2->pri[z]); + putchar('\n'); + } + } + printf("Char priority table:\n"); + { + struct __collate_st_char_pri *p2 = __collate_char_pri_table; + for (i = 0; i < UCHAR_MAX + 1; i++, p2++) { + printf("\t%s :", show(i)); + for(z = 0; z < info.directive_count; z++) + printf(" %d", p2->pri[z]); + putchar('\n'); + } + } + if (info.large_pri_count > 0) { + struct __collate_st_large_char_pri *p2 = __collate_large_char_pri_table; + printf("Large priority table:\n"); + for (i = info.large_pri_count; i-- > 0; p2++) { + printf("\t%s :", show(p2->val)); + for(z = 0; z < info.directive_count; z++) + printf(" %d", p2->pri.pri[z]); + putchar('\n'); + } + } +} +#endif diff --git a/adv_cmds/colldef/scan.l b/adv_cmds/colldef/scan.l new file mode 100644 index 0000000..ce14492 --- /dev/null +++ b/adv_cmds/colldef/scan.l @@ -0,0 +1,398 @@ +%x string s_name charmap defn nchar subs subs2 ldef elem +%{ +/*- + * Copyright (c) 1995 Alex Tatmanjants <alex@elvisti.kiev.ua> + * at Electronni Visti IA, Kiev, Ukraine. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD: src/usr.bin/colldef/scan.l,v 1.19 2002/08/23 04:18:26 ache Exp $"); + +#include <ctype.h> +#include <err.h> +#include <limits.h> +#include <unistd.h> +#include <string.h> +#include <wchar.h> +#include <sysexits.h> +#include <sys/types.h> +#include "collate.h" +#include "common.h" +#include "y.tab.h" + +int line_no = 1, save_no, fromsubs; +wchar_t buf0[BUFSIZE], *ptr; +wchar_t *buf = buf0; +wchar_t bufstr[BUFSIZE], *ptrsave; +FILE *map_fp; +YY_BUFFER_STATE main_buf, map_buf; +#ifdef FLEX_DEBUG +YYSTYPE yylval; +#endif /* FLEX_DEBUG */ +int yylex(void); +static int localedefmode = 0; +static orderpass = 0; +%} +%% +<INITIAL,charmap,nchar,subs,subs2,ldef>[ \t]+ ; +<subs2,ldef>\" { ptr = buf; BEGIN(string); } +<string>\< { + if(localedefmode) { + ptrsave = ptr; + ptr = buf = bufstr; + BEGIN(s_name); + } else { + if(ptr >= buf + BUFSIZE - 1) + errx(EX_UNAVAILABLE, "string buffer overflow near line %u, character '<'", + line_no); + *ptr++ = '<'; + } +} +<subs>\< { ptr = buf; fromsubs = 1; BEGIN(s_name); } +<ldef>[,;] return *yytext; +<ldef>forward { yylval.ch = DIRECTIVE_FORWARD; return ORDER_DIRECTIVE; } +<ldef>backward { yylval.ch = DIRECTIVE_BACKWARD; return ORDER_DIRECTIVE; } +<ldef>position { yylval.ch = DIRECTIVE_POSITION; return ORDER_DIRECTIVE; } +<ldef>collating[-_]element return COLLATING_ELEMENT; +<ldef>collating[-_]symbol return COLLATING_SYMBOL; +<ldef>from return FROM; +<ldef>\.\.\. return ELLIPSIS; +<ldef>IGNORE return IGNORE; +<ldef>UNDEFINED return UNDEFINED; +<ldef>order[-_]start return ORDER_START; +<ldef>order[-_]end { + char line[YY_BUF_SIZE]; + if (orderpass) + return ORDER_END; + /* The first pass only defined the left-most symbol. We reread the + * order lines, and forward references should now be resolved. */ + orderpass++; + YY_FLUSH_BUFFER; + rewind(yyin); + for(;;) { + if (fgets(line, sizeof(line), yyin) == NULL) + errx(EX_UNAVAILABLE, "EOF rescanning for order_start"); + if (*line == '#') + continue; + if (strstr(line, "order_start") != NULL) + break; + } + return ORDER_SECOND_PASS; +} +<ldef>END[ \t]+LC_COLLATE return END_LC_COLLATE; +<ldef>\n { + line_no++; + return '\n'; +} +<ldef>\< { ptr = buf; BEGIN(elem); } +<INITIAL>\< { ptr = buf; fromsubs = 0; BEGIN(s_name); } +<*>^#.*\n line_no++; +^\n line_no++; +<INITIAL>\\\n line_no++; +<INITIAL,nchar,subs>\\t { yylval.ch = '\t'; return CHAR; } +<INITIAL,nchar,subs>\\n { yylval.ch = '\n'; return CHAR; } +<INITIAL,nchar,subs>\\b { yylval.ch = '\b'; return CHAR; } +<INITIAL,nchar,subs>\\f { yylval.ch = '\f'; return CHAR; } +<INITIAL,nchar,subs>\\v { yylval.ch = '\v'; return CHAR; } +<INITIAL,nchar,subs>\\r { yylval.ch = '\r'; return CHAR; } +<INITIAL,nchar,subs>\\a { yylval.ch = '\a'; return CHAR; } +<subs2>\n { + line_no++; + BEGIN(INITIAL); + return '\n'; +} +<INITIAL,nchar>\n { + line_no++; + if (map_fp != NULL) { + ptr = buf; + BEGIN(defn); + } + return '\n'; +} +<INITIAL>[;,{}()] return *yytext; +<INITIAL>substitute { BEGIN(subs); return SUBSTITUTE; } +<INITIAL>LC_COLLATE { BEGIN(ldef); localedefmode++; return START_LC_COLLATE; } +<subs>with { BEGIN(subs2); return WITH; } +<INITIAL>order return ORDER; +<INITIAL,ldef>charmap BEGIN(charmap); +<INITIAL>;[ \t]*\.\.\.[ \t]*; return RANGE; +<INITIAL,nchar,subs>\\([0-7]{3}) { + u_int v; + + sscanf(&yytext[1], "%o", &v); + yylval.ch = v; + return CHAR; +} +<INITIAL,nchar,subs>\\x\{([0-9a-fA-F]{2,8})\} { + u_int v; + + sscanf(&yytext[3], "%x", &v); + yylval.ch = v; + return CHAR; +} +<INITIAL,nchar,subs>\\x([0-9a-fA-F]{2}) { + u_int v; + + sscanf(&yytext[2], "%x", &v); + yylval.ch = v; + return CHAR; +} +<INITIAL,nchar,subs>\\. { yylval.ch = yytext[1]; return CHAR; } +<INITIAL,nchar,subs>. { yylval.ch = *(u_char *)yytext; return CHAR; } +<defn>^\n line_no++; +<defn>[ \t]+ { + if (ptr == buf) + errx(EX_UNAVAILABLE, "map expected near line %u of %s", + line_no, map_name); + *ptr = 0; + if (localedefmode && *buf == '<' && ptr[-1] == '>') { + if (ptr == buf + 2) + errx(EX_UNAVAILABLE, "map expected near line %u of %s", + line_no, map_name); + *--ptr = 0; + wcscpy(yylval.str, buf + 1); + } else + wcscpy(yylval.str, buf); + BEGIN(nchar); + return DEFN; +} +<s_name,elem>\/\/ { + if(ptr >= buf + BUFSIZE - 1) + errx(EX_UNAVAILABLE, "name buffer overflow near line %u, character '/'", + line_no); + *ptr++ = '/'; +} +<s_name,elem>\/\> { + if(ptr >= buf + BUFSIZE - 1) + errx(EX_UNAVAILABLE, "name buffer overflow near line %u, character '>'", + line_no); + *ptr++ = '>'; +} +<string>\\\" { + if(ptr >= buf + BUFSIZE - 1) + errx(EX_UNAVAILABLE, "string buffer overflow near line %u, character '\"'", + line_no); + *ptr++ = '"'; +} +<elem>\> { + if (ptr == buf) + errx(EX_UNAVAILABLE, "non-empty name expected near line %u", + line_no); + *ptr = 0; + wcscpy(yylval.str, buf); + BEGIN(ldef); + return ELEM; +} +<s_name>\> { + struct symbol *s; + + if (ptr == buf) + errx(EX_UNAVAILABLE, "non-empty name expected near line %u", + line_no); + *ptr = 0; + s = getsymbol(buf, EXISTS); + switch (s->type) { + case SYMBOL_CHAR: + break; + case SYMBOL_CHAIN: + errx(EX_UNAVAILABLE, "name <%s> is chain type near line %u", + showwcs(buf, CHARMAP_SYMBOL_LEN), line_no); + case SYMBOL_SYMBOL: + errx(EX_UNAVAILABLE, "name <%s> is symbol type near line %u", + showwcs(buf, CHARMAP_SYMBOL_LEN), line_no); + default: + errx(EX_UNAVAILABLE, "name <%s>: unknown symbol type (%d) near line %u", + showwcs(buf, CHARMAP_SYMBOL_LEN), s->type, line_no); + } + if (localedefmode) { + ptr = ptrsave; + buf = buf0; + if(ptr >= buf + BUFSIZE - 1) + errx(EX_UNAVAILABLE, "string buffer overflow near line %u, character <%s>", + line_no, showwcs(bufstr, CHARMAP_SYMBOL_LEN)); + *ptr++ = s->u.wc; + BEGIN(string); + } else { + yylval.ch = s->u.wc; + if (fromsubs) + BEGIN(subs); + else + BEGIN(INITIAL); + return CHAR; + } +} +<string>\" { + *ptr = 0; + wcscpy(yylval.str, buf); + if (localedefmode) + BEGIN(ldef); + else + BEGIN(subs2); + return STRING; +} +<s_name,defn,elem>. { + const char *s = (map_fp != NULL) ? map_name : "input"; + + if (!isascii(*yytext) || !isprint(*yytext)) + errx(EX_UNAVAILABLE, "non-ASCII or non-printable character 0x%02x not allowed in the map/name near line %u of %s", + *yytext, line_no, s); + if(ptr >= buf + BUFSIZE - 1) + errx(EX_UNAVAILABLE, "map/name buffer overflow near line %u of %s, character '%c'", + line_no, s, *yytext); + *ptr++ = *yytext; +} +<string>\\t { + if(ptr >= buf + BUFSIZE - 1) + errx(EX_UNAVAILABLE, "string buffer overflow near line %u, character '\\t'", + line_no); + *ptr++ = '\t'; +} +<string>\\b { + if(ptr >= buf + BUFSIZE - 1) + errx(EX_UNAVAILABLE, "string buffer overflow near line %u, character '\\b'", + line_no); + *ptr++ = '\b'; +} +<string>\\f { + if(ptr >= buf + BUFSIZE - 1) + errx(EX_UNAVAILABLE, "string buffer overflow near line %u, character '\\f'", + line_no); + *ptr++ = '\f'; +} +<string>\\v { + if(ptr >= buf + BUFSIZE - 1) + errx(EX_UNAVAILABLE, "string buffer overflow near line %u, character '\\v'", + line_no); + *ptr++ = '\v'; +} +<string>\\n { + if(ptr >= buf + BUFSIZE - 1) + errx(EX_UNAVAILABLE, "string buffer overflow near line %u, character '\\n'", + line_no); + *ptr++ = '\n'; +} +<string>\\r { + if(ptr >= buf + BUFSIZE - 1) + errx(EX_UNAVAILABLE, "string buffer overflow near line %u, character '\\r'", + line_no); + *ptr++ = '\r'; +} +<string>\\a { + if(ptr >= buf + BUFSIZE - 1) + errx(EX_UNAVAILABLE, "string buffer overflow near line %u, character '\\a'", + line_no); + *ptr++ = '\a'; +} +<s_name,string,defn,elem>\n { + const char *s = (map_fp != NULL) ? map_name : "input"; + + errx(EX_UNAVAILABLE, "unterminated map/name/string near line %u of %s", line_no, s); +} +<s_name,string,nchar,elem><<EOF>> { + const char *s = (map_fp != NULL) ? map_name : "input"; + + errx(EX_UNAVAILABLE, "premature EOF in the name/string/char near line %u of %s", line_no, s); +} +<string>\\x\{([0-9a-f]{2,8})\} { + u_int v; + + sscanf(&yytext[3], "%x", &v); + *ptr++ = v; +} +<string>\\x([0-9a-f]{2}) { + u_int v; + + sscanf(&yytext[2], "%x", &v); + *ptr++ = v; +} +<string>\\([0-7]{3}) { + u_int v; + + sscanf(&yytext[1], "%o", &v); + *ptr++ = v; +} +<string>\\. { + if(ptr >= buf + BUFSIZE - 1) + errx(EX_UNAVAILABLE, "string buffer overflow near line %u, character '%c'", + line_no, yytext[1]); + *ptr++ = yytext[1]; +} +<string>. { + if(ptr >= buf + BUFSIZE - 1) + errx(EX_UNAVAILABLE, "string buffer overflow near line %u, character '%c'", + line_no, *yytext); + *ptr++ = *yytext; +} +<charmap>[^ \t\n]+ { + if(*yytext == '/') + strcpy(map_name, yytext); + else { + strcat(map_name, "/"); + strcat(map_name, yytext); + } + if((map_fp = fopen(map_name, "r")) == NULL) + err(EX_UNAVAILABLE, "can't open 'charmap' file %s", + map_name); + save_no = line_no; + line_no = 1; + map_buf = yy_new_buffer(map_fp, YY_BUF_SIZE); + main_buf = YY_CURRENT_BUFFER; + yy_switch_to_buffer(map_buf); + ptr = buf; + BEGIN(defn); +} +<charmap>\n { + errx(EX_UNAVAILABLE, "'charmap' file name expected near line %u", + line_no); +} +<charmap><<EOF>> { + errx(EX_UNAVAILABLE, "'charmap' file name expected near line %u", + line_no); +} +<INITIAL,defn><<EOF>> { + if(map_fp != NULL) { + if (ptr != buf) + errx(EX_UNAVAILABLE, "premature EOF in the map near line %u of %s", line_no, map_name); + yy_switch_to_buffer(main_buf); + yy_delete_buffer(map_buf); + fclose(map_fp); + map_fp = NULL; + line_no = save_no; + if (localedefmode) + BEGIN(ldef); + else + BEGIN(INITIAL); + } else + yyterminate(); +} +%% +#ifdef FLEX_DEBUG +main() +{ + while(yylex()) + ; + return 0; +} +#endif /* FLEX_DEBUG */ diff --git a/adv_cmds/finger/extern.h b/adv_cmds/finger/extern.h new file mode 100644 index 0000000..7b8f29c --- /dev/null +++ b/adv_cmds/finger/extern.h @@ -0,0 +1,68 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)extern.h 8.2 (Berkeley) 4/28/95 + * $FreeBSD: src/usr.bin/finger/extern.h,v 1.10 2005/09/19 10:11:46 dds Exp $ + */ + +#ifndef _EXTERN_H_ +#define _EXTERN_H_ + +extern char tbuf[1024]; /* Temp buffer for anybody. */ +extern int entries; /* Number of people. */ +extern DB *db; /* Database. */ +extern int d_first; +extern sa_family_t family; +extern int gflag; +extern int lflag; +extern time_t now; +extern int oflag; +extern int pplan; /* don't show .plan/.project */ +#ifndef __APPLE__ +extern int Tflag; +#endif +extern int invoker_root; /* Invoked by root */ + +void enter_lastlog(PERSON *); +PERSON *enter_person(struct passwd *); +void enter_where(struct utmpx *, PERSON *); +PERSON *find_person(const char *); +int hide(struct passwd *); +void lflag_print(void); +int match(struct passwd *, const char *); +void netfinger(char *); +PERSON *palloc(void); +char *prphone(char *); +void sflag_print(void); +int show_text(const char *, const char *, const char *); + +#endif /* !_EXTERN_H_ */ diff --git a/adv_cmds/finger/finger.1 b/adv_cmds/finger/finger.1 new file mode 100644 index 0000000..4fbdfeb --- /dev/null +++ b/adv_cmds/finger/finger.1 @@ -0,0 +1,257 @@ +.\" Copyright (c) 1989, 1990, 1993, 1994 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)finger.1 8.3 (Berkeley) 5/5/94 +.\" $FreeBSD: src/usr.bin/finger/finger.1,v 1.31 2005/09/19 10:11:46 dds Exp $ +.\" +.Dd July 17, 2004 +.Dt FINGER 1 +.Os +.Sh NAME +.Nm finger +.Nd user information lookup program +.Sh SYNOPSIS +.Nm +.Op Fl 46gklmpsho +.Op Ar user ...\& +.Op Ar user@host ...\& +.Sh DESCRIPTION +The +.Nm +utility displays information about the system users. +.Pp +Options are: +.Bl -tag -width indent +.It Fl 4 +Forces +.Nm +to use IPv4 addresses only. +.It Fl 6 +Forces +.Nm +to use IPv6 addresses only. +.It Fl g +This option restricts the gecos output to only the users' real +name. +It also has the side-effect of restricting the output +of the remote host when used in conjunction with the +.Fl h +option. +.It Fl h +When used in conjunction with the +.Fl s +option, the name of the remote host is displayed instead of the office +location and office phone. +.It Fl k +Disable all use of +.Xr utmpx 5 . +.It Fl l +Produce a multi-line format displaying all of the information +described for the +.Fl s +option as well as the user's home directory, home phone number, login +shell, mail status, and the contents of the files +.Pa .forward , +.Pa .plan , +.Pa .project +and +.Pa .pubkey +from the user's home directory. +.Pp +If idle time is at least a minute and less than a day, it is +presented in the form ``hh:mm''. +Idle times greater than a day are presented as ``d day[s]hh:mm''. +.Pp +Phone numbers specified as eleven digits are printed as ``+N-NNN-NNN-NNNN''. +Numbers specified as ten or seven digits are printed as the appropriate +subset of that string. +Numbers specified as five digits are printed as ``xN-NNNN''. +Numbers specified as four digits are printed as ``xNNNN''. +.Pp +If write permission is denied to the device, the phrase ``(messages off)'' +is appended to the line containing the device name. +One entry per user is displayed with the +.Fl l +option; if a user is logged on multiple times, terminal information +is repeated once per login. +.Pp +Mail status is shown as ``No Mail.'' if there is no mail at all, ``Mail +last read DDD MMM ## HH:MM YYYY (TZ)'' if the person has looked at their +mailbox since new mail arriving, or ``New mail received ...'', ``Unread +since ...'' if they have new mail. +.It Fl m +Prevent matching of +.Ar user +names. +.Ar User +is usually a login name; however, matching will also be done on the +users' real names, unless the +.Fl m +option is supplied. +All name matching performed by +.Nm +is case insensitive. +.It Fl o +When used in conjunction with the +.Fl s +option, the office location and office phone information is displayed +instead of the name of the remote host. +.It Fl p +Prevent +the +.Fl l +option of +.Nm +from displaying the contents of the +.Pa .forward , +.Pa .plan , +.Pa .project +and +.Pa .pubkey +files. +.It Fl s +Display the user's login name, real name, terminal name and write +status (as a ``*'' before the terminal name if write permission is +denied), idle time, login time, and either office location and office +phone number, or the remote host. +If +.Fl o +is given, the office location and office phone number is printed +(the default). +If +.Fl h +is given, the remote host is printed instead. +.Pp +Idle time is in minutes if it is a single integer, hours and minutes +if a ``:'' is present, or days if a ``d'' is present. +If it is an +.Dq * , +the login time indicates the time of last login. +Login time is displayed as the day name if less than 6 days, else month, day; +hours and minutes, unless more than six months ago, in which case the year +is displayed rather than the hours and minutes. +.Pp +Unknown devices as well as nonexistent idle and login times are +displayed as single asterisks. +.El +.Pp +If no options are specified, +.Nm +defaults to the +.Fl l +style output if operands are provided, otherwise to the +.Fl s +style. +Note that some fields may be missing, in either format, if information +is not available for them. +.Pp +If no arguments are specified, +.Nm +will print an entry for each user currently logged into the system. +.Pp +The +.Nm +utility may be used to look up users on a remote machine. +The format is to specify a +.Ar user +as +.Dq Li user@host , +or +.Dq Li @host , +where the default output +format for the former is the +.Fl l +style, and the default output format for the latter is the +.Fl s +style. +The +.Fl l +option is the only option that may be passed to a remote machine. +.Pp +If the file +.Pa .nofinger +exists in the user's home directory, +and the program is not run with superuser privileges, +.Nm +behaves as if the user in question does not exist. +.Pp +The optional +.Xr finger.conf 5 +configuration file can be used to specify aliases. +Since +.Nm +is invoked by +.Xr fingerd 8 , +aliases will work for both local and network queries. +.Sh ENVIRONMENT +The +.Nm +utility utilizes the following environment variable, if it exists: +.Bl -tag -width Fl +.It Ev FINGER +This variable may be set with favored options to +.Nm . +.El +.Sh FILES +.Bl -tag -width /var/log/lastlog -compact +.It Pa /etc/finger.conf +alias definition data base +.It Pa /var/log/lastlog +last login data base +.El +.Sh SEE ALSO +.Xr chpass 1 , +.Xr w 1 , +.Xr who 1 , +.Xr finger.conf 5 , +.Xr fingerd 8 +.Rs +.%A D. Zimmerman +.%T The Finger User Information Protocol +.%R RFC 1288 +.%D December, 1991 +.Re +.Sh HISTORY +The +.Nm +command appeared in +.Bx 3.0 . +.Sh BUGS +The current FINGER protocol RFC requires that the client keep the connection +fully open until the server closes. +This prevents the use of the optimal +three-packet T/TCP exchange. +(Servers which depend on this requirement are +bogus but have nonetheless been observed in the Internet at large.) +.Pp +The +.Nm +utility does not recognize multibyte characters. diff --git a/adv_cmds/finger/finger.c b/adv_cmds/finger/finger.c new file mode 100644 index 0000000..0cbb887 --- /dev/null +++ b/adv_cmds/finger/finger.c @@ -0,0 +1,416 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Tony Nardo of the Johns Hopkins University/Applied Physics Lab. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Luke Mewburn <lm@rmit.edu.au> added the following on 940622: + * - mail status ("No Mail", "Mail read:...", or "New Mail ..., + * Unread since ...".) + * - 4 digit phone extensions (3210 is printed as x3210.) + * - host/office toggling in short format with -h & -o. + * - short day names (`Tue' printed instead of `Jun 21' if the + * login time is < 6 days. + */ + +#ifndef lint +static const char copyright[] = +"@(#) Copyright (c) 1989, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#if 0 +#ifndef lint +static char sccsid[] = "@(#)finger.c 8.5 (Berkeley) 5/4/95"; +#endif +#endif + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD: src/usr.bin/finger/finger.c,v 1.36 2005/09/19 10:11:46 dds Exp $"); + +/* + * Finger prints out information about users. It is not portable since + * certain fields (e.g. the full user name, office, and phone numbers) are + * extracted from the gecos field of the passwd file which other UNIXes + * may not have or may use for other things. + * + * There are currently two output formats; the short format is one line + * per user and displays login name, tty, login time, real name, idle time, + * and either remote host information (default) or office location/phone + * number, depending on if -h or -o is used respectively. + * The long format gives the same information (in a more legible format) as + * well as home directory, shell, mail info, and .plan/.project files. + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <db.h> +#include <err.h> +#include <pwd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> +#include <utmpx.h> +#include <locale.h> + +#include "finger.h" +#include "pathnames.h" + +DB *db; +time_t now; +int entries, gflag, kflag, lflag, mflag, pplan, sflag, oflag, Tflag; +sa_family_t family = PF_UNSPEC; +int d_first = -1; +char tbuf[1024]; +int invoker_root = 0; + +static void loginlist(void); +static int option(int, char **); +static void usage(void); +static void userlist(int, char **); + +static int +option(int argc, char **argv) +{ + int ch; + + optind = 1; /* reset getopt */ + +#ifdef __APPLE__ + while ((ch = getopt(argc, argv, "46gklmpsho")) != -1) +#else + while ((ch = getopt(argc, argv, "46gklmpshoT")) != -1) +#endif + switch(ch) { + case '4': + family = AF_INET; + break; + case '6': + family = AF_INET6; + break; + case 'g': + gflag = 1; + break; + case 'k': + kflag = 1; /* keep going without utmpx */ + break; + case 'l': + lflag = 1; /* long format */ + break; + case 'm': + mflag = 1; /* force exact match of names */ + break; + case 'p': + pplan = 1; /* don't show .plan/.project */ + break; + case 's': + sflag = 1; /* short format */ + break; + case 'h': + oflag = 0; /* remote host info */ + break; + case 'o': + oflag = 1; /* office info */ + break; +#ifndef __APPLE__ + case 'T': + Tflag = 1; /* disable T/TCP */ + break; +#endif + case '?': + default: + usage(); + } + + return optind; +} + +static void +usage(void) +{ + (void)fprintf(stderr, + "usage: finger [-46gklmpshoT] [user ...] [user@host ...]\n"); + exit(1); +} + +int +main(int argc, char **argv) +{ + int envargc, argcnt; + char *envargv[3]; + struct passwd *pw; + static char myname[] = "finger"; + + if (getuid() == 0 || geteuid() == 0) { + invoker_root = 1; + if ((pw = getpwnam(UNPRIV_NAME)) && pw->pw_uid > 0) { + setgid(pw->pw_gid); + setuid(pw->pw_uid); + } else { + setgid(UNPRIV_UGID); + setuid(UNPRIV_UGID); + } + } + + (void) setlocale(LC_ALL, ""); + + /* remove this line to get remote host */ + oflag = 1; /* default to old "office" behavior */ + + /* + * Process environment variables followed by command line arguments. + */ + if ((envargv[1] = getenv("FINGER"))) { + envargc = 2; + envargv[0] = myname; + envargv[2] = NULL; + (void) option(envargc, envargv); + } + + argcnt = option(argc, argv); + argc -= argcnt; + argv += argcnt; + + (void)time(&now); + setpassent(1); + if (!*argv) { + /* + * Assign explicit "small" format if no names given and -l + * not selected. Force the -s BEFORE we get names so proper + * screening will be done. + */ + if (!lflag) + sflag = 1; /* if -l not explicit, force -s */ + loginlist(); + if (entries == 0) + (void)printf("No one logged on.\n"); + } else { + userlist(argc, argv); + /* + * Assign explicit "large" format if names given and -s not + * explicitly stated. Force the -l AFTER we get names so any + * remote finger attempts specified won't be mishandled. + */ + if (!sflag) + lflag = 1; /* if -s not explicit, force -l */ + } + if (entries) { + if (lflag) + lflag_print(); + else + sflag_print(); + } + return (0); +} + +static void +loginlist(void) +{ + PERSON *pn; + DBT data, key; + struct passwd *pw; + struct utmpx *user; + int r, sflag1; + char name[_UTX_USERSIZE + 1]; + + if (kflag) + errx(1, "can't list logins without reading utmpx"); + + setutxent(); + name[_UTX_USERSIZE] = '\0'; + while ((user = getutxent()) != NULL) { + if (!user->ut_user[0] || user->ut_type != USER_PROCESS) + continue; + if ((pn = find_person(user->ut_user)) == NULL) { + bcopy(user->ut_user, name, _UTX_USERSIZE); + if ((pw = getpwnam(name)) == NULL) + continue; + if (hide(pw)) + continue; + pn = enter_person(pw); + } + enter_where(user, pn); + } + endutxent(); + if (db && lflag) + for (sflag1 = R_FIRST;; sflag1 = R_NEXT) { + PERSON *tmp; + + r = (*db->seq)(db, &key, &data, sflag1); + if (r == -1) + err(1, "db seq"); + if (r == 1) + break; + memmove(&tmp, data.data, sizeof tmp); + enter_lastlog(tmp); + } +} + +static void +userlist(int argc, char **argv) +{ + PERSON *pn; + DBT data, key; + struct utmpx *user; + struct passwd *pw; + int r, sflag1, *used, *ip; + char **ap, **nargv, **np, **p; + FILE *conf_fp; + char conf_alias[LINE_MAX]; + char *conf_realname; + int conf_length; + + if ((nargv = malloc((argc+1) * sizeof(char *))) == NULL || + (used = calloc(argc, sizeof(int))) == NULL) + err(1, NULL); + + /* Pull out all network requests. */ + for (ap = p = argv, np = nargv; *p; ++p) + if (index(*p, '@')) + *np++ = *p; + else + *ap++ = *p; + + *np++ = NULL; + *ap++ = NULL; + + if (!*argv) + goto net; + + /* + * Mark any arguments beginning with '/' as invalid so that we + * don't accidently confuse them with expansions from finger.conf + */ + for (p = argv, ip = used; *p; ++p, ++ip) + if (**p == '/') { + *ip = 1; + warnx("%s: no such user", *p); + } + + /* + * Traverse the finger alias configuration file of the form + * alias:(user|alias), ignoring comment lines beginning '#'. + */ + if ((conf_fp = fopen(_PATH_FINGERCONF, "r")) != NULL) { + while(fgets(conf_alias, sizeof(conf_alias), conf_fp) != NULL) { + conf_length = strlen(conf_alias); + if (*conf_alias == '#' || conf_alias[--conf_length] != '\n') + continue; + conf_alias[conf_length] = '\0'; /* Remove trailing LF */ + if ((conf_realname = strchr(conf_alias, ':')) == NULL) + continue; + *conf_realname = '\0'; /* Replace : with NUL */ + for (p = argv; *p; ++p) { + if (strcmp(*p, conf_alias) == 0) { + if ((*p = strdup(conf_realname+1)) == NULL) { + err(1, NULL); + } + } + } + } + (void)fclose(conf_fp); + } + + /* + * Traverse the list of possible login names and check the login name + * and real name against the name specified by the user. If the name + * begins with a '/', try to read the file of that name instead of + * gathering the traditional finger information. + */ + if (mflag) + for (p = argv, ip = used; *p; ++p, ++ip) { + if (**p != '/' || *ip == 1 || !show_text("", *p, "")) { + if (((pw = getpwnam(*p)) != NULL) && !hide(pw)) + enter_person(pw); + else if (!*ip) + warnx("%s: no such user", *p); + } + } + else { + while ((pw = getpwent()) != NULL) { + for (p = argv, ip = used; *p; ++p, ++ip) + if (**p == '/' && *ip != 1 + && show_text("", *p, "")) + *ip = 1; + else if (match(pw, *p) && !hide(pw)) { + enter_person(pw); + *ip = 1; + } + } + for (p = argv, ip = used; *p; ++p, ++ip) + if (!*ip) + warnx("%s: no such user", *p); + } + + /* Handle network requests. */ +net: for (p = nargv; *p;) { + netfinger(*p++); + if (*p || entries) + printf("\n"); + } + + if (entries == 0) + return; + + if (kflag) + return; + + /* + * Scan thru the list of users currently logged in, saving + * appropriate data whenever a match occurs. + */ + setutxent(); + while ((user = getutxent()) != NULL) { + if (!user->ut_user && user->ut_type != USER_PROCESS) + continue; + if ((pn = find_person(user->ut_user)) == NULL) + continue; + enter_where(user, pn); + } + endutxent(); + if (db) + for (sflag1 = R_FIRST;; sflag1 = R_NEXT) { + PERSON *tmp; + + r = (*db->seq)(db, &key, &data, sflag1); + if (r == -1) + err(1, "db seq"); + if (r == 1) + break; + memmove(&tmp, data.data, sizeof tmp); + enter_lastlog(tmp); + } +} diff --git a/adv_cmds/finger/finger.conf.5 b/adv_cmds/finger/finger.conf.5 new file mode 100644 index 0000000..83ebc5b --- /dev/null +++ b/adv_cmds/finger/finger.conf.5 @@ -0,0 +1,91 @@ +.\" Copyright (c) 2000 Mark Knight <markk@knigma.org> +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD: src/usr.bin/finger/finger.conf.5,v 1.6 2005/02/09 18:04:22 ru Exp $ +.\" +.Dd August 16, 2000 +.Dt FINGER.CONF 5 +.Os +.Sh NAME +.Nm finger.conf +.Nd +.Xr finger 1 +alias configuration file +.Sh DESCRIPTION +The optional +.Nm +file is used to provide aliases that can be fingered by local +and network users. +This may be useful where a user's login name is not the same +as their preferred mail address, or for providing virtual login names +than can be fingered. +.Pp +Lines beginning with ``#'' are comments. +Other lines must consist of an +alias name and a target name separated by a colon. +A target name should be either a user, a forward +reference to another alias or the path of a world readable file. +.Pp +Where an alias points to a file, the contents of that file will be displayed +when the alias is fingered. +.Sh FILES +.Bl -tag -width /etc/finger.conf -compact +.It Pa /etc/finger.conf +.Xr finger 1 +alias definition data base +.El +.Sh EXAMPLES +.Bd -literal +# /etc/finger.conf alias definition file +# +# Format alias:(user|alias) +# +# Individual aliases +# +markk:mkn +john.smith:dev329 +john:dev329 +sue:/etc/finger/sue.txt +# +# Network status message +# +status:/usr/local/etc/status.txt +# +# Administrative redirects +# +root:admin +postmaster:admin +abuse:admin +# +# For the time being, 'sod' is sysadmin. +# +admin:sod +.Ed +.Sh SEE ALSO +.Xr finger 1 +.Sh HISTORY +Support for the +.Nm +file was submitted by Mark Knight <markk@knigma.org> and first appeared in +.Fx 4.2 . diff --git a/adv_cmds/finger/finger.h b/adv_cmds/finger/finger.h new file mode 100644 index 0000000..19b30fb --- /dev/null +++ b/adv_cmds/finger/finger.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Tony Nardo of the Johns Hopkins University/Applied Physics Lab. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)finger.h 8.1 (Berkeley) 6/6/93 + * $FreeBSD: src/usr.bin/finger/finger.h,v 1.5 2004/03/14 06:43:34 jmallett Exp $ + */ + +#ifndef _FINGER_H_ +#define _FINGER_H_ + +typedef struct person { + uid_t uid; /* user id */ + char *dir; /* user's home directory */ + char *homephone; /* pointer to home phone no. */ + char *name; /* login name */ + char *office; /* pointer to office name */ + char *officephone; /* pointer to office phone no. */ + char *realname; /* pointer to full name */ + char *shell; /* user's shell */ + time_t mailread; /* last time mail was read */ + time_t mailrecv; /* last time mail was received */ + struct where *whead, *wtail; /* list of where user is or has been */ +} PERSON; + +enum status { LASTLOG, LOGGEDIN }; + +typedef struct where { + struct where *next; /* next place user is or has been */ + enum status info; /* type/status of request */ + short writable; /* tty is writable */ + time_t loginat; /* time of (last) login */ + time_t idletime; /* how long idle (if logged in) */ + char tty[_UTX_LINESIZE+1]; /* null terminated tty line */ + char host[_UTX_HOSTSIZE+1]; /* null terminated remote host name */ +} WHERE; + +#define UNPRIV_NAME "nobody" /* Preferred privilege level */ +#define UNPRIV_UGID 32767 /* Default uid and gid */ +#define OUTPUT_MAX 100000 /* Do not keep listinging forever */ +#define TIME_LIMIT 360 /* Do not keep listinging forever */ + +#define UT_NAMESIZE 8 /* old utmp.h value */ + +#include "extern.h" + +#endif /* !_FINGER_H_ */ diff --git a/adv_cmds/finger/lprint.c b/adv_cmds/finger/lprint.c new file mode 100644 index 0000000..6e9b42d --- /dev/null +++ b/adv_cmds/finger/lprint.c @@ -0,0 +1,367 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Tony Nardo of the Johns Hopkins University/Applied Physics Lab. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if 0 +#ifndef lint +static char sccsid[] = "@(#)lprint.c 8.3 (Berkeley) 4/28/95"; +#endif +#endif + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD: src/usr.bin/finger/lprint.c,v 1.25 2004/03/14 06:43:34 jmallett Exp $"); + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <ctype.h> +#include <db.h> +#include <err.h> +#include <fcntl.h> +#include <langinfo.h> +#include <paths.h> +#include <pwd.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <utmpx.h> +#include "finger.h" +#include "pathnames.h" + +#define LINE_LEN 80 +#define TAB_LEN 8 /* 8 spaces between tabs */ + +static int demi_print(char *, int); +static void lprint(PERSON *); +static void vputc(unsigned char); + +void +lflag_print(void) +{ + PERSON *pn; + int sflag, r; + PERSON *tmp; + DBT data, key; + + for (sflag = R_FIRST;; sflag = R_NEXT) { + r = (*db->seq)(db, &key, &data, sflag); + if (r == -1) + err(1, "db seq"); + if (r == 1) + break; + memmove(&tmp, data.data, sizeof tmp); + pn = tmp; + if (sflag != R_FIRST) + putchar('\n'); + lprint(pn); + if (!pplan) { + (void)show_text(pn->dir, + _PATH_FORWARD, "Mail forwarded to"); + (void)show_text(pn->dir, _PATH_PROJECT, "Project"); + if (!show_text(pn->dir, _PATH_PLAN, "Plan")) + (void)printf("No Plan.\n"); + (void)show_text(pn->dir, + _PATH_PUBKEY, "Public key"); + } + } +} + +static void +lprint(PERSON *pn) +{ + struct tm *delta; + WHERE *w; + int cpr, len, maxlen; + struct tm *tp; + int oddfield; + char t[80]; + + if (d_first < 0) + d_first = (*nl_langinfo(D_MD_ORDER) == 'd'); + /* + * long format -- + * login name + * real name + * home directory + * shell + * office, office phone, home phone if available + * mail status + */ + (void)printf("Login: %-15s\t\t\tName: %s\nDirectory: %-25s", + pn->name, pn->realname, pn->dir); + (void)printf("\tShell: %-s\n", *pn->shell ? pn->shell : _PATH_BSHELL); + + if (gflag) + goto no_gecos; + /* + * try and print office, office phone, and home phone on one line; + * if that fails, do line filling so it looks nice. + */ +#define OFFICE_TAG "Office" +#define OFFICE_PHONE_TAG "Office Phone" + oddfield = 0; + if (pn->office && pn->officephone && + strlen(pn->office) + strlen(pn->officephone) + + sizeof(OFFICE_TAG) + 2 <= 5 * TAB_LEN) { + (void)snprintf(tbuf, sizeof(tbuf), "%s: %s, %s", + OFFICE_TAG, pn->office, prphone(pn->officephone)); + oddfield = demi_print(tbuf, oddfield); + } else { + if (pn->office) { + (void)snprintf(tbuf, sizeof(tbuf), "%s: %s", + OFFICE_TAG, pn->office); + oddfield = demi_print(tbuf, oddfield); + } + if (pn->officephone) { + (void)snprintf(tbuf, sizeof(tbuf), "%s: %s", + OFFICE_PHONE_TAG, prphone(pn->officephone)); + oddfield = demi_print(tbuf, oddfield); + } + } + if (pn->homephone) { + (void)snprintf(tbuf, sizeof(tbuf), "%s: %s", "Home Phone", + prphone(pn->homephone)); + oddfield = demi_print(tbuf, oddfield); + } + if (oddfield) + putchar('\n'); + +no_gecos: + /* + * long format con't: + * if logged in + * terminal + * idle time + * if messages allowed + * where logged in from + * if not logged in + * when last logged in + */ + /* find out longest device name for this user for formatting */ + for (w = pn->whead, maxlen = -1; w != NULL; w = w->next) + if ((len = strlen(w->tty)) > maxlen) + maxlen = len; + /* find rest of entries for user */ + for (w = pn->whead; w != NULL; w = w->next) { + if (w->info == LOGGEDIN) { + tp = localtime(&w->loginat); + strftime(t, sizeof(t), + d_first ? "%a %e %b %R (%Z)" : "%a %b %e %R (%Z)", + tp); + cpr = printf("On since %s on %s", t, w->tty); + /* + * idle time is tough; if have one, print a comma, + * then spaces to pad out the device name, then the + * idle time. Follow with a comma if a remote login. + */ + delta = gmtime(&w->idletime); + if (w->idletime != -1 && (delta->tm_yday || + delta->tm_hour || delta->tm_min)) { + cpr += printf("%-*s idle ", + maxlen - (int)strlen(w->tty) + 1, ","); + if (delta->tm_yday > 0) { + cpr += printf("%d day%s ", + delta->tm_yday, + delta->tm_yday == 1 ? "" : "s"); + } + cpr += printf("%d:%02d", + delta->tm_hour, delta->tm_min); + if (*w->host) { + putchar(','); + ++cpr; + } + } + if (!w->writable) + cpr += printf(" (messages off)"); + } else if (w->loginat == 0) { + cpr = printf("Never logged in."); + } else { + tp = localtime(&w->loginat); + if (now - w->loginat > 86400 * 365 / 2) { + strftime(t, sizeof(t), + d_first ? "%a %e %b %R %Y (%Z)" : + "%a %b %e %R %Y (%Z)", + tp); + } else { + strftime(t, sizeof(t), + d_first ? "%a %e %b %R (%Z)" : + "%a %b %e %R (%Z)", + tp); + } + cpr = printf("Last login %s on %s", t, w->tty); + } + if (*w->host) { + if (LINE_LEN < (cpr + 6 + strlen(w->host))) + (void)printf("\n "); + (void)printf(" from %s", w->host); + } + putchar('\n'); + } + if (pn->mailrecv == -1) + printf("No Mail.\n"); + else if (pn->mailrecv > pn->mailread) { + tp = localtime(&pn->mailrecv); + strftime(t, sizeof(t), + d_first ? "%a %e %b %R %Y (%Z)" : + "%a %b %e %R %Y (%Z)", + tp); + printf("New mail received %s\n", t); + tp = localtime(&pn->mailread); + strftime(t, sizeof(t), + d_first ? "%a %e %b %R %Y (%Z)" : + "%a %b %e %R %Y (%Z)", + tp); + printf(" Unread since %s\n", t); + } else { + tp = localtime(&pn->mailread); + strftime(t, sizeof(t), + d_first ? "%a %e %b %R %Y (%Z)" : + "%a %b %e %R %Y (%Z)", + tp); + printf("Mail last read %s\n", t); + } +} + +static int +demi_print(char *str, int oddfield) +{ + static int lenlast; + int lenthis, maxlen; + + lenthis = strlen(str); + if (oddfield) { + /* + * We left off on an odd number of fields. If we haven't + * crossed the midpoint of the screen, and we have room for + * the next field, print it on the same line; otherwise, + * print it on a new line. + * + * Note: we insist on having the right hand fields start + * no less than 5 tabs out. + */ + maxlen = 5 * TAB_LEN; + if (maxlen < lenlast) + maxlen = lenlast; + if (((((maxlen / TAB_LEN) + 1) * TAB_LEN) + + lenthis) <= LINE_LEN) { + while(lenlast < (4 * TAB_LEN)) { + putchar('\t'); + lenlast += TAB_LEN; + } + (void)printf("\t%s\n", str); /* force one tab */ + } else { + (void)printf("\n%s", str); /* go to next line */ + oddfield = !oddfield; /* this'll be undone below */ + } + } else + (void)printf("%s", str); + oddfield = !oddfield; /* toggle odd/even marker */ + lenlast = lenthis; + return(oddfield); +} + +int +show_text(const char *directory, const char *file_name, const char *header) +{ + struct stat sb; + FILE *fp; + int ch, cnt; + char *p, lastc; + int fd, nr; + + lastc = '\0'; + + (void)snprintf(tbuf, sizeof(tbuf), "%s/%s", directory, file_name); + if ((fd = open(tbuf, O_RDONLY)) < 0 || fstat(fd, &sb) || + sb.st_size == 0) + return(0); + + /* If short enough, and no newlines, show it on a single line.*/ + if (sb.st_size <= LINE_LEN - strlen(header) - 5) { + nr = read(fd, tbuf, sizeof(tbuf)); + if (nr <= 0) { + (void)close(fd); + return(0); + } + for (p = tbuf, cnt = nr; cnt--; ++p) + if (*p == '\n') + break; + if (cnt <= 1) { + if (*header != '\0') + (void)printf("%s: ", header); + for (p = tbuf, cnt = nr; cnt--; ++p) + if (*p != '\r') + vputc(lastc = *p); + if (lastc != '\n') + (void)putchar('\n'); + (void)close(fd); + return(1); + } + else + (void)lseek(fd, 0L, SEEK_SET); + } + if ((fp = fdopen(fd, "r")) == NULL) + return(0); + if (*header != '\0') + (void)printf("%s:\n", header); + while ((ch = getc(fp)) != EOF) + if (ch != '\r') + vputc(lastc = ch); + if (lastc != '\n') + (void)putchar('\n'); + (void)fclose(fp); + return(1); +} + +static void +vputc(unsigned char ch) +{ + int meta; + + if (!isprint(ch) && !isascii(ch)) { + (void)putchar('M'); + (void)putchar('-'); + ch = toascii(ch); + meta = 1; + } else + meta = 0; + if (isprint(ch) || (!meta && (ch == ' ' || ch == '\t' || ch == '\n'))) + (void)putchar(ch); + else { + (void)putchar('^'); + (void)putchar(ch == '\177' ? '?' : ch | 0100); + } +} diff --git a/adv_cmds/finger/net.c b/adv_cmds/finger/net.c new file mode 100644 index 0000000..cf0699d --- /dev/null +++ b/adv_cmds/finger/net.c @@ -0,0 +1,250 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Tony Nardo of the Johns Hopkins University/Applied Physics Lab. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if 0 +#ifndef lint +static char sccsid[] = "@(#)net.c 8.4 (Berkeley) 4/28/95"; +#endif +#endif + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD: src/usr.bin/finger/net.c,v 1.23 2004/05/16 22:08:15 stefanf Exp $"); + +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/uio.h> +#include <ctype.h> +#include <db.h> +#include <err.h> +#include <netdb.h> +#include <pwd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <utmpx.h> +#include "finger.h" + +static void cleanup(int sig); +static int do_protocol(const char *name, const struct addrinfo *ai); +static void trying(const struct addrinfo *ai); + +void +netfinger(char *name) +{ + int error, multi; + char *host; + struct addrinfo *ai, *ai0; + static struct addrinfo hint; + + host = strrchr(name, '@'); + if (host == 0) + return; + *host++ = '\0'; + signal(SIGALRM, cleanup); + alarm(TIME_LIMIT); + + hint.ai_flags = AI_CANONNAME; + hint.ai_family = family; + hint.ai_socktype = SOCK_STREAM; + + error = getaddrinfo(host, "finger", &hint, &ai0); + if (error) { + warnx("%s: %s", host, gai_strerror(error)); + return; + } + + multi = (ai0->ai_next) != 0; + + /* ai_canonname may not be filled in if the user specified an IP. */ + if (ai0->ai_canonname == 0) + printf("[%s]\n", host); + else + printf("[%s]\n", ai0->ai_canonname); + + for (ai = ai0; ai != 0; ai = ai->ai_next) { + if (multi) + trying(ai); + + error = do_protocol(name, ai); + if (!error) + break; + } + alarm(0); + freeaddrinfo(ai0); +} + +static int +do_protocol(const char *name, const struct addrinfo *ai) +{ + int cnt, line_len, s; + FILE *fp; + int c, lastc; + struct iovec iov[3]; + struct msghdr msg; + static char slash_w[] = "/W "; + static char neteol[] = "\r\n"; + + s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); + if (s < 0) { + warn("socket(%d, %d, %d)", ai->ai_family, ai->ai_socktype, + ai->ai_protocol); + return -1; + } + + msg.msg_name = (void *)ai->ai_addr; + msg.msg_namelen = ai->ai_addrlen; + msg.msg_iov = iov; + msg.msg_iovlen = 0; + msg.msg_control = 0; + msg.msg_controllen = 0; + msg.msg_flags = 0; + + /* -l flag for remote fingerd */ + if (lflag) { + iov[msg.msg_iovlen].iov_base = slash_w; + iov[msg.msg_iovlen++].iov_len = 3; + } + /* send the name followed by <CR><LF> */ + iov[msg.msg_iovlen].iov_base = strdup(name); + iov[msg.msg_iovlen++].iov_len = strlen(name); + iov[msg.msg_iovlen].iov_base = neteol; + iov[msg.msg_iovlen++].iov_len = 2; + +#ifdef __APPLE__ + if (connect(s, ai->ai_addr, ai->ai_addrlen) < 0) { +#else + /* + * -T disables data-on-SYN: compatibility option to finger broken + * hosts. Also, the implicit-open API is broken on IPv6, so do + * the explicit connect there, too. + */ + if ((Tflag || ai->ai_addr->sa_family == AF_INET6) + && connect(s, ai->ai_addr, ai->ai_addrlen) < 0) { +#endif + warn("connect"); + close(s); + return -1; + } + + if (sendmsg(s, &msg, 0) < 0) { + warn("sendmsg"); + close(s); + return -1; + } + + /* + * Read from the remote system; once we're connected, we assume some + * data. If none arrives, we hang until the user interrupts. + * + * If we see a <CR> or a <CR> with the high bit set, treat it as + * a newline; if followed by a newline character, only output one + * newline. + * + * Otherwise, all high bits are stripped; if it isn't printable and + * it isn't a space, we can simply set the 7th bit. Every ASCII + * character with bit 7 set is printable. + */ + lastc = 0; + if ((fp = fdopen(s, "r")) != NULL) { + cnt = 0; + line_len = 0; + while ((c = getc(fp)) != EOF) { + if (++cnt > OUTPUT_MAX) { + printf("\n\n Output truncated at %d bytes...\n", + cnt - 1); + break; + } + if (c == 0x0d) { + if (lastc == '\r') /* ^M^M - skip dupes */ + continue; + c = '\n'; + lastc = '\r'; + } else { + if (!isprint(c) && !isspace(c)) { + c &= 0x7f; + c |= 0x40; + } + if (lastc != '\r' || c != '\n') + lastc = c; + else { + lastc = '\n'; + continue; + } + } + putchar(c); + if (c != '\n' && ++line_len > _POSIX2_LINE_MAX) { + putchar('\\'); + putchar('\n'); + lastc = '\r'; + } + if (lastc == '\n' || lastc == '\r') + line_len = 0; + } + if (ferror(fp)) { + /* + * Assume that whatever it was set errno... + */ + warn("reading from network"); + } + if (lastc != '\n') + putchar('\n'); + + fclose(fp); + } + return 0; +} + +static void +trying(const struct addrinfo *ai) +{ + char buf[NI_MAXHOST]; + + if (getnameinfo(ai->ai_addr, ai->ai_addrlen, buf, sizeof buf, + (char *)0, 0, NI_NUMERICHOST) != 0) + return; /* XXX can't happen */ + + printf("Trying %s...\n", buf); +} + +void +cleanup(int sig __unused) +{ +#define ERRSTR "Timed out.\n" + write(STDERR_FILENO, ERRSTR, sizeof ERRSTR); + exit(1); +} + diff --git a/adv_cmds/finger/pathnames.h b/adv_cmds/finger/pathnames.h new file mode 100644 index 0000000..160252d --- /dev/null +++ b/adv_cmds/finger/pathnames.h @@ -0,0 +1,41 @@ +/*- + * Copyright (c) 2000 Mark Knight <markk@knigma.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/usr.bin/finger/pathnames.h,v 1.5 2001/07/30 16:50:47 yar Exp $ + */ + +#ifndef PATHNAMES_H + +#define _PATH_FORWARD ".forward" +#define _PATH_NOFINGER ".nofinger" +#define _PATH_PLAN ".plan" +#define _PATH_PROJECT ".project" +#define _PATH_PUBKEY ".pubkey" + +#ifndef _PATH_FINGERCONF +#define _PATH_FINGERCONF "/etc/finger.conf" +#endif /* _PATH_FINGERCONF */ + +#endif /* PATHNAMES_H */ diff --git a/adv_cmds/finger/sprint.c b/adv_cmds/finger/sprint.c new file mode 100644 index 0000000..8de1cba --- /dev/null +++ b/adv_cmds/finger/sprint.c @@ -0,0 +1,187 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Tony Nardo of the Johns Hopkins University/Applied Physics Lab. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if 0 +#ifndef lint +static char sccsid[] = "@(#)sprint.c 8.3 (Berkeley) 4/28/95"; +#endif +#endif + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD: src/usr.bin/finger/sprint.c,v 1.22 2003/04/02 20:22:29 rwatson Exp $"); + +#include <sys/types.h> +#include <sys/socket.h> +#include <db.h> +#include <err.h> +#include <langinfo.h> +#include <pwd.h> +#include <stdio.h> +#include <string.h> +#include <time.h> +#include <utmpx.h> +#include "finger.h" + +static void stimeprint(WHERE *); + +void +sflag_print(void) +{ + PERSON *pn; + WHERE *w; + int sflag, r, namelen; + char p[80]; + PERSON *tmp; + DBT data, key; + struct tm *lc; + + if (d_first < 0) + d_first = (*nl_langinfo(D_MD_ORDER) == 'd'); + /* + * short format -- + * login name + * real name + * terminal name (the XX of ttyXX) + * if terminal writeable (add an '*' to the terminal name + * if not) + * if logged in show idle time and day logged in, else + * show last login date and time. + * If > 6 months, show year instead of time. + * if (-o) + * office location + * office phone + * else + * remote host + */ +#define MAXREALNAME 20 +#define MAXHOSTNAME 17 /* in reality, hosts are never longer than 16 */ + (void)printf("%-*s %-*s%s %s\n", UT_NAMESIZE, "Login", MAXREALNAME, + "Name", " TTY Idle Login Time ", (gflag) ? "" : + oflag ? "Office Phone" : "Where"); + + for (sflag = R_FIRST;; sflag = R_NEXT) { + r = (*db->seq)(db, &key, &data, sflag); + if (r == -1) + err(1, "db seq"); + if (r == 1) + break; + memmove(&tmp, data.data, sizeof tmp); + pn = tmp; + + for (w = pn->whead; w != NULL; w = w->next) { + namelen = MAXREALNAME; + if (w->info == LOGGEDIN && !w->writable) + --namelen; /* leave space before `*' */ + (void)printf("%-*.*s %-*.*s", UT_NAMESIZE, _UTX_USERSIZE, + pn->name, MAXREALNAME, namelen, + pn->realname ? pn->realname : ""); + if (!w->loginat) { + (void)printf(" * * No logins "); + goto office; + } + (void)putchar(w->info == LOGGEDIN && !w->writable ? + '*' : ' '); + if (*w->tty) + (void)printf("%-3.3s ", + (strncmp(w->tty, "tty", 3) + && strncmp(w->tty, "cua", 3)) + ? w->tty : w->tty + 3); + else + (void)printf(" "); + if (w->info == LOGGEDIN) { + stimeprint(w); + (void)printf(" "); + } else + (void)printf(" * "); + lc = localtime(&w->loginat); +#define SECSPERDAY 86400 +#define DAYSPERWEEK 7 +#define DAYSPERNYEAR 365 + if (now - w->loginat < SECSPERDAY * (DAYSPERWEEK - 1)) { + (void)strftime(p, sizeof(p), "%a", lc); + } else { + (void)strftime(p, sizeof(p), + d_first ? "%e %b" : "%b %e", lc); + } + (void)printf("%-6.6s", p); + if (now - w->loginat >= SECSPERDAY * DAYSPERNYEAR / 2) { + (void)strftime(p, sizeof(p), "%Y", lc); + } else { + (void)strftime(p, sizeof(p), "%R", lc); + } + (void)printf(" %-5.5s", p); +office: + if (gflag) + goto no_gecos; + if (oflag) { + if (pn->office) + (void)printf(" %-7.7s", pn->office); + else if (pn->officephone) + (void)printf(" %-7.7s", " "); + if (pn->officephone) + (void)printf(" %-.9s", + prphone(pn->officephone)); + } else + (void)printf(" %.*s", MAXHOSTNAME, w->host); +no_gecos: + putchar('\n'); + } + } +} + +static void +stimeprint(WHERE *w) +{ + struct tm *delta; + + if (w->idletime == -1) { + (void)printf(" "); + return; + } + + delta = gmtime(&w->idletime); + if (!delta->tm_yday) + if (!delta->tm_hour) + if (!delta->tm_min) + (void)printf(" "); + else + (void)printf("%5d", delta->tm_min); + else + (void)printf("%2d:%02d", + delta->tm_hour, delta->tm_min); + else + (void)printf("%4dd", delta->tm_yday); +} diff --git a/adv_cmds/finger/util.c b/adv_cmds/finger/util.c new file mode 100644 index 0000000..6e7c925 --- /dev/null +++ b/adv_cmds/finger/util.c @@ -0,0 +1,419 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Tony Nardo of the Johns Hopkins University/Applied Physics Lab. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if 0 +#ifndef lint +static char sccsid[] = "@(#)util.c 8.3 (Berkeley) 4/28/95"; +#endif +#endif + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD: src/usr.bin/finger/util.c,v 1.22 2005/09/19 10:11:47 dds Exp $"); + +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <ctype.h> +#include <db.h> +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <paths.h> +#include <pwd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <utmpx.h> +#include "finger.h" +#include "pathnames.h" + +static void find_idle_and_ttywrite(WHERE *); +static void userinfo(PERSON *, struct passwd *); +static WHERE *walloc(PERSON *); + +int +match(struct passwd *pw, const char *user) +{ + char *p, *t; + char name[1024]; + + if (!strcasecmp(pw->pw_name, user)) + return(1); + + /* + * XXX + * Why do we skip asterisks!?!? + */ + (void)strncpy(p = tbuf, pw->pw_gecos, sizeof(tbuf)); + tbuf[sizeof(tbuf) - 1] = '\0'; + if (*p == '*') + ++p; + + /* Ampersands get replaced by the login name. */ + if ((p = strtok(p, ",")) == NULL) + return(0); + + for (t = name; t < &name[sizeof(name) - 1] && (*t = *p) != '\0'; ++p) { + if (*t == '&') { + (void)strncpy(t, pw->pw_name, + sizeof(name) - (t - name)); + name[sizeof(name) - 1] = '\0'; + while (t < &name[sizeof(name) - 1] && *++t) + continue; + } else { + ++t; + } + } + *t = '\0'; + for (t = name; (p = strtok(t, "\t ")) != NULL; t = NULL) + if (!strcasecmp(p, user)) + return(1); + return(0); +} + +void +enter_lastlog(PERSON *pn) +{ + WHERE *w; + struct lastlogx l, *ll; + char doit = 0; + + if ((ll = getlastlogxbyname(pn->name, &l)) == NULL) { + bzero(&l, sizeof(l)); + ll = &l; + } + if ((w = pn->whead) == NULL) + doit = 1; + else if (ll->ll_tv.tv_sec != 0) { + /* if last login is earlier than some current login */ + for (; !doit && w != NULL; w = w->next) + if (w->info == LOGGEDIN && w->loginat < ll->ll_tv.tv_sec) + doit = 1; + /* + * and if it's not any of the current logins + * can't use time comparison because there may be a small + * discrepancy since login calls time() twice + */ + for (w = pn->whead; doit && w != NULL; w = w->next) + if (w->info == LOGGEDIN && + strncmp(w->tty, ll->ll_line, _UTX_LINESIZE) == 0) + doit = 0; + } + if (doit) { + w = walloc(pn); + w->info = LASTLOG; + bcopy(ll->ll_line, w->tty, _UTX_LINESIZE); + w->tty[_UTX_LINESIZE] = 0; + bcopy(ll->ll_host, w->host, _UTX_HOSTSIZE); + w->host[_UTX_HOSTSIZE] = 0; + w->loginat = ll->ll_tv.tv_sec; + } +} + +void +enter_where(struct utmpx *ut, PERSON *pn) +{ + WHERE *w; + + w = walloc(pn); + w->info = LOGGEDIN; + bcopy(ut->ut_line, w->tty, _UTX_LINESIZE); + w->tty[_UTX_LINESIZE] = 0; + bcopy(ut->ut_host, w->host, _UTX_HOSTSIZE); + w->host[_UTX_HOSTSIZE] = 0; + w->loginat = (time_t)ut->ut_tv.tv_sec; + find_idle_and_ttywrite(w); +} + +PERSON * +enter_person(struct passwd *pw) +{ + DBT data, key; + PERSON *pn; + + if (db == NULL && + (db = dbopen(NULL, O_RDWR, 0, DB_BTREE, NULL)) == NULL) + err(1, NULL); + + key.data = pw->pw_name; + key.size = strlen(pw->pw_name); + + switch ((*db->get)(db, &key, &data, 0)) { + case 0: + memmove(&pn, data.data, sizeof pn); + return (pn); + default: + case -1: + err(1, "db get"); + /* NOTREACHED */ + case 1: + ++entries; + pn = palloc(); + userinfo(pn, pw); + pn->whead = NULL; + + data.size = sizeof(PERSON *); + data.data = &pn; + if ((*db->put)(db, &key, &data, 0)) + err(1, "db put"); + return (pn); + } +} + +PERSON * +find_person(const char *name) +{ + struct passwd *pw; + + int cnt; + DBT data, key; + PERSON *p; + char buf[_UTX_USERSIZE + 1]; + + if (!db) + return(NULL); + + if ((pw = getpwnam(name)) && hide(pw)) + return(NULL); + + /* Name may be only _UTX_USERSIZE long and not NUL terminated. */ + for (cnt = 0; cnt < _UTX_USERSIZE && *name; ++name, ++cnt) + buf[cnt] = *name; + buf[cnt] = '\0'; + key.data = buf; + key.size = cnt; + + if ((*db->get)(db, &key, &data, 0)) + return (NULL); + memmove(&p, data.data, sizeof p); + return (p); +} + +PERSON * +palloc(void) +{ + PERSON *p; + + if ((p = malloc(sizeof(PERSON))) == NULL) + err(1, NULL); + return(p); +} + +static WHERE * +walloc(PERSON *pn) +{ + WHERE *w; + + if ((w = malloc(sizeof(WHERE))) == NULL) + err(1, NULL); + if (pn->whead == NULL) + pn->whead = pn->wtail = w; + else { + pn->wtail->next = w; + pn->wtail = w; + } + w->next = NULL; + return(w); +} + +char * +prphone(char *num) +{ + char *p; + int len; + static char pbuf[20]; + + /* don't touch anything if the user has their own formatting */ + for (p = num; *p; ++p) + if (!isdigit(*p)) + return(num); + len = p - num; + p = pbuf; + switch(len) { + case 11: /* +0-123-456-7890 */ + *p++ = '+'; + *p++ = *num++; + *p++ = '-'; + /* FALLTHROUGH */ + case 10: /* 012-345-6789 */ + *p++ = *num++; + *p++ = *num++; + *p++ = *num++; + *p++ = '-'; + /* FALLTHROUGH */ + case 7: /* 012-3456 */ + *p++ = *num++; + *p++ = *num++; + *p++ = *num++; + break; + case 5: /* x0-1234 */ + case 4: /* x1234 */ + *p++ = 'x'; + *p++ = *num++; + break; + default: + return(num); + } + if (len != 4) { + *p++ = '-'; + *p++ = *num++; + } + *p++ = *num++; + *p++ = *num++; + *p++ = *num++; + *p = '\0'; + return(pbuf); +} + +static void +find_idle_and_ttywrite(WHERE *w) +{ + struct stat sb; + time_t touched; + int error; + + (void)snprintf(tbuf, sizeof(tbuf), "%s/%s", _PATH_DEV, w->tty); + + error = stat(tbuf, &sb); + if (error < 0 && errno == ENOENT) { + /* + * The terminal listed is not actually a terminal (i.e., + * ":0"). This is a failure, so we'll skip printing + * out the idle time, which is non-ideal but better + * than a bogus warning and idle time. + */ + w->idletime = -1; + return; + } else if (error < 0) { + warn("%s", tbuf); + w->idletime = -1; + return; + } + touched = sb.st_atime; + if (touched < w->loginat) { + /* tty untouched since before login */ + touched = w->loginat; + } + w->idletime = now < touched ? 0 : now - touched; + +#define TALKABLE 0220 /* tty is writable if 220 mode */ + w->writable = ((sb.st_mode & TALKABLE) == TALKABLE); +} + +static void +userinfo(PERSON *pn, struct passwd *pw) +{ + char *p, *t; + char *bp, name[1024]; + struct stat sb; + + pn->realname = pn->office = pn->officephone = pn->homephone = NULL; + + pn->uid = pw->pw_uid; + if ((pn->name = strdup(pw->pw_name)) == NULL) + err(1, "strdup failed"); + if ((pn->dir = strdup(pw->pw_dir)) == NULL) + err(1, "strdup failed"); + if ((pn->shell = strdup(pw->pw_shell)) == NULL) + err(1, "strdup failed"); + + /* why do we skip asterisks!?!? */ + (void)strncpy(bp = tbuf, pw->pw_gecos, sizeof(tbuf)); + tbuf[sizeof(tbuf) - 1] = '\0'; + if (*bp == '*') + ++bp; + + /* ampersands get replaced by the login name */ + if (!(p = strsep(&bp, ","))) + return; + for (t = name; t < &name[sizeof(name) - 1] && (*t = *p) != '\0'; ++p) { + if (*t == '&') { + (void)strncpy(t, pw->pw_name, + sizeof(name) - (t - name)); + name[sizeof(name) - 1] = '\0'; + if (islower(*t)) + *t = toupper(*t); + while (t < &name[sizeof(name) - 1] && *++t) + continue; + } else { + ++t; + } + } + *t = '\0'; + if ((pn->realname = strdup(name)) == NULL) + err(1, "strdup failed"); + pn->office = ((p = strsep(&bp, ",")) && *p) ? + strdup(p) : NULL; + pn->officephone = ((p = strsep(&bp, ",")) && *p) ? + strdup(p) : NULL; + pn->homephone = ((p = strsep(&bp, ",")) && *p) ? + strdup(p) : NULL; + (void)snprintf(tbuf, sizeof(tbuf), "%s/%s", _PATH_MAILDIR, pw->pw_name); + pn->mailrecv = -1; /* -1 == not_valid */ + if (stat(tbuf, &sb) < 0) { + if (errno != ENOENT) { + warn("%s", tbuf); + return; + } + } else if (sb.st_size != 0) { + pn->mailrecv = sb.st_mtime; + pn->mailread = sb.st_atime; + } +} + +/* + * Is this user hiding from finger? + * If ~<user>/.nofinger exists, return 1 (hide), else return 0 (nohide). + * Nobody can hide from root. + */ + +int +hide(struct passwd *pw) +{ + struct stat st; + char buf[MAXPATHLEN]; + + if (invoker_root || !pw->pw_dir) + return 0; + + snprintf(buf, sizeof(buf), "%s/%s", pw->pw_dir, _PATH_NOFINGER); + + if (stat(buf, &st) == 0) + return 1; + + return 0; +} diff --git a/adv_cmds/gencat/gencat.1 b/adv_cmds/gencat/gencat.1 new file mode 100644 index 0000000..bcead36 --- /dev/null +++ b/adv_cmds/gencat/gencat.1 @@ -0,0 +1,177 @@ +.\" $OpenBSD: gencat.1,v 1.3 1997/06/11 15:39:54 kstailey Exp $ +.\" +.\" Copyright (c) 1997 Ken Stailey +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. The name of the author may not be used to endorse or promote products +.\" derived from this software without specific prior written permission +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" $FreeBSD: src/usr.bin/gencat/gencat.1,v 1.9 2001/11/23 14:37:27 dd Exp $ +.\" +.Dd June 11, 1997 +.Dt GENCAT 1 +.Os +.Sh NAME +.Nm gencat +.Nd NLS catalog compiler +.Sh SYNOPSIS +.Nm +.Ar "output-file" +.Ar "input-files..." +.Sh DESCRIPTION +The +.Nm +utility merges the text NLS input files +.Ar "input-files..." +into a formatted message catalog file +.Ar "output-file" . +The file +.Ar "output-file" +will be created if it does not already exist. If +.Ar "output-file" +does exist, its messages will be included in the new +.Ar "output-file" . +If set and message numbers collide, the new message text defined in +.Ar "input-files..." +will replace the old message text currently contained in +.Ar "output-file" . +.Sh INPUT FILES +The format of a message text source file is defined below. Note that +the fields of a message text source line are separated by a single space +character: any other space characters are considered to be part of the +field contents. +.Pp +.Bl -tag -width 3n +.It Li $set Ar n comment +This line specifies the set identifier of the following messages until +the next +.Li $set +or end-of-file appears. The argument +.Ar n +is the set identifier which is defined as a number in the range +[1, (NL_SETMAX)]. Set identifiers must occur in ascending order within +a single source file, but need not be contiguous. Any string following +a space following the set identifier is treated as a comment. If no +.Li $set +directive is specified in a given source file, all messages will +be located in the default message set NL_SETD. +.It Li $del Ar n comment +This line deletes messages from set +.Ar n +from a message catalog. The +.Ar n +specifies a set number. Any string following a space following the set +number is treated as a comment. +.It Li $ Ar comment +A line beginning with +.Li $ +followed by a space is treated as a comment. +.It Ar m message-text +A message line consists of a message identifier +.Ar m +in the range [1, (NL_MSGMAX)]. The +.Ar message-text +is stored in the message catalog with the set identifier specified by +the last +.Li $set +directive, and the message identifier +.Ar m . +If the +.Ar message-text +is empty, and there is a space character following the message identifier, +an empty string is stored in the message catalog. If the +.Ar message-text +is empty, and if there is no space character following the message +identifier, then the existing message in the current set with the +specified message identifier is deleted from the catalog. Message +identifiers must be in ascending order within a single set, but +need not be contiguous. The +.Ar message-text +length must be in the range [0, (NL_TEXTMAX)]. +.It Li $quote Ar c +This line specifies an optional quote character +.Ar c +which can be used to surround +.Ar message-text +so that trailing space or empty messages are visible in message +source files. By default, or if an empty +.Li $quote +directive is specified, no quoting of +.Ar message-text +will be recognized. +.El +.Pp +Empty lines in message source files are ignored. The effect of lines +beginning with any character other than those described above is +undefined. +.Pp +Text strings can contain the following special characters and escape +sequences. In addition, if a quote character is defined, it may be +escaped as well to embed a literal quote character. +.Pp +.Bl -tag -width "\eooo" -offset indent -compact +.It Li \en +line feed +.It Li \et +horizontal tab +.It Li \ev +vertical tab +.It Li \eb +backspace +.It Li \er +carriage return +.It Li \ef +form feed +.It Li \e\e +backslash +.It Li \eooo +octal number in the range [000, 377] +.El +.Pp +A backslash character immediately before the end of the line in a file +is used to continue the line onto the next line, e.g.: +.Pp +.Dl 1 This line is continued \e +.Dl on this line. +.Pp +If the character following the backslash is not one of those specified, +the backslash is ignored. +.Sh DIAGNOSTICS +.Ex -std +.Sh SEE ALSO +.Xr catclose 3 , +.Xr catgets 3 , +.Xr catopen 3 +.Sh STANDARDS +The +.Nm +utility is compliant with the +.St -xpg4 +standard. +.Sh AUTHORS +.An -nosplit +This manual page was originally written by +.An Ken Stailey +and later revised by +.An Terry Lambert . +.Sh BUGS +A message catalog file created from a blank input file cannot be revised; +it must be deleted and recreated. diff --git a/adv_cmds/gencat/gencat.c b/adv_cmds/gencat/gencat.c new file mode 100644 index 0000000..e0d00e3 --- /dev/null +++ b/adv_cmds/gencat/gencat.c @@ -0,0 +1,199 @@ +/*********************************************************** +Copyright 1990, by Alfalfa Software Incorporated, Cambridge, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that Alfalfa's name not be used in +advertising or publicity pertaining to distribution of the software +without specific, written prior permission. + +ALPHALPHA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +ALPHALPHA BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +If you make any modifications, bugfixes or other changes to this software +we'd appreciate it if you could send a copy to us so we can keep things +up-to-date. Many thanks. + Kee Hinckley + Alfalfa Software, Inc. + 267 Allston St., #3 + Cambridge, MA 02139 USA + nazgul@alfalfa.com + +******************************************************************/ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD: src/usr.bin/gencat/gencat.c,v 1.9 2002/05/29 14:23:10 tjr Exp $"); + +#include <sys/file.h> +#include <sys/stat.h> +#include <err.h> +#include <paths.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "gencat.h" + +/* + * The spec says the syntax is "gencat catfile msgfile...". + * We extend it to: + * gencat [-lang C|C++|ANSIC] catfile msgfile [-h <header-file>]... + * Flags are order dependent, we'll take whatever lang was most recently chosen + * and use it to generate the next header file. The header files are generated + * at the point in the command line they are listed. Thus the sequence: + * gencat -lang C foo.cat foo.mcs -h foo.h -lang C++ bar.mcs -h bar.H + * will put constants from foo.mcs into foo.h and constants from bar.mcs into + * bar.h. Constants are not saved in the catalog file, so nothing will come + * from that, even if things have been defined before. The constants in foo.h + * will be in C syntax, in bar.H in C++ syntax. + */ + +static void writeIfChanged(char *, int, int); + +static void +usage(void) +{ + fprintf(stderr, "usage: gencat [-new] [-or] [-lang C|C++|ANSIC]\n" + " catfile msgfile [-h <header-file>]...\n"); + exit(1); +} + +int +main(int argc, char *argv[]) +{ + int ofd = -1, ifd, i; + char *catfile = NULL; + char *input = NULL; + int lang = MCLangC; + int new = FALSE; + int orConsts = FALSE; + + for (i = 1; i < argc; ++i) { + if (argv[i][0] == '-') { + if (strcmp(argv[i], "-lang") == 0) { + ++i; + if (strcmp(argv[i], "C") == 0) lang = MCLangC; + else if (strcmp(argv[i], "C++") == 0) lang = MCLangCPlusPlus; + else if (strcmp(argv[i], "ANSIC") == 0) lang = MCLangANSIC; + else { + errx(1, "unrecognized language: %s", argv[i]); + } + } else if (strcmp(argv[i], "-h") == 0) { + if (!input) + errx(1, "can't write to a header before reading something"); + ++i; + writeIfChanged(argv[i], lang, orConsts); + } else if (strcmp(argv[i], "-new") == 0) { + if (catfile) + errx(1, "you must specify -new before the catalog file name"); + new = TRUE; + } else if (strcmp(argv[i], "-or") == 0) { + orConsts = ~orConsts; + } else { + usage(); + } + } else { + if (!catfile) { + catfile = argv[i]; + if (new) { + if ((ofd = open(catfile, O_WRONLY|O_TRUNC|O_CREAT, 0666)) < 0) + errx(1, "unable to create a new %s", catfile); + } else if ((ofd = open(catfile, O_RDONLY)) < 0) { + if ((ofd = open(catfile, O_WRONLY|O_CREAT, 0666)) < 0) + errx(1, "unable to create %s", catfile); + } else { + MCReadCat(ofd); + close(ofd); + if ((ofd = open(catfile, O_WRONLY|O_TRUNC)) < 0) + errx(1, "unable to truncate %s", catfile); + } + } else { + input = argv[i]; + if ((ifd = open(input, O_RDONLY)) < 0) + errx(1, "unable to read %s", input); + MCParse(ifd); + close(ifd); + } + } + } + if (catfile) { + MCWriteCat(ofd); + exit(0); + } else { + usage(); + } + return 0; +} + +static void +writeIfChanged(char *fname, int lang, int orConsts) +{ + char tmpname[] = _PATH_TMP"/gencat.XXXXXX"; + char buf[BUFSIZ], tbuf[BUFSIZ], *cptr, *tptr; + int fd, tfd; + int diff = FALSE; + int len, tlen; + struct stat sbuf; + + /* If it doesn't exist, just create it */ + if (stat(fname, &sbuf)) { + if ((fd = open(fname, O_WRONLY|O_CREAT, 0666)) < 0) + errx(1, "unable to create header file %s", fname); + MCWriteConst(fd, lang, orConsts); + close(fd); + return; + } + + /* If it does exist, create a temp file for now */ + if ((tfd = mkstemp(tmpname)) < 0) + err(1, "mkstemp"); + unlink(tmpname); + + /* Write to the temp file and rewind */ + MCWriteConst(tfd, lang, orConsts); + + /* Open the real header file */ + if ((fd = open(fname, O_RDONLY)) < 0) + errx(1, "unable to read header file: %s", fname); + + /* Backup to the start of the temp file */ + if (lseek(tfd, (off_t)0, L_SET) < 0) + errx(1, "unable to seek in tempfile: %s", tmpname); + + /* Now compare them */ + while ((tlen = read(tfd, tbuf, BUFSIZ)) > 0) { + if ((len = read(fd, buf, BUFSIZ)) != tlen) { + diff = TRUE; + goto done; + } + for (cptr = buf, tptr = tbuf; cptr < buf+len; ++cptr, ++tptr) { + if (*tptr != *cptr) { + diff = TRUE; + goto done; + } + } + } +done: + if (diff) { + if (lseek(tfd, (off_t)0, L_SET) < 0) + errx(1, "unable to seek in tempfile: %s", tmpname); + close(fd); + if ((fd = open(fname, O_WRONLY|O_TRUNC)) < 0) + errx(1, "unable to truncate header file: %s", fname); + while ((len = read(tfd, buf, BUFSIZ)) > 0) { + if (write(fd, buf, (size_t)len) != len) + warnx("error writing to header file: %s", fname); + } + } + close(fd); + close(tfd); +} diff --git a/adv_cmds/gencat/gencat.h b/adv_cmds/gencat/gencat.h new file mode 100644 index 0000000..5e7e459 --- /dev/null +++ b/adv_cmds/gencat/gencat.h @@ -0,0 +1,87 @@ +/* $FreeBSD: src/usr.bin/gencat/gencat.h,v 1.4 2002/03/26 12:39:08 charnier Exp $ */ + +#ifndef GENCAT_H +#define GENCAT_H + +/*********************************************************** +Copyright 1990, by Alfalfa Software Incorporated, Cambridge, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that Alfalfa's name not be used in +advertising or publicity pertaining to distribution of the software +without specific, written prior permission. + +ALPHALPHA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +ALPHALPHA BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +If you make any modifications, bugfixes or other changes to this software +we'd appreciate it if you could send a copy to us so we can keep things +up-to-date. Many thanks. + Kee Hinckley + Alfalfa Software, Inc. + 267 Allston St., #3 + Cambridge, MA 02139 USA + nazgul@alfalfa.com + +******************************************************************/ + +/* + * $set n comment + * My extension: If the comment begins with # treat the next string + * as a constant identifier. + * $delset n comment + * n goes from 1 to NL_SETMAX + * Deletes a set from the MC + * $ comment + * My extension: If comment begins with # treat the next string as + * a constant identifier for the next message. + * m message-text + * m goes from 1 to NL_MSGMAX + * If message-text is empty, and a space or tab is present, put + * empty string in catalog. + * If message-text is empty, delete the message. + * Length of text is 0 to NL_TEXTMAX + * My extension: If '#' is used instead of a number, the number + * is generated automatically. A # followed by anything is an empty message. + * $quote c + * Optional quote character which can surround message-text to + * show where spaces are. + * + * Escape Characters + * \n (newline), \t (horiz tab), \v (vert tab), \b (backspace), + * \r (carriage return), \f (formfeed), \\ (backslash), \ddd (bitpattern + * in octal). + * Also, \ at end of line is a continuation. + * + */ + +#define MCLangC 0 +#define MCLangCPlusPlus 1 +#define MCLangANSIC 2 + +#define MAXTOKEN 1024 + +#define TRUE 1 +#define FALSE 0 + +extern void MCAddSet(int, char *); +extern void MCDelSet(int); +extern void MCAddMsg(int, const char *, char *); +extern void MCDelMsg(int); +extern void MCParse(int); +extern void MCReadCat(int); +extern void MCWriteConst(int, int, int); +extern void MCWriteCat(int); +extern long MCGetByteOrder(void); + +#endif /* GENCAT_H */ diff --git a/adv_cmds/gencat/genlib.c b/adv_cmds/gencat/genlib.c new file mode 100644 index 0000000..42b7ae2 --- /dev/null +++ b/adv_cmds/gencat/genlib.c @@ -0,0 +1,836 @@ +/*********************************************************** +Copyright 1990, by Alfalfa Software Incorporated, Cambridge, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that Alfalfa's name not be used in +advertising or publicity pertaining to distribution of the software +without specific, written prior permission. + +ALPHALPHA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +ALPHALPHA BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +If you make any modifications, bugfixes or other changes to this software +we'd appreciate it if you could send a copy to us so we can keep things +up-to-date. Many thanks. + Kee Hinckley + Alfalfa Software, Inc. + 267 Allston St., #3 + Cambridge, MA 02139 USA + nazgul@alfalfa.com + +******************************************************************/ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD: src/usr.bin/gencat/genlib.c,v 1.13 2002/12/24 07:40:10 davidxu Exp $"); + +#include <ctype.h> +#include <err.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "msgcat.h" +#include "gencat.h" +#include <machine/endian.h> +/* libkern/OSByteOrder is needed for the 64 bit byte swap */ +#include <libkern/OSByteOrder.h> + +#ifndef htonll +#define htonll(x) OSSwapHostToBigInt64(x) +#define ntohll(x) OSSwapBigToHostInt64(x) +#endif + +static char *curline = NULL; +static long lineno = 0; + +static void +warning(char *cptr, const char *msg) +{ + warnx("%s on line %ld\n%s", msg, lineno, (curline == NULL ? "" : curline) ); + if (cptr) { + char *tptr; + for (tptr = curline; tptr < cptr; ++tptr) putc(' ', stderr); + fprintf(stderr, "^\n"); + } +} + +static void +error(char *cptr, const char *msg) +{ + warning(cptr, msg); + exit(1); +} + +static void +corrupt(void) { + error(NULL, "corrupt message catalog"); +} + +static void +nomem(void) { + error(NULL, "out of memory"); +} + +static char * +gencat_getline(int fd) +{ + static size_t curlen = BUFSIZ; + static char buf[BUFSIZ], *bptr = buf, *bend = buf; + char *cptr, *cend; + long buflen; + + if (!curline) { + curline = (char *) malloc(curlen); + if (!curline) nomem(); + } + ++lineno; + + cptr = curline; + cend = curline + curlen; + while (TRUE) { + for (; bptr < bend && cptr < cend; ++cptr, ++bptr) { + if (*bptr == '\n') { + *cptr = '\0'; + ++bptr; + return(curline); + } else *cptr = *bptr; + } + if (bptr == bend) { + buflen = read(fd, buf, BUFSIZ); + if (buflen <= 0) { + if (cptr > curline) { + *cptr = '\0'; + return(curline); + } + return(NULL); + } + bend = buf + buflen; + bptr = buf; + } + if (cptr == cend) { + cptr = curline = (char *) realloc(curline, curlen *= 2); + if (!curline) nomem(); + cend = curline + curlen; + } + } +} + +static char * +token(char *cptr) +{ + static char tok[MAXTOKEN+1]; + char *tptr = tok; + + while (*cptr && isspace((unsigned char)*cptr)) ++cptr; + while (*cptr && !isspace((unsigned char)*cptr)) *tptr++ = *cptr++; + *tptr = '\0'; + return(tok); +} + +static char * +wskip(char *cptr) +{ + if (!*cptr || !isspace((unsigned char)*cptr)) { + warning(cptr, "expected a space"); + return(cptr); + } + while (*cptr && isspace((unsigned char)*cptr)) ++cptr; + return(cptr); +} + +static char * +cskip(char *cptr) +{ + if (!*cptr || isspace((unsigned char)*cptr)) { + warning(cptr, "wasn't expecting a space"); + return(cptr); + } + while (*cptr && !isspace((unsigned char)*cptr)) ++cptr; + return(cptr); +} + +static char * +getmsg(int fd, char *cptr, char quote) +{ + static char *msg = NULL; + static size_t msglen = 0; + size_t clen, i; + char *tptr; + int needq; + + if (quote && *cptr == quote) { + needq = TRUE; + ++cptr; + } else needq = FALSE; + + clen = strlen(cptr) + 1; + if (clen > msglen) { + if (msglen) msg = (char *) realloc(msg, clen); + else msg = (char *) malloc(clen); + if (!msg) nomem(); + msglen = clen; + } + tptr = msg; + + while (*cptr) { + if (quote && *cptr == quote) { + char *tmp; + tmp = cptr+1; + if (*tmp && (!isspace((unsigned char)*tmp) || *wskip(tmp))) { + warning(cptr, "unexpected quote character, ignoring"); + *tptr++ = *cptr++; + } else { + *cptr = '\0'; + } + } else if (*cptr == '\\') { + ++cptr; + switch (*cptr) { + case '\0': + cptr = gencat_getline(fd); + if (!cptr) error(NULL, "premature end of file"); + msglen += strlen(cptr); + i = tptr - msg; + msg = (char *) realloc(msg, msglen); + if (!msg) nomem(); + tptr = msg + i; + break; + +#define CASEOF(CS, CH) \ + case CS: \ + *tptr++ = CH; \ + ++cptr; \ + break; + + CASEOF('n', '\n') + CASEOF('t', '\t') + CASEOF('v', '\v') + CASEOF('b', '\b') + CASEOF('r', '\r') + CASEOF('f', '\f') + CASEOF('"', '"') + CASEOF('\'', '\'') + CASEOF('\\', '\\') + + default: + if (isdigit((unsigned char)*cptr)) { + *tptr = 0; + for (i = 0; i < 3; ++i) { + if (!isdigit((unsigned char)*cptr)) break; + if (*cptr > '7') warning(cptr, "octal number greater than 7?!"); + *tptr *= 8; + *tptr += (*cptr - '0'); + ++cptr; + } + ++tptr; + } else { + warning(cptr, "unrecognized escape sequence"); + } + } + } else { + *tptr++ = *cptr++; + } + } + *tptr = '\0'; + return(msg); +} + +static char * +dupstr(const char *ostr) +{ + char *nstr; + + nstr = strdup(ostr); + if (!nstr) error(NULL, "unable to allocate storage"); + return(nstr); +} + +/* + * The Global Stuff + */ + +typedef struct _msgT { + long msgId; + char *str; + char *hconst; + long offset; + struct _msgT *prev, *next; +} msgT; + +typedef struct _setT { + long setId; + char *hconst; + msgT *first, *last; + struct _setT *prev, *next; +} setT; + +typedef struct { + setT *first, *last; +} catT; + +static setT *curSet; +static catT *cat; + +/* + * Find the current byte order. There are of course some others, but + * this will do for now. Note that all we care about is "long". + */ +long +MCGetByteOrder(void) { + long l = 0x00010203; + char *cptr = (char *) &l; + + if (cptr[0] == 0 && cptr[1] == 1 && cptr[2] == 2 && cptr[3] == 3) + return MC68KByteOrder; + else return MCn86ByteOrder; +} + +void +MCParse(int fd) +{ + char *cptr, *str; + int setid = 1, msgid = 0; + char hconst[MAXTOKEN+1]; + char quote = 0; + + if (!cat) { + cat = (catT *) malloc(sizeof(catT)); + if (!cat) nomem(); + bzero(cat, sizeof(catT)); + } + + hconst[0] = '\0'; + + while ((cptr = gencat_getline(fd)) != NULL) { + if (*cptr == '$') { + ++cptr; + if (strncmp(cptr, "set", 3) == 0) { + cptr += 3; + cptr = wskip(cptr); + setid = atoi(cptr); + cptr = cskip(cptr); + if (*cptr) cptr = wskip(cptr); + if (*cptr == '#') { + ++cptr; + MCAddSet(setid, token(cptr)); + } else MCAddSet(setid, NULL); + msgid = 0; + } else if (strncmp(cptr, "delset", 6) == 0) { + cptr += 6; + cptr = wskip(cptr); + setid = atoi(cptr); + MCDelSet(setid); + } else if (strncmp(cptr, "quote", 5) == 0) { + cptr += 5; + if (!*cptr) quote = 0; + else { + cptr = wskip(cptr); + if (!*cptr) quote = 0; + else quote = *cptr; + } + } else if (isspace((unsigned char)*cptr)) { + cptr = wskip(cptr); + if (*cptr == '#') { + ++cptr; + strcpy(hconst, token(cptr)); + } + } else { + if (*cptr) { + cptr = wskip(cptr); + if (*cptr) warning(cptr, "unrecognized line"); + } + } + } else { + if (!curSet) MCAddSet(setid, NULL); + if (isdigit((unsigned char)*cptr) || *cptr == '#') { + if (*cptr == '#') { + ++msgid; + ++cptr; + if (!*cptr) { + MCAddMsg(msgid, "", hconst); + hconst[0] = '\0'; + continue; + } + if (!isspace((unsigned char)*cptr)) warning(cptr, "expected a space"); + ++cptr; + if (!*cptr) { + MCAddMsg(msgid, "", hconst); + hconst[0] = '\0'; + continue; + } + } else { + msgid = atoi(cptr); + cptr = cskip(cptr); + if (isspace(*cptr)) + cptr++; + /* if (*cptr) ++cptr; */ + } + if (!*cptr) { + if (isspace(cptr[-1])) { + MCAddMsg(msgid, "", hconst); + hconst[0] = '\0'; + } else { + MCDelMsg(msgid); + } + } else { + str = getmsg(fd, cptr, quote); + MCAddMsg(msgid, str, hconst); + hconst[0] = '\0'; + } + } + } + } +} + +void +MCReadCat(int fd) +{ + MCHeaderT mcHead; + MCMsgT mcMsg; + MCSetT mcSet; + msgT *msg; + setT *set; + int i; + char *data; + + cat = (catT *) malloc(sizeof(catT)); + if (!cat) nomem(); + bzero(cat, sizeof(catT)); + + /* While we deal with read/write this in network byte order we do NOT + deal with struct member padding issues, or even sizeof(long) issues, + those are left for a future genneration to curse either me, or the + original author for */ + + if (read(fd, &mcHead, sizeof(mcHead)) != sizeof(mcHead)) corrupt(); + if (strncmp(mcHead.magic, MCMagic, MCMagicLen) != 0) corrupt(); + if (ntohl(mcHead.majorVer) != MCMajorVer) error(NULL, "unrecognized catalog version"); + if ((ntohl(mcHead.flags) & MC68KByteOrder) == 0) error(NULL, "wrong byte order"); + + if (lseek(fd, ntohll(mcHead.firstSet), L_SET) == -1) corrupt(); + + while (TRUE) { + if (read(fd, &mcSet, sizeof(mcSet)) != sizeof(mcSet)) corrupt(); + if (mcSet.invalid) continue; + + set = (setT *) malloc(sizeof(setT)); + if (!set) nomem(); + bzero(set, sizeof(*set)); + if (cat->first) { + cat->last->next = set; + set->prev = cat->last; + cat->last = set; + } else cat->first = cat->last = set; + + set->setId = ntohl(mcSet.setId); + + /* Get the data */ + if (mcSet.dataLen) { + data = (char *) malloc((size_t)ntohl(mcSet.dataLen)); + if (!data) nomem(); + if (lseek(fd, ntohll(mcSet.data.off), L_SET) == -1) corrupt(); + if (read(fd, data, (size_t)ntohl(mcSet.dataLen)) != ntohl(mcSet.dataLen)) corrupt(); + if (lseek(fd, ntohll(mcSet.u.firstMsg), L_SET) == -1) corrupt(); + + for (i = 0; i < ntohl(mcSet.numMsgs); ++i) { + if (read(fd, &mcMsg, sizeof(mcMsg)) != sizeof(mcMsg)) corrupt(); + if (mcMsg.invalid) { + --i; + continue; + } + + msg = (msgT *) malloc(sizeof(msgT)); + if (!msg) nomem(); + bzero(msg, sizeof(*msg)); + if (set->first) { + set->last->next = msg; + msg->prev = set->last; + set->last = msg; + } else set->first = set->last = msg; + + msg->msgId = ntohl(mcMsg.msgId); + msg->str = dupstr((char *) (data + ntohll(mcMsg.msg.off))); + } + free(data); + } + if (!mcSet.nextSet) break; + if (lseek(fd, ntohll(mcSet.nextSet), L_SET) == -1) corrupt(); + } +} + + +static void +printS(int fd, const char *str) +{ + if (str) + write(fd, str, strlen(str)); +} + +static void +printL(int fd, long l) +{ + char buf[32]; + sprintf(buf, "%ld", l); + write(fd, buf, strlen(buf)); +} + +static void +printLX(int fd, long l) +{ + char buf[32]; + sprintf(buf, "%lx", l); + write(fd, buf, strlen(buf)); +} + +static void +genconst(int fd, int type, char *setConst, char *msgConst, long val) +{ + switch (type) { + case MCLangC: + if (!msgConst) { + printS(fd, "\n#define "); + printS(fd, setConst); + printS(fd, "Set"); + } else { + printS(fd, "#define "); + printS(fd, setConst); + printS(fd, msgConst); + } + printS(fd, "\t0x"); + printLX(fd, val); + printS(fd, "\n"); + break; + case MCLangCPlusPlus: + case MCLangANSIC: + if (!msgConst) { + printS(fd, "\nconst long "); + printS(fd, setConst); + printS(fd, "Set"); + } else { + printS(fd, "const long "); + printS(fd, setConst); + printS(fd, msgConst); + } + printS(fd, "\t= "); + printL(fd, val); + printS(fd, ";\n"); + break; + default: + error(NULL, "not a recognized (programming) language type"); + } +} + +void +MCWriteConst(int fd, int type, int orConsts) +{ + msgT *msg; + setT *set; + long id; + + if (orConsts && (type == MCLangC || type == MCLangCPlusPlus || type == MCLangANSIC)) { + printS(fd, "/* Use these Macros to compose and decompose setId's and msgId's */\n"); + printS(fd, "#ifndef MCMakeId\n"); + printS(fd, "# define MCMakeId(s,m)\t(unsigned long)(((unsigned short)s<<(sizeof(short)*8))\\\n"); + printS(fd, "\t\t\t\t\t|(unsigned short)m)\n"); + printS(fd, "# define MCSetId(id)\t(unsigned int) (id >> (sizeof(short) * 8))\n"); + printS(fd, "# define MCMsgId(id)\t(unsigned int) ((id << (sizeof(short) * 8))\\\n"); + printS(fd, "\t\t\t\t\t>> (sizeof(short) * 8))\n"); + printS(fd, "#endif\n"); + } + + for (set = cat->first; set; set = set->next) { + if (set->hconst) genconst(fd, type, set->hconst, NULL, set->setId); + + for (msg = set->first; msg; msg = msg->next) { + if (msg->hconst) { + if (orConsts) id = MCMakeId(set->setId, msg->msgId); + else id = msg->msgId; + genconst(fd, type, set->hconst, msg->hconst, id); + free(msg->hconst); + msg->hconst = NULL; + } + } + if (set->hconst) { + free(set->hconst); + set->hconst = NULL; + } + } +} + +void +MCWriteCat(int fd) +{ + MCHeaderT mcHead; + int cnt; + setT *set; + msgT *msg; + MCSetT mcSet; + MCMsgT mcMsg; + off_t pos; + + bcopy(MCMagic, mcHead.magic, MCMagicLen); + mcHead.majorVer = htonl(MCMajorVer); + mcHead.minorVer = htonl(MCMinorVer); + mcHead.flags = htonl(MC68KByteOrder); + mcHead.firstSet = 0; /* We'll be back to set this in a minute */ + + if (cat == NULL) + error(NULL, "cannot write empty catalog set"); + + for (cnt = 0, set = cat->first; set; set = set->next) ++cnt; + mcHead.numSets = htonl(cnt); + + /* I'm not inclined to mess with it, but it looks odd that we write + the header twice...and that we get the firstSet value from another + lseek rather then just 'sizeof(mcHead)' */ + + /* Also, this code doesn't seem to check returns from write! */ + + lseek(fd, (off_t)0L, L_SET); + write(fd, &mcHead, sizeof(mcHead)); + mcHead.firstSet = htonll(lseek(fd, (off_t)0L, L_INCR)); + lseek(fd, (off_t)0L, L_SET); + write(fd, &mcHead, sizeof(mcHead)); + + for (set = cat->first; set; set = set->next) { + bzero(&mcSet, sizeof(mcSet)); + + mcSet.setId = htonl(set->setId); + mcSet.invalid = FALSE; + + /* The rest we'll have to come back and change in a moment */ + pos = lseek(fd, (off_t)0L, L_INCR); + write(fd, &mcSet, sizeof(mcSet)); + + /* Now write all the string data */ + mcSet.data.off = htonll(lseek(fd, (off_t)0L, L_INCR)); + cnt = 0; + for (msg = set->first; msg; msg = msg->next) { + msg->offset = lseek(fd, (off_t)0L, L_INCR) - ntohll(mcSet.data.off); + mcSet.dataLen += write(fd, msg->str, strlen(msg->str) + 1); + ++cnt; + } + mcSet.u.firstMsg = htonll(lseek(fd, (off_t)0L, L_INCR)); + mcSet.numMsgs = htonl(cnt); + mcSet.dataLen = htonl(mcSet.dataLen); + + /* Now write the message headers */ + for (msg = set->first; msg; msg = msg->next) { + mcMsg.msgId = htonl(msg->msgId); + mcMsg.msg.off = htonll(msg->offset); + mcMsg.invalid = FALSE; + write(fd, &mcMsg, sizeof(mcMsg)); + } + + /* Go back and fix things up */ + + if (set == cat->last) { + mcSet.nextSet = 0; + lseek(fd, pos, L_SET); + write(fd, &mcSet, sizeof(mcSet)); + } else { + mcSet.nextSet = htonll(lseek(fd, (off_t)0L, L_INCR)); + lseek(fd, pos, L_SET); + write(fd, &mcSet, sizeof(mcSet)); + lseek(fd, ntohll(mcSet.nextSet), L_SET); + } + } +} + +void +MCAddSet(int setId, char *hconst) +{ + setT *set; + + if (setId <= 0) { + error(NULL, "setId's must be greater than zero"); + return; + } + + if (hconst && !*hconst) hconst = NULL; + for (set = cat->first; set; set = set->next) { + if (set->setId == setId) { + if (set->hconst && hconst) free(set->hconst); + set->hconst = NULL; + break; + } else if (set->setId > setId) { + setT *newSet; + + newSet = (setT *) malloc(sizeof(setT)); + if (!newSet) nomem(); + bzero(newSet, sizeof(setT)); + newSet->prev = set->prev; + newSet->next = set; + if (set->prev) set->prev->next = newSet; + else cat->first = newSet; + set->prev = newSet; + set = newSet; + break; + } + } + if (!set) { + set = (setT *) malloc(sizeof(setT)); + if (!set) nomem(); + bzero(set, sizeof(setT)); + + if (cat->first) { + set->prev = cat->last; + set->next = NULL; + cat->last->next = set; + cat->last = set; + } else { + set->prev = set->next = NULL; + cat->first = cat->last = set; + } + } + set->setId = setId; + if (hconst) set->hconst = dupstr(hconst); + curSet = set; +} + +void +MCAddMsg(int msgId, const char *str, char *hconst) +{ + msgT *msg; + + if (!curSet) + error(NULL, "can't specify a message when no set exists"); + + if (msgId <= 0) { + error(NULL, "msgId's must be greater than zero"); + return; + } + + if (hconst && !*hconst) hconst = NULL; + for (msg = curSet->first; msg; msg = msg->next) { + if (msg->msgId == msgId) { + if (msg->hconst && hconst) free(msg->hconst); + if (msg->str) free(msg->str); + msg->hconst = msg->str = NULL; + break; + } else if (msg->msgId > msgId) { + msgT *newMsg; + + newMsg = (msgT *) malloc(sizeof(msgT)); + if (!newMsg) nomem(); + bzero(newMsg, sizeof(msgT)); + newMsg->prev = msg->prev; + newMsg->next = msg; + if (msg->prev) msg->prev->next = newMsg; + else curSet->first = newMsg; + msg->prev = newMsg; + msg = newMsg; + break; + } + } + if (!msg) { + msg = (msgT *) malloc(sizeof(msgT)); + if (!msg) nomem(); + bzero(msg, sizeof(msgT)); + + if (curSet->first) { + msg->prev = curSet->last; + msg->next = NULL; + curSet->last->next = msg; + curSet->last = msg; + } else { + msg->prev = msg->next = NULL; + curSet->first = curSet->last = msg; + } + } + msg->msgId = msgId; + if (hconst) msg->hconst = dupstr(hconst); + msg->str = dupstr(str); +} + +void +MCDelSet(int setId) +{ + setT *set; + msgT *msg; + + for (set = cat->first; set; set = set->next) { + if (set->setId == setId) { + for (msg = set->first; msg; msg = msg->next) { + if (msg->hconst) free(msg->hconst); + if (msg->str) free(msg->str); + free(msg); + } + if (set->hconst) free(set->hconst); + + if (set->prev) set->prev->next = set->next; + else cat->first = set->next; + + if (set->next) set->next->prev = set->prev; + else cat->last = set->prev; + + free(set); + return; + } else if (set->setId > setId) break; + } + warning(NULL, "specified set doesn't exist"); +} + +void +MCDelMsg(int msgId) +{ + msgT *msg; + + if (!curSet) + error(NULL, "you can't delete a message before defining the set"); + + for (msg = curSet->first; msg; msg = msg->next) { + if (msg->msgId == msgId) { + if (msg->hconst) free(msg->hconst); + if (msg->str) free(msg->str); + + if (msg->prev) msg->prev->next = msg->next; + else curSet->first = msg->next; + + if (msg->next) msg->next->prev = msg->prev; + else curSet->last = msg->prev; + + free(msg); + return; + } else if (msg->msgId > msgId) break; + } + warning(NULL, "specified msg doesn't exist"); +} + +#if 0 /* this function is unsed and looks like debug thing */ + +void +MCDumpcat(fp) +FILE *fp; +{ + msgT *msg; + setT *set; + + if (!cat) + errx(1, "no catalog open"); + + for (set = cat->first; set; set = set->next) { + fprintf(fp, "$set %ld", set->setId); + if (set->hconst) + fprintf(fp, " # %s", set->hconst); + fprintf(fp, "\n\n"); + + for (msg = set->first; msg; msg = msg->next) { + if (msg->hconst) + fprintf(fp, "# %s\n", msg->hconst); + fprintf(fp, "%ld\t%s\n", msg->msgId, msg->str); + } + fprintf(fp, "\n"); + } + +} +#endif /* 0 */ diff --git a/adv_cmds/last/last.1 b/adv_cmds/last/last.1 new file mode 100644 index 0000000..8ffd49d --- /dev/null +++ b/adv_cmds/last/last.1 @@ -0,0 +1,111 @@ +.\" Copyright (c) 1980, 1990, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)last.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.Dt LAST 1 +.Os BSD 4 +.Sh NAME +.Nm last +.Nd indicate last logins of users and ttys +.Sh SYNOPSIS +.Nm +.Op Fl Ns Ar n +.Op Fl h Ar host +.Op Fl t Ar tty +.Op user ... +.Sh DESCRIPTION +.Nm Last +will list the sessions of specified +.Ar users , +.Ar ttys , +and +.Ar hosts , +in reverse time order. Each line of output contains +the user name, the tty from which the session was conducted, any +hostname, the start and stop times for the session, and the duration +of the session. If the session is still continuing or was cut short by +a crash or shutdown, +.Nm +will so indicate. +.Pp +.Bl -tag -width indent-two +.It Fl Ns Ar n +Limits the report to +.Ar n +lines. +.It Fl h Ar host +.Ar Host +names may be names or internet numbers. +.It Fl t Ar tty +Specify the +.Ar tty . +Tty names may be given fully or abbreviated, for example, +.Dq Li "last -t 03" +is +equivalent to +.Dq Li "last -t tty03" . +.El +.Pp +If +multiple arguments are given, the information which applies to any of the +arguments is printed, e.g., +.Dq Li "last root -t console" +would list all of +.Dq Li root Ns 's +sessions as well as all sessions on the console terminal. If no +users, hostnames or terminals are specified, +.Nm +prints a record of +all logins and logouts. +.Pp +The pseudo-user +.Ar reboot +logs in at reboots of the system, thus +.Dq Li last reboot +will give an indication of mean time between reboot. +.Pp +If +.Nm +is interrupted, it indicates to what date the search has +progressed. If interrupted with a quit signal +.Nm +indicates how +far the search has progressed and then continues. +.Sh SEE ALSO +.Xr lastcomm 1 , +.Xr utmpx 5 , +.Xr ac 8 +.Sh HISTORY +.Nm Last +appeared in +.Bx 3.0 . diff --git a/adv_cmds/last/last.c b/adv_cmds/last/last.c new file mode 100644 index 0000000..6439dd1 --- /dev/null +++ b/adv_cmds/last/last.c @@ -0,0 +1,419 @@ +/* + * Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved + * + * Copyright (c) 1987, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * The NEXTSTEP Software License Agreement specifies the terms + * and conditions for redistribution. + * + * @(#)last.c 8.2 (Berkeley) 4/2/94 + */ + + +#ifndef lint +static const char copyright[] = +"@(#) Copyright (c) 1987, 1993, 1994\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#include <sys/param.h> +#include <sys/stat.h> + +#include <err.h> +#include <fcntl.h> +#include <paths.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <tzfile.h> +#include <unistd.h> +#include <utmpx.h> +#include <ctype.h> + +#define NO 0 /* false/no */ +#define YES 1 /* true/yes */ + +static const struct utmpx *prev; /* previous utmpx structure */ + +/* values from utmp.h, used for print formatting */ +#define UT_NAMESIZE 8 /* old utmp.h value */ +#define UT_LINESIZE 8 +#define UT_HOSTSIZE 16 + +typedef struct arg { + const char *name; /* argument */ +#define HOST_TYPE -2 +#define TTY_TYPE -3 +#define USER_TYPE -4 + int type; /* type of arg */ + struct arg *next; /* linked list pointer */ +} ARG; +ARG *arglist; /* head of linked list */ + +typedef struct ttytab { + long logout; /* log out time */ + char id[_UTX_IDSIZE]; /* terminal id */ + pid_t pid; + struct ttytab *next; /* linked list pointer */ +} TTY; +TTY *ttylist; /* head of linked list */ + +static const char *crmsg; /* cause of last reboot */ +static long currentout, /* current logout value */ + maxrec; /* records to display */ +time_t now; + +void addarg __P((int, const char *)); +TTY *addtty __P((const char *, pid_t)); +void hostconv __P((const char *)); +void onintr __P((int)); +const char *ttyconv __P((const char *)); +int want __P((struct utmpx *, int)); +void wtmp __P((void)); + +int +main(argc, argv) + int argc; + char *argv[]; +{ + extern int optind; + extern char *optarg; + int ch; + char *p; + char *myname = *argv; + + if ((p = strrchr(myname, '/')) != NULL) + myname = p + 1; + maxrec = -1; + while ((ch = getopt(argc, argv, "0123456789f:h:t:")) != EOF) + switch (ch) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + /* + * kludge: last was originally designed to take + * a number after a dash. + */ + if (maxrec == -1) { + p = argv[optind - 1]; + if (p[0] == '-' && p[1] == ch && !p[2]) + maxrec = atol(++p); + else + maxrec = atol(argv[optind] + 1); + if (!maxrec) + exit(0); + } + break; + case 'h': + hostconv(optarg); + addarg(HOST_TYPE, optarg); + break; + case 't': + addarg(TTY_TYPE, ttyconv(optarg)); + break; + case 'f': + warnx("-f is unsupported"); + break; + case '?': + default: + (void)fprintf(stderr, + "usage: last [-#] [-t tty] [-h hostname] [user ...]\n"); + exit(1); + } + + if (argc) { + setlinebuf(stdout); + for (argv += optind; *argv; ++argv) { +#define COMPATIBILITY +#ifdef COMPATIBILITY + /* code to allow "last p5" to work */ + addarg(TTY_TYPE, ttyconv(*argv)); +#endif + addarg(USER_TYPE, *argv); + } + } + wtmp(); + exit(0); +} + +/* + * wtmp -- + * read through the wtmp file + */ + +void +wtmp() +{ + + struct utmpx *bp; /* current structure */ + TTY *T; /* tty list entry */ + long delta; /* time difference */ + char *ct; + + (void)time(&now); + (void)signal(SIGINT, onintr); + (void)signal(SIGQUIT, onintr); + + setutxent_wtmp(0); /* zero means reverse chronological order */ + while ((bp = getutxent_wtmp()) != NULL) { + prev = bp; + switch(bp->ut_type) { + case BOOT_TIME: + case SHUTDOWN_TIME: + /* everybody just logged out */ + for (T = ttylist; T; T = T->next) + T->logout = -bp->ut_tv.tv_sec; + currentout = -bp->ut_tv.tv_sec; + crmsg = bp->ut_type == BOOT_TIME ? "crash" : "shutdown"; + if (want(bp, NO)) { + ct = ctime(&bp->ut_tv.tv_sec); + printf("%-*s %-*s %-*.*s %10.10s %5.5s \n", + UT_NAMESIZE, bp->ut_type == BOOT_TIME ? "reboot" : "shutdown", + UT_LINESIZE, "~", + UT_HOSTSIZE, _UTX_HOSTSIZE, + bp->ut_host, ct, ct + 11); + if (maxrec != -1 && !--maxrec) + return; + } + continue; + case OLD_TIME: + case NEW_TIME: + if (want(bp, NO)) { + ct = ctime(&bp->ut_tv.tv_sec); + printf("%-*s %-*s %-*.*s %10.10s %5.5s \n", + UT_NAMESIZE, "date", + UT_LINESIZE, bp->ut_type == OLD_TIME ? "|" : "{", + UT_HOSTSIZE, _UTX_HOSTSIZE, bp->ut_host, + ct, ct + 11); + if (maxrec && !--maxrec) + return; + } + continue; + case USER_PROCESS: + case DEAD_PROCESS: + /* find associated tty */ + for (T = ttylist;; T = T->next) { + if (!T) { + /* add new one */ + T = addtty(bp->ut_id, bp->ut_pid); + break; + } + if (!memcmp(T->id, bp->ut_id, _UTX_IDSIZE) && T->pid == bp->ut_pid) + break; + } + if (bp->ut_type != DEAD_PROCESS && want(bp, YES)) { + ct = ctime(&bp->ut_tv.tv_sec); + printf("%-*.*s %-*.*s %-*.*s %10.10s %5.5s ", + UT_NAMESIZE, _UTX_USERSIZE, bp->ut_user, + UT_LINESIZE, _UTX_LINESIZE, bp->ut_line, + UT_HOSTSIZE, _UTX_HOSTSIZE, bp->ut_host, + ct, ct + 11); + if (!T->logout) + puts(" still logged in"); + else { + if (T->logout < 0) { + T->logout = -T->logout; + printf("- %s", crmsg); + } + else + printf("- %5.5s", + ctime(&T->logout)+11); + delta = T->logout - bp->ut_tv.tv_sec; + if (delta < SECSPERDAY) + printf(" (%5.5s)\n", + asctime(gmtime(&delta))+11); + else + printf(" (%ld+%5.5s)\n", + delta / SECSPERDAY, + asctime(gmtime(&delta))+11); + } + if (maxrec != -1 && !--maxrec) + return; + } + T->logout = bp->ut_tv.tv_sec; + continue; + } + } + endutxent_wtmp(); + ct = ctime(prev ? &prev->ut_tv.tv_sec : &now); + printf("\nwtmp begins %10.10s %5.5s \n", ct, ct + 11); +} + +/* + * want -- + * see if want this entry + */ +int +want(bp, check) + struct utmpx *bp; + int check; +{ + ARG *step; + + if (!arglist) + return (YES); + + for (step = arglist; step; step = step->next) + switch(step->type) { + case HOST_TYPE: + if (!strncasecmp(step->name, bp->ut_host, _UTX_HOSTSIZE)) + return (YES); + break; + case TTY_TYPE: + { + char *line = bp->ut_line; + if (check) { + /* + * when uucp and ftp log in over a network, the entry in + * the utmpx file is the name plus their process id. See + * etc/ftpd.c and usr.bin/uucp/uucpd.c for more information. + */ + if (!strncmp(line, "ftp", sizeof("ftp") - 1)) + line = "ftp"; + else if (!strncmp(line, "uucp", sizeof("uucp") - 1)) + line = "uucp"; + } + if (!strncmp(step->name, line, _UTX_LINESIZE)) + return (YES); + break; + } + case USER_TYPE: + if (bp->ut_type == BOOT_TIME && !strncmp(step->name, "reboot", _UTX_USERSIZE)) + return (YES); + if (bp->ut_type == SHUTDOWN_TIME && !strncmp(step->name, "shutdown", _UTX_USERSIZE)) + return (YES); + if (!strncmp(step->name, bp->ut_user, _UTX_USERSIZE)) + return (YES); + break; + } + return (NO); +} + +/* + * addarg -- + * add an entry to a linked list of arguments + */ +void +addarg(type, arg) + int type; + const char *arg; +{ + ARG *cur; + + if (!(cur = (ARG *)malloc((u_int)sizeof(ARG)))) + err(1, "malloc failure"); + cur->next = arglist; + cur->type = type; + cur->name = arg; + arglist = cur; +} + +/* + * addtty -- + * add an entry to a linked list of ttys + */ +TTY * +addtty(id, pid) + const char *id; + pid_t pid; +{ + TTY *cur; + + if (!(cur = (TTY *)malloc((u_int)sizeof(TTY)))) + err(1, "malloc failure"); + cur->next = ttylist; + cur->logout = currentout; + memmove(cur->id, id, _UTX_IDSIZE); + cur->pid = pid; + return (ttylist = cur); +} + +/* + * hostconv -- + * convert the hostname to search pattern; if the supplied host name + * has a domain attached that is the same as the current domain, rip + * off the domain suffix since that's what login(1) does. + */ +void +hostconv(arg) + const char *arg; +{ + static int first = 1; + static char *hostdot, name[MAXHOSTNAMELEN]; + char *argdot; + + if (!(argdot = strchr(arg, '.'))) + return; + if (first) { + first = 0; + if (gethostname(name, sizeof(name))) + err(1, "gethostname"); + hostdot = strchr(name, '.'); + } + if (hostdot && !strcasecmp(hostdot, argdot)) + *argdot = '\0'; +} + +/* + * ttyconv -- + * convert tty to correct name. + */ +const char * +ttyconv(arg) + const char *arg; +{ + char *mval; + int kludge = 0; + int len = strlen(arg); + + /* + * kludge -- we assume that most tty's end with + * a two character suffix. + */ + if (len == 2) + kludge = 8; /* either 6 for "ttyxx" or 8 for "console"; use largest */ + /* + * kludge -- we assume cloning ptys names are "ttys" followed by + * more than one digit + */ + else if (len > 2 && *arg == 's') { + const char *cp = arg + 1; + while(*cp && isdigit(*cp)) + cp++; + if (*cp == 0) + kludge = len + sizeof("tty"); + } + if (kludge) { + if (!(mval = malloc(kludge))) + err(1, "malloc failure"); + if (!strcmp(arg, "co")) + (void)strcpy(mval, "console"); + else { + (void)strcpy(mval, "tty"); + (void)strcpy(mval + sizeof("tty") - 1, arg); + } + return (mval); + } + if (!strncmp(arg, _PATH_DEV, sizeof(_PATH_DEV) - 1)) + return (arg + sizeof(_PATH_DEV) - 1); + return (arg); +} + +/* + * onintr -- + * on interrupt, we inform the user how far we've gotten + */ +void +onintr(signo) + int signo; +{ + char *ct; + + ct = ctime(prev ? &prev->ut_tv.tv_sec : &now); + printf("\ninterrupted %10.10s %5.5s \n", ct, ct + 11); + if (signo == SIGINT) + exit(1); + (void)fflush(stdout); /* fix required for rsh */ +} diff --git a/adv_cmds/locale/locale.1 b/adv_cmds/locale/locale.1 new file mode 100644 index 0000000..e4df365 --- /dev/null +++ b/adv_cmds/locale/locale.1 @@ -0,0 +1,101 @@ +.\"Modified from man(1) of FreeBSD, the NetBSD mdoc.template, and mdoc.samples. +.\"See Also: +.\"man mdoc.samples for a complete listing of options +.\"man mdoc for the short list of editing options +.\"/usr/share/misc/mdoc.template +.Dd August 27, 2004 +.Dt LOCALE 1 +.Os Darwin +.Sh NAME +.Nm locale +.Nd display locale settings +.Sh SYNOPSIS +.Nm +.Op Fl a|m +.Nm +.Op Fl ck +.Ar name +.Op ... +.Sh DESCRIPTION +.Nm +displays information about the current locale, or a list of all available +locales. +.Pp +When +.Nm +is run with no arguments, +it will display the current source of each locale category. +.Pp +When +.Nm +is given the name of a category, +it acts as if it had been given each keyword in that category. +For each keyword it is given, the current value +is displayed. +.Sh OPTIONS +.Bl -tag -width -indent +.It Fl a +Lists all public locales. +.It Fl c Ar name ... +Lists the category name before each keyword, +unless it is the same category as the previously displayed keyword. +.It Fl k Ar name ... +Displays the name of each keyword prior to its value. +.It Fl m +Lists all available public charmaps. +Darwin locales do not support charmaps, so list all CODESETs instead. +.El +.Pp +.Sh OPERANDS +The following operand is supported: +.Pp +.Ar name +is the name of a keyword or category to display. A list of all keywords +and categories can be shown with the following command: +.Bd -literal +locale -ck LC_ALL +.Ed +.Pp +.Sh ENVIRONMENT +.Bl -tag -width "LC_MESSAGES" +.It Ev LANG +Used as a substitute for any unset +.Ev LC_* +variable. If +.Ev LANG +is unset, it will act as if set to "C". If any of +.Ev LANG +or +.Ev LC_* +are set to invalid values, +.Nm +acts as if they are all unset. +.It Ev LC_ALL +Will override the setting of all other +.Ev LC_* +variables. +.It Ev LC_COLLATE +Sets the locale for the LC_COLLATE category. +.It Ev LC_CTYPE +Sets the locale for the LC_CTYPE category. +.It Ev LC_MESSAGES +Sets the locale for the LC_MESSAGES category. +.It Ev LC_MONETARY +Sets the locale for the LC_MONETARY category. +.It Ev LC_NUMERIC +Sets the locale for the LC_NUMERIC category. +.It Ev LC_TIME +Sets the locale for the LC_TIME category. +.El +.Sh SEE ALSO +.Xr localedef 1 , +.Xr localeconv 3 , +.Xr nl_langinfo 3 , +.Xr setlocale 3 +.Sh STANDARDS +The +.Nm +utility conforms to IEEE Std 1003.1-2001 (``POSIX.1''). +.Sh HISTORY +.Nm +appeared in Mac OS X 10.4 diff --git a/adv_cmds/locale/locale.cc b/adv_cmds/locale/locale.cc new file mode 100644 index 0000000..88c7784 --- /dev/null +++ b/adv_cmds/locale/locale.cc @@ -0,0 +1,428 @@ +#include <iostream> +#include <sstream> +#include <map> +#include <set> +#include <vector> +#include <algorithm> + +#include <unistd.h> +#include <langinfo.h> +#include <locale.h> +#include <xlocale.h> +#include <sys/types.h> +#include <dirent.h> + +#define LAST(array) array + (sizeof(array) / sizeof(*array)) + +#define LC_SPECIAL (LC_COLLATE+LC_CTYPE+LC_MESSAGES+LC_MONETARY+LC_NUMERIC+LC_TIME) + +using namespace std; + +enum vtype { + V_STR, V_NUM +}; + +template<typename T> string tostr(T val) { + ostringstream ss; + ss << val; + return ss.str(); +} + +string quote(string s) { + return '"' + s + '"'; +} + +class keyword { + public: + virtual string get_category() const { return category; } + virtual string get_keyword() const { return kword; } + virtual string get_value(bool show_quotes) const { + return (show_quotes && t == V_STR) ? quote(value) : value; } + + virtual ~keyword() { } + protected: + keyword(int category_, string kword, string value, vtype t) + : kword(kword), value(value), t(t) { + switch(category_) { + case LC_COLLATE: + category = "LC_COLLATE"; + break; + case LC_CTYPE: + category = "LC_CTYPE"; + break; + case LC_MESSAGES: + category = "LC_MESSAGES"; + break; + case LC_MONETARY: + category = "LC_MONETARY"; + break; + case LC_NUMERIC: + category = "LC_NUMERIC"; + break; + case LC_TIME: + category = "LC_TIME"; + break; + case LC_SPECIAL: + category = "LC_SPECIAL"; + break; + default: + { + ostringstream lc; + lc << "LC_" << category_; + category = lc.str(); + } + break; + } + } + + string category, kword, value; + vtype t; +}; + +struct keyword_cmp { + bool operator()(const keyword *a, const keyword *b) const { + return a->get_category() < b->get_category(); + } +}; + +class li_keyword : public keyword { + public: + li_keyword(int category, string kword, int itemnum, vtype t = V_STR) + : keyword(category, kword, nl_langinfo(itemnum), t) { } +}; + +class lia_keyword : public keyword { + protected: + vector<string> values; + public: + virtual string get_value(bool show_quotes) const { + ostringstream ss; + vector<string>::const_iterator s(values.begin()), e(values.end()), i(s); + + for(; i < e; ++i) { + if (i != s) { + ss << ';'; + } + if (show_quotes && t == V_STR) { + ss << quote(*i); + } else { + ss << *i; + } + } + + return ss.str(); + } + + lia_keyword(int category, string kword, int *s, int *e, vtype t = V_STR) + : keyword(category, kword, "", t) { + for(; s < e; ++s) { + values.push_back(nl_langinfo(*s)); + } + } +}; + +class lc_keyword : public keyword { + public: + lc_keyword(int category, string kword, string value, vtype t = V_STR) + : keyword(category, kword, value, t) { } +}; + +void usage(char *argv0) { + clog << "usage: " << argv0 << "[-a|-m]\n or: " + << argv0 << " [-cCk] name..." << endl; +} + +void list_all_valid_locales() { + string locale_dir("/usr/share/locale"); + bool found_C = false, found_POSIX = false; + DIR *d = opendir(locale_dir.c_str()); + struct dirent *de; + static string expected[] = { "LC_COLLATE", "LC_CTYPE", "LC_MESSAGES", + "LC_NUMERIC", "LC_TIME" }; + + for(de = readdir(d); de; de = readdir(d)) { + string lname(de->d_name, de->d_namlen); + string ldir(locale_dir + "/" + lname); + int cnt = 0; + DIR *ld = opendir(ldir.c_str()); + if (ld) { + struct dirent *lde; + for(lde = readdir(ld); lde; lde = readdir(ld)) { + string fname(lde->d_name, lde->d_namlen); + if (LAST(expected) != find(expected, LAST(expected), fname)) { + cnt++; + } + } + closedir(ld); + + if (cnt == LAST(expected) - expected) { + cout << lname << endl; + if (lname == "C") { + found_C = true; + } + if (lname == "POSIX") { + found_POSIX = true; + } + } + } + } + closedir(d); + if (!found_C) { + cout << "C" << endl; + } + if (!found_POSIX) { + cout << "POSIX" << endl; + } +} + +void show_all_unique_codesets() { + string locale_dir("/usr/share/locale"); + DIR *d = opendir(locale_dir.c_str()); + struct dirent *de; + static string expected[] = { "LC_COLLATE", "LC_CTYPE", "LC_MESSAGES", + "LC_NUMERIC", "LC_TIME" }; + set<string> codesets; + for(de = readdir(d); de; de = readdir(d)) { + string lname(de->d_name, de->d_namlen); + string ldir(locale_dir + "/" + lname); + int cnt = 0; + DIR *ld = opendir(ldir.c_str()); + if (ld) { + struct dirent *lde; + for(lde = readdir(ld); lde; lde = readdir(ld)) { + string fname(lde->d_name, lde->d_namlen); + if (LAST(expected) != find(expected, LAST(expected), fname)) { + cnt++; + } + } + closedir(ld); + + if (cnt == LAST(expected) - expected) { + locale_t xloc = newlocale(LC_ALL_MASK, lname.c_str(), NULL); + if (xloc) { + char *cs = nl_langinfo_l(CODESET, xloc); + if (cs && *cs && (codesets.find(cs) == codesets.end())) { + cout << cs << endl; + codesets.insert(cs); + } + freelocale(xloc); + } + } + } + } + closedir(d); +} + +typedef map<string, keyword *> keywords_t; +keywords_t keywords; + +typedef map<string, vector<keyword *> > catorgies_t; +catorgies_t catoriges; + +void add_kw(keyword *k) { + keywords.insert(make_pair(k->get_keyword(), k)); + catorgies_t::iterator c = catoriges.find(k->get_category()); + if (c != catoriges.end()) { + c->second.push_back(k); + } else { + vector<keyword *> v; + v.push_back(k); + catoriges.insert(make_pair(k->get_category(), v)); + } +} + +string grouping(char *g) { + ostringstream ss; + if (*g == 0) { + ss << "0"; + } else { + ss << static_cast<int>(*g); + while(*++g) { + ss << ";" << static_cast<int>(*g); + } + } + return ss.str(); +} + +void init_keywords() { + struct lconv *lc = localeconv(); + if (lc) { + add_kw(new lc_keyword(LC_NUMERIC, "decimal_point", lc->decimal_point)); + add_kw(new lc_keyword(LC_NUMERIC, "thousands_sep", lc->thousands_sep)); + add_kw(new lc_keyword(LC_NUMERIC, "grouping", grouping(lc->grouping))); + add_kw(new lc_keyword(LC_MONETARY, "int_curr_symbol", lc->int_curr_symbol)); + add_kw(new lc_keyword(LC_MONETARY, "currency_symbol", lc->currency_symbol)); + add_kw(new lc_keyword(LC_MONETARY, "mon_decimal_point", lc->mon_decimal_point)); + add_kw(new lc_keyword(LC_MONETARY, "mon_thousands_sep", lc->mon_thousands_sep)); + add_kw(new lc_keyword(LC_MONETARY, "mon_grouping", grouping(lc->mon_grouping))); + add_kw(new lc_keyword(LC_MONETARY, "positive_sign", lc->positive_sign)); + add_kw(new lc_keyword(LC_MONETARY, "negative_sign", lc->negative_sign)); + add_kw(new lc_keyword(LC_MONETARY, "int_frac_digits", tostr((int)lc->int_frac_digits), V_NUM)); + add_kw(new lc_keyword(LC_MONETARY, "frac_digits", tostr((int)lc->frac_digits), V_NUM)); + add_kw(new lc_keyword(LC_MONETARY, "p_cs_precedes", tostr((int)lc->p_cs_precedes), V_NUM)); + add_kw(new lc_keyword(LC_MONETARY, "p_sep_by_space", tostr((int)lc->p_sep_by_space), V_NUM)); + add_kw(new lc_keyword(LC_MONETARY, "n_cs_precedes", tostr((int)lc->n_cs_precedes), V_NUM)); + add_kw(new lc_keyword(LC_MONETARY, "n_sep_by_space", tostr((int)lc->n_sep_by_space), V_NUM)); + add_kw(new lc_keyword(LC_MONETARY, "p_sign_posn", tostr((int)lc->p_sign_posn), V_NUM)); + add_kw(new lc_keyword(LC_MONETARY, "n_sign_posn", tostr((int)lc->n_sign_posn), V_NUM)); + add_kw(new lc_keyword(LC_MONETARY, "int_p_cs_precedes", tostr((int)lc->int_p_cs_precedes), V_NUM)); + add_kw(new lc_keyword(LC_MONETARY, "int_n_cs_precedes", tostr((int)lc->int_n_cs_precedes), V_NUM)); + add_kw(new lc_keyword(LC_MONETARY, "int_p_sep_by_space", tostr((int)lc->int_p_sep_by_space), V_NUM)); + add_kw(new lc_keyword(LC_MONETARY, "int_n_sep_by_space", tostr((int)lc->int_n_sep_by_space), V_NUM)); + add_kw(new lc_keyword(LC_MONETARY, "int_p_sign_posn", tostr((int)lc->int_p_sign_posn), V_NUM)); + add_kw(new lc_keyword(LC_MONETARY, "int_n_sign_posn", tostr((int)lc->int_n_sign_posn), V_NUM)); + } + + int abdays[] = {ABDAY_1, ABDAY_2, ABDAY_3, ABDAY_4, ABDAY_5, ABDAY_6, ABDAY_7}; + add_kw(new lia_keyword(LC_TIME, "ab_day", abdays, LAST(abdays))); + add_kw(new lia_keyword(LC_TIME, "abday", abdays, LAST(abdays))); + + int days[] = {DAY_1, DAY_2, DAY_3, DAY_4, DAY_5, DAY_6, DAY_7}; + add_kw(new lia_keyword(LC_TIME, "day", days, LAST(days))); + + int abmons[] = {ABMON_1, ABMON_2, ABMON_3, ABMON_4, ABMON_5, ABMON_6, ABMON_7, ABMON_8, ABMON_9, ABMON_10, ABMON_11, ABMON_12}; + add_kw(new lia_keyword(LC_TIME, "abmon", abmons, LAST(abmons))); + + int mons[] = {MON_1, MON_2, MON_3, MON_4, MON_5, MON_6, MON_7, MON_8, MON_9, MON_10, MON_11, MON_12}; + add_kw(new lia_keyword(LC_TIME, "mon", mons, LAST(mons))); + + int am_pms[] = {AM_STR, PM_STR}; + add_kw(new lia_keyword(LC_TIME, "am_pm", am_pms, LAST(am_pms))); + + add_kw(new li_keyword(LC_TIME, "t_fmt_ampm", T_FMT_AMPM)); + add_kw(new li_keyword(LC_TIME, "era", ERA)); + add_kw(new li_keyword(LC_TIME, "era_d_fmt", ERA_D_FMT)); + add_kw(new li_keyword(LC_TIME, "era_t_fmt", ERA_T_FMT)); + add_kw(new li_keyword(LC_TIME, "era_d_t_fmt", ERA_D_T_FMT)); + add_kw(new li_keyword(LC_TIME, "alt_digits", ALT_DIGITS)); + + add_kw(new li_keyword(LC_TIME, "d_t_fmt", D_T_FMT)); + add_kw(new li_keyword(LC_TIME, "d_fmt", D_FMT)); + add_kw(new li_keyword(LC_TIME, "t_fmt", T_FMT)); + + add_kw(new li_keyword(LC_MESSAGES, "yesexpr", YESEXPR)); + add_kw(new li_keyword(LC_MESSAGES, "noexpr", NOEXPR)); + add_kw(new li_keyword(LC_MESSAGES, "yesstr", YESSTR)); + add_kw(new li_keyword(LC_MESSAGES, "nostr", NOSTR)); + + add_kw(new li_keyword(LC_CTYPE, "charmap", CODESET)); + add_kw(new lc_keyword(LC_SPECIAL, "categories", "LC_COLLATE LC_CTYPE LC_MESSAGES LC_MONETARY LC_NUMERIC LC_TIME")); + + // add_kw: CRNCYSTR D_MD_ORDER CODESET RADIXCHAR THOUSEP +} + +void show_keyword(string &last_cat, bool sw_categories, bool sw_keywords, + keyword *k) { + if (sw_categories && last_cat != k->get_category()) { + last_cat = k->get_category(); + cout << last_cat << endl; + } + if (sw_keywords) { + cout << k->get_keyword() << "="; + } + cout << k->get_value(sw_keywords) << endl; +} + +int main(int argc, char *argv[]) { + int sw; + bool sw_all_locales = false, sw_categories = false, sw_keywords = false, + sw_charmaps = false; + + while(-1 != (sw = getopt(argc, argv, "ackm"))) { + switch(sw) { + case 'a': + sw_all_locales = true; + break; + case 'c': + sw_categories = true; + break; + case 'k': + sw_keywords = true; + break; + case 'm': + sw_charmaps = true; + break; + default: + usage(argv[0]); + exit(1); + } + } + + if ((sw_all_locales && sw_charmaps) + || ((sw_all_locales || sw_charmaps) && (sw_keywords || sw_categories)) + ) { + usage(argv[0]); + exit(1); + } + + setlocale(LC_ALL, ""); + + if (!(sw_all_locales || sw_categories || sw_keywords || sw_charmaps) + && argc == optind) { + char *lang = getenv("LANG"); + cout << "LANG=" << quote(lang ? lang : "") << endl; + cout << "LC_COLLATE=" << quote(setlocale(LC_COLLATE, NULL)) << endl; + cout << "LC_CTYPE=" << quote(setlocale(LC_CTYPE, NULL)) << endl; + cout << "LC_MESSAGES=" << quote(setlocale(LC_MESSAGES, NULL)) << endl; + cout << "LC_MONETARY=" << quote(setlocale(LC_MONETARY, NULL)) << endl; + cout << "LC_NUMERIC=" << quote(setlocale(LC_NUMERIC, NULL)) << endl; + cout << "LC_TIME=" << quote(setlocale(LC_TIME, NULL)) << endl; + if (getenv("LC_ALL")) { + cout << "LC_ALL=" << quote(setlocale(LC_ALL, NULL)) << endl; + } else { + cout << "LC_ALL=" << endl; + } + + return 0; + } + + if (sw_all_locales) { + list_all_valid_locales(); + return 0; + } + + if (sw_charmaps) { + show_all_unique_codesets(); + return 0; + } + + init_keywords(); + string last_cat(""); + int exit_val = 0; + for(int i = optind; i < argc; ++i) { + keywords_t::iterator ki = keywords.find(argv[i]); + if (ki != keywords.end()) { + show_keyword(last_cat, sw_categories, sw_keywords, ki->second); + } else { + catorgies_t::iterator ci = catoriges.find(argv[i]); + if (ci != catoriges.end()) { + vector<keyword *>::iterator vi(ci->second.begin()), + ve(ci->second.end()); + for(; vi != ve; ++vi) { + show_keyword(last_cat, sw_categories, sw_keywords, *vi); + } + } else if (argv[i] == string("LC_ALL")) { + ki = keywords.begin(); + keywords_t::iterator ke = keywords.end(); + for(; ki != ke; ++ki) { + show_keyword(last_cat, sw_categories, sw_keywords, ki->second); + } + } else { + if (argv[i] == string("LC_CTYPE") + || argv[i] == string("LC_COLLATE")) { + // It would be nice to print a warning, + // but we aren't allowed (locale.ex test#14) + if (sw_categories) { + cout << argv[i] << endl; + } + } else { + clog << "unknown keyword " + << argv[i] << endl; + exit_val = 1; + } + } + } + } + + return exit_val; +} diff --git a/adv_cmds/localedef/charmap.p-1 b/adv_cmds/localedef/charmap.p-1 new file mode 100644 index 0000000..3901dd9 --- /dev/null +++ b/adv_cmds/localedef/charmap.p-1 @@ -0,0 +1,23 @@ +CHARMAP +<space> \x20 +<dollar> \x24 +<A> \101 +<a> \141 +<A-acute> \346 +<a-acute> \365 +<A-grave> \300 +<a-grave> \366 +<b> \142 +<B> \102 +<C> \103 +<c> \143 +<c-cedilla> \347 +<d> \x64 +<E> \x65 +<H> \110 +<h> \150 +<eszet> \xb7 +<s> \x73 +<z> \x7a +<e> \x65 +END CHARMAP diff --git a/adv_cmds/localedef/charmap.p-2 b/adv_cmds/localedef/charmap.p-2 new file mode 100644 index 0000000..75a3fdf --- /dev/null +++ b/adv_cmds/localedef/charmap.p-2 @@ -0,0 +1,115 @@ +CHARMAP +<NUL> \000 +<alert> \007 +<backspace> \010 +<tab> \011 +<newline> \012 +<vertical-tab> \013 +<form-feed> \014 +<carriage-return> \015 +<space> \040 +<exclamation-mark> \041 +<quotation-mark> \042 +<number-sign> \043 +<dollar-sign> \044 +<percent-sign> \045 +<ampersand> \046 +<apostrophe> \047 +<left-parenthesis> \050 +<right-parenthesis> \051 +<asterisk> \052 +<plus-sign> \053 +<comma> \054 +<hyphen> \055 +<hyphen-minus> \055 +<period> \056 +<full-stop> \056 +<slash> \057 +<solidus> \057 +<zero> \060 +<one> \061 +<two> \062 +<three> \063 +<four> \064 +<five> \065 +<six> \066 +<seven> \067 +<eight> \070 +<nine> \071 +<colon> \072 +<semicolon> \073 +<less-then-sign> \074 +<equals-sign> \075 +<greater-then-sign> \076 +<question-mark> \077 +<commercial-at> \100 +<A> \101 +<B> \102 +<C> \103 +<D> \104 +<E> \105 +<F> \106 +<G> \107 +<H> \110 +<I> \111 +<J> \112 +<K> \113 +<L> \114 +<M> \115 +<N> \116 +<O> \117 +<P> \120 +<Q> \121 +<R> \122 +<S> \123 +<T> \124 +<U> \125 +<V> \126 +<W> \127 +<X> \130 +<Y> \131 +<Z> \132 +<left-square-bracket> \133 +<backslash> \134 +<reverse-solidus> \134 +<right-square-bracket> \135 +<circumflex> \136 +<circumflex-accent> \136 +<underscore> \137 +<underline> \137 +<low-line> \137 +<grave-accent> \140 +<a> \141 +<b> \142 +<c> \143 +<d> \144 +<e> \145 +<f> \146 +<g> \147 +<h> \150 +<i> \151 +<j> \152 +<k> \153 +<l> \154 +<m> \155 +<n> \156 +<o> \157 +<p> \160 +<q> \161 +<r> \162 +<s> \163 +<t> \164 +<u> \165 +<v> \166 +<w> \167 +<x> \170 +<y> \171 +<z> \172 +<left-brace> \173 +<left-curly-bracket> \173 +<vertical-line> \174 +<right-brace> \175 +<right-curly-bracket> \175 +<tilde> \176 +<DEL> \177 +END CHARMAP diff --git a/adv_cmds/localedef/charmap.test b/adv_cmds/localedef/charmap.test new file mode 100644 index 0000000..fd40463 --- /dev/null +++ b/adv_cmds/localedef/charmap.test @@ -0,0 +1,38 @@ +CHARMAP +<mb_cur_max> 2 +<mb_cur_min> 2 + +<acute-accent> \047 +<grave-accent> \140 + +<A> \x41 +<B> \102 +<C> C +<D> \104 +<E> "E" +<F> \d70 + +<backslash> \\ +<double-E> "<E><E>" + +<A-grave> \x60\x41 +<A-acute> \x27\x41 +<a-grave> \x60\x61 +<a-acute> \x27\x61 + +<j0101>...<j0104> \x12\x34 +END CHARMAP + +WIDTH +<A>...<D> 1 +<j0101>...<j0104> 2 +<no-such-symbol> 27 + +<A-grave> 2 +<A-acute> 2 +<a-grave> 2 +<a-acute> 2 + +WIDTH_DEFAULT 1 + +END WIDTH diff --git a/adv_cmds/localedef/def.a55 b/adv_cmds/localedef/def.a55 new file mode 100644 index 0000000..386e1c1 --- /dev/null +++ b/adv_cmds/localedef/def.a55 @@ -0,0 +1,6 @@ +LC_COLLATE +order_start forward +order_start forward;forward;forward +<a> +order_end +END LC_COLLATE diff --git a/adv_cmds/localedef/def.p-1 b/adv_cmds/localedef/def.p-1 new file mode 100644 index 0000000..adef476 --- /dev/null +++ b/adv_cmds/localedef/def.p-1 @@ -0,0 +1,157 @@ +# +LC_CTYPE +lower <a>;<b>;<c>;<c-cedilla>;<d>;...;<z> +upper A;B;C;C;...;Z +space \x20;\x09;\x0a;\x0b;\x0c;\x0d +blank \040;\011 +toupper (<a>,<A>);(b,B);(c,C);(c,C);(d,D);(z,Z) +digit 3;2 +END LC_CTYPE +# +LC_COLLATE +# +# The following example of collation is based on the proposed +# Canadian standard Z243.4.1-1990, "Canadian Alphanumeric +# Ordering Standard For Character sets of CSA Z234.4 Standard". +# (Other parts of this example locale definition file do not +# purport to relate to Canada, or to any other real culture.) +# The proposed standard defines a 4-weight collation, such that +# in the first pass, characters are compared without regard to +# case or accents; in second pass, backwards compare without +# regard to case; in the third pass, forward compare without +# regard to diacriticals. In the 3 first passes, non-alphabetic +# characters are ignored; in the fourth pass, only special +# characters are considered, such that "The string that has a +# special character in the lowest position comes first. If two +# strings have a special character in the same position, the +# collation value of the special character determines ordering. +# +# Only a subset of the character set is used here; mostly to +# illustrate the set-up. +# +# +collating-symbol <LOW_VALUE> +collating-symbol <LOWER-CASE> +collating-symbol <SUBSCRIPT-LOWER> +collating-symbol <SUPERSCRIPT-LOWER> +collating-symbol <UPPER-CASE> +collating-symbol <NO-ACCENT> +collating-symbol <PECULIAR> +collating-symbol <LIGATURE> +collating-symbol <ACUTE> +collating-symbol <GRAVE> +collating-symbol <RING-ABOVE> +collating-symbol <DIAERESIS> +collating-symbol <TILDE> +# Further collating-symbols follow. +# +# Properly, the standard does not include any multi-character +# collating elements; the one below is added for completeness. +# +collating_element <ch> from "<c><h>" +collating_element <CH> from "<C><H>" +collating_element <Ch> from "<C><h>" +collating_element <AE> from "<A><E>" +collating_element <ae> from "<a><e>" +# +order_start forward;backward;forward;forward,position +# +# Collating symbols are specified first in the sequence to allocate +# basic collation values to them, lower than that of any character. +<LOW_VALUE> +<LOWER-CASE> +<SUBSCRIPT-LOWER> +<SUPERSCRIPT-LOWER> +<UPPER-CASE> +<NO-ACCENT> +<PECULIAR> +<LIGATURE> +<ACUTE> +<GRAVE> +<RING-ABOVE> +<DIAERESIS> +<TILDE> +# Further collating symbols are given a basic collating value here. +# +# Here follow special characters. +<space> IGNORE;IGNORE;IGNORE;<space> +# Other special characters follow here. +# +# Here follow the regular characters. +<a> <a>;<NO-ACCENT>;<LOWER-CASE>;IGNORE +<A> <a>;<NO-ACCENT>;<UPPER-CASE>;IGNORE +<a-acute> <a>;<ACUTE>;<LOWER-CASE>;IGNORE +<A-acute> <a>;<ACUTE>;<UPPER-CASE>;IGNORE +<a-grave> <a>;<GRAVE>;<LOWER-CASE>;IGNORE +<A-grave> <a>;<GRAVE>;<UPPER-CASE>;IGNORE +<ae> "<a><e>";"<LIGATURE><LIGATURE>";\ + "<LOWER-CASE><LOWER-CASE>";IGNORE +<AE> "<a><e>";"<LIGATURE><LIGATURE>";\ + "<UPPER-CASE><UPPER-CASE>";IGNORE +<b> <b>;<NO-ACCENT>;<LOWER-CASE>;IGNORE +... ...;<NO-ACCENT>;<LOWER-CASE>;IGNORE +<z> ...;<NO-ACCENT>;<LOWER-CASE>;IGNORE +<B> <b>;<NO-ACCENT>;<UPPER-CASE>;IGNORE +<c> <c>;<NO-ACCENT>;<LOWER-CASE>;IGNORE +<C> <c>;<NO-ACCENT>;<UPPER-CASE>;IGNORE +<ch> <ch>;<NO-ACCENT>;<LOWER-CASE>;IGNORE +<Ch> <ch>;<NO-ACCENT>;<PECULIAR>;IGNORE +<CH> <ch>;<NO-ACCENT>;<UPPER-CASE>;IGNORE +# +# As an example, the strings "Bach" and "bach" could be encoded (for +# compare purposes) as: +# "Bach" <b>;<a>;<ch>;<LOW_VALUE>;<NO_ACCENT>;<NO_ACCENT>;\ +# <NO_ACCENT>;<LOW_VALUE>;<UPPER>;<LOWER>;<LOWER>;<NULL> +# "bach" <b>;<a>;<ch>;<LOW_VALUE>;<NO_ACCENT>;<NO_ACCENT>;\ +# <NO_ACCENT>;<LOW_VALUE>;<LOWER>;<LOWER>;<LOWER>;<NULL> +# +# The two strings are equal in pass 1 and 2, but differ in pass 3. +# +# Further characters follow. +# +UNDEFINED IGNORE;IGNORE;IGNORE;IGNORE +# +order_end +# +END LC_COLLATE +# +LC_MONETARY +int_curr_symbol "USD " +currency_symbol "$" +mon_decimal_point "." +mon_grouping 3;0 +positive_sign "" +negative_sign "-" +p_cs_precedes 1 +n_sign_posn 0 +END LC_MONETARY +# +LC_NUMERIC +copy "US_en.ASCII" +decimal_point . +thousands_sep \, +grouping 3;3 +END LC_NUMERIC +# +LC_TIME +abday "Sun";"Mon";"Tue";"Wed";"Thu";"Fri";"Sat" +# +day "Sunday";"Monday";"Tuesday";"Wednesday";\ + "Thursday";"Friday";"Saturday" +# +abmon "Jan";"Feb";"Mar";"Apr";"May";"Jun";\ + "Jul";"Aug";"Sep";"Oct";"Nov";"Dec" +# +mon "January";"February";"March";"April";\ + "May";"June";"July";"August";"September";\ + "October";"November";"December" +# +d_t_fmt "%a %b %d %T %Z %Y\n" +am_pm "Am";"Pm" +END LC_TIME +# +LC_MESSAGES +yesexpr "^([yY][[:alpha:]]*)|(OK)" +# +noexpr "^[nN][[:alpha:]]*" +END LC_MESSAGES diff --git a/adv_cmds/localedef/def.p-2 b/adv_cmds/localedef/def.p-2 new file mode 100644 index 0000000..9b6ee15 --- /dev/null +++ b/adv_cmds/localedef/def.p-2 @@ -0,0 +1,280 @@ +LC_CTYPE +# The following is the POSIX locale LC_CTYPE. +# "alpha" is by default "upper" and "lower" +# "alnum" is by definition "alpha" and "digit" +# "print" is by default "alnum", "punct" and the <space> character +# "graph" is by default "alnum" and "punct" +# +upper <A>;<B>;<C>;<D>;<E>;<F>;<G>;<H>;<I>;<J>;<K>;<L>;<M>;\ + <N>;<O>;<P>;<Q>;<R>;<S>;<T>;<U>;<V>;<W>;<X>;<Y>;<Z> +# +lower <a>;<b>;<c>;<d>;<e>;<f>;<g>;<h>;<i>;<j>;<k>;<l>;<m>;\ + <n>;<o>;<p>;<q>;<r>;<s>;<t>;<u>;<v>;<w>;<x>;<y>;<z> +# +digit <zero>;<one>;<two>;<three>;<four>;<five>;<six>;\ + <seven>;<eight>;<nine> +# +space <tab>;<newline>;<vertical-tab>;<form-feed>;\ + <carriage-return>;<space> +# +cntrl <alert>;<backspace>;<tab>;<newline>;<vertical-tab>;\ + <form-feed>;<carriage-return>;\ + <NUL>;<SOH>;<STX>;<ETX>;<EOT>;<ENQ>;<ACK>;<SO>;\ + <SI>;<DLE>;<DC1>;<DC2>;<DC3>;<DC4>;<NAK>;<SYN>;\ + <ETB>;<CAN>;<EM>;<SUB>;<ESC>;<IS4>;<IS3>;<IS2>;\ + <IS1>;<DEL> +# +punct <exclamation-mark>;<quotation-mark>;<number-sign>;\ + <dollar-sign>;<percent-sign>;<ampersand>;<apostrophe>;\ + <left-parenthesis>;<right-parenthesis>;<asterisk>;\ + <plus-sign>;<comma>;<hyphen>;<period>;<slash>;\ + <colon>;<semicolon>;<less-than-sign>;<equals-sign>;\ + <greater-than-sign>;<question-mark>;<commercial-at>;\ + <left-square-bracket>;<backslash>;<right-square-bracket>;\ + <circumflex>;<underscore>;<grave-accent>;<left-curly-bracket>;\ + <vertical-line>;<right-curly-bracket>;<tilde> +# +xdigit <zero>;<one>;<two>;<three>;<four>;<five>;<six>;<seven>;\ + <eight>;<nine>;<A>;<B>;<C>;<D>;<E>;<F>;<a>;<b>;<c>;<d>;<e>;<f> +# +blank <space>;<tab> +# +toupper (<a>,<A>);(<b>,<B>);(<c>,<C>);(<d>,<D>);(<e>,<E>);\ + (<f>,<F>);(<g>,<G>);(<h>,<H>);(<i>,<I>);(<j>,<J>);\ + (<k>,<K>);(<l>,<L>);(<m>,<M>);(<n>,<N>);(<o>,<O>);\ + (<p>,<P>);(<q>,<Q>);(<r>,<R>);(<s>,<S>);(<t>,<T>);\ + (<u>,<U>);(<v>,<V>);(<w>,<W>);(<x>,<X>);(<y>,<Y>);(<z>,<Z>) +# +tolower (<A>,<a>);(<B>,<b>);(<C>,<c>);(<D>,<d>);(<E>,<e>);\ + (<F>,<f>);(<G>,<g>);(<H>,<h>);(<I>,<i>);(<J>,<j>);\ + (<K>,<k>);(<L>,<l>);(<M>,<m>);(<N>,<n>);(<O>,<o>);\ + (<P>,<p>);(<Q>,<q>);(<R>,<r>);(<S>,<s>);(<T>,<t>);\ + (<U>,<u>);(<V>,<v>);(<W>,<w>);(<X>,<x>);(<Y>,<y>);(<Z>,<z>) +END LC_CTYPE +LC_COLLATE +# This is the POSIX locale definition for the LC_COLLATE category. +# The order is the same as in the ASCII codeset. +order_start forward +<NUL> +<SOH> +<STX> +<ETX> +<EOT> +<ENQ> +<ACK> +<alert> +<backspace> +<tab> +<newline> +<vertical-tab> +<form-feed> +<carriage-return> +<SO> +<SI> +<DLE> +<DC1> +<DC2> +<DC3> +<DC4> +<NAK> +<SYN> +<ETB> +<CAN> +<EM> +<SUB> +<ESC> +<IS4> +<IS3> +<IS2> +<IS1> +<space> +<exclamation-mark> +<quotation-mark> +<number-sign> +<dollar-sign> +<percent-sign> +<ampersand> +<apostrophe> +<left-parenthesis> +<right-parenthesis> +<asterisk> +<plus-sign> +<comma> +<hyphen> +<period> +<slash> +<zero> +<one> +<two> +<three> +<four> +<five> +<six> +<seven> +<eight> +<nine> +<colon> +<semicolon> +<less-than-sign> +<equals-sign> +<greater-than-sign> +<question-mark> +<commercial-at> +<A> +<B> +<C> +<D> +<E> +<F> +<G> +<H> +<I> +<J> +<K> +<L> +<M> +<N> +<O> +<P> +<Q> +<R> +<S> +<T> +<U> +<V> +<W> +<X> +<Y> +<Z> +<left-square-bracket> +<backslash> +<right-square-bracket> +<circumflex> +<underscore> +<grave-accent> +<a> +<b> +<c> +<d> +<e> +<f> +<g> +<h> +<i> +<j> +<k> +<l> +<m> +<n> +<o> +<p> +<q> +<r> +<s> +<t> +<u> +<v> +<w> +<x> +<y> +<z> +<left-curly-bracket> +<vertical-line> +<right-curly-bracket> +<tilde> +<DEL> +order_end +# +END LC_COLLATE +LC_MONETARY +# This is the POSIX locale definition for +# the LC_MONETARY category. +# +int_curr_symbol "" +currency_symbol "" +mon_decimal_point "" +mon_thousands_sep "" +mon_grouping -1 +positive_sign "" +negative_sign "" +int_frac_digits -1 +p_cs_precedes -1 +p_sep_by_space -1 +n_cs_precedes -1 +n_sep_by_space -1 +p_sign_posn -1 +n_sign_posn -1 +# +END LC_MONETARY +LC_NUMERIC +# This is the POSIX locale definition for +# the LC_NUMERIC category. +# +decimal_point "<period>" +thousands_sep "" +grouping -1 +# +END LC_NUMERIC +LC_TIME +# This is the POSIX locale definition for +# the LC_TIME category. +# +# Abbreviated weekday names (%a) +abday "<S><u><n>";"<M><o><n>";"<T><u><e>";"<W><e><d>";\ + "<T><h><u>";"<F><r><i>";"<S><a><t>" +# +# Full weekday names (%A) +day "<S><u><n><d><a><y>";"<M><o><n><d><a><y>";\ + "<T><u><e><s><d><a><y>";"<W><e><d><n><e><s><d><a><y>";\ + "<T><h><u><r><s><d><a><y>";"<F><r><i><d><a><y>";\ + "<S><a><t><u><r><d><a><y>" +# +# Abbreviated month names (%b) +abmon "<J><a><n>";"<F><e><b>";"<M><a><r>";\ + "<A><p><r>";"<M><a><y>";"<J><u><n>";\ + "<J><u><l>";"<A><u><g>";"<S><e><p>";\ + "<O><c><t>";"<N><o><v>";"<D><e><c>" +# +# Full month names (%B) +mon "<J><a><n><u><a><r><y>";"<F><e><b><r><u><a><r><y>";\ + "<M><a><r><c><h>";"<A><p><r><i><l>";\ + "<M><a><y>";"<J><u><n><e>";\ + "<J><u><l><y>";"<A><u><g><u><s><t>";\ + "<S><e><p><t><e><m><b><e><r>";"<O><c><t><o><b><e><r>";\ + "<N><o><v><e><m><b><e><r>";"<D><e><c><e><m><b><e><r>" +# +# Equivalent of AM/PM (%p) "AM";"PM" +am_pm "<A><M>";"<P><M>" +# +# Appropriate date and time representation (%c) +# "%a %b %e %H:%M:%S %Y" +d_t_fmt "<percent-sign><a><space><percent-sign><b>\ + <space><percent-sign><e><space><percent-sign><H>\ + <colon><percent-sign><M><colon><percent-sign><S>\ + <space><percent-sign><Y>" +# +# Appropriate date representation (%x) "%m/%d/%y" +d_fmt "<percent-sign><m><slash><percent-sign><d>\ + <slash><percent-sign><y>" +# +# Appropriate time representation (%X) "%H:%M:%S" +t_fmt "<percent-sign><H><colon><percent-sign><M>\ + <colon><percent-sign><S>" +# +# Appropriate 12-hour time representation (%r) "%I:%M:%S %p" +t_fmt_ampm "<percent-sign><I><colon><percent-sign><M><colon>\ + <percent-sign><S> <percent-sign><p>" +# +END LC_TIME +LC_MESSAGES +# This is the POSIX locale definition for +# the LC_MESSAGES category. +# +yesexpr "<circumflex><left-square-bracket><y><Y><right-square-bracket>" +# +noexpr "<circumflex><left-square-bracket><n><N><right-square-bracket>" +# +yesstr "yes" +nostr "no" +END LC_MESSAGES + diff --git a/adv_cmds/localedef/localedef.1 b/adv_cmds/localedef/localedef.1 new file mode 100644 index 0000000..c8f3907 --- /dev/null +++ b/adv_cmds/localedef/localedef.1 @@ -0,0 +1,122 @@ +.\"Modified from man(1) of FreeBSD, the NetBSD mdoc.template, and mdoc.samples. +.Dd September 9, 2004 +.Dt LOCALEDEF 1 +.Os Darwin +.Sh NAME +.Nm localedef +.Nd define locale environment +.Sh SYNOPSIS +.Nm +.Op Fl c +.Op Fl f Ar charmap +.Op Fl i Ar sourcefile +.Ar name +." localedef [-c][-f charmap][-i sourcefile] name +.Sh DESCRIPTION +The +.Nm +utility reads source definitions for one or more locale categories +belonging to the same locale from the file named in the +.Fl i +option (if specified) or from standard input. +.Pp +The +.Ar name +operand identifies the target locale. The +.Nm +utility supports +the creation of public, or generally accessible locales, as well +as private, or restricted-access locales. +.Pp +Each category source definition is identified by the corresponding +environment variable name and terminated by an END category-name +statement. +.Pp +.Bl -tag -width "LC_MONETARY" -compact -offset indent +.It LC_CTYPE +Defines character classification and case conversion. +.It LC_COLLATE +Defines collation rules. +.It LC_MONETARY +Defines the format and symbols used in formatting of monetary information. +.It LC_NUMERIC +Defines the decimal delimiter, grouping, and grouping symbol for non-monetary numeric editing. +.It LC_TIME +Defines the format and content of date and time information. +.It LC_MESSAGES +Defines the format and values of affirmative and negative responses. +.El +.Sh OPTIONS +The following options are supported: +.Pp +.Bl -tag -width -indent +.It Fl c +Create permanent output even if warning messages have been issued. +.It Fl f Ar charmap +Specify the pathname of a file containing a mapping of character symbols and collating element symbols to actual character encodings. +.It Fl i Ar sourcefile +The pathname of a file containing the source definitions. If this option is not present, source definitions will be read from standard input. +.El +.Sh OPERANDS +The following operand is supported: +.Bl -tag -width -indent +.It Ar name +Identifies the locale. +If the name contains one or more slash characters, +.Ar name +will be interpreted as a pathname +where the created locale definitions will be stored. +If +.Ar name +does not contain any slash characters, +the locale will be public. +This capability is restricted to users with appropriate privileges. +(As a consequence of specifying one name, +although several categories can be processed in one execution, +only categories belonging to the same locale can be processed.) +.El +.Sh ENVIRONMENT +The following environment variables affect the execution of +.Nm : +.Bl -tag -width "LC_COLLATE" +.It Ev LANG +Provide a default value for the internationalization variables +that are unset or null. +If LANG is unset or null, +the corresponding value from the implementation-dependent default locale +will be used. +If any of the internationalization variables contains an invalid setting, +the utility will behave as if none of the variables had been defined. +.It Ev LC_ALL +If set to a non-empty string value, override the values of all the other internationalization variables. +.It Ev LC_COLLATE +(This variable has no effect on +.Nm ; +the POSIX locale will be used for this category.) +.It Ev LC_CTYPE +Determine the locale for the interpretation of sequences of bytes +of text data as characters +(for example, single- as opposed to multi-byte characters +in arguments and input files). +This variable has no effect on the processing of +.Nm +input data; +the POSIX locale is used for this purpose, +regardless of the value of this variable. +.It Ev LC_MESSAGES +Determine the locale that should be used to affect the format and contents of diagnostic messages written to standard error. +.It Ev NLSPATH +Determine the location of message catalogues for the processing of LC_MESSAGES. +.El +.Sh EXIT STATUS +The following exit values are returned: +.Bl -tag -width -indent +.It 0 +No errors occurred and the locales were successfully created. +.It 1 +Warnings occurred and the locales were successfully created. +.It 2 +The locale specification exceeded implementation limits or the coded character set or sets used were not supported by the implementation, and no locale was created. +.It >2 +Warnings or errors occurred and no output was created. +.El diff --git a/adv_cmds/localedef/localedef.pl b/adv_cmds/localedef/localedef.pl new file mode 100644 index 0000000..222eda0 --- /dev/null +++ b/adv_cmds/localedef/localedef.pl @@ -0,0 +1,1166 @@ +#!/usr/bin/perl -w + +use strict; +use Getopt::Std; +use Fcntl qw(O_TRUNC O_CREAT O_WRONLY SEEK_SET); +use File::Temp qw(tempfile); +use IO::File; + +my %opt; +getopts("cf:u:i:", \%opt); + +my $comment_char = "#"; +my $escape_char = "\\"; +my $val_match = undef; # set in set_escape +my %sym = (); +my %width = (); +my %ctype_classes = ( + # there are the charactors that get automagically included, there is no + # standard way to avoid them. XXX even if you have a charset without + # some of these charactors defined! + + # They are accessable in a regex via [:classname:], and libc has a + # isX() for most of these. + upper => {map { ($_, 1); } qw(A B C D E F G H I J K L M N O P Q R S T U V W X Y Z)}, + lower => {map { ($_, 1); } qw(a b c d e f g h i j k l m n o p q r s t u v w x y z)}, + alpha => {}, + #alnum => {}, + digit => {map { ($_, 1); } qw(0 1 2 3 4 5 6 7 8 9)}, + space => {}, + cntrl => {}, + punct => {}, + graph => {}, + print => {}, + xdigit => {map { ($_, 1); } qw(0 1 2 3 4 5 6 7 8 9 A B C D E F a b c d e f)}, + blank => {" " => 1, "\t" => 1}, + + toupper => {map { ($_, "\U$_"); } qw(a b c d e f g h i j k l m n o p q r s t u v w x y z)}, + tolower => {map { ($_, "\L$_"); } qw(A B C D E F G H I J K L M N O P Q R S T U V W X Y Z)}, +); + +my %cele = ( + # collating-elements -- these are a lot like %sym that only works + # in LC_COLLATE, can also be accessed in a regex via [.element.] +); + +my %csym = ( + # collating-symbols -- these are used to define a set of charactors + # that compare as equals (in one or more passes), can also be accessed + # in a regex via [=symbol=] +); + +my @corder = (); # collating order +my @corder_weights = (); # collating directions (forward, backward, position) + +my @colldef = (); + +my(%monetary, %numeric, %time, %messages); + +# This is the default charmap, unlike %ctype_classes you _can_ avoid this +# merely by having your own charmap definition file +my $default_charmap = <<EOT; +CHARMAP +<NUL> \\000 +<alert> \\007 +<backspace> \\010 +<tab> \\011 +<newline> \\012 +<vertical-tab> \\013 +<form-feed> \\014 +<carriage-return> \\015 +<space> \\040 +<exclamation-mark> \\041 +<quotation-mark> \\042 +<number-sign> \\043 +<dollar-sign> \\044 +<percent-sign> \\045 +<ampersand> \\046 +<apostrophe> \\047 +<left-parenthesis> \\050 +<right-parenthesis> \\051 +<asterisk> \\052 +<plus-sign> \\053 +<comma> \\054 +<hyphen> \\055 +<hyphen-minus> \\055 +<period> \\056 +<full-stop> \\056 +<slash> \\057 +<solidus> \\057 +<zero> \\060 +<one> \\061 +<two> \\062 +<three> \\063 +<four> \\064 +<five> \\065 +<six> \\066 +<seven> \\067 +<eight> \\070 +<nine> \\071 +<colon> \\072 +<semicolon> \\073 +<less-then-sign> \\074 +<less-than-sign> \\074 +<equals-sign> \\075 +<greater-then-sign> \\076 +<greater-than-sign> \\076 +<question-mark> \\077 +<commercial-at> \\100 +<A> \\101 +<B> \\102 +<C> \\103 +<D> \\104 +<E> \\105 +<F> \\106 +<G> \\107 +<H> \\110 +<I> \\111 +<J> \\112 +<K> \\113 +<L> \\114 +<M> \\115 +<N> \\116 +<O> \\117 +<P> \\120 +<Q> \\121 +<R> \\122 +<S> \\123 +<T> \\124 +<U> \\125 +<V> \\126 +<W> \\127 +<X> \\130 +<Y> \\131 +<Z> \\132 +<left-square-bracket> \\133 +<backslash> \\134 +<reverse-solidus> \\134 +<right-square-bracket> \\135 +<circumflex> \\136 +<circumflex-accent> \\136 +<underscore> \\137 +<underline> \\137 +<low-line> \\137 +<grave-accent> \\140 +<a> \\141 +<b> \\142 +<c> \\143 +<d> \\144 +<e> \\145 +<f> \\146 +<g> \\147 +<h> \\150 +<i> \\151 +<j> \\152 +<k> \\153 +<l> \\154 +<m> \\155 +<n> \\156 +<o> \\157 +<p> \\160 +<q> \\161 +<r> \\162 +<s> \\163 +<t> \\164 +<u> \\165 +<v> \\166 +<w> \\167 +<x> \\170 +<y> \\171 +<z> \\172 +<left-brace> \\173 +<left-curly-bracket> \\173 +<vertical-line> \\174 +<right-brace> \\175 +<right-curly-bracket> \\175 +<tilde> \\176 +<DEL> \\177 + +<SOH> \\x01 +<STX> \\x02 +<ETX> \\x03 +<EOT> \\x04 +<ENQ> \\x05 +<ACK> \\x06 +<BEL> \\x07 +<BS> \\x08 +<HT> \\x09 +<NL> \\x0a +<VT> \\x0b +<NP> \\x0c +<CR> \\x0d +<SO> \\x0e +<SI> \\x0f +<DLE> \\x10 +<DC1> \\x11 +<DC2> \\x12 +<DC3> \\x13 +<DC4> \\x14 +<NAK> \\x15 +<SYN> \\x16 +<ETB> \\x17 +<CAN> \\x18 +<EM> \\x19 +<SUB> \\x1a +<ESC> \\x1b +<FS> \\x1c +<IS4> \\x1c +<GS> \\x1d +<IS3> \\x1d +<RS> \\x1e +<IS2> \\x1e +<US> \\x1f +<IS1> \\x1f +END CHARMAP +EOT + +&set_escape($escape_char); + +use strict qw(vars); + +if (@ARGV != 1) { + &exit(4, "usage: $0 [-c] [-f charmap-file] [-u codesetname] [-i localdef-file] LOCALENAME\n"); +} + +my $locale_dir = $ARGV[0]; +$locale_dir = "/usr/share/locale/$locale_dir" unless ($locale_dir =~ m{/}); + +my $CMAP; +if (defined($opt{'f'})) { + # Using new IO::File $opt{'f'}, "r" runs into problems with long path names + sysopen(CMAP_KLUDGE, $opt{'f'}, O_RDONLY) || &exit(4, "Can't open $opt{f}: $!\n"); + $CMAP = new IO::Handle; + $CMAP->fdopen(fileno(CMAP_KLUDGE), "r") || &exit(4, "Can't fdopen $opt{f}: $!\n"); +} else { + # er, not everyone gets IO::Scalar, so use an unamed tmp file + # $CMAP = new IO::Scalar \$default_charmap; + $CMAP = new_tmpfile IO::File; + print $CMAP $default_charmap; + seek $CMAP, 0, SEEK_SET; +} + +while(<$CMAP>) { + if (m/^\s*CHARMAP\s*$/) { + &parse_charmaps(); + } elsif (m/^\s*WIDTH\s*$/) { + &parse_widths(); + } elsif (m/^\s*($comment_char.*)?$/) { + } else { + chomp; + &exit(4, "syntax error on line $. ($_)"); + } +} +&parse_widths() if (0 == %width); + +if (defined($opt{'i'})) { + sysopen(STDIN, $opt{'i'}, 0) || &exit(4, "Can't open localdef file $opt{i}: $!"); +} else { + $opt{'i'} = "/dev/stdin"; +} + +my %LC_parsers = ( + NONE => [\&parse_LC_NONE, qr/^\s*((escape|comment)_char\s+$val_match\s*)?$/], + CTYPE => [\&parse_LC_CTYPE, qr/^\s*(\S+)\s+(\S+.*?)\s*$/], + COLLATE => [\&parse_LC_COLLATE, qr/^\s*(<[^>\s]+>|order_end|END|(\S*)\s+(\S+.*?)|collating[_-]element\s*<[^>]+>\s+from\s+$val_match)\s*$/, 1], + TIME => [\&parse_LC_TIME, qr/^\s*(ab_?day|day|abmon|mon|d_t_fmt|d_fmt|t_fmt|am_pm|t_fmt_ampm|era|era_d_fmt|era_t_fmt|era_d_t_fmt|alt_digits|copy|END)\s+(\S+.*?)\s*$/], + NUMERIC => [\&parse_LC_NUMERIC, qr/^\s*(decimal_point|thousands_sep|grouping|END|copy)\s+(\S+.*?)\s*$/], + MONETARY => [\&parse_LC_MONETARY, qr/^\s*(int_curr_symbol|currency_symbol|mon_decimal_point|mon_thousands_sep|mon_grouping|positive_sign|negative_sign|int_frac_digits|frac_digits|p_cs_precedes|p_sep_by_space|n_cs_precedes|n_sep_by_space|p_sign_posn|n_sign_posn|int_p_cs_precedes|int_n_cs_precedes|int_p_sep_by_space|int_n_sep_by_space|int_p_sign_posn|int_n_sign_posn|copy|END)\s+(\S+.*?)\s*$/], + MESSAGES => [\&parse_LC_MESSAGES, qr/^\s*(END|yesexpr|noexpr|yesstr|nostr|copy)\s+(\S+.*?)\s*$/], + "COLLATE order" => [\&parse_collate_order, qr/^\s*(order_end|(<[^>\s]+>|UNDEFINED|\Q...\E)(\s+\S+.*)?)\s*$/], +); +my($current_LC, $parse_func, $validate_line, $call_parse_on_END) + = ("NONE", $LC_parsers{"NONE"}->[0], $LC_parsers{"NONE"}->[1], undef); + +while(<STDIN>) { + next if (m/^\s*($comment_char.*)?\s*$/); + if (m/\Q$escape_char\E$/) { + chomp; + chop; + my $tmp = <STDIN>; + if (!defined($tmp)) { + &exit(4, "Syntax error, last line ($.) of $opt{i} is marked as a continued line\n"); + } + $tmp =~ s/^\s*//; + $_ .= $tmp; + redo; + } + + if ($current_LC eq "NONE" && m/^\s*LC_([A-Z]+)\s*$/) { + &set_parser($1); + next; + } + + unless (m/$validate_line/) { + &exit(4, "Syntax error on line $. of $opt{i}\n"); + } + + my($action, $args); + if (m/^\s*(\S*)(\s+(\S+.*?))?\s*$/) { + ($action, $args) = ($1, $3); + } else { + $action = $_; + chomp $action; + } + + if ($action eq "END") { + if ($args ne "LC_$current_LC" || $current_LC eq "NONE") { + &exit(4, "Syntax error on line $. of $opt{i} attempting to end $args when LC_$current_LC is open\n"); + } + if ($call_parse_on_END) { + &{$parse_func}($action, $args); + } + &set_parser("NONE"); + } else { + &{$parse_func}($action, $args); + } +} + +mkdir($locale_dir); +&run_mklocale(); +&write_lc_money(); +&write_lc_time(); +&write_lc_messages(); +&write_lc_numeric(); +&write_lc_collate(); +exit 0; + +sub parse_charmaps { + while(<$CMAP>) { + # XXX need to parse out <code_set_name>, <mb_cur_max>, <mb_cur_min>, + # <escape_char>, and <comment_char> before the generic "<sym> val" + if (m/^\s*<([\w\-]+)>\s+($val_match+)\s*$/) { + my($sym, $val) = ($1, $2); + $val = &parse_value_double_backwhack($val); + $sym{$sym} = $val; + } elsif (m/^\s*<([\w\-]*\d)>\s*\Q...\E\s*<([\w\-]*\d)>\s+($val_match+)\s*$/) { + # We don't deal with $se < $ss, or overflow of the last byte of $vs + # then again the standard doesn't say anything in particular needs + # to happen for those cases + my($ss, $se, $vs) = ($1, $2, $3); + $vs = &parse_value_double_backwhack($vs); + my $vlast = length($vs) -1; + for(my($s, $v) = ($ss, $vs); $s cmp $se; $s++) { + $sym{$s} = $v; + substr($v, $vlast) = chr(ord(substr($v, $vlast)) +1) + } + } elsif (m/^\s*END\s+CHARMAP\s*$/) { + return; + } elsif (m/^\s*($comment_char.*)?$/) { + } else { + &exit(4, "syntax error on line $."); + } + } +} + +sub parse_widths { + my $default = 1; + my @syms; + + while(<$CMAP>) { + if (m/^\s*<([\w\-]+)>\s+(\d+)\s*$/) { + my($sym, $w) = ($1, $2); + print "$sym width $w\n"; + if (!defined($sym{$sym})) { + warn "localedef: can't set width of unknown symbol $sym on line $.\n"; + } else { + $width{$sym} = $w; + } + } elsif (m/^\s*<([\w\-]+)>\s*\Q...\E\s*<([\w\-]+)>\s+(\d+)\s*$/) { + my($ss, $se, $w) = ($1, $2, $3); + if (!@syms) { + @syms = sort { $a cmp $b } keys(%sym); + } + + # Yes, we could do a binary search for find $ss in @syms + foreach my $s (@syms) { + if (($s cmp $ss) >= 0) { + last if (($s cmp $se) > 0); + } + } + } elsif (m/^\s*WIDTH_DEFAULT\s+(\d+)\s*$/) { + $default = $1; + } elsif (m/^\s*END\s+WIDTH\s*$/) { + last; + } elsif (m/^\s*($comment_char.*)?$/) { + } else { + &exit(4, "syntax error on line $."); + } + } + + foreach my $s (keys(%sym)) { + if (!defined($width{$s})) { + $width{$s} = $default; + } + } +} + +# This parses a single value in any of the 7 forms it can appear in, +# returns [0] the parsed value and [1] the remander of the string +sub parse_value_return_extra { + my $val = ""; + local($_) = $_[0]; + + while(1) { + $val .= &unsym($1), next + if (m/\G"((?:[^"\Q$escape_char\E]+|\Q$escape_char\E.)*)"/gc); + $val .= chr(oct($1)), next + if (m/\G\Q$escape_char\E([0-7]+)/gc); + $val .= chr(0+$1), next + if (m/\G\Q$escape_char\Ed([0-9]+)/gc); + $val .= pack("H*", $1), next + if (m/\G\Q$escape_char\Ex([0-9a-fA-F]+)/gc); + $val .= $1, next + if (m/\G([^,;<>\s\Q$escape_char()\E])/gc); + $val .= $1 + if (m/\G(?:\Q$escape_char\E)([,;<>\Q$escape_char()\E])/gc); + $val .= &unsym($1), next + if (m/\G(<[^>]+>)/gc); + + m/\G(.*)$/; + + return ($val, $1); + } +} + +# Parse one value, if there is more then one value alert the media +sub parse_value { + my ($ret, $err) = &parse_value_return_extra($_[0]); + if ($err ne "") { + &exit(4, "Syntax error, unexpected '$err' in value (after '$ret') on line $.\n"); + } + + return $ret; +} + +sub parse_value_double_backwhack { + my($val) = @_; + + my ($ret, $err) = &parse_value_return_extra($val); + return $ret if ($err eq ""); + + $val =~ s{\\\\}{\\}g; + ($ret, $err) = &parse_value_return_extra($val); + if ($err ne "") { + &exit(4, "Syntax error, unexpected '$err' in value (after '$ret') on line $.\n"); + } + + return $ret; +} +# $values is the string to parse, $dot_expand is a function ref that will +# return an array to insert when "X;...;Y" is parsed (undef means that +# construct is a syntax error), $nest is true if parens indicate a nested +# value string should be parsed and put in an array ref, $return_extra +# is true if any unparsable trailing junk should be returned as the last +# element (otherwise it is a syntax error). Any text matching the regex +# $specials is returned as an hash. +sub parse_values { + my($values, $sep, $dot_expand, $nest, $return_extra, $specials) = @_; + my(@ret, $live_dots); + + while($values ne "") { + if (defined($specials) && $values =~ s/^($specials)($sep|$)//) { + push(@ret, { $1, undef }); + next; + } + if ($nest && $values =~ s/^\(//) { + my @subret = &parse_values($values, ',', $dot_expand, $nest, 1, $specials); + $values = pop(@subret); + push(@ret, [@subret]); + unless ($values =~ s/^\)($sep)?//) { + &exit(4, "Syntax error, unmatched open paren on line $. of $opt{i}\n"); + } + next; + } + + my($v, $l) = &parse_value_return_extra($values); + $values = $l; + + if ($live_dots) { + splice(@ret, -1, 1, &{$dot_expand}($ret[$#ret], $v)); + $live_dots = 0; + } else { + push(@ret, $v); + } + + if (defined($dot_expand) && $values =~ s/^$sep\Q...\E$sep//) { + $live_dots = 1; + } elsif($values =~ s/^$sep//) { + # Normal case + } elsif($values =~ m/^$/) { + last; + } else { + last if ($return_extra); + &exit(4, "Syntax error parsing arguments on line $. of $opt{i}\n"); + } + } + + if ($live_dots) { + splice(@ret, -1, 1, &{$dot_expand}($ret[$#ret], undef)); + } + if ($return_extra) { + push(@ret, $values); + } + + return @ret; +} + +sub parse_LC_NONE { + my($cmd, $arg) = @_; + + if ($cmd eq "comment_char") { + $comment_char = &parse_value($arg); + } elsif($cmd eq "escape_char") { + &set_escape_char(&parse_value($arg)); + } elsif($cmd eq "") { + } else { + &exit(4, "Syntax error on line $. of $opt{i}\n"); + } +} + +sub parse_LC_CTYPE { + my($cmd, $arg) = @_; + + my $ctype_classes = join("|", keys(%ctype_classes)); + if ($cmd eq "copy") { + # XXX -- the locale command line utility doesn't currently + # output any LC_CTYPE info, so there isn't much of a way + # to implent copy yet + &exit(2, "copy not supported on line $. of $opt{i}\n"); + } elsif($cmd eq "charclass") { + my $cc = &parse_value($arg); + if (!defined($ctype_classes{$cc})) { + $ctype_classes{$cc} = []; + } else { + warn "charclass $cc defined more then once\n"; + } + } elsif($cmd =~ m/^to(upper|lower)$/) { + my @arg = &parse_values($arg, ';', undef, 1); + foreach my $p (@arg) { + &exit(4, "Syntax error on line $. of $opt{i} ${cmd}'s arguments must be character pairs like (a,A);(b,B)\n") if ("ARRAY" ne ref $p || 2 != @$p); + } + foreach my $pair (@arg) { + $ctype_classes{$cmd}{$pair->[0]} = $pair->[1]; + } + } elsif($cmd =~ m/^($ctype_classes)$/) { + my @arg = &parse_values($arg, ';', \&dot_expand, 0); + foreach my $c (@arg) { + $ctype_classes{$1}->{$c} = 1; + } + } elsif($cmd =~ "END") { + &add_to_ctype_class('alpha', keys(%{$ctype_classes{'lower'}})); + &add_to_ctype_class('alpha', keys(%{$ctype_classes{'upper'}})); + foreach my $c (qw(alpha lower upper)) { + foreach my $d (qw(cntrl digit punct space)) { + &deny_in_ctype_class($c, $d, keys(%{$ctype_classes{$d}})); + } + } + + &add_to_ctype_class('space', keys(%{$ctype_classes{'blank'}})); + foreach my $d (qw(upper lower alpha digit graph xdigit)) { + &deny_in_ctype_class('space', $d, keys(%{$ctype_classes{$d}})); + } + + foreach my $d (qw(upper lower alpha digit punct graph print xdigit)) { + &deny_in_ctype_class('cntrl', $d, keys(%{$ctype_classes{$d}})); + } + + foreach my $d (qw(upper lower alpha digit cntrl xdigit space)) { + &deny_in_ctype_class('punct', $d, keys(%{$ctype_classes{$d}})); + } + + foreach my $c (qw(graph print)) { + foreach my $a (qw(upper lower alpha digit xdigit punct)) { + &add_to_ctype_class($c, keys(%{$ctype_classes{$a}})); + } + foreach my $d (qw(cntrl)) { + &deny_in_ctype_class($c, $d, keys(%{$ctype_classes{$d}})); + } + } + &add_to_ctype_class('print', keys(%{$ctype_classes{'space'}})); + + # Yes, this is a requirment of the standard + &exit(2, "The digit class must have exactly 10 elements\n") if (10 != values(%{$ctype_classes{'digit'}})); + foreach my $d (values %{$ctype_classes{'digit'}}) { + if (!defined $ctype_classes{'xdigits'}->{$d}) { + &exit(4, "$d isn't in class xdigits, but all digits must appaer in xdigits\n"); + } + } + + $ctype_classes{'alnum'} = {} unless defined $ctype_classes{'alnum'}; + foreach my $a (qw(alpha digit)) { + &add_to_ctype_class('alnum', keys(%{$ctype_classes{$a}})); + } + + } else { + &exit(4, "Syntax error on line $. of $opt{i}\n"); + } +} + +sub parse_LC_COLLATE { + my ($cmd, $arg) = @_; + if (defined($arg) && $arg ne "") { + push(@colldef, "$cmd $arg"); + } else { + push(@colldef, "$cmd"); + } +} + +sub parse_collate_order { + my($cmd, $arg) = @_; + + if ($cmd =~ m/order[-_]end/) { + # restore the parent parser + &set_parser("COLLATE"); + my $undef_at; + for(my $i = 0; $i <= $#corder; ++$i) { + next unless "ARRAY" eq ref($corder[$i]); + # If ... appears as the "key" for a order entry it means the + # rest of the line is duplicated once for everything in the + # open ended range (key-pev-line, key-next-line). Any ... + # in the weight fields are delt with by &fixup_collate_order_args + if ($corder[$i]->[0] eq "...") { + my(@sym, $from, $to); + + my @charset = sort { $sym{$a} cmp $sym{$b} } keys(%sym); + if ($i != 0) { + $from = $corder[$i -1]->[0]; + } else { + $from = $charset[0]; + } + if ($i != $#corder) { + $to = $corder[$i +1]->[0]; + } else { + $to = $charset[$#charset]; + } + + my @expand; + my($s, $e) = (&parse_value($from), &parse_value($to)); + foreach my $c (@charset) { + if (($sym{$c} cmp $s) > 0) { + last if (($sym{$c} cmp $e) >= 0); + my @entry = @{$corder[$i]}; + $entry[0] = "<$c>"; + push(@expand, \@entry); + } + } + splice(@corder, $i, 1, @expand); + } elsif($corder[$i]->[0] eq "UNDEFINED") { + $undef_at = $i; + next; + } + &fixup_collate_order_args($corder[$i]); + } + + if ($undef_at) { + my @insert; + my %cused = map { ("ARRAY" eq ref $_) ? ($_->[0], undef) : () } @corder; + foreach my $s (keys(%sym)) { + next if (exists $cused{"<$s>"}); + my @entry = @{$corder[$undef_at]}; + $entry[0] = "<$s>"; + &fixup_collate_order_args(\@entry); + push(@insert, \@entry); + } + splice(@corder, $undef_at, 1, @insert); + } + } elsif((!defined $arg) || $arg eq "") { + if (!exists($csym{$cmd})) { + my($decode, $was_sym) = &unsym_with_check($cmd); + if ($was_sym) { + my %dots = ( "..." => undef ); + my @dots = (\%dots) x (0+@corder_weights); + push(@corder, [$cmd, @dots]); + } else { + warn "Undefined collation symbol $cmd used on line $. of $opt{i}\n"; + } + } else { + push(@corder, $cmd); + } + } else { + unless (defined($cele{$cmd} || defined $sym{$cmd})) { + warn "Undefined collation element or charset sym $cmd used on line $. of $opt{i}\n"; + } else { + # This expands all the symbols (but not colating elements), which + # makes life easier for dealing with ..., but harder for + # outputing the actual table at the end where we end up + # converting literal sequences back into symbols in some cases + my @args = &parse_values($arg, ';', undef, 0, 0, + qr/IGNORE|\Q...\E/); + + if (@args != @corder_weights) { + if (@args < @corder_weights) { + &exit(4, "Only " . (0 + @args) + . " weights supplied on line $. of $opt{i}, needed " + . (0 + @corder_weights) + . "\n"); + } else { + &exit(4, "Too many weights supplied on line $. of $opt{i}," + . " wanted " . (0 + @corder_weights) . " but had " + . (0 + @args) + . "\n"); + } + } + + push(@corder, [$cmd, @args]); + } + } +} + +sub parse_LC_MONETARY { + my($cmd, $arg) = @_; + + if ($cmd eq "copy") { + &do_copy(&parse_value($arg)); + } elsif($cmd eq "END") { + } elsif($cmd eq "mon_grouping") { + my @v = &parse_values($arg, ';', undef, 0); + $monetary{$cmd} = \@v; + } else { + my $v = &parse_value($arg); + $monetary{$cmd} = $v; + } +} + +sub parse_LC_MESSAGES { + my($cmd, $arg) = @_; + + if ($cmd eq "copy") { + &do_copy(&parse_value($arg)); + } elsif($cmd eq "END") { + } else { + my $v = &parse_value($arg); + $messages{$cmd} = $v; + } +} + +sub parse_LC_NUMERIC { + my($cmd, $arg) = @_; + + if ($cmd eq "copy") { + &do_copy(&parse_value($arg)); + } elsif($cmd eq "END") { + } elsif($cmd eq "grouping") { + my @v = &parse_values($arg, ';', undef, 0); + $numeric{$cmd} = \@v; + } else { + my $v = &parse_value($arg); + $numeric{$cmd} = $v; + } +} + +sub parse_LC_TIME { + my($cmd, $arg) = @_; + + $cmd =~ s/^ab_day$/abday/; + + if ($cmd eq "copy") { + &do_copy(&parse_value($arg)); + } elsif($cmd eq "END") { + } elsif($cmd =~ m/abday|day|mon|abmon|am_pm|alt_digits/) { + my @v = &parse_values($arg, ';', undef, 0); + $time{$cmd} = \@v; + } elsif($cmd eq "era") { + my @v = &parse_values($arg, ':', undef, 0); + $time{$cmd} = \@v; + } else { + my $v = &parse_value($arg); + $time{$cmd} = $v; + } +} + + +############################################################################### + +sub run_mklocale { + my $L = (new IO::File "|/usr/bin/mklocale -o $locale_dir/LC_CTYPE") || &exit(5, "$0: Can't start mklocale $!\n"); + if (defined($opt{'u'})) { + $L->print(qq{ENCODING "$opt{u}"\n}); + } else { + if ($ARGV[0] =~ m/(big5|euc|gb18030|gb2312|gbk|mskanji|utf-8)/i) { + my $enc = uc($1); + $L->print(qq{ENCODING "$enc"\n}); + } elsif($ARGV[0] =~ m/utf8/) { + $L->print(qq{ENCODING "UTF-8"\n}); + } else { + $L->print(qq{ENCODING "NONE"\n}); + } + } + foreach my $class (keys(%ctype_classes)) { + unless ($class =~ m/^(tolower|toupper|alpha|control|digit|grah|lower|space|upper|xdigit|blank|print|ideogram|special|phonogram)$/) { + $L->print("# skipping $class\n"); + next; + } + + if (!%{$ctype_classes{$class}}) { + $L->print("# Nothing in \U$class\n"); + next; + } + + if ($class =~ m/^to/) { + my $t = $class; + $t =~ s/^to/map/; + $L->print("\U$t "); + + foreach my $from (keys(%{$ctype_classes{$class}})) { + $L->print("[", &hexchars($from), " ", + &hexchars($ctype_classes{$class}->{$from}), "] "); + } + } else { + $L->print("\U$class "); + + foreach my $rune (keys(%{$ctype_classes{$class}})) { + $L->print(&hexchars($rune), " "); + } + } + $L->print("\n"); + } + + my @width; + foreach my $s (keys(%width)) { + my $w = $width{$s}; + $w = 3 if ($w > 3); + push(@{$width[$w]}, &hexchars($sym{$s})); + } + for(my $w = 0; $w <= $#width; ++$w) { + next if (!defined $width[$w]); + next if (0 == @{$width[$w]}); + $L->print("SWIDTH$w ", join(" ", @{$width[$w]}), "\n"); + } + + if (!$L->close()) { + if (0 == $!) { + &exit(5, "Bad return from mklocale $?"); + } else { + &exit(5, "Couldn't close mklocale pipe: $!"); + } + } +} + +############################################################################### + +sub hexchars { + my($str) = $_[0]; + my($ret); + + $ret = unpack "H*", $str; + &exit(2, "Rune >4 bytes ($ret; for $str)") if (length($ret) > 8); + + return "0x" . $ret; +} + +sub hexseq { + my($str) = $_[0]; + my($ret); + + $ret = unpack "H*", $str; + $ret =~ s/(..)/\\x$1/g; + + return $ret; +} + +# dot_expand in the target charset +sub dot_expand { + my($s, $e) = @_; + my(@ret); + + my @charset = sort { $a cmp $b } values(%sym); + foreach my $c (@charset) { + if (($c cmp $s) >= 0) { + last if (($c cmp $e) > 0); + push(@ret, $c); + } + } + + return @ret; +} + +# Convert symbols into literal values +sub unsym { + my @ret = &unsym_with_check(@_); + return $ret[0]; +} + +# Convert symbols into literal values (return[0]), and a count of how +# many symbols were converted (return[1]). +sub unsym_with_check { + my($str) = $_[0]; + + my $rx = join("|", keys(%sym)); + return ($str, 0) if ($rx eq ""); + my $found = $str =~ s/<($rx)>/$sym{$1}/eg; + + return ($str, $found); +} + +# Convert a string of literals back into symbols. It is an error +# for there to be literal values that can't be mapped back. The +# converter uses a gredy algo. It is likely this could be done +# more efficently with a regex ctrated at runtime. It would also be +# a good idea to only create %rsym if %sym changes, but that isn't +# the simplest thing to do in perl5. +sub resym { + my($str) = $_[0]; + my(%rsym, $k, $v); + my $max_len = 0; + my $ret = ""; + + while(($k, $v) = each(%sym)) { + # Collisions in $v are ok, we merely need a mapping, not the + # identical mapping + $rsym{$v} = $k; + $max_len = length($v) if (length($v) > $max_len); + } + + SYM: while("" ne $str) { + foreach my $l ($max_len .. 1) { + next if ($l > length($str)); + my $s = substr($str, 0, $l); + if (defined($rsym{$s})) { + $ret .= "<" . $rsym{$s} . ">"; + substr($str, 0, $l) = ""; + next SYM; + } + } + &exit(4, "Can't convert $str ($_[0]) back into symbolic form\n"); + } + + return $ret; +} + +sub set_escape { + $escape_char = $_[0]; + $val_match = qr/"(?:[^"\Q$escape_char\E]+|\Q$escape_char\E")+"|(?:\Q$escape_char\E(?:[0-7]+|d[0-9]+|x[0-9a-fA-F]+))|[^,;<>\s\Q$escape_char\E]|(?:\Q$escape_char\E)[,;<>\Q$escape_char\E]/; +} + +sub set_parser { + my $section = $_[0]; + ($current_LC, $parse_func, $validate_line, $call_parse_on_END) + = ($section, $LC_parsers{$section}->[0], $LC_parsers{$section}->[1], + $LC_parsers{$section}->[2]); + unless (defined $parse_func) { + &exit(4, "Unknown section name LC_$section on line $. of $opt{i}\n"); + } +} + +sub do_copy { + my($from) = @_; + local($ENV{LC_ALL}) = $from; + + my $C = (new IO::File "/usr/bin/locale -k LC_$current_LC |") || &exit(5, "can't fork locale during copy of LC_$current_LC"); + while(<$C>) { + if (s/=\s*$/ ""/ || s/=/ /) { + if (m/$validate_line/ && m/^\s*(\S*)(\s+(\S+.*?))?\s*$/) { + my($action, $args) = ($1, $3); + &{$parse_func}($action, $args); + } else { + &exit(4, "Syntax error on line $. of locale -k output" + . " during copy $current_LC\n"); + } + } else { + &exit(4, "Ill-formed line $. from locale -k during copy $current_LC\n"); + } + } + $C->close() || &exit(5, "copying LC_$current_LC from $from failed"); +} + +sub fixup_collate_order_args { + my $co = $_[0]; + + foreach my $s (@{$co}[1..$#{$co}]) { + if ("HASH" eq ref($s) && exists($s->{"..."})) { + $s = $co->[0]; + } + } +} + +sub add_to_ctype_class { + my($class, @runes) = @_; + + my $c = $ctype_classes{$class}; + foreach my $r (@runes) { + $c->{$r} = 2 unless exists $c->{$r}; + } +} + +sub deny_in_ctype_class { + my($class, $deny_reason, @runes) = @_; + + my $c = $ctype_classes{$class}; + foreach my $r (@runes) { + next unless exists $c->{$r}; + $deny_reason =~ s/^(\S+)$/can't belong in class $class and in class $1 at the same time/; + &exit(4, &hexchars($r) . " " . $deny_reason . "\n"); + } +} + +# write_lc_{money,time,messages} all use the existing Libc format, which +# is raw text with each record terminated by a newline, and records +# in a predetermined order. + +sub write_lc_money { + my $F = (new IO::File "$locale_dir/LC_MONETARY", O_TRUNC|O_WRONLY|O_CREAT, 0666) || &exit(4, "$0 can't create $locale_dir/LC_MONETARY: $!"); + foreach my $s (qw(int_curr_symbol currency_symbol mon_decimal_point mon_thousands_sep mon_grouping positive_sign negative_sign int_frac_digits frac_digits p_cs_precedes p_sep_by_space n_cs_precedes n_sep_by_space p_sign_posn n_sign_posn int_p_cs_precedes int_n_cs_precedes int_p_sep_by_space int_n_sep_by_space int_p_sign_posn int_n_sign_posn)) { + if (exists $monetary{$s}) { + my $v = $monetary{$s}; + if ("ARRAY" eq ref $v) { + $F->print(join(";", @$v), "\n"); + } else { + $F->print("$v\n"); + } + } else { + if ($s =~ m/^(int_curr_symbol|currency_symbol|mon_decimal_point|mon_thousands_sep|positive_sign|negative_sign)$/) { + $F->print("\n"); + } else { + $F->print("-1\n"); + } + } + } +} + +sub write_lc_time { + my $F = (new IO::File "$locale_dir/LC_TIME", O_TRUNC|O_WRONLY|O_CREAT, 0666) || &exit(4, "$0 can't create $locale_dir/LC_TIME: $!"); + my %array_cnt = (abmon => 12, mon => 12, abday => 7, day => 7, alt_month => 12, am_pm => 2); + + $time{"md_order"} = "md" unless defined $time{"md_order"}; + + foreach my $s (qw(abmon mon abday day t_fmt d_fmt d_t_fmt am_pm d_t_fmt mon md_order t_fmt_ampm)) { + my $cnt = $array_cnt{$s}; + my $v = $time{$s}; + + if (defined $v) { + if (defined $cnt) { + my @a = @{$v}; + &exit(4, "$0: $s has " . (0 + @a) + . " elements, it needs to have exactly $cnt\n") + unless (@a == $cnt); + $F->print(join("\n", @a), "\n"); + } else { + $F->print("$v\n"); + } + } else { + $cnt = 1 if !defined $cnt; + $F->print("\n" x $cnt); + } + } +} + +sub write_lc_messages { + mkdir("$locale_dir/LC_MESSAGES"); + my $F = (new IO::File "$locale_dir/LC_MESSAGES/LC_MESSAGES", O_TRUNC|O_WRONLY|O_CREAT, 0666) || &exit(4, "$0 can't create $locale_dir/LC_MESSAGES/LC_MESSAGES: $!"); + + foreach my $s (qw(yesexpr noexpr yesstr nostr)) { + my $v = $messages{$s}; + + if (defined $v) { + $F->print("$v\n"); + } else { + $F->print("\n"); + } + } +} + +sub write_lc_numeric { + my $F = (new IO::File "$locale_dir/LC_NUMERIC", O_TRUNC|O_WRONLY|O_CREAT, 0666) || &exit(4, "$0 can't create $locale_dir/LC_NUMERIC: $!"); + + foreach my $s (qw(decimal_point thousands_sep grouping)) { + if (exists $numeric{$s}) { + my $v = $numeric{$s}; + if ("ARRAY" eq ref $v) { + $F->print(join(";", @$v), "\n"); + } else { + $F->print("$v\n"); + } + } else { + $F->print("\n"); + } + } +} + +sub bylenval { + return 0 if ("ARRAY" ne ref $a || "ARRAY" ne ref $b); + + my($aval, $af) = &unsym_with_check($a->[0]); + $aval = $cele{$a->[0]} unless $af; + my($bval, $bf) = &unsym_with_check($b->[0]); + $bval = $cele{$b->[0]} unless $bf; + + my $r = length($aval) - length($bval); + return $r if $r; + return $aval cmp $bval; +} + +sub write_lc_collate { + return unless @colldef; + + # colldef doesn't parse the whole glory of SuSv3 charmaps, and we + # already have, so we cna spit out a simplifyed one; unfortunitly + # it doesn't like "/dev/fd/N" so we need a named tmp file + my($CMAP, $cmapname) = tempfile(DIR => "/tmp"); + foreach my $s (keys(%sym)) { + $CMAP->print("<$s>\t", sprintf "\\x%02x\n", ord($sym{$s})); + } + $CMAP->flush(); + unshift(@colldef, qq{charmap $cmapname}); + unshift(@colldef, "LC_COLLATE"); + $colldef[$#colldef] = "END LC_COLLATE"; + + # Can't just use /dev/stdin, colldef appears to use seek, + # and even seems to need a named temp file (re-open?) + my($COL, $colname) = tempfile(DIR => "/tmp"); + $COL->print(join("\n", @colldef), "\n"); + $COL->flush(); + + my $rc = system( + "/usr/bin/colldef -o $locale_dir/LC_COLLATE $colname"); + unlink $colname, $cmapname; + if ($rc) { + &exit(1, "Bad return from colldef $rc"); + } +} + +# Pack an int of unknown size into a series of bytes, each of which +# contains 7 bits of data, and the top bit is clear on the last +# byte of data. Also works on arrays -- does not encode the size of +# the array. This format is great for data that tends to have fewer +# then 21 bits. +sub pack_p_int { + if (@_ > 1) { + my $ret = ""; + foreach my $v (@_) { + $ret .= &pack_p_int($v); + } + + return $ret; + } + + my $v = $_[0]; + my $b; + + &exit(4, "pack_p_int only works on positive values") if ($v < 0); + if ($v < 128) { + $b = chr($v); + } else { + $b = chr(($v & 0x7f) | 0x80); + $b .= pack_p_int($v >> 7); + } + return $b; +} + +sub strip_angles { + my $s = $_[0]; + $s =~ s/^<(.*)>$/$1/; + return $s; +} + +# For localedef +# xc=0 "no warnings, locale defined" +# xc=1 "warnings, locale defined" +# xc=2 "implmentation limits or unsupported charactor sets, no locale defined" +# xc=3 "can't create new locales" +# xc=4+ "wornings or errors, no locale defined" +sub exit { + my($xc, $message) = @_; + + print STDERR $message; + exit $xc; +} diff --git a/adv_cmds/lsvfs/lsvfs.1 b/adv_cmds/lsvfs/lsvfs.1 new file mode 100644 index 0000000..411ea17 --- /dev/null +++ b/adv_cmds/lsvfs/lsvfs.1 @@ -0,0 +1,67 @@ +.\" Copyright (c) 1998-2003 Apple Computer, Inc. All rights reserved. +.\" +.\" @APPLE_LICENSE_HEADER_START@ +.\" +.\" The contents of this file constitute Original Code as defined in and +.\" are subject to the Apple Public Source License Version 1.1 (the +.\" "License"). You may not use this file except in compliance with the +.\" License. Please obtain a copy of the License at +.\" http://www.apple.com/publicsource and read it before using this file. +.\" +.\" This Original Code and all software distributed under the License are +.\" distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER +.\" EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +.\" INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +.\" FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the +.\" License for the specific language governing rights and limitations +.\" under the License. +.\" +.\" @APPLE_LICENSE_HEADER_END@ +.\" +.Dd January 4, 2003 +.Dt LSVFS 1 +.Os +.Sh NAME +.Nm lsvfs +.Nd list known virtual file systems +.Sh SYNOPSIS +.Nm +.Op Ar vfsname Ar ... +.Sh DESCRIPTION +The +.Nm +command lists information about the currently loaded virtual filesystem +modules. +When +.Ar vfsname +arguments are given, +.Nm +lists information about the specified VFS modules. +Otherwise, +.Nm +lists all currently loaded modules. +The information is as follows: +.Pp +.Bl -tag -compact -width Filesystem +.It Filesystem +the name of the filesystem, as would be used in the +.Ar type +parameter to +.Xr mount 2 +and the +.Fl t +option to +.Xr mount 8 +.It Refs +the number of references to this VFS; i.e., the number of currently +mounted filesystems of this type +.It Flags +flag bits +.El +.Sh SEE ALSO +.Xr mount 2 , +.Xr mount 8 +.Sh HISTORY +The command from which this tool was derived, as well as this manual, +originally appeared in +.Fx 2.0 . diff --git a/adv_cmds/lsvfs/lsvfs.c b/adv_cmds/lsvfs/lsvfs.c new file mode 100644 index 0000000..73f4135 --- /dev/null +++ b/adv_cmds/lsvfs/lsvfs.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) 1998-2003 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#include <sys/mount.h> +#include <sys/types.h> +#include <sys/sysctl.h> + +#include <err.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> + +#define FMT "%-32.32s %5d %s\n" +#define HDRFMT "%-32.32s %5.5s %s\n" +#define DASHES "-------------------------------- ----- ---------------\n" + +static const char *fmt_flags(int flags); + +int +main(int argc, char *argv[]) +{ + struct vfsconf vfc; + int mib[4], max, x; + size_t len; + + printf(HDRFMT, "Filesystem", "Refs", "Flags"); + fputs(DASHES, stdout); + + if (argc > 1) { + for (x = 1; x < argc; x++) + if (getvfsbyname(argv[x], &vfc) == 0) + printf(FMT, vfc.vfc_name, vfc.vfc_refcount, + fmt_flags(vfc.vfc_flags)); + else + warnx("VFS %s unknown or not loaded", argv[x]); + } else { + mib[0] = CTL_VFS; + mib[1] = VFS_GENERIC; + mib[2] = VFS_MAXTYPENUM; + len = sizeof(int); + if (sysctl(mib, 3, &max, &len, NULL, 0) != 0) + errx(1, "sysctl"); + mib[2] = VFS_CONF; + + len = sizeof(vfc); + for (x = 0; x < max; x++) { + mib[3] = x; + if (sysctl(mib, 4, &vfc, &len, NULL, 0) != 0) { + if (errno != ENOTSUP) + errx(1, "sysctl"); + } else { + printf(FMT, vfc.vfc_name, vfc.vfc_refcount, + fmt_flags(vfc.vfc_flags)); + } + } + } + + return 0; +} + +static const char * +fmt_flags(int flags) +{ + static char buf[sizeof "local, dovolfs"]; + int comma = 0; + + buf[0] = '\0'; + + if(flags & MNT_LOCAL) { + if(comma++) strcat(buf, ", "); + strcat(buf, "local"); + } + + if(flags & MNT_DOVOLFS) { + if(comma++) strcat(buf, ", "); + strcat(buf, "dovolfs"); + } + + return buf; +} diff --git a/adv_cmds/mklocale/extern.h b/adv_cmds/mklocale/extern.h new file mode 100644 index 0000000..f2037dd --- /dev/null +++ b/adv_cmds/mklocale/extern.h @@ -0,0 +1,40 @@ +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Paul Borman at Krystal Technologies. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/usr.bin/mklocale/extern.h,v 1.1 2002/04/28 12:34:54 markm Exp $ + */ + +int yylex(void); +int yyparse(void); diff --git a/adv_cmds/mklocale/ldef.h b/adv_cmds/mklocale/ldef.h new file mode 100644 index 0000000..da9e015 --- /dev/null +++ b/adv_cmds/mklocale/ldef.h @@ -0,0 +1,68 @@ +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Paul Borman at Krystal Technologies. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ldef.h 8.1 (Berkeley) 6/6/93 + * $FreeBSD: src/usr.bin/mklocale/ldef.h,v 1.5 2007/11/07 14:46:22 rafan Exp $ + */ + +#include <sys/types.h> +#ifdef __APPLE__ +#include <inttypes.h> +#include <limits.h> +#endif /* __APPLE__ */ +#include "runefile.h" + +/* + * This should look a LOT like a _RuneEntry + */ +typedef struct rune_list { + int32_t min; + int32_t max; + int32_t map; + uint32_t *types; + struct rune_list *next; +} rune_list; + +typedef struct rune_map { + uint32_t map[_CACHED_RUNES]; + rune_list *root; +} rune_map; + +#ifdef __APPLE__ +typedef struct { + char name[CHARCLASS_NAME_MAX]; + uint32_t mask; +} rune_charclass; +#endif /* __APPLE__ */ diff --git a/adv_cmds/mklocale/lex.l b/adv_cmds/mklocale/lex.l new file mode 100644 index 0000000..9ffbaca --- /dev/null +++ b/adv_cmds/mklocale/lex.l @@ -0,0 +1,179 @@ +%{ +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Paul Borman at Krystal Technologies. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)lex.l 8.1 (Berkeley) 6/6/93"; +#endif +#endif /* not lint */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD: src/usr.bin/mklocale/lex.l,v 1.9 2005/02/26 21:47:54 ru Exp $"); + +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> + +#include "ldef.h" +#include "y.tab.h" +#include "extern.h" +%} + +ODIGIT [0-7] +DIGIT [0-9] +XDIGIT [0-9a-fA-F] +W [\t\n\r ] + +%% +\'.\' { yylval.rune = (unsigned char)yytext[1]; + return(RUNE); } + +'\\a' { yylval.rune = '\a'; + return(RUNE); } +'\\b' { yylval.rune = '\b'; + return(RUNE); } +'\\f' { yylval.rune = '\f'; + return(RUNE); } +'\\n' { yylval.rune = '\n'; + return(RUNE); } +'\\r' { yylval.rune = '\r'; + return(RUNE); } +'\\t' { yylval.rune = '\t'; + return(RUNE); } +'\\v' { yylval.rune = '\v'; + return(RUNE); } + +0x{XDIGIT}+ { yylval.rune = strtol(yytext, 0, 16); + return(RUNE); } +0{ODIGIT}+ { yylval.rune = strtol(yytext, 0, 8); + return(RUNE); } +{DIGIT}+ { yylval.rune = strtol(yytext, 0, 10); + return(RUNE); } + + +MAPLOWER { return(MAPLOWER); } +MAPUPPER { return(MAPUPPER); } +TODIGIT { return(DIGITMAP); } +INVALID { return(INVALID); } + +ALPHA { yylval.i = _CTYPE_A|_CTYPE_R|_CTYPE_G; + return(LIST); } +CONTROL { yylval.i = _CTYPE_C; + return(LIST); } +DIGIT { yylval.i = _CTYPE_D|_CTYPE_R|_CTYPE_G; + return(LIST); } +GRAPH { yylval.i = _CTYPE_G|_CTYPE_R; + return(LIST); } +LOWER { yylval.i = _CTYPE_L|_CTYPE_R|_CTYPE_G; + return(LIST); } +PUNCT { yylval.i = _CTYPE_P|_CTYPE_R|_CTYPE_G; + return(LIST); } +SPACE { yylval.i = _CTYPE_S; + return(LIST); } +UPPER { yylval.i = _CTYPE_U|_CTYPE_R|_CTYPE_G; + return(LIST); } +XDIGIT { yylval.i = _CTYPE_X|_CTYPE_R|_CTYPE_G; + return(LIST); } +BLANK { yylval.i = _CTYPE_B; + return(LIST); } +PRINT { yylval.i = _CTYPE_R; + return(LIST); } +IDEOGRAM { yylval.i = _CTYPE_I|_CTYPE_R|_CTYPE_G; + return(LIST); } +SPECIAL { yylval.i = _CTYPE_T|_CTYPE_R|_CTYPE_G; + return(LIST); } +PHONOGRAM { yylval.i = _CTYPE_Q|_CTYPE_R|_CTYPE_G; + return(LIST); } +SWIDTH0 { yylval.i = _CTYPE_SW0; return(LIST); } +SWIDTH1 { yylval.i = _CTYPE_SW1; return(LIST); } +SWIDTH2 { yylval.i = _CTYPE_SW2; return(LIST); } +SWIDTH3 { yylval.i = _CTYPE_SW3; return(LIST); } + +VARIABLE[\t ] { static char vbuf[1024]; + char *v = vbuf; + while ((*v = input()) && *v != '\n') + ++v; + if (*v) { + unput(*v); + *v = 0; + } + yylval.str = vbuf; + return(VARIABLE); + } + +ENCODING { return(ENCODING); } + +CHARCLASS { return(CHARCLASS); } + +\".*\" { char *e = yytext + 1; + yylval.str = e; + while (*e && *e != '"') + ++e; + *e = 0; + return(STRING); } + +\<|\(|\[ { return(LBRK); } + +\>|\)|\] { return(RBRK); } + +\- { return(THRU); } +\.\.\. { return(THRU); } + +\: { return(':'); } + +{W}+ ; + +^\#.*\n ; +\/\* { char lc = 0; + do { + while ((lc) != '*') + if ((lc = input()) == 0) + break; + } while((lc = input()) != '/'); + } + +\\$ ; +. { printf("Lex is skipping '%s'\n", yytext); } +%% + +#if !defined(yywrap) +int +yywrap() +{ + return(1); +} +#endif diff --git a/adv_cmds/mklocale/mklocale.1 b/adv_cmds/mklocale/mklocale.1 new file mode 100644 index 0000000..8f2ec0e --- /dev/null +++ b/adv_cmds/mklocale/mklocale.1 @@ -0,0 +1,308 @@ +.\" Copyright (c) 1993, 1994 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" Paul Borman at Krystal Technologies. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)mklocale.1 8.2 (Berkeley) 4/18/94 +.\" $FreeBSD: src/usr.bin/mklocale/mklocale.1,v 1.28 2008/01/22 00:04:50 ache Exp $ +.\" +.Dd October 17, 2004 +.Dt MKLOCALE 1 +.Os +.Sh NAME +.Nm mklocale +.Nd make LC_CTYPE locale files +.Sh SYNOPSIS +.Nm +.Op Fl d +.Ar "< src-file" +.Ar "> language/LC_CTYPE" +.Nm +.Op Fl d +.Fl o +.Ar language/LC_CTYPE +.Ar src-file +.Sh DESCRIPTION +The +.Nm +utility reads a +.Dv LC_CTYPE +source file from standard input and produces a +.Dv LC_CTYPE +binary file on standard output suitable for placement in +.Pa /usr/share/locale/ Ns Ar language Ns Pa /LC_CTYPE . +.Pp +The format of +.Ar src-file +is quite simple. +It consists of a series of lines which start with a keyword and have +associated data following. +C style comments are used +to place comments in the file. +.Pp +Following options are available: +.Bl -tag -width indent +.It Fl d +Turns on debugging messages. +.It Fl o +Specify output file. +.El +.Pp +Besides the keywords which will be listed below, +the following are valid tokens in +.Ar src-file : +.Bl -tag -width ".Ar literal" +.It Dv RUNE +A +.Dv RUNE +may be any of the following: +.Bl -tag -width ".Ar 0x[0-9a-z]*" +.It Ar 'x' +The ASCII character +.Ar x . +.It Ar '\ex' +The ANSI C character +.Ar \ex +where +.Ar \ex +is one of +.Dv \ea , +.Dv \eb , +.Dv \ef , +.Dv \en , +.Dv \er , +.Dv \et , +or +.Dv \ev . +.It Ar 0x[0-9a-z]* +A hexadecimal number representing a rune code. +.It Ar 0[0-7]* +An octal number representing a rune code. +.It Ar [1-9][0-9]* +A decimal number representing a rune code. +.El +.It Dv STRING +A string enclosed in double quotes ("). +.It Dv THRU +Either +.Dv ... +or +.Dv - . +Used to indicate ranges. +.It Ar literal +The follow characters are taken literally: +.Bl -tag -width ".Dv <\|\|(\|\|[" +.It Dv "<\|(\|[" +Used to start a mapping. +All are equivalent. +.It Dv ">\|\^)\|]" +Used to end a mapping. +All are equivalent. +.It Dv : +Used as a delimiter in mappings. +.El +.El +.Pp +Key words which should only appear once are: +.Bl -tag -width ".Dv PHONOGRAM" +.It Dv ENCODING +Followed by a +.Dv STRING +which indicates the encoding mechanism to be used for this locale. +The current encodings are: +.Bl -tag -width ".Dv MSKanji" +.It Dv ASCII +American Standard Code for Information Interchange. +.It Dv BIG5 +The +.Dq Big5 +encoding of Chinese. +.It Dv EUC +.Dv EUC +encoding as used by several +vendors of +.Ux +systems. +.It Dv GB18030 +PRC national standard for encoding of Chinese text. +.It Dv GB2312 +Older PRC national standard for encoding Chinese text. +.It Dv GBK +A widely used encoding method for Chinese text, +backwards compatible with GB\ 2312-1980. +.It Dv MSKanji +The method of encoding Japanese used by Microsoft, +loosely based on JIS. +Also known as +.Dq "Shift JIS" +and +.Dq SJIS . +.It Dv NONE +No translation and the default. +.It Dv UTF-8 +The +.Dv UTF-8 +transformation format of +.Tn ISO +10646 +as defined by RFC 2279. +.El +.It Dv VARIABLE +This keyword must be followed by a single tab or space character, +after which encoding specific data is placed. +Currently only the +.Dv "EUC" +encoding requires variable data. +See +.Xr euc 5 +for further details. +.It Dv INVALID +(obsolete) +A single +.Dv RUNE +follows and is used as the invalid rune for this locale. +.El +.Pp +The following keywords may appear multiple times and have the following +format for data: +.Bl -tag -width ".Dv <RUNE1 THRU RUNEn : RUNE2>" -offset indent +.It Dv <RUNE1 RUNE2> +.Dv RUNE1 +is mapped to +.Dv RUNE2 . +.It Dv <RUNE1 THRU RUNEn : RUNE2> +Runes +.Dv RUNE1 +through +.Dv RUNEn +are mapped to +.Dv RUNE2 +through +.Dv RUNE2 ++ n-1. +.El +.Bl -tag -width ".Dv PHONOGRAM" +.It Dv MAPLOWER +Defines the tolower mappings. +.Dv RUNE2 +is the lower case representation of +.Dv RUNE1 . +.It Dv MAPUPPER +Defines the toupper mappings. +.Dv RUNE2 +is the upper case representation of +.Dv RUNE1 . +.It Dv TODIGIT +Defines a map from runes to their digit value. +.Dv RUNE2 +is the integer value represented by +.Dv RUNE1 . +For example, the ASCII character +.Ql 0 +would map to the decimal value 0. +Only values up to 255 +are allowed. +.El +.Pp +The following keywords may appear multiple times and have the following +format for data: +.Bl -tag -width ".Dv RUNE1 THRU RUNEn" -offset indent +.It Dv RUNE +This rune has the property defined by the keyword. +.It Dv "RUNE1 THRU RUNEn" +All the runes between and including +.Dv RUNE1 +and +.Dv RUNEn +have the property defined by the keyword. +.El +.Bl -tag -width ".Dv PHONOGRAM" +.It Dv ALPHA +Defines runes which are alphabetic, printable and graphic. +.It Dv CONTROL +Defines runes which are control characters. +.It Dv DIGIT +Defines runes which are decimal digits, printable and graphic. +.It Dv GRAPH +Defines runes which are graphic and printable. +.It Dv LOWER +Defines runes which are lower case, printable and graphic. +.It Dv PUNCT +Defines runes which are punctuation, printable and graphic. +.It Dv SPACE +Defines runes which are spaces. +.It Dv UPPER +Defines runes which are upper case, printable and graphic. +.It Dv XDIGIT +Defines runes which are hexadecimal digits, printable and graphic. +.It Dv BLANK +Defines runes which are blank. +.It Dv PRINT +Defines runes which are printable. +.It Dv IDEOGRAM +Defines runes which are ideograms, printable and graphic. +.It Dv SPECIAL +Defines runes which are special characters, printable and graphic. +.It Dv PHONOGRAM +Defines runes which are phonograms, printable and graphic. +.It Dv SWIDTH0 +Defines runes with display width 0. +.It Dv SWIDTH1 +Defines runes with display width 1. +.It Dv SWIDTH2 +Defines runes with display width 2. +.It Dv SWIDTH3 +Defines runes with display width 3. +.El +.Pp +If no display width explicitly defined, width 1 assumed +for printable runes by default. +.Sh SEE ALSO +.Xr colldef 1 , +.Xr setlocale 3 , +.Xr wcwidth 3 , +.Xr big5 5 , +.Xr euc 5 , +.Xr gb18030 5 , +.Xr gb2312 5 , +.Xr gbk 5 , +.Xr mskanji 5 , +.Xr utf8 5 +.Sh HISTORY +The +.Nm +utility first appeared in +.Bx 4.4 . +.Sh BUGS +The +.Nm +utility is overly simplistic. diff --git a/adv_cmds/mklocale/runefile.h b/adv_cmds/mklocale/runefile.h new file mode 100644 index 0000000..6b3f9f7 --- /dev/null +++ b/adv_cmds/mklocale/runefile.h @@ -0,0 +1,87 @@ +/*- + * Copyright (c) 2005 Ruslan Ermilov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libc/locale/runefile.h,v 1.1 2005/05/16 09:32:41 ru Exp $ + */ + +#ifndef _RUNEFILE_H_ +#define _RUNEFILE_H_ + +#include <sys/types.h> + +#ifndef _CACHED_RUNES +#define _CACHED_RUNES (1 << 8) +#endif + +typedef struct { + int32_t min; + int32_t max; + int32_t map; +#ifdef __APPLE__ + int32_t __types_fake; +#endif /* __APPLE__ */ +} _FileRuneEntry; + +typedef struct { + char magic[8]; + char encoding[32]; + +#ifdef __APPLE__ + int32_t __sgetrune_fake; + int32_t __sputrune_fake; + int32_t __invalid_rune; +#endif /* __APPLE__ */ + + uint32_t runetype[_CACHED_RUNES]; + int32_t maplower[_CACHED_RUNES]; + int32_t mapupper[_CACHED_RUNES]; + + int32_t runetype_ext_nranges; +#ifdef __APPLE__ + int32_t __runetype_ext_ranges_fake; +#endif /* __APPLE__ */ + int32_t maplower_ext_nranges; +#ifdef __APPLE__ + int32_t __maplower_ext_ranges_fake; +#endif /* __APPLE__ */ + int32_t mapupper_ext_nranges; +#ifdef __APPLE__ + int32_t __mapupper_ext_ranges_fake; +#endif /* __APPLE__ */ + +#ifdef __APPLE__ + int32_t __variable_fake; +#endif /* __APPLE__ */ + int32_t variable_len; + +#ifdef __APPLE__ + int32_t ncharclasses; + int32_t __charclasses_fake; +#endif /* __APPLE__ */ +} _FileRuneLocale; + +#define _FILE_RUNE_MAGIC_1 "RuneMag1" + +#endif /* !_RUNEFILE_H_ */ diff --git a/adv_cmds/mklocale/yacc.y b/adv_cmds/mklocale/yacc.y new file mode 100644 index 0000000..f76498d --- /dev/null +++ b/adv_cmds/mklocale/yacc.y @@ -0,0 +1,929 @@ +%{ +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Paul Borman at Krystal Technologies. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)yacc.y 8.1 (Berkeley) 6/6/93"; +#endif /* 0 */ +#endif /* not lint */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD: src/usr.bin/mklocale/yacc.y,v 1.28 2008/01/22 00:04:50 ache Exp $"); + +#include <arpa/inet.h> + +#include <ctype.h> +#include <err.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "ldef.h" +#include "extern.h" +#include "runefile.h" + +#define MAX_CHARCLASS 4 +#define CHARCLASSBIT 4 + +static void *xmalloc(unsigned int sz); +static uint32_t *xlalloc(unsigned int sz); +void yyerror(const char *s); +static uint32_t *xrelalloc(uint32_t *old, unsigned int sz); +static void dump_tables(void); +static void cleanout(void); + +const char *locale_file = "<stdout>"; + +rune_map maplower = { { 0 }, NULL }; +rune_map mapupper = { { 0 }, NULL }; +rune_map types = { { 0 }, NULL }; + +_FileRuneLocale new_locale = { "", "", 0, 0, 0, {}, {}, {}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +char *variable = NULL; + +rune_charclass charclasses[MAX_CHARCLASS]; +int charclass_index = 0; + +void set_map(rune_map *, rune_list *, uint32_t); +void set_digitmap(rune_map *, rune_list *); +void add_map(rune_map *, rune_list *, uint32_t); +static void usage(void); +%} + +%union { + int32_t rune; + int i; + char *str; + + rune_list *list; +} + +%token <rune> RUNE +%token LBRK +%token RBRK +%token THRU +%token MAPLOWER +%token MAPUPPER +%token DIGITMAP +%token CHARCLASS +%token <i> LIST +%token <str> VARIABLE +%token ENCODING +%token INVALID +%token <str> STRING + +%type <list> list +%type <list> map + + +%% + +locale : /* empty */ + | table + { dump_tables(); } + ; + +table : entry + | table entry + ; + +entry : ENCODING STRING + { if (strcmp($2, "NONE") && + strcmp($2, "ASCII") && + strcmp($2, "UTF-8") && + strcmp($2, "EUC") && + strcmp($2, "GBK") && + strcmp($2, "GB18030") && + strcmp($2, "GB2312") && + strcmp($2, "BIG5") && + strcmp($2, "MSKanji") && + strcmp($2, "UTF2")) + warnx("ENCODING %s is not supported by libc", $2); + strncpy(new_locale.encoding, $2, + sizeof(new_locale.encoding)); } + | VARIABLE + { new_locale.variable_len = strlen($1) + 1; + variable = xmalloc(new_locale.variable_len); + strcpy(variable, $1); + } + | INVALID RUNE + { warnx("the INVALID keyword is deprecated"); } + | LIST list + { set_map(&types, $2, $1); } + | MAPLOWER map + { set_map(&maplower, $2, 0); } + | MAPUPPER map + { set_map(&mapupper, $2, 0); } + | DIGITMAP map + { + if (($2->map >= 0) && ($2->map <= 255)) { /* Data corruption otherwise */ + set_digitmap(&types, $2); + } + } + | CHARCLASS STRING list + { + int i; + if (strlen($2) > CHARCLASS_NAME_MAX) + errx(1, "Exceeded maximum charclass name size (%d) \"%s\"", CHARCLASS_NAME_MAX, $2); + for(i = 0; i < charclass_index; i++) + if (strncmp(charclasses[i].name, $2, CHARCLASS_NAME_MAX) == 0) + break; + if (i >= charclass_index) { + if (charclass_index >= MAX_CHARCLASS) + errx(1, "Exceeded maximum number of charclasses (%d)", MAX_CHARCLASS); + strncpy(charclasses[charclass_index].name, $2, CHARCLASS_NAME_MAX); + charclasses[charclass_index].mask = (1 << (charclass_index + CHARCLASSBIT)); + charclass_index++; + } + set_map(&types, $3, charclasses[i].mask); + } + ; + +list : RUNE + { + $$ = (rune_list *)xmalloc(sizeof(rune_list)); + $$->min = $1; + $$->max = $1; + $$->next = 0; + } + | RUNE THRU RUNE + { + $$ = (rune_list *)xmalloc(sizeof(rune_list)); + $$->min = $1; + $$->max = $3; + $$->next = 0; + } + | list RUNE + { + $$ = (rune_list *)xmalloc(sizeof(rune_list)); + $$->min = $2; + $$->max = $2; + $$->next = $1; + } + | list RUNE THRU RUNE + { + $$ = (rune_list *)xmalloc(sizeof(rune_list)); + $$->min = $2; + $$->max = $4; + $$->next = $1; + } + ; + +map : LBRK RUNE RUNE RBRK + { + $$ = (rune_list *)xmalloc(sizeof(rune_list)); + $$->min = $2; + $$->max = $2; + $$->map = $3; + $$->next = 0; + } + | map LBRK RUNE RUNE RBRK + { + $$ = (rune_list *)xmalloc(sizeof(rune_list)); + $$->min = $3; + $$->max = $3; + $$->map = $4; + $$->next = $1; + } + | LBRK RUNE THRU RUNE ':' RUNE RBRK + { + $$ = (rune_list *)xmalloc(sizeof(rune_list)); + $$->min = $2; + $$->max = $4; + $$->map = $6; + $$->next = 0; + } + | map LBRK RUNE THRU RUNE ':' RUNE RBRK + { + $$ = (rune_list *)xmalloc(sizeof(rune_list)); + $$->min = $3; + $$->max = $5; + $$->map = $7; + $$->next = $1; + } + ; +%% + +int debug; +FILE *fp; + +static void +cleanout(void) +{ + if (fp != NULL) + unlink(locale_file); +} + +int +main(int ac, char *av[]) +{ + int x; + + fp = stdout; + + while ((x = getopt(ac, av, "do:")) != -1) { + switch(x) { + case 'd': + debug = 1; + break; + case 'o': + locale_file = optarg; + if ((fp = fopen(locale_file, "w")) == NULL) + err(1, "%s: fopen", locale_file); + atexit(cleanout); + break; + default: + usage(); + } + } + + switch (ac - optind) { + case 0: + break; + case 1: + if (freopen(av[optind], "r", stdin) == 0) + err(1, "%s: freopen", av[optind]); + break; + default: + usage(); + } + for (x = 0; x < _CACHED_RUNES; ++x) { + mapupper.map[x] = x; + maplower.map[x] = x; + } + memcpy(new_locale.magic, _RUNE_MAGIC_A, sizeof(new_locale.magic)); + + yyparse(); + + return(0); +} + +static void +usage() +{ + fprintf(stderr, "usage: mklocale [-d] [-o output] [source]\n"); + exit(1); +} + +void +yyerror(s) + const char *s; +{ + fprintf(stderr, "%s\n", s); +} + +static void * +xmalloc(sz) + unsigned int sz; +{ + void *r = malloc(sz); + if (!r) + errx(1, "xmalloc"); + return(r); +} + +static uint32_t * +xlalloc(sz) + unsigned int sz; +{ + uint32_t *r = (uint32_t *)malloc(sz * sizeof(uint32_t)); + if (!r) + errx(1, "xlalloc"); + return(r); +} + +static uint32_t * +xrelalloc(old, sz) + uint32_t *old; + unsigned int sz; +{ + uint32_t *r = (uint32_t *)realloc((char *)old, + sz * sizeof(uint32_t)); + if (!r) + errx(1, "xrelalloc"); + return(r); +} + +void +set_map(map, list, flag) + rune_map *map; + rune_list *list; + uint32_t flag; +{ + while (list) { + rune_list *nlist = list->next; + add_map(map, list, flag); + list = nlist; + } +} + +void +set_digitmap(map, list) + rune_map *map; + rune_list *list; +{ + int32_t i; + + while (list) { + rune_list *nlist = list->next; + for (i = list->min; i <= list->max; ++i) { + if (list->map + (i - list->min)) { + rune_list *tmp = (rune_list *)xmalloc(sizeof(rune_list)); + tmp->min = i; + tmp->max = i; + add_map(map, tmp, list->map + (i - list->min)); + } + } + free(list); + list = nlist; + } +} + +void +add_map(map, list, flag) + rune_map *map; + rune_list *list; + uint32_t flag; +{ + int32_t i; + rune_list *lr = 0; + rune_list *r; + int32_t run; + + while (list->min < _CACHED_RUNES && list->min <= list->max) { + if (flag) + map->map[list->min++] |= flag; + else + map->map[list->min++] = list->map++; + } + + if (list->min > list->max) { + free(list); + return; + } + + run = list->max - list->min + 1; + + if (!(r = map->root) || (list->max < r->min - 1) + || (!flag && list->max == r->min - 1)) { + if (flag) { + list->types = xlalloc(run); + for (i = 0; i < run; ++i) + list->types[i] = flag; + } + list->next = map->root; + map->root = list; + return; + } + + for (r = map->root; r && r->max + 1 < list->min; r = r->next) + lr = r; + + if (!r) { + /* + * We are off the end. + */ + if (flag) { + list->types = xlalloc(run); + for (i = 0; i < run; ++i) + list->types[i] = flag; + } + list->next = 0; + lr->next = list; + return; + } + + if (list->max < r->min - 1) { + /* + * We come before this range and we do not intersect it. + * We are not before the root node, it was checked before the loop + */ + if (flag) { + list->types = xlalloc(run); + for (i = 0; i < run; ++i) + list->types[i] = flag; + } + list->next = lr->next; + lr->next = list; + return; + } + + /* + * At this point we have found that we at least intersect with + * the range pointed to by `r', we might intersect with one or + * more ranges beyond `r' as well. + */ + + if (!flag && list->map - list->min != r->map - r->min) { + /* + * There are only two cases when we are doing case maps and + * our maps needn't have the same offset. When we are adjoining + * but not intersecting. + */ + if (list->max + 1 == r->min) { + lr->next = list; + list->next = r; + return; + } + if (list->min - 1 == r->max) { + list->next = r->next; + r->next = list; + return; + } + errx(1, "error: conflicting map entries"); + } + + if (list->min >= r->min && list->max <= r->max) { + /* + * Subset case. + */ + + if (flag) { + for (i = list->min; i <= list->max; ++i) + r->types[i - r->min] |= flag; + } + free(list); + return; + } + if (list->min <= r->min && list->max >= r->max) { + /* + * Superset case. Make him big enough to hold us. + * We might need to merge with the guy after him. + */ + if (flag) { + list->types = xlalloc(list->max - list->min + 1); + + for (i = list->min; i <= list->max; ++i) + list->types[i - list->min] = flag; + + for (i = r->min; i <= r->max; ++i) + list->types[i - list->min] |= r->types[i - r->min]; + + free(r->types); + r->types = list->types; + } else { + r->map = list->map; + } + r->min = list->min; + r->max = list->max; + free(list); + } else if (list->min < r->min) { + /* + * Our tail intersects his head. + */ + if (flag) { + list->types = xlalloc(r->max - list->min + 1); + + for (i = r->min; i <= r->max; ++i) + list->types[i - list->min] = r->types[i - r->min]; + + for (i = list->min; i < r->min; ++i) + list->types[i - list->min] = flag; + + for (i = r->min; i <= list->max; ++i) + list->types[i - list->min] |= flag; + + free(r->types); + r->types = list->types; + } else { + r->map = list->map; + } + r->min = list->min; + free(list); + return; + } else { + /* + * Our head intersects his tail. + * We might need to merge with the guy after him. + */ + if (flag) { + r->types = xrelalloc(r->types, list->max - r->min + 1); + + for (i = list->min; i <= r->max; ++i) + r->types[i - r->min] |= flag; + + for (i = r->max+1; i <= list->max; ++i) + r->types[i - r->min] = flag; + } + r->max = list->max; + free(list); + } + + /* + * Okay, check to see if we grew into the next guy(s) + */ + while ((lr = r->next) && r->max >= lr->min) { + if (flag) { + if (r->max >= lr->max) { + /* + * Good, we consumed all of him. + */ + for (i = lr->min; i <= lr->max; ++i) + r->types[i - r->min] |= lr->types[i - lr->min]; + } else { + /* + * "append" him on to the end of us. + */ + r->types = xrelalloc(r->types, lr->max - r->min + 1); + + for (i = lr->min; i <= r->max; ++i) + r->types[i - r->min] |= lr->types[i - lr->min]; + + for (i = r->max+1; i <= lr->max; ++i) + r->types[i - r->min] = lr->types[i - lr->min]; + + r->max = lr->max; + } + } else { + if (lr->max > r->max) + r->max = lr->max; + } + + r->next = lr->next; + + if (flag) + free(lr->types); + free(lr); + } +} + +static void +dump_tables() +{ + int x, first_d, curr_d; + rune_list *list; + + /* + * See if we can compress some of the istype arrays + */ + for(list = types.root; list; list = list->next) { + list->map = list->types[0]; + for (x = 1; x < list->max - list->min + 1; ++x) { + if ((int32_t)list->types[x] != list->map) { + list->map = 0; + break; + } + } + } + + first_d = curr_d = -1; + for (x = 0; x < _CACHED_RUNES; ++x) { + uint32_t r = types.map[x]; + + if (r & _CTYPE_D) { + if (first_d < 0) + first_d = curr_d = x; + else if (x != curr_d + 1) + errx(1, "error: DIGIT range is not contiguous"); + else if (x - first_d > 9) + errx(1, "error: DIGIT range is too big"); + else + curr_d++; + if (!(r & _CTYPE_X)) + errx(1, + "error: DIGIT range is not a subset of XDIGIT range"); + } + } + if (first_d < 0) + errx(1, "error: no DIGIT range defined in the single byte area"); + else if (curr_d - first_d < 9) + errx(1, "error: DIGIT range is too small in the single byte area"); + + new_locale.ncharclasses = htonl(charclass_index); + + /* + * Fill in our tables. Do this in network order so that + * diverse machines have a chance of sharing data. + * (Machines like Crays cannot share with little machines due to + * word size. Sigh. We tried.) + */ + for (x = 0; x < _CACHED_RUNES; ++x) { + new_locale.runetype[x] = htonl(types.map[x]); + new_locale.maplower[x] = htonl(maplower.map[x]); + new_locale.mapupper[x] = htonl(mapupper.map[x]); + } + + /* + * Count up how many ranges we will need for each of the extents. + */ + list = types.root; + + while (list) { + new_locale.runetype_ext_nranges++; + list = list->next; + } + new_locale.runetype_ext_nranges = + htonl(new_locale.runetype_ext_nranges); + + list = maplower.root; + + while (list) { + new_locale.maplower_ext_nranges++; + list = list->next; + } + new_locale.maplower_ext_nranges = + htonl(new_locale.maplower_ext_nranges); + + list = mapupper.root; + + while (list) { + new_locale.mapupper_ext_nranges++; + list = list->next; + } + new_locale.mapupper_ext_nranges = + htonl(new_locale.mapupper_ext_nranges); + + new_locale.variable_len = htonl(new_locale.variable_len); + + /* + * Okay, we are now ready to write the new locale file. + */ + + /* + * PART 1: The _FileRuneLocale structure + */ + if (fwrite((char *)&new_locale, sizeof(new_locale), 1, fp) != 1) { + err(1, "%s: _FileRuneLocale structure", locale_file); + } + /* + * PART 2: The runetype_ext structures (not the actual tables) + */ + list = types.root; + + while (list) { + _FileRuneEntry re; + + re.min = htonl(list->min); + re.max = htonl(list->max); + re.map = htonl(list->map); +#ifdef __APPLE__ + re.__types_fake = 0; +#endif + + if (fwrite((char *)&re, sizeof(re), 1, fp) != 1) { + err(1, "%s: runetype_ext structures", locale_file); + } + + list = list->next; + } + /* + * PART 3: The maplower_ext structures + */ + list = maplower.root; + + while (list) { + _FileRuneEntry re; + + re.min = htonl(list->min); + re.max = htonl(list->max); + re.map = htonl(list->map); +#ifdef __APPLE__ + re.__types_fake = 0; +#endif + + if (fwrite((char *)&re, sizeof(re), 1, fp) != 1) { + err(1, "%s: maplower_ext structures", locale_file); + } + + list = list->next; + } + /* + * PART 4: The mapupper_ext structures + */ + list = mapupper.root; + + while (list) { + _FileRuneEntry re; + + re.min = htonl(list->min); + re.max = htonl(list->max); + re.map = htonl(list->map); +#ifdef __APPLE__ + re.__types_fake = 0; +#endif + + if (fwrite((char *)&re, sizeof(re), 1, fp) != 1) { + err(1, "%s: mapupper_ext structures", locale_file); + } + + list = list->next; + } + /* + * PART 5: The runetype_ext tables + */ + list = types.root; + + while (list) { + for (x = 0; x < list->max - list->min + 1; ++x) + list->types[x] = htonl(list->types[x]); + + if (!list->map) { + if (fwrite((char *)list->types, + (list->max - list->min + 1) * sizeof(uint32_t), + 1, fp) != 1) { + err(1, "%s: runetype_ext tables", locale_file); + } + } + list = list->next; + } + /* + * PART 6: The charclass names table + */ + for (x = 0; x < charclass_index; ++x) { + charclasses[x].mask = ntohl(charclasses[x].mask); + if (fwrite((char *)&charclasses[x], sizeof(rune_charclass), 1, fp) != 1) { + err(1, "%s: charclass names tables", locale_file); + } + } + /* + * PART 7: And finally the variable data + * SUSv3 says fwrite returns zero when either size or nitems is zero. + */ + if (ntohl(new_locale.variable_len) > 0 && fwrite(variable, + ntohl(new_locale.variable_len), 1, fp) != 1) { + err(1, "%s: variable data", locale_file); + } + if (fclose(fp) != 0) { + err(1, "%s: fclose", locale_file); + } + fp = NULL; + + if (!debug) + return; + + if (new_locale.encoding[0]) + fprintf(stderr, "ENCODING %s\n", new_locale.encoding); + if (variable) + fprintf(stderr, "VARIABLE %s\n", variable); + + fprintf(stderr, "\nMAPLOWER:\n\n"); + + for (x = 0; x < _CACHED_RUNES; ++x) { + if (isprint(maplower.map[x])) + fprintf(stderr, " '%c'", (int)maplower.map[x]); + else if (maplower.map[x]) + fprintf(stderr, "%04x", maplower.map[x]); + else + fprintf(stderr, "%4x", 0); + if ((x & 0xf) == 0xf) + fprintf(stderr, "\n"); + else + fprintf(stderr, " "); + } + fprintf(stderr, "\n"); + + for (list = maplower.root; list; list = list->next) + fprintf(stderr, "\t%04x - %04x : %04x\n", list->min, list->max, list->map); + + fprintf(stderr, "\nMAPUPPER:\n\n"); + + for (x = 0; x < _CACHED_RUNES; ++x) { + if (isprint(mapupper.map[x])) + fprintf(stderr, " '%c'", (int)mapupper.map[x]); + else if (mapupper.map[x]) + fprintf(stderr, "%04x", mapupper.map[x]); + else + fprintf(stderr, "%4x", 0); + if ((x & 0xf) == 0xf) + fprintf(stderr, "\n"); + else + fprintf(stderr, " "); + } + fprintf(stderr, "\n"); + + for (list = mapupper.root; list; list = list->next) + fprintf(stderr, "\t%04x - %04x : %04x\n", list->min, list->max, list->map); + + + fprintf(stderr, "\nTYPES:\n\n"); + + for (x = 0; x < _CACHED_RUNES; ++x) { + uint32_t r = types.map[x]; + + if (r) { + if (isprint(x)) + fprintf(stderr, " '%c': %2d", x, (int)(r & 0xff)); + else + fprintf(stderr, "%04x: %2d", x, (int)(r & 0xff)); + + fprintf(stderr, " %4s", (r & _CTYPE_A) ? "alph" : ""); + fprintf(stderr, " %4s", (r & _CTYPE_C) ? "ctrl" : ""); + fprintf(stderr, " %4s", (r & _CTYPE_D) ? "dig" : ""); + fprintf(stderr, " %4s", (r & _CTYPE_G) ? "graf" : ""); + fprintf(stderr, " %4s", (r & _CTYPE_L) ? "low" : ""); + fprintf(stderr, " %4s", (r & _CTYPE_P) ? "punc" : ""); + fprintf(stderr, " %4s", (r & _CTYPE_S) ? "spac" : ""); + fprintf(stderr, " %4s", (r & _CTYPE_U) ? "upp" : ""); + fprintf(stderr, " %4s", (r & _CTYPE_X) ? "xdig" : ""); + fprintf(stderr, " %4s", (r & _CTYPE_B) ? "blnk" : ""); + fprintf(stderr, " %4s", (r & _CTYPE_R) ? "prnt" : ""); + fprintf(stderr, " %4s", (r & _CTYPE_I) ? "ideo" : ""); + fprintf(stderr, " %4s", (r & _CTYPE_T) ? "spec" : ""); + fprintf(stderr, " %4s", (r & _CTYPE_Q) ? "phon" : ""); + fprintf(stderr, "\n"); + } + } + + for (list = types.root; list; list = list->next) { + if (list->map && list->min + 3 < list->max) { + uint32_t r = list->map; + + fprintf(stderr, "%04x: %2d", + (uint32_t)list->min, (int)(r & 0xff)); + + fprintf(stderr, " %4s", (r & _CTYPE_A) ? "alph" : ""); + fprintf(stderr, " %4s", (r & _CTYPE_C) ? "ctrl" : ""); + fprintf(stderr, " %4s", (r & _CTYPE_D) ? "dig" : ""); + fprintf(stderr, " %4s", (r & _CTYPE_G) ? "graf" : ""); + fprintf(stderr, " %4s", (r & _CTYPE_L) ? "low" : ""); + fprintf(stderr, " %4s", (r & _CTYPE_P) ? "punc" : ""); + fprintf(stderr, " %4s", (r & _CTYPE_S) ? "spac" : ""); + fprintf(stderr, " %4s", (r & _CTYPE_U) ? "upp" : ""); + fprintf(stderr, " %4s", (r & _CTYPE_X) ? "xdig" : ""); + fprintf(stderr, " %4s", (r & _CTYPE_B) ? "blnk" : ""); + fprintf(stderr, " %4s", (r & _CTYPE_R) ? "prnt" : ""); + fprintf(stderr, " %4s", (r & _CTYPE_I) ? "ideo" : ""); + fprintf(stderr, " %4s", (r & _CTYPE_T) ? "spec" : ""); + fprintf(stderr, " %4s", (r & _CTYPE_Q) ? "phon" : ""); + fprintf(stderr, "\n...\n"); + + fprintf(stderr, "%04x: %2d", + (uint32_t)list->max, (int)(r & 0xff)); + + fprintf(stderr, " %4s", (r & _CTYPE_A) ? "alph" : ""); + fprintf(stderr, " %4s", (r & _CTYPE_C) ? "ctrl" : ""); + fprintf(stderr, " %4s", (r & _CTYPE_D) ? "dig" : ""); + fprintf(stderr, " %4s", (r & _CTYPE_G) ? "graf" : ""); + fprintf(stderr, " %4s", (r & _CTYPE_L) ? "low" : ""); + fprintf(stderr, " %4s", (r & _CTYPE_P) ? "punc" : ""); + fprintf(stderr, " %4s", (r & _CTYPE_S) ? "spac" : ""); + fprintf(stderr, " %4s", (r & _CTYPE_U) ? "upp" : ""); + fprintf(stderr, " %4s", (r & _CTYPE_X) ? "xdig" : ""); + fprintf(stderr, " %4s", (r & _CTYPE_B) ? "blnk" : ""); + fprintf(stderr, " %4s", (r & _CTYPE_R) ? "prnt" : ""); + fprintf(stderr, " %4s", (r & _CTYPE_I) ? "ideo" : ""); + fprintf(stderr, " %4s", (r & _CTYPE_T) ? "spec" : ""); + fprintf(stderr, " %4s", (r & _CTYPE_Q) ? "phon" : ""); + fprintf(stderr, "\n"); + } else + for (x = list->min; x <= list->max; ++x) { + uint32_t r = ntohl(list->types[x - list->min]); + + if (r) { + fprintf(stderr, "%04x: %2d", x, (int)(r & 0xff)); + + fprintf(stderr, " %4s", (r & _CTYPE_A) ? "alph" : ""); + fprintf(stderr, " %4s", (r & _CTYPE_C) ? "ctrl" : ""); + fprintf(stderr, " %4s", (r & _CTYPE_D) ? "dig" : ""); + fprintf(stderr, " %4s", (r & _CTYPE_G) ? "graf" : ""); + fprintf(stderr, " %4s", (r & _CTYPE_L) ? "low" : ""); + fprintf(stderr, " %4s", (r & _CTYPE_P) ? "punc" : ""); + fprintf(stderr, " %4s", (r & _CTYPE_S) ? "spac" : ""); + fprintf(stderr, " %4s", (r & _CTYPE_U) ? "upp" : ""); + fprintf(stderr, " %4s", (r & _CTYPE_X) ? "xdig" : ""); + fprintf(stderr, " %4s", (r & _CTYPE_B) ? "blnk" : ""); + fprintf(stderr, " %4s", (r & _CTYPE_R) ? "prnt" : ""); + fprintf(stderr, " %4s", (r & _CTYPE_I) ? "ideo" : ""); + fprintf(stderr, " %4s", (r & _CTYPE_T) ? "spec" : ""); + fprintf(stderr, " %4s", (r & _CTYPE_Q) ? "phon" : ""); + fprintf(stderr, "\n"); + } + } + } +} diff --git a/adv_cmds/pkill/entitlements.plist b/adv_cmds/pkill/entitlements.plist new file mode 100644 index 0000000..b0a6726 --- /dev/null +++ b/adv_cmds/pkill/entitlements.plist @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>com.apple.sysmond.client</key> + <true/> +</dict> +</plist> diff --git a/adv_cmds/pkill/pkill.1 b/adv_cmds/pkill/pkill.1 new file mode 100644 index 0000000..672b185 --- /dev/null +++ b/adv_cmds/pkill/pkill.1 @@ -0,0 +1,232 @@ +.\" $NetBSD: pkill.1,v 1.8 2003/02/14 15:59:18 grant Exp $ +.\" +.\" $FreeBSD: src/bin/pkill/pkill.1,v 1.8 2010/07/12 01:58:46 brian Exp $ +.\" +.\" Copyright (c) 2002 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to The NetBSD Foundation +.\" by Andrew Doran. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +.\" POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd February 11, 2010 +.Dt PKILL 1 +.Os +.Sh NAME +.Nm pgrep , pkill +.Nd find or signal processes by name +.Sh SYNOPSIS +.Nm pgrep +.Op Fl Lafilnoqvx +.Op Fl F Ar pidfile +.Op Fl G Ar gid +.Op Fl P Ar ppid +.Op Fl U Ar uid +.Op Fl d Ar delim +.Op Fl g Ar pgrp +.Op Fl t Ar tty +.Op Fl u Ar euid +.Ar pattern ... +.Nm pkill +.Op Fl Ar signal +.Op Fl ILafilnovx +.Op Fl F Ar pidfile +.Op Fl G Ar gid +.Op Fl P Ar ppid +.Op Fl U Ar uid +.Op Fl g Ar pgrp +.Op Fl t Ar tty +.Op Fl u Ar euid +.Ar pattern ... +.Sh DESCRIPTION +The +.Nm pgrep +command searches the process table on the running system and prints the +process IDs of all processes that match the criteria given on the command +line. +.Pp +The +.Nm pkill +command searches the process table on the running system and signals all +processes that match the criteria given on the command line. +.Pp +The following options are available: +.Bl -tag -width ".Fl F Ar pidfile" +.It Fl F Ar pidfile +Restrict matches to a process whose PID is stored in the +.Ar pidfile +file. +.It Fl G Ar gid +Restrict matches to processes with a real group ID in the comma-separated +list +.Ar gid . +.It Fl I +Request confirmation before attempting to signal each process. +.It Fl L +The +.Ar pidfile +file given for the +.Fl F +option must be locked with the +.Xr flock 2 +syscall or created with +.Xr pidfile 3 . +.It Fl P Ar ppid +Restrict matches to processes with a parent process ID in the +comma-separated list +.Ar ppid . +.It Fl U Ar uid +Restrict matches to processes with a real user ID in the comma-separated +list +.Ar uid . +.It Fl d Ar delim +Specify a delimiter to be printed between each process ID. +The default is a newline. +This option can only be used with the +.Nm pgrep +command. +.It Fl a +Include process ancestors in the match list. +By default, the current +.Nm pgrep +or +.Nm pkill +process and all of its ancestors are excluded (unless +.Fl v +is used). +.It Fl f +Match against full argument lists. +The default is to match against process names. +.It Fl g Ar pgrp +Restrict matches to processes with a process group ID in the comma-separated +list +.Ar pgrp . +The value zero is taken to mean the process group ID of the running +.Nm pgrep +or +.Nm pkill +command. +.It Fl i +Ignore case distinctions in both the process table and the supplied pattern. +.It Fl l +Long output. +For +.Nm pgrep , +print the process name in addition to the process ID for each matching +process. +If used in conjunction with +.Fl f , +print the process ID and the full argument list for each matching process. +For +.Nm pkill , +display the kill command used for each process killed. +.It Fl n +Select only the newest (most recently started) of the matching processes. +.It Fl o +Select only the oldest (least recently started) of the matching processes. +.It Fl q +Do not write anything to standard output. +.It Fl t Ar tty +Restrict matches to processes associated with a terminal in the +comma-separated list +.Ar tty . +Terminal names may be of the form +.Pa tty Ns Ar xx +or the shortened form +.Ar xx . +A single dash +.Pq Ql - +matches processes not associated with a terminal. +.It Fl u Ar euid +Restrict matches to processes with an effective user ID in the +comma-separated list +.Ar euid . +.It Fl v +Reverse the sense of the matching; display processes that do not match the +given criteria. +.It Fl x +Require an exact match of the process name, or argument list if +.Fl f +is given. +The default is to match any substring. +.It Fl Ns Ar signal +A non-negative decimal number or symbolic signal name specifying the signal +to be sent instead of the default +.Dv TERM . +This option is valid only when given as the first argument to +.Nm pkill . +.El +.Pp +If any +.Ar pattern +operands are specified, they are used as regular expressions to match +the command name or full argument list of each process. +.Pp +Note that a running +.Nm pgrep +or +.Nm pkill +process will never consider itself as +a potential match. +.Sh EXIT STATUS +The +.Nm pgrep +and +.Nm pkill +utilities +return one of the following values upon exit: +.Bl -tag -width indent +.It 0 +One or more processes were matched. +.It 1 +No processes were matched. +.It 2 +Invalid options were specified on the command line. +.It 3 +An internal error occurred. +.El +.Sh SEE ALSO +.Xr kill 1 , +.Xr killall 1 , +.Xr ps 1 , +.Xr flock 2 , +.Xr kill 2 , +.Xr sigaction 2 , +.Xr pidfile 3 , +.Xr re_format 7 +.\" Xr signal 7 +.Sh HISTORY +The +.Nm pkill +and +.Nm pgrep +utilities +first appeared in +.Nx 1.6 . +They are modelled after utilities of the same name that appeared in Sun +Solaris 7. +They made their first appearance in +.Fx 5.3 . +.Sh AUTHORS +.An Andrew Doran +.Aq ad@NetBSD.org diff --git a/adv_cmds/pkill/pkill.c b/adv_cmds/pkill/pkill.c new file mode 100644 index 0000000..668d656 --- /dev/null +++ b/adv_cmds/pkill/pkill.c @@ -0,0 +1,1111 @@ +/* $NetBSD: pkill.c,v 1.16 2005/10/10 22:13:20 kleink Exp $ */ + +/*- + * Copyright (c) 2002 The NetBSD Foundation, Inc. + * Copyright (c) 2005 Pawel Jakub Dawidek <pjd@FreeBSD.org> + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Andrew Doran. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD: src/bin/pkill/pkill.c,v 1.12 2011/02/04 16:40:50 jilles Exp $"); + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/sysctl.h> +#include <sys/proc.h> +#include <sys/queue.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/user.h> + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <limits.h> +#include <paths.h> +#include <string.h> +#include <unistd.h> +#include <signal.h> +#include <regex.h> +#include <ctype.h> +#include <fcntl.h> +#ifndef __APPLE__ +#include <kvm.h> +#endif +#include <err.h> +#include <pwd.h> +#include <grp.h> +#include <errno.h> +#include <locale.h> + +#ifdef __APPLE__ +#include <xpc/xpc.h> +#include <sys/proc_info.h> +#include <os/assumes.h> +#include <sysmon.h> +#endif + +#define STATUS_MATCH 0 +#define STATUS_NOMATCH 1 +#define STATUS_BADUSAGE 2 +#define STATUS_ERROR 3 + +#define MIN_PID 5 +#define MAX_PID 99999 + +#ifdef __APPLE__ +/* Ignore system processes and myself. */ +#define PSKIP(kp) ((pid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PID)) == mypid || \ + ((xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_FLAGS)) & PROC_FLAG_SYSTEM) != 0)) +#else +/* Ignore system-processes (if '-S' flag is not specified) and myself. */ +#define PSKIP(kp) ((kp)->ki_pid == mypid || \ + (!kthreads && ((kp)->ki_flag & P_KTHREAD) != 0)) +#endif + +enum listtype { + LT_GENERIC, + LT_USER, + LT_GROUP, + LT_TTY, + LT_PGRP, +#ifndef __APPLE__ + LT_JID, +#endif + LT_SID +}; + +struct list { + SLIST_ENTRY(list) li_chain; + long li_number; +}; + +SLIST_HEAD(listhead, list); + +#ifdef __APPLE__ +static sysmon_table_t plist; +#else +static struct kinfo_proc *plist; +#endif +static char *selected; +static const char *delim = "\n"; +static int nproc; +static int pgrep; +static int signum = SIGTERM; +static int newest; +static int oldest; +static int interactive; +static int inverse; +static int longfmt; +static int matchargs; +static int fullmatch; +#ifndef __APPLE__ +static int kthreads; +#endif +static int cflags = REG_EXTENDED; +static int quiet; +#ifndef __APPLE__ +static kvm_t *kd; +#endif +static pid_t mypid; + +static struct listhead euidlist = SLIST_HEAD_INITIALIZER(euidlist); +static struct listhead ruidlist = SLIST_HEAD_INITIALIZER(ruidlist); +static struct listhead rgidlist = SLIST_HEAD_INITIALIZER(rgidlist); +static struct listhead pgrplist = SLIST_HEAD_INITIALIZER(pgrplist); +static struct listhead ppidlist = SLIST_HEAD_INITIALIZER(ppidlist); +static struct listhead tdevlist = SLIST_HEAD_INITIALIZER(tdevlist); +#ifndef __APPLE__ +static struct listhead sidlist = SLIST_HEAD_INITIALIZER(sidlist); +static struct listhead jidlist = SLIST_HEAD_INITIALIZER(jidlist); +#endif + +static void usage(void) __attribute__((__noreturn__)); +#ifdef __APPLE__ +static int killact(const sysmon_row_t); +static int grepact(const sysmon_row_t); +#else +static int killact(const struct kinfo_proc *); +static int grepact(const struct kinfo_proc *); +#endif +static void makelist(struct listhead *, enum listtype, char *); +static int takepid(const char *, int); + +#ifdef __APPLE__ +static sysmon_table_t +copy_process_info(void) +{ + dispatch_semaphore_t sema; + sysmon_request_t request; + __block sysmon_table_t result = NULL; + + sema = dispatch_semaphore_create(0); + request = sysmon_request_create_with_error(SYSMON_REQUEST_TYPE_PROCESS, ^(sysmon_table_t table, const char *error_str) { + if (table) { + result = sysmon_retain(table); + } else { + fprintf(stderr, "sysmon request failed with error: %s\n", error_str); + } + dispatch_semaphore_signal(sema); + }); + sysmon_request_add_attribute(request, SYSMON_ATTR_PROC_PID); + sysmon_request_add_attribute(request, SYSMON_ATTR_PROC_FLAGS); + sysmon_request_add_attribute(request, SYSMON_ATTR_PROC_UID); + sysmon_request_add_attribute(request, SYSMON_ATTR_PROC_COMM); + sysmon_request_add_attribute(request, SYSMON_ATTR_PROC_ARGUMENTS); + sysmon_request_add_attribute(request, SYSMON_ATTR_PROC_RUID); + sysmon_request_add_attribute(request, SYSMON_ATTR_PROC_RGID); + sysmon_request_add_attribute(request, SYSMON_ATTR_PROC_PPID); + sysmon_request_add_attribute(request, SYSMON_ATTR_PROC_PGID); + sysmon_request_add_attribute(request, SYSMON_ATTR_PROC_TDEV); + sysmon_request_add_attribute(request, SYSMON_ATTR_PROC_START); + sysmon_request_execute(request); + dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); + dispatch_release(sema); + sysmon_release(request); + + return result; +} +#endif /* __APPLE__ */ + +int +main(int argc, char **argv) +{ +#ifdef __APPLE__ + char buf[_POSIX2_LINE_MAX], *bufp, *mstr, *p, *q, *pidfile; + xpc_object_t pargv; +#else + char buf[_POSIX2_LINE_MAX], *mstr, **pargv, *p, *q, *pidfile; + const char *execf, *coref; +#endif + int ancestors, debug_opt, did_action; + int i, ch, bestidx, rv, criteria, pidfromfile, pidfilelock; +#ifdef __APPLE__ + __block size_t jsz; + int (*action)(const sysmon_row_t); + sysmon_row_t kp; +#else + size_t jsz; + int (*action)(const struct kinfo_proc *); + struct kinfo_proc *kp; +#endif + struct list *li; +#ifdef __APPLE__ + int64_t best_tval; +#else + struct timeval best_tval; +#endif + regex_t reg; + regmatch_t regmatch; + pid_t pid; + + setlocale(LC_ALL, ""); + + if (strcmp(getprogname(), "pgrep") == 0) { + action = grepact; + pgrep = 1; + } else { + action = killact; + p = argv[1]; + + if (argc > 1 && p[0] == '-') { + p++; + i = (int)strtol(p, &q, 10); + if (*q == '\0') { + signum = i; + argv++; + argc--; + } else { + if (strncasecmp(p, "SIG", 3) == 0) + p += 3; + for (i = 1; i < NSIG; i++) + if (strcasecmp(sys_signame[i], p) == 0) + break; + if (i != NSIG) { + signum = i; + argv++; + argc--; + } + } + } + } + + ancestors = 0; + criteria = 0; + debug_opt = 0; + pidfile = NULL; + pidfilelock = 0; + quiet = 0; +#ifndef __APPLE__ + execf = NULL; + coref = _PATH_DEVNULL; +#endif + +#ifdef __APPLE__ + while ((ch = getopt(argc, argv, "DF:G:ILP:U:ad:fg:ilnoqt:u:vx")) != -1) +#else + while ((ch = getopt(argc, argv, "DF:G:ILM:N:P:SU:ad:fg:ij:lnoqs:t:u:vx")) != -1) +#endif + switch (ch) { + case 'D': + debug_opt++; + break; + case 'F': + pidfile = optarg; + criteria = 1; + break; + case 'G': + makelist(&rgidlist, LT_GROUP, optarg); + criteria = 1; + break; + case 'I': + if (pgrep) + usage(); + interactive = 1; + break; + case 'L': + pidfilelock = 1; + break; +#ifndef __APPLE__ + case 'M': + coref = optarg; + break; + case 'N': + execf = optarg; + break; +#endif + case 'P': + makelist(&ppidlist, LT_GENERIC, optarg); + criteria = 1; + break; +#ifndef __APPLE__ + case 'S': + if (!pgrep) + usage(); + kthreads = 1; + break; +#endif + case 'U': + makelist(&ruidlist, LT_USER, optarg); + criteria = 1; + break; + case 'a': + ancestors++; + break; + case 'd': + if (!pgrep) + usage(); + delim = optarg; + break; + case 'f': + matchargs = 1; + break; + case 'g': + makelist(&pgrplist, LT_PGRP, optarg); + criteria = 1; + break; + case 'i': + cflags |= REG_ICASE; + break; +#ifndef __APPLE__ + case 'j': + makelist(&jidlist, LT_JID, optarg); + criteria = 1; + break; +#endif + case 'l': + longfmt = 1; + break; + case 'n': + newest = 1; + criteria = 1; + break; + case 'o': + oldest = 1; + criteria = 1; + break; + case 'q': + if (!pgrep) + usage(); + quiet = 1; + break; +#ifndef __APPLE__ + case 's': + makelist(&sidlist, LT_SID, optarg); + criteria = 1; + break; +#endif /* !__APPLE__ */ + case 't': + makelist(&tdevlist, LT_TTY, optarg); + criteria = 1; + break; + case 'u': + makelist(&euidlist, LT_USER, optarg); + criteria = 1; + break; + case 'v': + inverse = 1; + break; + case 'x': + fullmatch = 1; + break; + default: + usage(); + /* NOTREACHED */ + } + + argc -= optind; + argv += optind; + if (argc != 0) + criteria = 1; + if (!criteria) + usage(); + if (newest && oldest) + errx(STATUS_ERROR, "Options -n and -o are mutually exclusive"); + if (pidfile != NULL) + pidfromfile = takepid(pidfile, pidfilelock); + else { + if (pidfilelock) { + errx(STATUS_ERROR, + "Option -L doesn't make sense without -F"); + } + pidfromfile = -1; + } + + mypid = getpid(); + +#ifdef __APPLE__ + plist = copy_process_info(); + if (plist == NULL) { + errx(STATUS_ERROR, "Cannot get process list"); + } + nproc = sysmon_table_get_count(plist); +#else + /* + * Retrieve the list of running processes from the kernel. + */ + kd = kvm_openfiles(execf, coref, NULL, O_RDONLY, buf); + if (kd == NULL) + errx(STATUS_ERROR, "Cannot open kernel files (%s)", buf); + + /* + * Use KERN_PROC_PROC instead of KERN_PROC_ALL, since we + * just want processes and not individual kernel threads. + */ + plist = kvm_getprocs(kd, KERN_PROC_PROC, 0, &nproc); + if (plist == NULL) { + errx(STATUS_ERROR, "Cannot get process list (%s)", + kvm_geterr(kd)); + } +#endif + + /* + * Allocate memory which will be used to keep track of the + * selection. + */ + if ((selected = malloc(nproc)) == NULL) { + err(STATUS_ERROR, "Cannot allocate memory for %d processes", + nproc); + } + memset(selected, 0, nproc); + + /* + * Refine the selection. + */ + for (; *argv != NULL; argv++) { + if ((rv = regcomp(®, *argv, cflags)) != 0) { + regerror(rv, ®, buf, sizeof(buf)); + errx(STATUS_BADUSAGE, + "Cannot compile regular expression `%s' (%s)", + *argv, buf); + } + +#ifdef __APPLE__ + for (i = 0; i < nproc; i++) { + kp = sysmon_table_get_row(plist, i); +#else + for (i = 0, kp = plist; i < nproc; i++, kp++) { +#endif + if (PSKIP(kp)) { + if (debug_opt > 0) + fprintf(stderr, "* Skipped %5d %3d %s\n", +#ifdef __APPLE__ + (pid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PID)), + (uid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_UID)), + xpc_string_get_string_ptr(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_COMM))); +#else + kp->ki_pid, kp->ki_uid, kp->ki_comm); +#endif + continue; + } + +#ifdef __APPLE__ + if (matchargs && + (pargv = sysmon_row_get_value(kp, SYSMON_ATTR_PROC_ARGUMENTS)) != NULL) { + jsz = 0; + os_assert(sizeof(buf) == _POSIX2_LINE_MAX); + bufp = buf; + xpc_array_apply(pargv, ^(size_t index, xpc_object_t value) { + if (jsz >= _POSIX2_LINE_MAX) { + return (bool)false; + } + jsz += snprintf(bufp + jsz, + _POSIX2_LINE_MAX - jsz, + index < xpc_array_get_count(pargv) - 1 ? "%s " : "%s", + xpc_string_get_string_ptr(value)); + return (bool)true; + }); +#else + if (matchargs && + (pargv = kvm_getargv(kd, kp, 0)) != NULL) { + jsz = 0; + while (jsz < sizeof(buf) && *pargv != NULL) { + jsz += snprintf(buf + jsz, + sizeof(buf) - jsz, + pargv[1] != NULL ? "%s " : "%s", + pargv[0]); + pargv++; + } +#endif + mstr = buf; + } else +#ifdef __APPLE__ + { + /* + * comm is limited to 15 bytes (MAXCOMLEN - 1). + * Try to use argv[0] (trimmed) if available. + */ + mstr = NULL; + pargv = sysmon_row_get_value(kp, SYSMON_ATTR_PROC_ARGUMENTS); + if (pargv != NULL && xpc_array_get_count(pargv) > 0) { + const char *tmp = xpc_array_get_string(pargv, 0); + if (tmp != NULL) { + mstr = strrchr(tmp, '/'); + if (mstr != NULL) { + mstr++; + } else { + mstr = (char *)tmp; + } + } + } + + /* Fall back to "comm" if we failed to get argv[0]. */ + if (mstr == NULL || *mstr == '\0') { + mstr = (char *)xpc_string_get_string_ptr(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_COMM)); + } + + /* Couldn't find process name, it probably exited. */ + if (mstr == NULL) { + continue; + } + } +#else + mstr = kp->ki_comm; +#endif + + rv = regexec(®, mstr, 1, ®match, 0); + if (rv == 0) { + if (fullmatch) { + if (regmatch.rm_so == 0 && + regmatch.rm_eo == + (off_t)strlen(mstr)) + selected[i] = 1; + } else + selected[i] = 1; + } else if (rv != REG_NOMATCH) { + regerror(rv, ®, buf, sizeof(buf)); + errx(STATUS_ERROR, + "Regular expression evaluation error (%s)", + buf); + } + if (debug_opt > 1) { + const char *rv_res = "NoMatch"; + if (selected[i]) + rv_res = "Matched"; + fprintf(stderr, "* %s %5d %3d %s\n", rv_res, +#ifdef __APPLE__ + (pid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PID)), + (uid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_UID)), + mstr); +#else + kp->ki_pid, kp->ki_uid, mstr); +#endif + } + } + + regfree(®); + } + +#ifdef __APPLE__ + for (i = 0; i < nproc; i++) { + kp = sysmon_table_get_row(plist, i); +#else + for (i = 0, kp = plist; i < nproc; i++, kp++) { +#endif + if (PSKIP(kp)) + continue; + +#ifdef __APPLE__ + if (pidfromfile >= 0 && (pid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PID)) != pidfromfile) { +#else + if (pidfromfile >= 0 && kp->ki_pid != pidfromfile) { +#endif + selected[i] = 0; + continue; + } + + SLIST_FOREACH(li, &ruidlist, li_chain) +#ifdef __APPLE__ + if ((uid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_RUID)) == (uid_t)li->li_number) +#else + if (kp->ki_ruid == (uid_t)li->li_number) +#endif + break; + if (SLIST_FIRST(&ruidlist) != NULL && li == NULL) { + selected[i] = 0; + continue; + } + + SLIST_FOREACH(li, &rgidlist, li_chain) +#ifdef __APPLE__ + if ((gid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_RGID)) == (gid_t)li->li_number) +#else + if (kp->ki_rgid == (gid_t)li->li_number) +#endif + break; + if (SLIST_FIRST(&rgidlist) != NULL && li == NULL) { + selected[i] = 0; + continue; + } + + SLIST_FOREACH(li, &euidlist, li_chain) +#ifdef __APPLE__ + if ((uid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_UID)) == (uid_t)li->li_number) +#else + if (kp->ki_uid == (uid_t)li->li_number) +#endif + break; + if (SLIST_FIRST(&euidlist) != NULL && li == NULL) { + selected[i] = 0; + continue; + } + + SLIST_FOREACH(li, &ppidlist, li_chain) +#ifdef __APPLE__ + if ((pid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PPID)) == (pid_t)li->li_number) +#else + if (kp->ki_ppid == (pid_t)li->li_number) +#endif + break; + if (SLIST_FIRST(&ppidlist) != NULL && li == NULL) { + selected[i] = 0; + continue; + } + + SLIST_FOREACH(li, &pgrplist, li_chain) +#ifdef __APPLE__ + if ((pid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PGID)) == (pid_t)li->li_number) +#else + if (kp->ki_pgid == (pid_t)li->li_number) +#endif + break; + if (SLIST_FIRST(&pgrplist) != NULL && li == NULL) { + selected[i] = 0; + continue; + } + + SLIST_FOREACH(li, &tdevlist, li_chain) { + if (li->li_number == -1 && +#ifdef __APPLE__ + (xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_FLAGS)) & PROC_FLAG_CONTROLT) == 0) +#else + (kp->ki_flag & P_CONTROLT) == 0) +#endif + break; +#ifdef __APPLE__ + if ((dev_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_TDEV)) == (dev_t)li->li_number) +#else + if (kp->ki_tdev == (dev_t)li->li_number) +#endif + break; + } + if (SLIST_FIRST(&tdevlist) != NULL && li == NULL) { + selected[i] = 0; + continue; + } + +#ifndef __APPLE__ + SLIST_FOREACH(li, &sidlist, li_chain) + if (kp->ki_sid == (pid_t)li->li_number) + break; + if (SLIST_FIRST(&sidlist) != NULL && li == NULL) { + selected[i] = 0; + continue; + } + + SLIST_FOREACH(li, &jidlist, li_chain) { + /* A particular jail ID, including 0 (not in jail) */ + if (kp->ki_jid == (int)li->li_number) + break; + /* Any jail */ + if (kp->ki_jid > 0 && li->li_number == -1) + break; + } + if (SLIST_FIRST(&jidlist) != NULL && li == NULL) { + selected[i] = 0; + continue; + } +#endif /* !__APPLE__ */ + + if (argc == 0) + selected[i] = 1; + } + + if (!ancestors) { + pid = mypid; + while (pid) { +#ifdef __APPLE__ + for (i = 0; i < nproc; i++) { + kp = sysmon_table_get_row(plist, i); +#else + for (i = 0, kp = plist; i < nproc; i++, kp++) { +#endif + if (PSKIP(kp)) + continue; +#ifdef __APPLE__ + if ((pid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PID)) == pid) { + selected[i] = 0; + pid = (pid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PPID)); + break; + } +#else + if (kp->ki_pid == pid) { + selected[i] = 0; + pid = kp->ki_ppid; + break; + } +#endif + } + if (i == nproc) { + if (pid == mypid) + pid = getppid(); + else + break; /* Maybe we're in a jail ? */ + } + } + } + + if (newest || oldest) { +#ifdef __APPLE__ + best_tval = 0; +#else + best_tval.tv_sec = 0; + best_tval.tv_usec = 0; +#endif + bestidx = -1; + +#ifdef __APPLE__ + for (i = 0; i < nproc; i++) { + kp = sysmon_table_get_row(plist, i); +#else + for (i = 0, kp = plist; i < nproc; i++, kp++) { +#endif + if (!selected[i]) + continue; + if (bestidx == -1) { + /* The first entry of the list which matched. */ + ; +#ifdef __APPLE__ + } else if (xpc_date_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_START)) > best_tval) { +#else + } else if (timercmp(&kp->ki_start, &best_tval, >)) { +#endif + /* This entry is newer than previous "best". */ + if (oldest) /* but we want the oldest */ + continue; + } else { + /* This entry is older than previous "best". */ + if (newest) /* but we want the newest */ + continue; + } + /* This entry is better than previous "best" entry. */ +#ifdef __APPLE__ + best_tval = xpc_date_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_START)); +#else + best_tval.tv_sec = kp->ki_start.tv_sec; + best_tval.tv_usec = kp->ki_start.tv_usec; +#endif + bestidx = i; + } + + memset(selected, 0, nproc); + if (bestidx != -1) + selected[bestidx] = 1; + } + + /* + * Take the appropriate action for each matched process, if any. + */ + did_action = 0; +#ifdef __APPLE__ + for (i = 0, rv = 0; i < nproc; i++) { + kp = sysmon_table_get_row(plist, i); +#else + for (i = 0, rv = 0, kp = plist; i < nproc; i++, kp++) { +#endif + if (PSKIP(kp)) + continue; + if (selected[i]) { + if (longfmt && !pgrep) { + did_action = 1; +#ifdef __APPLE__ + printf("kill -%d %d\n", signum, (int)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PID))); +#else + printf("kill -%d %d\n", signum, kp->ki_pid); +#endif + } + if (inverse) + continue; + } else if (!inverse) + continue; + rv |= (*action)(kp); + } + if (!did_action && !pgrep && longfmt) + fprintf(stderr, + "No matching processes belonging to you were found\n"); + + exit(rv ? STATUS_MATCH : STATUS_NOMATCH); +} + +static void +usage(void) +{ + const char *ustr; + + if (pgrep) +#ifdef __APPLE__ + ustr = "[-Lfilnoqvx] [-d delim]"; +#else + ustr = "[-LSfilnoqvx] [-d delim]"; +#endif + else + ustr = "[-signal] [-ILfilnovx]"; + + fprintf(stderr, +#ifdef __APPLE__ + "usage: %s %s [-F pidfile] [-G gid]\n" + " [-P ppid] [-U uid] [-g pgrp]\n" +#else + "usage: %s %s [-F pidfile] [-G gid] [-M core] [-N system]\n" + " [-P ppid] [-U uid] [-g pgrp] [-j jid] [-s sid]\n" +#endif + " [-t tty] [-u euid] pattern ...\n", getprogname(), + ustr); + + exit(STATUS_BADUSAGE); +} + +static void +#ifdef __APPLE__ +show_process(const sysmon_row_t kp) +#else +show_process(const struct kinfo_proc *kp) +#endif +{ +#ifdef __APPLE__ + xpc_object_t argv; +#else + char **argv; +#endif + + if (quiet) { + assert(pgrep); + return; + } +#ifdef __APPLE__ + if ((longfmt || !pgrep) && matchargs && + (argv = sysmon_row_get_value(kp, SYSMON_ATTR_PROC_ARGUMENTS)) != NULL) { + printf("%d ", (int)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PID))); + (void)xpc_array_apply(argv, ^(size_t index, xpc_object_t value) { + printf("%s", xpc_string_get_string_ptr(value)); + if (index < xpc_array_get_count(argv) - 1) + putchar(' '); + return (bool)true; + }); + } else if (longfmt || !pgrep) + printf("%d %s", + (int)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PID)), + xpc_string_get_string_ptr(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_COMM))); + else + printf("%d", (int)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PID))); +#else + if ((longfmt || !pgrep) && matchargs && + (argv = kvm_getargv(kd, kp, 0)) != NULL) { + printf("%d ", (int)kp->ki_pid); + for (; *argv != NULL; argv++) { + printf("%s", *argv); + if (argv[1] != NULL) + putchar(' '); + } + } else if (longfmt || !pgrep) + printf("%d %s", (int)kp->ki_pid, kp->ki_comm); + else + printf("%d", (int)kp->ki_pid); +#endif +} + +static int +#ifdef __APPLE__ +killact(const sysmon_row_t kp) +#else +killact(const struct kinfo_proc *kp) +#endif +{ + int ch, first; + + if (interactive) { + /* + * Be careful, ask before killing. + */ + printf("kill "); + show_process(kp); + printf("? "); + fflush(stdout); + first = ch = getchar(); + while (ch != '\n' && ch != EOF) + ch = getchar(); + if (first != 'y' && first != 'Y') + return (1); + } +#ifdef __APPLE__ + if (kill((pid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PID)), signum) == -1) { +#else + if (kill(kp->ki_pid, signum) == -1) { +#endif + /* + * Check for ESRCH, which indicates that the process + * disappeared between us matching it and us + * signalling it; don't issue a warning about it. + */ + if (errno != ESRCH) +#ifdef __APPLE__ + warn("signalling pid %d", (int)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PID))); +#else + warn("signalling pid %d", (int)kp->ki_pid); +#endif + /* + * Return 0 to indicate that the process should not be + * considered a match, since we didn't actually get to + * signal it. + */ + return (0); + } + return (1); +} + +static int +#ifdef __APPLE__ +grepact(const sysmon_row_t kp) +#else +grepact(const struct kinfo_proc *kp) +#endif +{ + + show_process(kp); + if (!quiet) + printf("%s", delim); + return (1); +} + +static void +makelist(struct listhead *head, enum listtype type, char *src) +{ + struct list *li; + struct passwd *pw; + struct group *gr; + struct stat st; + const char *cp; + char *sp, *ep, buf[MAXPATHLEN]; + int empty; + + empty = 1; + + while ((sp = strsep(&src, ",")) != NULL) { + if (*sp == '\0') + usage(); + + if ((li = malloc(sizeof(*li))) == NULL) { + err(STATUS_ERROR, "Cannot allocate %zu bytes", + sizeof(*li)); + } + + SLIST_INSERT_HEAD(head, li, li_chain); + empty = 0; + + li->li_number = (uid_t)strtol(sp, &ep, 0); + if (*ep == '\0') { + switch (type) { + case LT_PGRP: + if (li->li_number == 0) + li->li_number = getpgrp(); + break; +#ifndef __APPLE__ + case LT_SID: + if (li->li_number == 0) + li->li_number = getsid(mypid); + break; + case LT_JID: + if (li->li_number < 0) + errx(STATUS_BADUSAGE, + "Negative jail ID `%s'", sp); + /* For compatibility with old -j */ + if (li->li_number == 0) + li->li_number = -1; /* any jail */ + break; +#endif /* !__APPLE__ */ + case LT_TTY: + if (li->li_number < 0) + errx(STATUS_BADUSAGE, + "Negative /dev/pts tty `%s'", sp); + snprintf(buf, sizeof(buf), _PATH_DEV "pts/%s", + sp); + if (stat(buf, &st) != -1) + goto foundtty; + if (errno == ENOENT) + errx(STATUS_BADUSAGE, "No such tty: `" + _PATH_DEV "pts/%s'", sp); + err(STATUS_ERROR, "Cannot access `" + _PATH_DEV "pts/%s'", sp); + break; + default: + break; + } + continue; + } + + switch (type) { + case LT_USER: + if ((pw = getpwnam(sp)) == NULL) + errx(STATUS_BADUSAGE, "Unknown user `%s'", sp); + li->li_number = pw->pw_uid; + break; + case LT_GROUP: + if ((gr = getgrnam(sp)) == NULL) + errx(STATUS_BADUSAGE, "Unknown group `%s'", sp); + li->li_number = gr->gr_gid; + break; + case LT_TTY: + if (strcmp(sp, "-") == 0) { + li->li_number = -1; + break; + } else if (strcmp(sp, "co") == 0) { + cp = "console"; + } else { + cp = sp; + } + + snprintf(buf, sizeof(buf), _PATH_DEV "%s", cp); + if (stat(buf, &st) != -1) + goto foundtty; + + snprintf(buf, sizeof(buf), _PATH_DEV "tty%s", cp); + if (stat(buf, &st) != -1) + goto foundtty; + + if (errno == ENOENT) + errx(STATUS_BADUSAGE, "No such tty: `%s'", sp); + err(STATUS_ERROR, "Cannot access `%s'", sp); + +foundtty: if ((st.st_mode & S_IFCHR) == 0) + errx(STATUS_BADUSAGE, "Not a tty: `%s'", sp); + + li->li_number = st.st_rdev; + break; +#ifndef __APPLE__ + case LT_JID: + if (strcmp(sp, "none") == 0) + li->li_number = 0; + else if (strcmp(sp, "any") == 0) + li->li_number = -1; + else if (*ep != '\0') + errx(STATUS_BADUSAGE, + "Invalid jail ID `%s'", sp); + break; +#endif /* !__APPLE__ */ + default: + usage(); + } + } + + if (empty) + usage(); +} + +static int +takepid(const char *pidfile, int pidfilelock) +{ + char *endp, line[BUFSIZ]; + FILE *fh; + long rval; + + fh = fopen(pidfile, "r"); + if (fh == NULL) + err(STATUS_ERROR, "Cannot open pidfile `%s'", pidfile); + + if (pidfilelock) { + /* + * If we can lock pidfile, this means that daemon is not + * running, so would be better not to kill some random process. + */ + if (flock(fileno(fh), LOCK_EX | LOCK_NB) == 0) { + (void)fclose(fh); + errx(STATUS_ERROR, "File '%s' can be locked", pidfile); + } else { + if (errno != EWOULDBLOCK) { + errx(STATUS_ERROR, + "Error while locking file '%s'", pidfile); + } + } + } + + if (fgets(line, sizeof(line), fh) == NULL) { + if (feof(fh)) { + (void)fclose(fh); + errx(STATUS_ERROR, "Pidfile `%s' is empty", pidfile); + } + (void)fclose(fh); + err(STATUS_ERROR, "Cannot read from pid file `%s'", pidfile); + } + (void)fclose(fh); + + rval = strtol(line, &endp, 10); + if (*endp != '\0' && !isspace((unsigned char)*endp)) + errx(STATUS_ERROR, "Invalid pid in file `%s'", pidfile); + else if (rval < MIN_PID || rval > MAX_PID) + errx(STATUS_ERROR, "Invalid pid in file `%s'", pidfile); + return (rval); +} diff --git a/adv_cmds/ps/entitlements.plist b/adv_cmds/ps/entitlements.plist new file mode 100644 index 0000000..eaaf1de --- /dev/null +++ b/adv_cmds/ps/entitlements.plist @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>com.apple.system-task-ports</key> + <true/> + <key>task_for_pid-allow</key> + <true/> +</dict> +</plist> diff --git a/adv_cmds/ps/extern.h b/adv_cmds/ps/extern.h new file mode 100644 index 0000000..d3f6503 --- /dev/null +++ b/adv_cmds/ps/extern.h @@ -0,0 +1,98 @@ +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)extern.h 8.3 (Berkeley) 4/2/94 + * $FreeBSD: extern.h,v 1.8 1998/05/25 05:07:17 steve Exp $ + */ + +struct kinfo; +struct nlist; +struct var; +struct varent; + +extern fixpt_t ccpu; +extern int cflag, eval, fscale, nlistread, rawcpu; +#ifdef __APPLE__ +extern uint64_t mempages; +#else +extern unsigned long mempages; +#endif +extern time_t now; +extern int showthreads, sumrusage, termwidth, totwidth; +extern STAILQ_HEAD(velisthead, varent) varlist; + +__BEGIN_DECLS +int get_task_info(KINFO *); +void command(KINFO *, VARENT *); +void just_command(KINFO *, VARENT *); +void args(KINFO *, VARENT *); +int s_command(KINFO *); +int s_just_command(KINFO *); +int s_args(KINFO *); +void cputime(KINFO *, VARENT *); +void pstime(KINFO *, VARENT *); +void p_etime(KINFO *, VARENT *); +int s_etime(KINFO *); +void putime(KINFO *, VARENT *); +int donlist(void); +void evar(KINFO *, VARENT *); +VARENT *find_varentry(VAR *); +const char *fmt_argv(char **, char *, size_t); +int getpcpu(KINFO *); +double getpmem(KINFO *); +void logname(KINFO *, VARENT *); +void longtname(KINFO *, VARENT *); +void lstarted(KINFO *, VARENT *); +void maxrss(KINFO *, VARENT *); +void nlisterr(struct nlist *); +void p_rssize(KINFO *, VARENT *); +void pagein(KINFO *, VARENT *); +void parsefmt(const char *, int); +void pcpu(KINFO *, VARENT *); +void pmem(KINFO *, VARENT *); +void pri(KINFO *, VARENT *); +void rtprior(KINFO *, VARENT *); +void printheader(void); +void pvar(KINFO *, VARENT *); +void runame(KINFO *, VARENT *); +void rvar(KINFO *, VARENT *); +int s_runame(KINFO *); +int s_uname(KINFO *); +void showkey(void); +void started(KINFO *, VARENT *); +void state(KINFO *, VARENT *); +void tdev(KINFO *, VARENT *); +void tname(KINFO *, VARENT *); +void tsize(KINFO *, VARENT *); +void ucomm(KINFO *, VARENT *); +void uname(KINFO *, VARENT *); +void uvar(KINFO *, VARENT *); +void vsize(KINFO *, VARENT *); +void wchan(KINFO *, VARENT *); +void wq(KINFO *, VARENT *); +__END_DECLS diff --git a/adv_cmds/ps/fmt.c b/adv_cmds/ps/fmt.c new file mode 100644 index 0000000..26ba3dc --- /dev/null +++ b/adv_cmds/ps/fmt.c @@ -0,0 +1,132 @@ +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if 0 +#ifndef lint +static char sccsid[] = "@(#)fmt.c 8.4 (Berkeley) 4/15/94"; +#endif +#endif + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD: src/bin/ps/fmt.c,v 1.34 2004/06/22 02:18:29 gad Exp $"); + +#include <sys/types.h> +#include <sys/time.h> +#include <sys/resource.h> + +#include <err.h> +#include <limits.h> +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <vis.h> + +#include "ps.h" + +static char *cmdpart(char *); +static char *shquote(char **); + +static char * +shquote(char **argv) +{ + long arg_max; + static size_t buf_size; + size_t len; + char **p, *dst, *src; + static char *buf = NULL; + + if (buf == NULL) { + if ((arg_max = sysconf(_SC_ARG_MAX)) == -1) + errx(1, "sysconf _SC_ARG_MAX failed"); + if (arg_max >= LONG_MAX / 4 || arg_max >= (long)(SIZE_MAX / 4)) + errx(1, "sysconf _SC_ARG_MAX preposterously large"); + buf_size = 4 * arg_max + 1; + if ((buf = malloc(buf_size)) == NULL) + errx(1, "malloc failed"); + } + + if (*argv == NULL) { + buf[0] = '\0'; + return (buf); + } + dst = buf; + for (p = argv; (src = *p++) != NULL; ) { + if (*src == '\0') + continue; + len = (buf_size - 1 - (dst - buf)) / 4; + strvisx(dst, src, strlen(src) < len ? strlen(src) : len, + VIS_NL | VIS_CSTYLE); + while (*dst != '\0') + dst++; + if ((buf_size - 1 - (dst - buf)) / 4 > 0) + *dst++ = ' '; + } + /* Chop off trailing space */ + if (dst != buf && dst[-1] == ' ') + dst--; + *dst = '\0'; + return (buf); +} + +static char * +cmdpart(char *arg0) +{ + char *cp; + + return ((cp = strrchr(arg0, '/')) != NULL ? cp + 1 : arg0); +} + +const char * +fmt_argv(char **argv, char *cmd, size_t maxlen) +{ + size_t len; + char *ap, *cp; + + if (argv == NULL || argv[0] == NULL) { + if (cmd == NULL) + return (""); + ap = NULL; + len = maxlen + 3; + } else { + ap = shquote(argv); + len = strlen(ap) + maxlen + 4; + } + cp = malloc(len); + if (cp == NULL) + errx(1, "malloc failed"); + if (ap == NULL) + sprintf(cp, "[%.*s]", (int)maxlen, cmd); + else if (strncmp(cmdpart(argv[0]), cmd, maxlen) != 0) + sprintf(cp, "%s (%.*s)", ap, (int)maxlen, cmd); + else + strcpy(cp, ap); + return (cp); +} diff --git a/adv_cmds/ps/keyword.c b/adv_cmds/ps/keyword.c new file mode 100644 index 0000000..ff311b4 --- /dev/null +++ b/adv_cmds/ps/keyword.c @@ -0,0 +1,340 @@ +/*- + * Copyright (c) 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if 0 +#ifndef lint +static char sccsid[] = "@(#)keyword.c 8.5 (Berkeley) 4/2/94"; +#else +static const char rcsid[] = + "$FreeBSD: keyword.c,v 1.23 1999/01/26 02:38:09 julian Exp $"; +#endif /* not lint */ +#endif + +#include <sys/param.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <sys/proc.h> +#include <sys/sysctl.h> +#include <sys/user.h> + +#include <err.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "ps.h" + +VAR *findvar(char *, int, char **header); +static int vcmp(const void *, const void *); + +/* Compute offset in common structures. */ +#define POFF(x) offsetof(struct extern_proc, x) +#define EOFF(x) offsetof(struct eproc, x) +#define UOFF(x) offsetof(struct usave, x) +#define ROFF(x) offsetof(struct rusage, x) + +#define EMULLEN 13 /* enough for "FreeBSD ELF32" */ +#define LWPFMT "d" +#define LWPLEN 6 +#define NLWPFMT "d" +#define NLWPLEN 4 +#ifdef __APPLE__ +#define UIDFMT "d" +#else +#define UIDFMT "u" +#endif +#define UIDLEN 5 +#define PIDFMT "d" +#define PIDLEN 5 +#define USERLEN 16 + +/* PLEASE KEEP THE TABLE BELOW SORTED ALPHABETICALLY!!! */ +static VAR var[] = { + /* 4133537: 5 characters to accomodate 100% or more */ + {"%cpu", "%CPU", NULL, 0, pcpu, NULL, 5, 0, CHAR, NULL, 0}, + {"%mem", "%MEM", NULL, 0, pmem, NULL, 4}, + {"acflag", "ACFLG", + NULL, 0, pvar, NULL, 3, POFF(p_acflag), USHORT, "x"}, + {"acflg", "", "acflag"}, + {"args", "ARGS", NULL, COMM|LJUST|USER|DSIZ, args, s_args, 64}, + {"blocked", "", "sigmask"}, + {"caught", "", "sigcatch"}, + {"comm", "COMM", NULL, COMM|LJUST|USER|DSIZ, just_command, s_just_command, 16}, + {"command", "COMMAND", NULL, COMM|LJUST|USER|DSIZ, command, s_command, 16}, + {"cpu", "CPU", NULL, 0, pvar, NULL, 3, POFF(p_estcpu), UINT, "d"}, + {"cputime", "", "time"}, + {"etime", "ELAPSED", NULL, USER|DSIZ, p_etime, s_etime, 20}, + /* 5861775: Make F column 8 characters. */ + {"f", "F", NULL, 0, pvar, NULL, 8, POFF(p_flag), INT, "x"}, + {"flags", "", "f"}, + {"gid", "GID", NULL, 0, evar, NULL, UIDLEN, EOFF(e_ucred.cr_gid), + UINT, UIDFMT}, + {"group", "GROUP", "gid"}, + {"ignored", "", "sigignore"}, + {"inblk", "INBLK", + NULL, USER, rvar, NULL, 4, ROFF(ru_inblock), LONG, "ld"}, + {"inblock", "", "inblk"}, + {"jobc", "JOBC", NULL, 0, evar, NULL, 4, EOFF(e_jobc), SHORT, "d"}, + {"ktrace", "KTRACE", + NULL, 0, pvar, NULL, 8, POFF(p_traceflag), INT, "x"}, + {"ktracep", "KTRACEP", + NULL, 0, pvar, NULL, 8, POFF(p_tracep), LONG, "lx"}, + {"lim", "LIM", NULL, 0, maxrss, NULL, 5}, + {"login", "LOGIN", NULL, LJUST, logname, NULL, MAXLOGNAME-1}, + {"logname", "", "login"}, + {"lstart", "STARTED", NULL, LJUST|USER, lstarted, NULL, 28}, + {"majflt", "MAJFLT", + NULL, USER, rvar, NULL, 4, ROFF(ru_majflt), LONG, "ld"}, + {"minflt", "MINFLT", + NULL, USER, rvar, NULL, 4, ROFF(ru_minflt), LONG, "ld"}, + {"msgrcv", "MSGRCV", + NULL, USER, rvar, NULL, 4, ROFF(ru_msgrcv), LONG, "ld"}, + {"msgsnd", "MSGSND", + NULL, USER, rvar, NULL, 4, ROFF(ru_msgsnd), LONG, "ld"}, + {"ni", "", "nice"}, + {"nice", "NI", NULL, 0, pvar, NULL, 2, POFF(p_nice), CHAR, "d"}, + {"nivcsw", "NIVCSW", + NULL, USER, rvar, NULL, 5, ROFF(ru_nivcsw), LONG, "ld"}, + {"nsignals", "", "nsigs"}, + {"nsigs", "NSIGS", + NULL, USER, rvar, NULL, 4, ROFF(ru_nsignals), LONG, "ld"}, + {"nswap", "NSWAP", + NULL, USER, rvar, NULL, 4, ROFF(ru_nswap), LONG, "ld"}, + {"nvcsw", "NVCSW", + NULL, USER, rvar, NULL, 5, ROFF(ru_nvcsw), LONG, "ld"}, + {"nwchan", "WCHAN", NULL, 0, pvar, NULL, 6, POFF(p_wchan), KPTR, "lx"}, + {"oublk", "OUBLK", + NULL, USER, rvar, NULL, 4, ROFF(ru_oublock), LONG, "ld"}, + {"oublock", "", "oublk"}, + {"p_ru", "P_RU", NULL, 0, pvar, NULL, 6, POFF(p_ru), KPTR, "lx"}, + {"paddr", "PADDR", NULL, 0, evar, NULL, sizeof(void *) * 2, EOFF(e_paddr), KPTR, "lx"}, + {"pagein", "PAGEIN", NULL, USER, pagein, NULL, 6}, + {"pcpu", "", "%cpu"}, + {"pending", "", "sig"}, + {"pgid", "PGID", + NULL, 0, evar, NULL, PIDLEN, EOFF(e_pgid), UINT, PIDFMT}, + {"pid", "PID", NULL, 0, pvar, NULL, PIDLEN, POFF(p_pid), UINT, PIDFMT}, + {"pmem", "", "%mem"}, + {"ppid", "PPID", + NULL, 0, evar, NULL, PIDLEN, EOFF(e_ppid), UINT, PIDFMT}, + {"pri", "PRI", NULL, 0, pri, NULL, 3}, + {"pstime", "", "stime"}, + {"putime", "", "utime"}, + {"re", "RE", NULL, 0, pvar, NULL, 3, POFF(p_swtime), UINT, "d"}, + {"rgid", "RGID", NULL, 0, evar, NULL, UIDLEN, EOFF(e_pcred.p_rgid), + UINT, UIDFMT}, + {"rgroup", "RGROUP", "rgid"}, + {"rss", "RSS", NULL, 0, p_rssize, NULL, 6}, +#if FIXME + {"rtprio", "RTPRIO", NULL, 0, rtprior, NULL, 7, POFF(p_rtprio)}, +#endif /* FIXME */ + {"ruid", "RUID", NULL, 0, evar, NULL, UIDLEN, EOFF(e_pcred.p_ruid), + UINT, UIDFMT}, + {"ruser", "RUSER", NULL, LJUST|DSIZ, runame, s_runame, USERLEN}, + {"sess", "SESS", NULL, 0, evar, NULL, 6, EOFF(e_sess), KPTR, "lx"}, + {"sig", "PENDING", NULL, 0, pvar, NULL, 8, POFF(p_siglist), INT, "x"}, +#if FIXME + {"sigcatch", "CAUGHT", + NULL, 0, evar, NULL, 8, EOFF(e_procsig.ps_sigcatch), UINT, "x"}, + {"sigignore", "IGNORED", + NULL, 0, evar, NULL, 8, EOFF(e_procsig.ps_sigignore), UINT, "x"}, +#endif /* FIXME */ + {"sigmask", "BLOCKED", + NULL, 0, pvar, NULL, 8, POFF(p_sigmask), UINT, "x"}, + {"sl", "SL", NULL, 0, pvar, NULL, 3, POFF(p_slptime), UINT, "d"}, + {"start", "STARTED", NULL, LJUST|USER, started, NULL, 7}, + {"stat", "", "state"}, + {"state", "STAT", NULL, 0, state, NULL, 4}, + {"stime", "STIME", NULL, USER, pstime, NULL, 9}, + {"svgid", "SVGID", NULL, 0, + evar, NULL, UIDLEN, EOFF(e_pcred.p_svgid), UINT, UIDFMT}, + {"svuid", "SVUID", NULL, 0, + evar, NULL, UIDLEN, EOFF(e_pcred.p_svuid), UINT, UIDFMT}, + {"tdev", "TDEV", NULL, 0, tdev, NULL, 4}, + {"time", "TIME", NULL, USER, cputime, NULL, 9}, + {"tpgid", "TPGID", + NULL, 0, evar, NULL, 4, EOFF(e_tpgid), UINT, PIDFMT}, + {"tsess", "TSESS", NULL, 0, evar, NULL, 6, EOFF(e_tsess), KPTR, "lx"}, + {"tsiz", "TSIZ", NULL, 0, tsize, NULL, 8}, + {"tt", "TT ", NULL, 0, tname, NULL, 5}, + {"tty", "TTY", NULL, LJUST, longtname, NULL, 8}, + {"ucomm", "UCOMM", NULL, LJUST, ucomm, NULL, MAXCOMLEN}, + {"uid", "UID", NULL, 0, evar, NULL, UIDLEN, EOFF(e_ucred.cr_uid), + UINT, UIDFMT}, + {"upr", "UPR", NULL, 0, pvar, NULL, 3, POFF(p_usrpri), CHAR, "d"}, + {"user", "USER", NULL, LJUST|DSIZ, uname, s_uname, USERLEN}, + {"usrpri", "", "upr"}, + {"utime", "UTIME", NULL, USER, putime, NULL, 9}, + {"vsize", "", "vsz"}, + {"vsz", "VSZ", NULL, 0, vsize, NULL, 8}, + {"wchan", "WCHAN", NULL, LJUST, wchan, NULL, 6}, + {"wq", "WQ", NULL, 0, wq, NULL, 4, 0, CHAR, NULL, 0}, + {"wqb", "WQB", NULL, 0, wq, NULL, 4, 0, CHAR, NULL, 0}, + {"wql", "WQL", NULL, 0, wq, NULL, 3, 0, CHAR, NULL, 0}, + {"wqr", "WQR", NULL, 0, wq, NULL, 4, 0, CHAR, NULL, 0}, + {"xstat", "XSTAT", NULL, 0, pvar, NULL, 4, POFF(p_xstat), USHORT, "x"}, + {""}, +}; + +void +showkey(void) +{ + VAR *v; + int i; + const char *p, *sep; + + i = 0; + sep = ""; + for (v = var; *(p = v->name); ++v) { + int len = strlen(p); + if (termwidth && (i += len + 1) > termwidth) { + i = len; + sep = "\n"; + } + (void) printf("%s%s", sep, p); + sep = " "; + } + (void) printf("\n"); +} + +void +parsefmt(const char *p, int user) +{ + char *tempstr, *tempstr1; + +#define FMTSEP " \t,\n" + tempstr1 = tempstr = strdup(p); + while (tempstr && *tempstr) { + char *cp, *hp; + VAR *v; + struct varent *vent; + +#ifndef __APPLE__ + /* + * If an item contains an equals sign, it specifies a column + * header, may contain embedded separator characters and + * is always the last item. + */ + if (tempstr[strcspn(tempstr, "="FMTSEP)] != '=') +#endif /* !__APPLE__ */ + while ((cp = strsep(&tempstr, FMTSEP)) != NULL && + *cp == '\0') + /* void */; +#ifndef __APPLE__ + else { + cp = tempstr; + tempstr = NULL; + } +#endif /* !__APPLE__ */ + if (cp == NULL || !(v = findvar(cp, user, &hp))) + continue; + if (!user) { + /* + * If the user is NOT adding this field manually, + * get on with our lives if this VAR is already + * represented in the list. + */ + vent = find_varentry(v); + if (vent != NULL) + continue; + } + if ((vent = malloc(sizeof(struct varent))) == NULL) + errx(1, "malloc failed"); + vent->header = v->header; + if (hp) { + hp = strdup(hp); + if (hp) + vent->header = hp; + } + vent->var = malloc(sizeof(*vent->var)); + if (vent->var == NULL) + errx(1, "malloc failed"); + memcpy(vent->var, v, sizeof(*vent->var)); + STAILQ_INSERT_TAIL(&varlist, vent, next_ve); + } + free(tempstr1); + if (STAILQ_EMPTY(&varlist)) { + warnx("no valid keywords; valid keywords:"); + showkey(); + exit(1); + } +} + +VAR * +findvar(char *p, int user, char **header) +{ + size_t rflen; + VAR *v, key; + char *hp, *realfmt; + + hp = strchr(p, '='); + if (hp) + *hp++ = '\0'; + + key.name = p; + v = bsearch(&key, var, sizeof(var)/sizeof(VAR) - 1, sizeof(VAR), vcmp); + + if (v && v->alias) { + /* + * If the user specified an alternate-header for this + * (aliased) format-name, then we need to copy that + * alternate-header when making the recursive call to + * process the alias. + */ + if (hp == NULL) + parsefmt(v->alias, user); + else { + /* + * XXX - This processing will not be correct for + * any alias which expands into a list of format + * keywords. Presently there are no aliases + * which do that. + */ + rflen = strlen(v->alias) + strlen(hp) + 2; + realfmt = malloc(rflen); + snprintf(realfmt, rflen, "%s=%s", v->alias, hp); + parsefmt(realfmt, user); + } + return ((VAR *)NULL); + } + if (!v) { + warnx("%s: keyword not found", p); + eval = 1; + } + if (header) + *header = hp; + return (v); +} + +static int +vcmp(const void *a, const void *b) +{ + return (strcmp(((const VAR *)a)->name, ((const VAR *)b)->name)); +} diff --git a/adv_cmds/ps/nlist.c b/adv_cmds/ps/nlist.c new file mode 100644 index 0000000..90a2303 --- /dev/null +++ b/adv_cmds/ps/nlist.c @@ -0,0 +1,86 @@ +/*- + * Copyright (c) 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if 0 +#ifndef lint +static char sccsid[] = "@(#)nlist.c 8.4 (Berkeley) 4/2/94"; +#endif /* not lint */ +#endif + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD: src/bin/ps/nlist.c,v 1.21 2004/04/06 20:06:49 markm Exp $"); + +#include <sys/types.h> +#include <sys/sysctl.h> +#ifdef __APPLE__ +#include <sys/resource.h> +#endif + +#include <stddef.h> + +#include "ps.h" + +fixpt_t ccpu; /* kernel _ccpu variable */ +int nlistread; /* if nlist already read. */ +#ifdef __APPLE__ +uint64_t mempages; /* number of pages of phys. memory */ +#else +unsigned long mempages; /* number of pages of phys. memory */ +#endif +int fscale; /* kernel _fscale variable */ + +int +donlist(void) +{ +#ifdef __APPLE__ + int mib[2]; +#endif + size_t oldlen; + +#ifdef __APPLE__ + mib[0] = CTL_HW; + mib[1] = HW_MEMSIZE; + oldlen = sizeof(mempages); + if (sysctl(mib, 2, &mempages, &oldlen, NULL, 0) == -1) + return (1); + fscale = 100; +#else + oldlen = sizeof(ccpu); + if (sysctlbyname("kern.ccpu", &ccpu, &oldlen, NULL, 0) == -1) + return (1); + oldlen = sizeof(fscale); + if (sysctlbyname("kern.fscale", &fscale, &oldlen, NULL, 0) == -1) + return (1); + oldlen = sizeof(mempages); + if (sysctlbyname("hw.availpages", &mempages, &oldlen, NULL, 0) == -1) + return (1); +#endif + nlistread = 1; + return (0); +} diff --git a/adv_cmds/ps/print.c b/adv_cmds/ps/print.c new file mode 100644 index 0000000..103ba48 --- /dev/null +++ b/adv_cmds/ps/print.c @@ -0,0 +1,1225 @@ +/*- + * Copyright (c) 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)print.c 8.6 (Berkeley) 4/16/94"; +#endif +static const char rcsid[] = + "$FreeBSD: print.c,v 1.33 1998/11/25 09:34:00 dfr Exp $"; +#endif /* not lint */ + +#include <sys/param.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <sys/ucred.h> +#include <sys/proc.h> +#include <sys/stat.h> + +#include <sys/ucred.h> +#include <sys/user.h> +#include <sys/sysctl.h> +#include <sys/cdefs.h> + +#if FIXME +#include <vm/vm.h> +#endif /* FIXME */ +#include <err.h> +#include <langinfo.h> +#include <libproc.h> +#include <math.h> +#include <nlist.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <vis.h> +#include <pwd.h> + +#include "ps.h" + +extern int mflg, print_all_thread, print_thread_num; + +void +printheader(void) +{ + VAR *v; + struct varent *vent; + + STAILQ_FOREACH(vent, &varlist, next_ve) + if (*vent->header != '\0') + break; + if (!vent) + return; + + STAILQ_FOREACH(vent, &varlist, next_ve) { + v = vent->var; + if (v->flag & LJUST) { + if (STAILQ_NEXT(vent, next_ve) == NULL) /* last one */ + (void)printf("%s", vent->header); + else + (void)printf("%-*s", v->width, vent->header); + } else + (void)printf("%*s", v->width, vent->header); + if (STAILQ_NEXT(vent, next_ve) != NULL) + (void)putchar(' '); + } + (void)putchar('\n'); +} + +/* + * Get command and arguments. + * + * If the global variable eflg is non-zero and the user has permission to view + * the process's environment, the environment is included. + * + * on return argvlen is the length of the extracted string, argv0len is + * the length of the command (same as argvlen if show_args is true) + */ +static void +getproclline(KINFO *k, char **command_name, int *argvlen, int *argv0len, + int show_args) +{ + int mib[3], argmax, nargs, c = 0; + size_t size; + char *procargs, *sp, *np, *cp; + extern int eflg; + + /* Get the maximum process arguments size. */ + mib[0] = CTL_KERN; + mib[1] = KERN_ARGMAX; + + size = sizeof(argmax); + if (sysctl(mib, 2, &argmax, &size, NULL, 0) == -1) { + goto ERROR_A; + } + + /* Allocate space for the arguments. */ + procargs = (char *)malloc(argmax); + if (procargs == NULL) { + goto ERROR_A; + } + + /* + * Make a sysctl() call to get the raw argument space of the process. + * The layout is documented in start.s, which is part of the Csu + * project. In summary, it looks like: + * + * /---------------\ 0x00000000 + * : : + * : : + * |---------------| + * | argc | + * |---------------| + * | arg[0] | + * |---------------| + * : : + * : : + * |---------------| + * | arg[argc - 1] | + * |---------------| + * | 0 | + * |---------------| + * | env[0] | + * |---------------| + * : : + * : : + * |---------------| + * | env[n] | + * |---------------| + * | 0 | + * |---------------| <-- Beginning of data returned by sysctl() is here. + * | argc | + * |---------------| + * | exec_path | + * |:::::::::::::::| + * | | + * | String area. | + * | | + * |---------------| <-- Top of stack. + * : : + * : : + * \---------------/ 0xffffffff + */ + mib[0] = CTL_KERN; + mib[1] = KERN_PROCARGS2; + mib[2] = KI_PROC(k)->p_pid; + + size = (size_t)argmax; + if (sysctl(mib, 3, procargs, &size, NULL, 0) == -1) { + goto ERROR_B; + } + + memcpy(&nargs, procargs, sizeof(nargs)); + cp = procargs + sizeof(nargs); + + /* Skip the saved exec_path. */ + for (; cp < &procargs[size]; cp++) { + if (*cp == '\0') { + /* End of exec_path reached. */ + break; + } + } + if (cp == &procargs[size]) { + goto ERROR_B; + } + + /* Skip trailing '\0' characters. */ + for (; cp < &procargs[size]; cp++) { + if (*cp != '\0') { + /* Beginning of first argument reached. */ + break; + } + } + if (cp == &procargs[size]) { + goto ERROR_B; + } + /* Save where the argv[0] string starts. */ + sp = cp; + + /* + * Iterate through the '\0'-terminated strings and convert '\0' to ' ' + * until a string is found that has a '=' character in it (or there are + * no more strings in procargs). There is no way to deterministically + * know where the command arguments end and the environment strings + * start, which is why the '=' character is searched for as a heuristic. + */ + for (np = NULL; c < nargs && cp < &procargs[size]; cp++) { + if (*cp == '\0') { + c++; + if (np != NULL) { + /* Convert previous '\0'. */ + *np = ' '; + } else { + *argv0len = cp - sp; + } + /* Note location of current '\0'. */ + np = cp; + + if (!show_args) { + /* + * Don't convert '\0' characters to ' '. + * However, we needed to know that the + * command name was terminated, which we + * now know. + */ + break; + } + } + } + + /* + * If eflg is non-zero, continue converting '\0' characters to ' ' + * characters until no more strings that look like environment settings + * follow. + */ + if ( show_args && (eflg != 0) && ( (getuid() == 0) || (KI_EPROC(k)->e_pcred.p_ruid == getuid()) ) ) { + for (; cp < &procargs[size]; cp++) { + if (*cp == '\0') { + if (np != NULL) { + if (&np[1] == cp) { + /* + * Two '\0' characters in a row. + * This should normally only + * happen after all the strings + * have been seen, but in any + * case, stop parsing. + */ + break; + } + /* Convert previous '\0'. */ + *np = ' '; + } + /* Note location of current '\0'. */ + np = cp; + } + } + } + + /* + * sp points to the beginning of the arguments/environment string, and + * np should point to the '\0' terminator for the string. + */ + if (np == NULL || np == sp) { + /* Empty or unterminated string. */ + goto ERROR_B; + } + + /* Make a copy of the string. */ + *argvlen = asprintf(command_name, "%s", sp); + + /* Clean up. */ + free(procargs); + return; + + ERROR_B: + free(procargs); + ERROR_A: + *argv0len = *argvlen + = asprintf(command_name, "(%s)", KI_PROC(k)->p_comm); +} + +/* Return value is malloc'ed, please free it */ +char * +get_command_and_or_args(KINFO *k, int show_cmd, int show_args) +{ + char *vis_args; + + char *rawcmd, *cmd; + int cmdlen, argv0len = 0; + + + if(!mflg || (print_all_thread && (print_thread_num== 0))) { + getproclline(k, &rawcmd, &cmdlen, &argv0len, show_args); + + if (cflag) { + /* Ignore the path in cmd, if any. */ + for (cmd = &rawcmd[cmdlen - 1]; cmd > rawcmd; cmd--) { + if (*cmd == '/') { + cmd++; + break; + } + } + } else { + cmd = rawcmd; + } + + if (!show_cmd) { + cmd += argv0len; + if (*cmd) { + cmd++; + } + } + + if ((vis_args = malloc(strlen(cmd) * 4 + 1)) == NULL) + err(1, NULL); + strvis(vis_args, cmd, VIS_TAB | VIS_NL | VIS_NOSLASH); + free(rawcmd); + return vis_args; + } else { + return strdup(""); + } +} + +int +s_command_and_or_args(KINFO *k, int show_cmd, int show_args) +{ + char *s = get_command_and_or_args(k, show_cmd, show_args); + int sz = strlen(s); + free(s); + + return sz; +} + +void +p_command_and_or_args(KINFO *k, VARENT *ve, int show_cmd, int show_args, + int no_trunc) +{ + VAR *v = ve->var; + char *s = get_command_and_or_args(k, show_cmd, show_args); + + if (STAILQ_NEXT(ve, next_ve) == NULL) { + /* last field */ + if (termwidth == UNLIMITED) { + fputs(s, stdout); + } else { + int left; + char *cp; + + left = termwidth - (totwidth - v->width); + if (left < 1 || no_trunc) { + /* already wrapped, just use std * width */ + left = v->width; + } + for(cp = s; --left >= 0 && *cp;) { + (void)putchar(*cp++); + } + } + } else { + /* XXX env? */ + (void)printf("%-*.*s", v->width, v->width, s); + } + + free(s); +} + +int s_command(KINFO *k) { + return s_command_and_or_args(k, 1, !cflag); +} + +int s_args(KINFO *k) { + return s_command_and_or_args(k, 1, 1); +} + +int s_just_command(KINFO *k) { + return s_command_and_or_args(k, 1, 0); +} + +void command(KINFO *k, VARENT *ve) { + p_command_and_or_args(k, ve, 1, !cflag, 0); +} + +void args(KINFO *k, VARENT *ve) { + p_command_and_or_args(k, ve, 1, 1, 1); +} + +void just_command(KINFO *k, VARENT *ve) { + p_command_and_or_args(k, ve, 1, 0, 0); +} + +void +ucomm(k, ve) + KINFO *k; + VARENT *ve; +{ + VAR *v; + + v = ve->var; + (void)printf("%-*s", v->width, KI_PROC(k)->p_comm); +} + +char *getname(uid) + uid_t uid; +{ + register struct passwd *pw; + struct passwd *getpwuid(); + + pw = getpwuid((short)uid); + if (pw == NULL) { + return( "UNKNOWN" ); + } + return( pw->pw_name ); +} + +void +logname(KINFO *k, VARENT *ve) +{ + VAR *v; + char *s; + + v = ve->var; + (void)printf("%-*s", v->width, (s = getname(KI_EPROC(k)->e_ucred.cr_uid), *s) ? s : "-"); +} + +extern int mach_state_order(); +void +state(k, ve) + KINFO *k; + VARENT *ve; +{ + struct extern_proc *p; + int flag,j; + char *cp; + VAR *v; + char buf[16]; + extern char mach_state_table[]; + + v = ve->var; + p = KI_PROC(k); + flag = p->p_flag; + cp = buf; + + if(!mflg ) { + switch (p->p_stat) { + + case SSTOP: + *cp = 'T'; + break; + + case SZOMB: + *cp = 'Z'; + break; + + default: + *cp = mach_state_table[k->state]; + } + cp++; + if (p->p_nice < 0) + *cp++ = '<'; + else if (p->p_nice > 0) + *cp++ = 'N'; + if (flag & P_TRACED) + *cp++ = 'X'; + if (flag & P_WEXIT && p->p_stat != SZOMB) + *cp++ = 'E'; + if (flag & P_PPWAIT) + *cp++ = 'V'; + if (flag & (P_SYSTEM | P_NOSWAP | P_PHYSIO)) + *cp++ = 'L'; + if (KI_EPROC(k)->e_flag & EPROC_SLEADER) + *cp++ = 's'; + if ((flag & P_CONTROLT) && KI_EPROC(k)->e_pgid == KI_EPROC(k)->e_tpgid) + *cp++ = '+'; + *cp = '\0'; + (void)printf("%-*s", v->width, buf); + } else if (print_all_thread) { + j = mach_state_order(k->thval[print_thread_num].tb.run_state, + k->thval[print_thread_num].tb.sleep_time); + *cp++ = mach_state_table[j]; + *cp++='\0'; + (void)printf("%-*s", v->width, buf); + } else { + (void)printf("%-*s", v->width, " "); + } + +} + +void +pri(k, ve) + KINFO *k; + VARENT *ve; +{ + VAR *v; + int j=0; + char c = '?'; + + v = ve->var; + if (!mflg ) { + (void)printf("%*d", v->width, k->curpri); + } else if (print_all_thread) { + switch(k->thval[print_thread_num].tb.policy) { + case POLICY_TIMESHARE : + j = k->thval[print_thread_num].schedinfo.tshare.cur_priority; + c = 'T'; + break; + case POLICY_FIFO : + j = k->thval[print_thread_num].schedinfo.fifo.base_priority; + c = 'F'; + break; + case POLICY_RR : + j = k->thval[print_thread_num].schedinfo.rr.base_priority; + c = 'R'; + break; + default : + j = 0; + } + (void)printf("%*d%c", v->width - 1, j, c); + }else { + j=0; + (void)printf("%*d", v->width, j); + + } +} + +void +uname(k, ve) + KINFO *k; + VARENT *ve; +{ + VAR *v; + + v = ve->var; + if(!mflg || (print_all_thread && (print_thread_num== 0))) + (void)printf("%-*s", + (int)v->width, + user_from_uid(KI_EPROC(k)->e_ucred.cr_uid, 0)); + else + (void)printf("%-*s", (int)v->width, " "); +} + +int +s_uname(KINFO *k) +{ + return (strlen(user_from_uid(KI_EPROC(k)->e_ucred.cr_uid, 0))); +} + +void +runame(k, ve) + KINFO *k; + VARENT *ve; +{ + VAR *v; + + v = ve->var; + (void)printf("%-*s", + (int)v->width, user_from_uid(KI_EPROC(k)->e_pcred.p_ruid, 0)); +} + +int +s_runame(KINFO *k) +{ + return (strlen(user_from_uid(KI_EPROC(k)->e_pcred.p_ruid, 0))); +} + +void +tdev(k, ve) + KINFO *k; + VARENT *ve; +{ + VAR *v; + dev_t dev; + char buff[16]; + + v = ve->var; + dev = KI_EPROC(k)->e_tdev; + if (dev == NODEV) + (void)printf("%*s", v->width, "??"); + else { + (void)snprintf(buff, sizeof(buff), + "%d/%d", major(dev), minor(dev)); + (void)printf("%*s", v->width, buff); + } +} + +void +tname(k, ve) + KINFO *k; + VARENT *ve; +{ + VAR *v; + dev_t dev; + char *ttname; + + v = ve->var; + + if(!mflg || (print_all_thread && (print_thread_num== 0))) { + dev = KI_EPROC(k)->e_tdev; + if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL) + (void)printf("%*s ", v->width-1, "??"); + else { + if (strncmp(ttname, "tty", 3) == 0 || + strncmp(ttname, "cua", 3) == 0) + ttname += 3; + (void)printf("%*.*s%c", v->width-1, v->width-1, ttname, + KI_EPROC(k)->e_flag & EPROC_CTTY ? ' ' : '-'); + } + } + else { + (void)printf("%*s ", v->width-1, " "); + } +} + +void +longtname(k, ve) + KINFO *k; + VARENT *ve; +{ + VAR *v; + dev_t dev; + char *ttname; + + v = ve->var; + dev = KI_EPROC(k)->e_tdev; + if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL) + (void)printf("%-*s", v->width, "??"); + else + (void)printf("%-*s", v->width, ttname); +} + +void +started(KINFO *k, VARENT *ve) +{ + VAR *v; + time_t then; + struct tm *tp; + static int use_ampm = -1; + char buf[100]; + + v = ve->var; + if (use_ampm < 0) + use_ampm = (*nl_langinfo(T_FMT_AMPM) != '\0'); + then = KI_PROC(k)->p_starttime.tv_sec; + tp = localtime(&then); + if (now - KI_PROC(k)->p_starttime.tv_sec < 24 * 3600) { + (void)strftime(buf, sizeof(buf), + use_ampm ? "%l:%M%p" : "%k:%M ", tp); + } else if (now - KI_PROC(k)->p_starttime.tv_sec < 7 * 86400) { + (void)strftime(buf, sizeof(buf), + use_ampm ? "%a%I%p" : "%a%H ", tp); + } else + (void)strftime(buf, sizeof(buf), "%e%b%y", tp); + (void)printf("%-*s", v->width, buf); +} + +void +lstarted(k, ve) + KINFO *k; + VARENT *ve; +{ + VAR *v; + time_t then; + char buf[100]; + + v = ve->var; + then = KI_PROC(k)->p_starttime.tv_sec; + (void)strftime(buf, sizeof(buf) -1, "%c", localtime(&then)); + (void)printf("%-*s", v->width, buf); +} + +char *get_etime(KINFO *k) { + struct timeval tv; + gettimeofday(&tv, NULL); + long e = tv.tv_sec - KI_PROC(k)->p_starttime.tv_sec; + + char *ret; + + if (e > 100*60*60*24) { + asprintf(&ret, "%ld-%02ld:%02ld:%02ld", + e / (60*60*24), + (e / (60*60)) % 24, + (e / 60) % 60, + e % 60); + } else if (e > 60*60*24) { + asprintf(&ret, "%02ld-%02ld:%02ld:%02ld", + e / (60*60*24), + (e / (60*60)) % 24, + (e / 60) % 60, + e % 60); + } else if (e > 60*60) { + asprintf(&ret, "%02ld:%02ld:%02ld", + (e / (60*60)), + (e / 60) % 60, + e % 60); + } else { + asprintf(&ret, "%02ld:%02ld", + (e / 60), + e % 60); + } + + return ret; +} + +void p_etime(KINFO *k, VARENT *ve) { + char *str = get_etime(k); + printf("%*s", ve->var->width, str); + free(str); +} + +int s_etime(KINFO *k) { + char *str = get_etime(k); + int sz = strlen(str); + free(str); + return sz; +} + +void +wchan(k, ve) + KINFO *k; + VARENT *ve; +{ + VAR *v; + + v = ve->var; + if (KI_PROC(k)->p_wchan) { + if (KI_PROC(k)->p_wmesg) + (void)printf("%-*.*s", v->width, v->width, + KI_EPROC(k)->e_wmesg); + else +#if FIXME + (void)printf("%-*lx", v->width, + (long)KI_PROC(k)->p_wchan &~ KERNBASE); +#else /* FIXME */ + (void)printf("%-*lx", v->width, + (long)KI_PROC(k)->p_wchan); +#endif /* FIXME */ + } else + (void)printf("%-*s", v->width, "-"); +} + +#define pgtok(a) (((a)*getpagesize())/1024) + +void +vsize(k, ve) + KINFO *k; + VARENT *ve; +{ + VAR *v; + + v = ve->var; +#if FIXME + (void)printf("%*d", v->width, + (KI_EPROC(k)->e_vm.vm_map.size/1024)); +#else /* FIXME */ + (void)printf("%*lu", v->width, + (u_long)((k)->tasks_info.virtual_size)/1024); +#endif /* FIXME */ +} + +void +p_rssize(k, ve) /* doesn't account for text */ + KINFO *k; + VARENT *ve; +{ + VAR *v; +/* FIXME LATER */ + v = ve->var; + /* (void)printf("%*ld", v->width, "-"); */ + (void)printf("%*lu", v->width, + (u_long)((k)->tasks_info.resident_size)/1024); +} + +void +cputime(k, ve) + KINFO *k; + VARENT *ve; +{ + VAR *v; + long secs; + long psecs; /* "parts" of a second. first micro, then centi */ + char obuff[128]; + time_value_t total_time, system_time; + v = ve->var; +#if FIXME + if (KI_PROC(k)->p_stat == SZOMB || !k->ki_u.u_valid) { + secs = 0; + psecs = 0; + } else { + /* + * This counts time spent handling interrupts. We could + * fix this, but it is not 100% trivial (and interrupt + * time fractions only work on the sparc anyway). XXX + */ +#if FIXME + secs = KI_PROC(k)->p_runtime / 1000000; + psecs = KI_PROC(k)->p_runtime % 1000000; +#endif /* FIXME */ + if (sumrusage) { + secs += k->ki_u.u_cru.ru_utime.tv_sec + + k->ki_u.u_cru.ru_stime.tv_sec; + psecs += k->ki_u.u_cru.ru_utime.tv_usec + + k->ki_u.u_cru.ru_stime.tv_usec; + } + /* + * round and scale to 100's + */ + psecs = (psecs + 5000) / 10000; + secs += psecs / 100; + psecs = psecs % 100; + } +#else /* FIXME */ + total_time = k->tasks_info.user_time; + system_time = k->tasks_info.system_time; + + time_value_add(&total_time, &k->times.user_time); + time_value_add(&system_time, &k->times.system_time); + time_value_add(&total_time, &system_time); + + secs = total_time.seconds; + psecs = total_time.microseconds; + /* + * round and scale to 100's + */ + psecs = (psecs + 5000) / 10000; + secs += psecs / 100; + psecs = psecs % 100; +#endif /* FIXME */ + (void)snprintf(obuff, sizeof(obuff), + "%3ld:%02ld.%02ld", secs/60, secs%60, psecs); + (void)printf("%*s", v->width, obuff); +} + +void +putime(k, ve) + KINFO *k; + VARENT *ve; +{ + VAR *v; + long secs; + long psecs; /* "parts" of a second. first micro, then centi */ + char obuff[128]; + time_value_t user_time; + + + v = ve->var; + if (!mflg) { + user_time = k->tasks_info.user_time; + time_value_add(&user_time, &k->times.user_time); + } else if (print_all_thread) { + user_time = k->thval[print_thread_num].tb.user_time; + } else { + user_time.seconds =0; + user_time.microseconds =0; + } + + secs = user_time.seconds; + psecs = user_time.microseconds; + /* + * round and scale to 100's + */ + psecs = (psecs + 5000) / 10000; + secs += psecs / 100; + psecs = psecs % 100; + + (void)snprintf(obuff, sizeof(obuff), + "%3ld:%02ld.%02ld", secs/60, secs%60, psecs); + (void)printf("%*s", v->width, obuff); +} + +void +pstime(k, ve) + KINFO *k; + VARENT *ve; +{ + VAR *v; + long secs; + long psecs; /* "parts" of a second. first micro, then centi */ + char obuff[128]; + time_value_t system_time; + + v = ve->var; + if (!mflg) { + system_time = k->tasks_info.system_time; + time_value_add(&system_time, &k->times.system_time); + } else if (print_all_thread) { + system_time = k->thval[print_thread_num].tb.system_time; + } else { + system_time.seconds =0; + system_time.microseconds =0; + } + secs = system_time.seconds; + psecs = system_time.microseconds; + /* + * round and scale to 100's + */ + psecs = (psecs + 5000) / 10000; + secs += psecs / 100; + psecs = psecs % 100; + + (void)snprintf(obuff, sizeof(obuff), + "%3ld:%02ld.%02ld", secs/60, secs%60, psecs); + (void)printf("%*s", v->width, obuff); + +} + +int +getpcpu(k) + KINFO *k; +{ +#if FIXME + struct proc *p; + static int failure; + + if (!nlistread) + failure = donlist(); + if (failure) + return (0.0); + p = KI_PROC(k); +#define fxtofl(fixpt) ((double)(fixpt) / fscale) + + /* XXX - I don't like this */ + if (p->p_swtime == 0 || (p->p_flag & P_INMEM) == 0) + return (0.0); + if (rawcpu) + return (100.0 * fxtofl(p->p_pctcpu)); + return (100.0 * fxtofl(p->p_pctcpu) / + (1.0 - exp(p->p_swtime * log(fxtofl(ccpu))))); +#else + return (k->cpu_usage); +#endif /* FIXME */ +} + +#ifndef TH_USAGE_SCALE +#define TH_USAGE_SCALE 1000 +#endif /* !TH_USAGE_SCALE */ + +void +pcpu(KINFO *k, VARENT *ve) +{ + VAR *v; + int cp; + + if (!mflg) { + cp = getpcpu(k); + } else if (print_all_thread) { + cp = k->thval[print_thread_num].tb.cpu_usage; + } else { + cp = 0; + } + + v = ve->var; + (void)printf("%*.1f", v->width, ((double)cp) * 100.0 / ((double)TH_USAGE_SCALE)); +} + +double +getpmem(k) + KINFO *k; +{ + static int failure; + double fracmem; + + if (!nlistread) + failure = donlist(); + if (failure) + return (0.0); +#if FIXME + p = KI_PROC(k); + e = KI_EPROC(k); + if ((p->p_flag & P_INMEM) == 0) + return (0.0); + /* XXX want pmap ptpages, segtab, etc. (per architecture) */ + szptudot = UPAGES; + /* XXX don't have info about shared */ + fracmem = ((float)e->e_vm.vm_rssize + szptudot)/mempages; + return (100.0 * fracmem); +#else /* FIXME */ + fracmem = ((float)k->tasks_info.resident_size)/(double)mempages; + return (100.0 * fracmem); +#endif /* FIXME */ +} + +void +pmem(k, ve) + KINFO *k; + VARENT *ve; +{ + VAR *v; + + v = ve->var; + (void)printf("%*.1f", v->width, getpmem(k)); +} + +void +pagein(k, ve) + KINFO *k; + VARENT *ve; +{ + VAR *v; + + v = ve->var; + (void)printf("%*ld", v->width, + k->ki_u.u_valid ? k->ki_u.u_ru.ru_majflt : 0); +} + +void +maxrss(k, ve) + KINFO *k; + VARENT *ve; +{ + VAR *v; + + v = ve->var; + /* XXX not yet */ + (void)printf("%*s", v->width, "-"); +} + +void +tsize(k, ve) + KINFO *k; + VARENT *ve; +{ + VAR *v; + int dummy=0; + + v = ve->var; +#if 0 + (void)printf("%*ld", v->width, (long)pgtok(KI_EPROC(k)->e_vm.vm_tsize)); +#else + (void)printf("%*ld", v->width, (long)dummy); +#endif +} + +void +rtprior(k, ve) + KINFO *k; + VARENT *ve; +{ +#if FIXME + + VAR *v; + struct rtprio *prtp; + char str[8]; + unsigned prio, type; + + v = ve->var; + prtp = (struct rtprio *) ((char *)KI_PROC(k) + v->off); + prio = prtp->prio; + type = prtp->type; + switch (type) { + case RTP_PRIO_REALTIME: + snprintf(str, sizeof(str), "real:%u", prio); + break; + case RTP_PRIO_NORMAL: + strncpy(str, "normal", sizeof(str)); + break; + case RTP_PRIO_IDLE: + snprintf(str, sizeof(str), "idle:%u", prio); + break; + default: + snprintf(str, sizeof(str), "%u:%u", type, prio); + break; + } + str[sizeof(str) - 1] = '\0'; + (void)printf("%*s", v->width, str); +#endif /* FIXME */ +} + +/* + * Generic output routines. Print fields from various prototype + * structures. + */ +static void +printval(void *bp, VAR *v) +{ + static char ofmt[32] = "%"; + const char *fcp; + char *cp; + + cp = ofmt + 1; + fcp = v->fmt; + if (v->flag & LJUST) + *cp++ = '-'; + *cp++ = '*'; + while ((*cp++ = *fcp++)); + + switch (v->type) { + case CHAR: + (void)printf(ofmt, v->width, *(char *)bp); + break; + case UCHAR: + (void)printf(ofmt, v->width, *(u_char *)bp); + break; + case SHORT: + (void)printf(ofmt, v->width, *(short *)bp); + break; + case USHORT: + (void)printf(ofmt, v->width, *(u_short *)bp); + break; + case INT: + (void)printf(ofmt, v->width, *(int *)bp); + break; + case UINT: + (void)printf(ofmt, v->width, *(u_int *)bp); + break; + case LONG: + (void)printf(ofmt, v->width, *(long *)bp); + break; + case ULONG: + (void)printf(ofmt, v->width, *(u_long *)bp); + break; + case KPTR: +#if FIXME + (void)printf(ofmt, v->width, *(u_long *)bp &~ KERNBASE); +#else /* FIXME */ + (void)printf(ofmt, v->width, *(u_long *)bp); +#endif /* FIXME */ + break; + default: + errx(1, "unknown type %d", v->type); + } +} + +void +pvar(k, ve) + KINFO *k; + VARENT *ve; +{ + VAR *v; + + v = ve->var; + printval((char *)((char *)KI_PROC(k) + v->off), v); +} + +void +evar(k, ve) + KINFO *k; + VARENT *ve; +{ + VAR *v; + + v = ve->var; + printval((char *)((char *)KI_EPROC(k) + v->off), v); +} + +void +uvar(k, ve) + KINFO *k; + VARENT *ve; +{ + VAR *v; + + v = ve->var; + if (k->ki_u.u_valid) + printval((char *)((char *)&k->ki_u + v->off), v); + else + (void)printf("%*s", v->width, "-"); +} + +void +rvar(k, ve) + KINFO *k; + VARENT *ve; +{ + VAR *v; + + v = ve->var; + if (k->ki_u.u_valid) + printval((char *)((char *)(&k->ki_u.u_ru) + v->off), v); + else + (void)printf("%*s", v->width, "-"); +} + +void +wq(KINFO *k, VARENT *ve) +{ + VAR *v; + struct proc_workqueueinfo wqinfo; + int len; + int ret; + uint32_t nthreads; + + len = sizeof(wqinfo); + ret = proc_pidinfo(KI_PROC(k)->p_pid, PROC_PIDWORKQUEUEINFO, 0, &wqinfo, len); + + v = ve->var; + + if (len == ret && len == PROC_PIDWORKQUEUEINFO_SIZE) { + if (strcmp(v->name, "wql") == 0) { + char *s; + switch (wqinfo.pwq_state & (WQ_EXCEEDED_CONSTRAINED_THREAD_LIMIT | WQ_EXCEEDED_TOTAL_THREAD_LIMIT)) { + case 0: + s = "-"; + break; + case WQ_EXCEEDED_CONSTRAINED_THREAD_LIMIT: + s = "C"; + break; + case WQ_EXCEEDED_TOTAL_THREAD_LIMIT: + s = "T"; + break; + default: + s = "CT"; + break; + } + printf("%*s", v->width, s); + return; + } + if (strcmp(v->name, "wqr") == 0) + nthreads = wqinfo.pwq_runthreads; + else if (strcmp(v->name, "wqb") == 0) + nthreads = wqinfo.pwq_blockedthreads; + else + nthreads = wqinfo.pwq_nthreads; + printf("%*d", v->width, nthreads); + } else + printf("%*s", v->width, "-"); +} diff --git a/adv_cmds/ps/ps.1 b/adv_cmds/ps/ps.1 new file mode 100644 index 0000000..20eed1c --- /dev/null +++ b/adv_cmds/ps/ps.1 @@ -0,0 +1,663 @@ +.\"- +.\" Copyright (c) 1980, 1990, 1991, 1993, 1994 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)ps.1 8.3 (Berkeley) 4/18/94 +.\" $FreeBSD: src/bin/ps/ps.1,v 1.86 2005/04/29 11:10:27 maxim Exp $ +.\" +.Dd March 20, 2005 +.Dt PS 1 +.Os +.Sh NAME +.Nm ps +.Nd process status +.Sh SYNOPSIS +.Nm +.Op Fl AaCcEefhjlMmrSTvwXx +.Op Fl O Ar fmt | Fl o Ar fmt +.Op Fl G Ar gid Ns Op , Ns Ar gid Ns Ar ... +.Op Fl g Ar grp Ns Op , Ns Ar grp Ns Ar ... +.Op Fl u Ar uid Ns Op , Ns Ar uid Ns Ar ... +.Op Fl p Ar pid Ns Op , Ns Ar pid Ns Ar ... +.Op Fl t Ar tty Ns Op , Ns Ar tty Ns Ar ... +.Op Fl U Ar user Ns Op , Ns Ar user Ns Ar ... +.Nm +.Op Fl L +.Sh DESCRIPTION +The +.Nm +utility +displays a header line, followed by lines containing information about +all of your +processes that have controlling terminals. +.Pp +A different set of processes can be selected for display by using any +combination of the +.Fl a , G , g , p , T , t , U , +and +.Fl u +options. +If more than one of these options are given, then +.Nm +will select all processes which are matched by at least one of the +given options. +.Pp +For the processes which have been selected for display, +.Nm +will usually display one line per process. +The +.Fl M +option may result in multiple output lines (one line per thread) for +some processes. +By default all of these output lines are sorted first by controlling +terminal, then by process ID. +The +.Fl m , r , +and +.Fl v +options will change the sort order. +If more than one sorting option was given, then the selected processes +will be sorted by the last sorting option which was specified. +.Pp +For the processes which have been selected for display, the information +to display is selected based on a set of keywords (see the +.Fl L , O , +and +.Fl o +options). +The default output format includes, for each process, the process' ID, +controlling terminal, CPU time (including both user and system time), +state, and associated command. +.Pp +The options are as follows: +.Bl -tag -width indent +.It Fl A +Display information about other users' processes, +including those without controlling terminals. +.It Fl a +Display information about other users' processes as well as your own. +This will skip any processes which do not have a controlling terminal, +unless the +.Fl x +option is also specified. +.It Fl C +Change the way the CPU percentage is calculated by using a +.Dq raw +CPU calculation that ignores +.Dq resident +time (this normally has +no effect). +.It Fl c +Change the +.Dq command +column output to just contain the executable name, +rather than the full command line. +.It Fl d +Like +.Fl A , +but excludes session leaders. +.It Fl E +Display the environment as well. +This does not reflect changes in the environment after process launch. +.It Fl e +Identical to +.Fl A . +.It Fl f +Display the uid, pid, parent pid, recent CPU usage, process start time, +controlling tty, elapsed CPU usage, and the associated command. +If the +.Fl u +option is also used, display the user name rather then the numeric uid. +When +.Fl o +or +.Fl O +is used to add to the display following +.Fl f , +the command field is not truncated as severely as it is in other formats. +.It Fl G +Display information about processes +which are running with the specified real group IDs. +.It Fl g +Display information about processes with the specified +process group leaders. +.It Fl h +Repeat the information header as often as necessary +to guarantee one header per page of information. +.It Fl j +Print information associated with the following keywords: +.Cm user , pid , ppid , pgid , sess , jobc , state , tt , time , +and +.Cm command . +.It Fl L +List the set of keywords available for the +.Fl O +and +.Fl o +options. +.It Fl l +Display information associated with the following keywords: +.Cm uid , pid , ppid , flags , cpu , pri , nice , vsz=SZ , rss , +.Cm wchan , state=S , paddr=ADDR , tty , time , +and +.Cm command=CMD . +.It Fl M +Print the threads corresponding to each task. +.It Fl m +Sort by memory usage, instead of the combination of controlling +terminal and process ID. +.It Fl O +Add the information associated with the space or comma separated list +of keywords specified, after the process ID, +in the default information +display. +Keywords may be appended with an equals +.Pq Ql = +sign and a string. +This causes the printed header to use the specified string instead of +the standard header. +.It Fl o +Display information associated with the space or comma separated +list of keywords specified. +Multiple keywords may also be given in the form of more than one +.Fl o +option. +Keywords may be appended with an equals +.Pq Ql = +sign and a string. +This causes the printed header to use the specified string instead of +the standard header. +If all keywords have empty header texts, no header line is written. +.It Fl p +Display information about processes which match the specified process IDs. +.It Fl r +Sort by current CPU usage, instead of the combination of controlling +terminal and process ID. +.It Fl S +Change the way the process time is calculated by summing all exited +children to their parent process. +.It Fl T +Display information about processes attached to the device associated +with the standard input. +.It Fl t +Display information about processes attached to the specified terminal +devices. +.It Fl U +Display the processes belonging to the specified real user IDs. +.It Fl u +Display the processes belonging to the specified usernames. +.It Fl v +Display information associated with the following keywords: +.Cm pid , state , time , sl , re , pagein , vsz , rss , lim , tsiz , +.Cm %cpu , %mem , +and +.Cm command . +The +.Fl v +option implies the +.Fl m +option. +.It Fl w +Use 132 columns to display information, instead of the default which +is your window size. +If the +.Fl w +option is specified more than once, +.Nm +will use as many columns as necessary without regard for your window size. +When output is not to a terminal, an unlimited number of columns are +always used. +.It Fl X +When displaying processes matched by other options, skip any processes +which do not have a controlling terminal. +.It Fl x +When displaying processes matched by other options, include processes +which do not have a controlling terminal. +This is the opposite of the +.Fl X +option. +If both +.Fl X +and +.Fl x +are specified in the same command, then +.Nm +will use the one which was specified last. +.El +.Pp +A complete list of the available keywords is given below. +Some of these keywords are further specified as follows: +.Bl -tag -width lockname +.It Cm %cpu +The CPU utilization of the process; +this is a decaying average over up to a minute of previous (real) time. +Because the time base over which this is computed varies +(some processes may be very young), +it is possible for the sum of all +.Cm %cpu +fields to exceed 100%. +.It Cm %mem +The percentage of real memory used by this process. +.It Cm flags +The flags associated with the process as in +the include file +.In sys/proc.h : +.Bl -column P_STOPPED_SINGLE 0x4000000 +.It Dv "P_ADVLOCK" Ta No "0x00001 Process may hold a POSIX advisory lock" +.It Dv "P_CONTROLT" Ta No "0x00002 Has a controlling terminal" +.It Dv "P_LP64" Ta No "0x00004 Process is LP64" +.It Dv "P_NOCLDSTOP" Ta No "0x00008 No SIGCHLD when children stop" +.It Dv "P_PPWAIT" Ta No "0x00010 Parent is waiting for child to exec/exit" +.It Dv "P_PROFIL" Ta No "0x00020 Has started profiling" +.It Dv "P_SELECT" Ta No "0x00040 Selecting; wakeup/waiting danger" +.It Dv "P_CONTINUED" Ta No "0x00080 Process was stopped and continued" +.It Dv "P_SUGID" Ta No "0x00100 Had set id privileges since last exec" +.It Dv "P_SYSTEM" Ta No "0x00200 System proc: no sigs, stats or swapping" +.It Dv "P_TIMEOUT" Ta No "0x00400 Timing out during sleep" +.It Dv "P_TRACED" Ta No "0x00800 Debugged process being traced" +.It Dv "P_WAITED" Ta No "0x01000 Debugging process has waited for child" +.It Dv "P_WEXIT" Ta No "0x02000 Working on exiting" +.It Dv "P_EXEC" Ta No "0x04000 Process called exec" +.It Dv "P_OWEUPC" Ta No "0x08000 Owe process an addupc() call at next ast" +.It Dv "P_WAITING" Ta No "0x40000 Process has a wait() in progress" +.It Dv "P_KDEBUG" Ta No "0x80000 Kdebug tracing on for this process" +.El +.It Cm lim +The soft limit on memory used, specified via a call to +.Xr setrlimit 2 . +.It Cm lstart +The exact time the command started, using the +.Ql %c +format described in +.Xr strftime 3 . +.It Cm nice +The process scheduling increment (see +.Xr setpriority 2 ) . +.It Cm rss +the real memory (resident set) size of the process (in 1024 byte units). +.It Cm start +The time the command started. +If the command started less than 24 hours ago, the start time is +displayed using the +.Dq Li %l:ps.1p +format described in +.Xr strftime 3 . +If the command started less than 7 days ago, the start time is +displayed using the +.Dq Li %a6.15p +format. +Otherwise, the start time is displayed using the +.Dq Li %e%b%y +format. +.It Cm state +The state is given by a sequence of characters, for example, +.Dq Li RWNA . +The first character indicates the run state of the process: +.Pp +.Bl -tag -width indent -compact +.It Li I +Marks a process that is idle (sleeping for longer than about 20 seconds). +.It Li R +Marks a runnable process. +.It Li S +Marks a process that is sleeping for less than about 20 seconds. +.It Li T +Marks a stopped process. +.It Li U +Marks a process in uninterruptible wait. +.It Li Z +Marks a dead process (a +.Dq zombie ) . +.El +.Pp +Additional characters after these, if any, indicate additional state +information: +.Pp +.Bl -tag -width indent -compact +.It Li + +The process is in the foreground process group of its control terminal. +.It Li < +The process has raised CPU scheduling priority. +.It Li > +The process has specified a soft limit on memory requirements and is +currently exceeding that limit; such a process is (necessarily) not +swapped. +.It Li A +the process has asked for random page replacement +.Pf ( Dv VA_ANOM , +from +.Xr vadvise 2 , +for example, +.Xr lisp 1 +in a garbage collect). +.It Li E +The process is trying to exit. +.It Li L +The process has pages locked in core (for example, for raw +.Tn I/O ) . +.It Li N +The process has reduced CPU scheduling priority (see +.Xr setpriority 2 ) . +.It Li S +The process has asked for +.Tn FIFO +page replacement +.Pf ( Dv VA_SEQL , +from +.Xr vadvise 2 , +for example, a large image processing program using virtual memory to +sequentially address voluminous data). +.It Li s +The process is a session leader. +.It Li V +The process is suspended during a +.Xr vfork 2 . +.It Li W +The process is swapped out. +.It Li X +The process is being traced or debugged. +.El +.It Cm tt +An abbreviation for the pathname of the controlling terminal, if any. +The abbreviation consists of the three letters following +.Pa /dev/tty , +or, for the console, +.Dq Li con . +This is followed by a +.Ql - +if the process can no longer reach that +controlling terminal (i.e., it has been revoked). +.It Cm wchan +The event (an address in the system) on which a process waits. +When printed numerically, the initial part of the address is +trimmed off and the result is printed in hex, for example, 0x80324000 prints +as 324000. +.El +.Pp +When printing using the command keyword, a process that has exited and +has a parent that has not yet waited for the process (in other words, a zombie) +is listed as +.Dq Li <defunct> , +and a process which is blocked while trying +to exit is listed as +.Dq Li <exiting> . +If the arguments cannot be located (usually because it has not been set, as is +the case of system processes and/or kernel threads) the command name is printed +within square brackets. +The process can change the arguments shown with +.Xr setproctitle 3 . +Otherwise, +.Nm +makes an educated guess as to the file name and arguments given when the +process was created by examining memory or the swap area. +The method is inherently somewhat unreliable and in any event a process +is entitled to destroy this information. +The ucomm (accounting) keyword can, however, be depended on. +If the arguments are unavailable or do not agree with the ucomm keyword, +the value for the ucomm keyword is appended to the arguments in parentheses. +.Sh KEYWORDS +The following is a complete list of the available keywords and their +meanings. +Several of them have aliases (keywords which are synonyms). +.Pp +.Bl -tag -width ".Cm sigignore" -compact +.It Cm %cpu +percentage CPU usage (alias +.Cm pcpu ) +.It Cm %mem +percentage memory usage (alias +.Cm pmem ) +.It Cm acflag +accounting flag (alias +.Cm acflg ) +.It Cm args +command and arguments +.It Cm comm +command +.It Cm command +command and arguments +.It Cm cpu +short-term CPU usage factor (for scheduling) +.It Cm etime +elapsed running time +.It Cm flags +the process flags, in hexadecimal (alias +.Cm f ) +.It Cm gid +processes group id (alias +.Cm group ) +.It Cm inblk +total blocks read (alias +.Cm inblock ) +.It Cm jobc +job control count +.It Cm ktrace +tracing flags +.It Cm ktracep +tracing vnode +.It Cm lim +memoryuse limit +.It Cm logname +login name of user who started the session +.It Cm lstart +time started +.It Cm majflt +total page faults +.It Cm minflt +total page reclaims +.It Cm msgrcv +total messages received (reads from pipes/sockets) +.It Cm msgsnd +total messages sent (writes on pipes/sockets) +.It Cm nice +nice value (alias +.Cm ni ) +.It Cm nivcsw +total involuntary context switches +.It Cm nsigs +total signals taken (alias +.Cm nsignals ) +.It Cm nswap +total swaps in/out +.It Cm nvcsw +total voluntary context switches +.It Cm nwchan +wait channel (as an address) +.It Cm oublk +total blocks written (alias +.Cm oublock ) +.It Cm p_ru +resource usage (valid only for zombie) +.It Cm paddr +swap address +.It Cm pagein +pageins (same as majflt) +.It Cm pgid +process group number +.It Cm pid +process ID +.It Cm ppid +parent process ID +.It Cm pri +scheduling priority +.It Cm re +core residency time (in seconds; 127 = infinity) +.It Cm rgid +real group ID +.It Cm rss +resident set size +.It Cm ruid +real user ID +.It Cm ruser +user name (from ruid) +.It Cm sess +session ID +.It Cm sig +pending signals (alias +.Cm pending ) +.It Cm sigmask +blocked signals (alias +.Cm blocked ) +.It Cm sl +sleep time (in seconds; 127 = infinity) +.It Cm start +time started +.It Cm state +symbolic process state (alias +.Cm stat ) +.It Cm svgid +saved gid from a setgid executable +.It Cm svuid +saved UID from a setuid executable +.It Cm tdev +control terminal device number +.It Cm time +accumulated CPU time, user + system (alias +.Cm cputime ) +.It Cm tpgid +control terminal process group ID +.\".It Cm trss +.\"text resident set size (in Kbytes) +.It Cm tsess +control terminal session ID +.It Cm tsiz +text size (in Kbytes) +.It Cm tt +control terminal name (two letter abbreviation) +.It Cm tty +full name of control terminal +.It Cm ucomm +name to be used for accounting +.It Cm uid +effective user ID +.It Cm upr +scheduling priority on return from system call (alias +.Cm usrpri ) +.It Cm user +user name (from UID) +.It Cm utime +user CPU time (alias +.Cm putime ) +.It Cm vsz +virtual size in Kbytes (alias +.Cm vsize ) +.It Cm wchan +wait channel (as a symbolic name) +.It Cm wq +total number of workqueue threads +.It Cm wqb +number of blocked workqueue threads +.It Cm wqr +number of running workqueue threads +.It Cm wql +workqueue limit status (C = constrained thread limit, T = total thread limit) +.It Cm xstat +exit or stop status (valid only for stopped or zombie process) +.El +.Sh ENVIRONMENT +The following environment variables affect the execution of +.Nm : +.Bl -tag -width ".Ev COLUMNS" +.It Ev COLUMNS +If set, specifies the user's preferred output width in column positions. +By default, +.Nm +attempts to automatically determine the terminal width. +.El +.Sh FILES +.Bl -tag -width ".Pa /boot/kernel/kernel" -compact +.It Pa /dev +special files and device names +.It Pa /var/run/dev.db +/dev name database +.It Pa /var/db/kvm_kernel.db +system namelist database +.El +.Sh LEGACY DESCRIPTION +In legacy mode, +.Nm +functions as described above, with the following differences: +.Bl -tag -width indent +.It Fl e +Display the environment as well. Same as +.Fl E . +.It Fl g +Ignored for compatibility. Takes no argument. +.It Fl l +Display information associated with the following keywords: +.Cm uid , pid , ppid , cpu , pri , nice , vsz , rss , wchan , state , +.Cm tt, time , +and +.Cm command . +.It Fl u +Display information associated with the following keywords: +.Cm user , pid , %cpu , %mem , vsz , rss , tt , state , start , time , +and +.Cm command . +The +.Fl u +option implies the +.Fl r +option. +.El +.Pp +The biggest change is in the interpretation of the +.Fl u +option, +which now displays processes belonging to the specified username(s). +Thus, "ps -aux" will fail (unless you want to know about user "x"). +As a convenience, however, "ps aux" still works as it did in Tiger. +.Pp +For more information about legacy mode, see +.Xr compat 5 . +.Sh SEE ALSO +.Xr kill 1 , +.Xr w 1 , +.Xr kvm 3 , +.Xr strftime 3 , +.Xr sysctl 8 +.Sh STANDARDS +The +.Nm +utility supports the +.St -susv3 +standard. +.Sh HISTORY +The +.Nm +command appeared in +.At v4 . +.Sh BUGS +Since +.Nm +cannot run faster than the system and is run as any other scheduled +process, the information it displays can never be exact. +.Pp +The +.Nm +utility does not correctly display argument lists containing multibyte +characters. diff --git a/adv_cmds/ps/ps.c b/adv_cmds/ps/ps.c new file mode 100644 index 0000000..72c0242 --- /dev/null +++ b/adv_cmds/ps/ps.c @@ -0,0 +1,1373 @@ +/*- + * Copyright (c) 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ------+---------+---------+-------- + --------+---------+---------+---------* + * Copyright (c) 2004 - Garance Alistair Drosehn <gad@FreeBSD.org>. + * All rights reserved. + * + * Significant modifications made to bring `ps' options somewhat closer + * to the standard for `ps' as described in SingleUnixSpec-v3. + * ------+---------+---------+-------- + --------+---------+---------+---------* + */ + +#ifndef lint +static const char copyright[] = +"@(#) Copyright (c) 1990, 1993, 1994\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#if 0 +#ifndef lint +static char sccsid[] = "@(#)ps.c 8.4 (Berkeley) 4/2/94"; +#endif /* not lint */ +#endif + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD: src/bin/ps/ps.c,v 1.110 2005/02/09 17:37:38 ru Exp $"); + +#include <sys/param.h> +#ifdef __APPLE__ +#include <sys/time.h> +#endif /* __APPLE__ */ +#include <sys/proc.h> +#include <sys/user.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <sys/sysctl.h> +#include <sys/mount.h> +#include <sys/resourcevar.h> + +#include <ctype.h> +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <grp.h> +#ifndef __APPLE__ +#include <kvm.h> +#endif /* !__APPLE__ */ +#include <limits.h> +#include <locale.h> +#include <paths.h> +#include <pwd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "ps.h" + +#ifdef __APPLE__ +#include <get_compat.h> +#else /* !__APPLE__ */ +#define COMPAT_MODE(func, mode) (1) +#endif /* __APPLE__ */ + +#define W_SEP " \t" /* "Whitespace" list separators */ +#define T_SEP "," /* "Terminate-element" list separators */ + +#ifdef LAZY_PS +#define DEF_UREAD 0 +#define OPT_LAZY_f "f" +#else +#define DEF_UREAD 1 /* Always do the more-expensive read. */ +#define OPT_LAZY_f /* I.e., the `-f' option is not added. */ +#endif + +/* + * isdigit takes an `int', but expects values in the range of unsigned char. + * This wrapper ensures that values from a 'char' end up in the correct range. + */ +#define isdigitch(Anychar) isdigit((u_char)(Anychar)) + +int cflag; /* -c */ +int eval; /* Exit value */ +time_t now; /* Current time(3) value */ +int rawcpu; /* -C */ +int sumrusage; /* -S */ +int termwidth; /* Width of the screen (0 == infinity). */ +int totwidth; /* Calculated-width of requested variables. */ + +struct velisthead varlist = STAILQ_HEAD_INITIALIZER(varlist); + +#ifndef __APPLE__ +static int forceuread = DEF_UREAD; /* Do extra work to get u-area. */ +static kvm_t *kd; +#endif /* !__APPLE__ */ +static KINFO *kinfo; +static int needcomm; /* -o "command" */ +static int needenv; /* -e */ +static int needuser; /* -o "user" */ +static int optfatal; /* Fatal error parsing some list-option. */ + +static enum sort { DEFAULT, SORTMEM, SORTCPU } sortby = DEFAULT; + +struct listinfo; +typedef int addelem_rtn(struct listinfo *_inf, const char *_elem); + +struct listinfo { + int count; + int maxcount; + int elemsize; + addelem_rtn *addelem; + const char *lname; + union { + gid_t *gids; + pid_t *pids; + dev_t *ttys; + uid_t *uids; + void *ptr; + } l; +}; + +#ifndef __APPLE__ +static int check_procfs(void); +#endif /* !__APPLE__ */ +static int addelem_gid(struct listinfo *, const char *); +static int addelem_pid(struct listinfo *, const char *); +static int addelem_tty(struct listinfo *, const char *); +static int addelem_uid(struct listinfo *, const char *); +static void add_list(struct listinfo *, const char *); +static void dynsizevars(KINFO *); +static void *expand_list(struct listinfo *); +#ifndef __APPLE__ +static const char * + fmt(char **(*)(kvm_t *, const struct kinfo_proc *, int), + KINFO *, char *, int); +#endif /* !__APPLE__ */ +static void free_list(struct listinfo *); +static void init_list(struct listinfo *, addelem_rtn, int, const char *); +static char *kludge_oldps_options(const char *, char *, const char *, int *); +static int pscomp(const void *, const void *); +static void saveuser(KINFO *); +static void scanvars(void); +static void sizevars(void); +static void usage(int); + +/* 5842004: Fix -f option. */ +VAR *findvar(char *, int, char **); + +/* p_ == POSIX/SUSv3/UNIX2003 format */ +static char dfmt[] = "pid,tt,state,time,command"; +static char jfmt[] = "user,pid,ppid,pgid,sess,jobc,state,tt,time,command"; +static char lfmt[] = "uid,pid,ppid,cpu,pri,nice,vsz,rss,wchan,state," + "tt,time,command"; +static char o1[] = "pid"; +static char o2[] = "tt,state,time,command"; +static char ufmt[] = "user,pid,%cpu,%mem,vsz,rss,tt,state,start,time,command"; +static char vfmt[] = "pid,state,time,sl,re,pagein,vsz,rss,lim,tsiz," + "%cpu,%mem,command"; +#ifndef __APPLE__ +static char Zfmt[] = "label"; +#endif /* !__APPLE__ */ +char p_dfmt[] = "pid tty time command=CMD"; +char p_ffmt[] = "uid pid ppid cpu=C start=STIME tty time command=CMD"; +char p_uffmt[] = "user pid ppid cpu=C start=STIME tty time command=CMD"; +char p_lfmt[] = "uid pid ppid flags cpu pri nice vsz=SZ rss wchan state=S paddr=ADDR tty time command=CMD"; +char mfmt[] = "user pid tt %cpu state pri stime utime command"; + +int eflg = 0; +int mflg = 0; /* if -M option to display all mach threads */ +int print_thread_num = 0; +int print_all_thread = 0; + +#define PS_ARGS (u03 ? "aACcdeEfg:G:hjLlMmO:o:p:rSTt:U:u:vwx" : \ + "aACcdeEgG:hjLlMmO:o:p:rSTt:U:uvwx") + +int +main(int argc, char *argv[]) +{ + struct listinfo gidlist, pgrplist, pidlist; + struct listinfo ruidlist, sesslist, ttylist, uidlist; + struct kinfo_proc *kp; + KINFO *next_KINFO; + struct varent *vent; + struct winsize ws; +#ifndef __APPLE__ + const char *nlistf, *memf; +#endif /* !__APPLE__ */ + char *cols; + int all, ch, elem, flag, _fmt, i, lineno; + int nentries, nkept, nselectors; + int prtheader, showthreads, wflag, what, xkeep, xkeep_implied; +#ifndef __APPLE__ + char errbuf[_POSIX2_LINE_MAX]; +#endif /* !__APPLE__ */ + struct kinfo_proc *kprocbuf; + int j; + int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 }; + size_t bufSize = 0; + size_t orig_bufSize = 0; + int local_error=0; + int retry_count = 0; + int u03 = COMPAT_MODE("bin/ps", "unix2003"); +#ifdef __APPLE__ + int dflag = 0; +#endif /* __APPLE__ */ + + (void) setlocale(LC_ALL, ""); + time(&now); /* Used by routines in print.c. */ + + if ((cols = getenv("COLUMNS")) != NULL && *cols != '\0') + termwidth = atoi(cols); + else if ((ioctl(STDOUT_FILENO, TIOCGWINSZ, (char *)&ws) == -1 && + ioctl(STDERR_FILENO, TIOCGWINSZ, (char *)&ws) == -1 && + ioctl(STDIN_FILENO, TIOCGWINSZ, (char *)&ws) == -1) || + ws.ws_col == 0) + termwidth = 79; + else + termwidth = ws.ws_col - 1; + + /* + * Hide a number of option-processing kludges in a separate routine, + * to support some historical BSD behaviors, such as `ps axu'. + */ + if (argc > 1) + argv[1] = kludge_oldps_options(PS_ARGS, argv[1], argv[2], &u03); + + all = _fmt = nselectors = optfatal = 0; + prtheader = showthreads = wflag = xkeep_implied = 0; + xkeep = -1; /* Neither -x nor -X. */ + init_list(&gidlist, addelem_gid, sizeof(gid_t), "group"); + init_list(&pgrplist, addelem_pid, sizeof(pid_t), "process group"); + init_list(&pidlist, addelem_pid, sizeof(pid_t), "process id"); + init_list(&ruidlist, addelem_uid, sizeof(uid_t), "ruser"); + init_list(&sesslist, addelem_pid, sizeof(pid_t), "session id"); + init_list(&ttylist, addelem_tty, sizeof(dev_t), "tty"); + init_list(&uidlist, addelem_uid, sizeof(uid_t), "user"); +#ifndef __APPLE__ + memf = nlistf = _PATH_DEVNULL; +#endif /* !__APPLE__ */ + while ((ch = getopt(argc, argv, PS_ARGS)) != -1) + switch ((char)ch) { +#ifdef __APPLE__ + case 'd': + dflag = 1; +#endif /* __APPLE__ */ + case 'A': + /* + * Exactly the same as `-ax'. This has been + * added for compatability with SUSv3, but for + * now it will not be described in the man page. + */ + nselectors++; + all = xkeep = 1; + break; + case 'a': + nselectors++; + all = 1; + break; + case 'C': + rawcpu = 1; + break; + case 'c': + cflag = 1; + break; + case 'e': /* XXX set ufmt */ + if (u03) { + nselectors++; + all = xkeep = 1; + break; + } + case 'E': + needenv = 1; + eflg = 1; + break; +#ifdef LAZY_PS + case 'f': + if (getuid() == 0 || getgid() == 0) + forceuread = 1; + break; +#endif + case 'f': + termwidth = UNLIMITED; /* 4990408 */ + if (u03 && uidlist.count == 0) { + parsefmt(p_ffmt, 0); + /* This is a unplesent little trick that makes + ./ps -f -p PID -o pid,comm,args + print out the whole command even if they slap + more fields on after it and gobble up too much + space */ + VAR *v = findvar("command", 0, NULL); + if (v) { + v->width = 64; + } + } else { + parsefmt(p_uffmt, 0); + } + _fmt = 1; + break; + case 'G': + add_list(&gidlist, optarg); + xkeep_implied = 1; + nselectors++; + break; + case 'g': + /* The historical BSD-ish (from SunOS) behavior. */ + if (!u03) break; + + add_list(&pgrplist, optarg); + xkeep_implied = 1; + nselectors++; + break; +#ifndef __APPLE__ + case 'H': + showthreads = KERN_PROC_INC_THREAD; + break; +#endif /* !__APPLE__ */ + case 'h': + prtheader = ws.ws_row > 5 ? ws.ws_row : 22; + break; + case 'j': + parsefmt(jfmt, 0); + _fmt = 1; + jfmt[0] = '\0'; + break; + case 'L': + showkey(); + exit(0); + case 'l': + parsefmt(u03 ? p_lfmt : lfmt, 0); + _fmt = 1; + lfmt[0] = '\0'; + break; + case 'M': +#ifndef __APPLE__ + memf = optarg; +#else + parsefmt(mfmt, 0); + _fmt = 1; + mfmt[0] = '\0'; + mflg = 1; +#endif /* 0 */ + break; + case 'm': + sortby = SORTMEM; + break; +#ifndef __APPLE__ + case 'N': + nlistf = optarg; + break; +#endif /* !__APPLE__ */ + case 'O': + parsefmt(o1, 1); + parsefmt(optarg, 1); + parsefmt(o2, 1); + o1[0] = o2[0] = '\0'; + _fmt = 1; + break; + case 'o': + parsefmt(optarg, 1); + _fmt = 1; + break; + case 'p': + add_list(&pidlist, optarg); + /* + * Note: `-p' does not *set* xkeep, but any values + * from pidlist are checked before xkeep is. That + * way they are always matched, even if the user + * specifies `-X'. + */ + nselectors++; + break; + case 'r': + sortby = SORTCPU; + break; + case 'S': + sumrusage = 1; + break; + case 'T': + if ((optarg = ttyname(STDIN_FILENO)) == NULL) + errx(1, "stdin: not a terminal"); + /* FALLTHROUGH */ + case 't': + add_list(&ttylist, optarg); + xkeep_implied = 1; + nselectors++; + break; + case 'U': + add_list(&ruidlist, optarg); + xkeep_implied = 1; + nselectors++; + break; + case 'u': + if (u03) { + /* This is what SUSv3 defines as the `-u' option. */ + add_list(&uidlist, optarg); + xkeep_implied = 1; + nselectors++; + break; + } + parsefmt(ufmt, 0); + sortby = SORTCPU; + _fmt = 1; + ufmt[0] = '\0'; + break; + case 'v': + parsefmt(vfmt, 0); + sortby = SORTMEM; + _fmt = 1; + vfmt[0] = '\0'; + break; + case 'w': + if (wflag) + termwidth = UNLIMITED; + else if (termwidth < 131) + termwidth = 131; + wflag++; + break; + case 'X': + /* + * Note that `-X' and `-x' are not standard "selector" + * options. For most selector-options, we check *all* + * processes to see if any are matched by the given + * value(s). After we have a set of all the matched + * processes, then `-X' and `-x' govern whether we + * modify that *matched* set for processes which do + * not have a controlling terminal. `-X' causes + * those processes to be deleted from the matched + * set, while `-x' causes them to be kept. + */ + xkeep = 0; + break; + case 'x': + xkeep = 1; + break; + case '?': + default: + usage(u03); + } + argc -= optind; + argv += optind; + +#ifdef __APPLE__ + /* 3862041 */ + if (!isatty(STDOUT_FILENO)) + termwidth = UNLIMITED; +#endif /* __APPLE__ */ + + /* + * If the user specified ps -e then they want a copy of the process + * environment kvm_getenvv(3) attempts to open /proc/<pid>/mem. + * Check to make sure that procfs is mounted on /proc, otherwise + * print a warning informing the user that output will be incomplete. + */ +#ifndef __APPLE__ + if (needenv == 1 && check_procfs() == 0) + warnx("Process environment requires procfs(5)"); +#endif /* !__APPLE__ */ + /* + * If there arguments after processing all the options, attempt + * to treat them as a list of process ids. + */ + while (*argv) { + if (!isdigitch(**argv)) + break; + add_list(&pidlist, *argv); + argv++; + } + if (*argv) { + fprintf(stderr, "%s: illegal argument: %s\n", + getprogname(), *argv); + usage(u03); + } + if (optfatal) + exit(1); /* Error messages already printed. */ + if (xkeep < 0) /* Neither -X nor -x was specified. */ + xkeep = xkeep_implied; + +#if FIXME + kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf); + if (kd == 0) + errx(1, "%s", errbuf); +#endif /* FIXME */ + + if (!_fmt) { + if (u03 && uidlist.count != 0) { + parsefmt("uid", 0); + } + parsefmt(u03 ? p_dfmt : dfmt, 0); + } + + if (nselectors == 0) { + uidlist.l.ptr = malloc(sizeof(uid_t)); + if (uidlist.l.ptr == NULL) + errx(1, "malloc failed"); + nselectors = 1; + uidlist.count = uidlist.maxcount = 1; + *uidlist.l.uids = getuid(); + } + + /* + * scan requested variables, noting what structures are needed, + * and adjusting header widths as appropriate. + */ + scanvars(); + + /* + * Get process list. If the user requested just one selector- + * option, then kvm_getprocs can be asked to return just those + * processes. Otherwise, have it return all processes, and + * then this routine will search that full list and select the + * processes which match any of the user's selector-options. + */ + what = KERN_PROC_ALL; + flag = 0; + if (nselectors == 1) { + if (gidlist.count == 1) { +#if 0 + what = KERN_PROC_RGID | showthreads; + flag = *gidlist.l.gids; + nselectors = 0; +#endif /* 0 */ + } else if (pgrplist.count == 1) { + what = KERN_PROC_PGRP | showthreads; + flag = *pgrplist.l.pids; + nselectors = 0; + } else if (pidlist.count == 1) { + what = KERN_PROC_PID | showthreads; + flag = *pidlist.l.pids; + nselectors = 0; + } else if (ruidlist.count == 1) { + what = KERN_PROC_RUID | showthreads; + flag = *ruidlist.l.uids; + nselectors = 0; + } else if (sesslist.count == 1) { + what = KERN_PROC_SESSION | showthreads; + flag = *sesslist.l.pids; + nselectors = 0; + } else if (ttylist.count == 1) { + what = KERN_PROC_TTY | showthreads; + flag = *ttylist.l.ttys; + nselectors = 0; + } else if (uidlist.count == 1) { + what = (xkeep ? KERN_PROC_RUID : KERN_PROC_UID) | showthreads; + flag = *uidlist.l.uids; + nselectors = 0; + } + } + + /* + * select procs + */ + nentries = -1; +#if FIXME + kp = kvm_getprocs(kd, what, flag, &nentries); + if ((kp == NULL && nentries > 0) || (kp != NULL && nentries < 0)) + errx(1, "%s", kvm_geterr(kd)); +#else /* FIXME */ + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = what; + mib[3] = flag; + + if (sysctl(mib, 4, NULL, &bufSize, NULL, 0) < 0) { + perror("Failure calling sysctl"); + return 0; + } + + kprocbuf= kp = (struct kinfo_proc *)malloc(bufSize); + + retry_count = 0; + orig_bufSize = bufSize; + for(retry_count=0; ; retry_count++) { + /* retry for transient errors due to load in the system */ + local_error = 0; + bufSize = orig_bufSize; + if ((local_error = sysctl(mib, 4, kp, &bufSize, NULL, 0)) < 0) { + if (retry_count < 1000) { + /* 1 sec back off */ + sleep(1); + continue; + } + perror("Failure calling sysctl"); + return 0; + } else if (local_error == 0) { + break; + } + /* 1 sec back off */ + sleep(1); + } + + /* This has to be after the second sysctl since the bufSize + may have changed. */ + nentries = bufSize / sizeof(struct kinfo_proc); +#endif /* FIXME */ + nkept = 0; + if (nentries > 0) { + if ((kinfo = calloc(nentries, sizeof(*kinfo))) == NULL) + errx(1, "malloc failed"); + for (i = nentries; --i >= 0; ++kp) { +#ifdef __APPLE__ + if (kp->kp_proc.p_pid == 0) { + continue; + } +#endif /* __APPLE__ */ + +#ifdef __APPLE__ + if (dflag && (kp->kp_proc.p_pid == kp->kp_eproc.e_pgid)) + continue; +#endif /* __APPLE__ */ + + /* + * If the user specified multiple selection-criteria, + * then keep any process matched by the inclusive OR + * of all the selection-criteria given. + */ + if (pidlist.count > 0) { + for (elem = 0; elem < pidlist.count; elem++) + if (kp->kp_proc.p_pid == pidlist.l.pids[elem]) + goto keepit; + } + /* + * Note that we had to process pidlist before + * filtering out processes which do not have + * a controlling terminal. + */ + if (xkeep == 0) { + if ((kp->kp_eproc.e_tdev == NODEV || + (kp->kp_proc.p_flag & P_CONTROLT) == 0)) + continue; + } + if (all || nselectors == 0) + goto keepit; + if (gidlist.count > 0) { + for (elem = 0; elem < gidlist.count; elem++) + if (kp->kp_eproc.e_pcred.p_rgid == gidlist.l.gids[elem]) + goto keepit; + } + if (pgrplist.count > 0) { + for (elem = 0; elem < pgrplist.count; elem++) + if (kp->kp_eproc.e_pgid == + pgrplist.l.pids[elem]) + goto keepit; + } + if (ruidlist.count > 0) { + for (elem = 0; elem < ruidlist.count; elem++) + if (kp->kp_eproc.e_pcred.p_ruid == + ruidlist.l.uids[elem]) + goto keepit; + } +#if 0 + if (sesslist.count > 0) { + for (elem = 0; elem < sesslist.count; elem++) + if (kp->ki_sid == sesslist.l.pids[elem]) + goto keepit; + } +#endif + if (ttylist.count > 0) { + for (elem = 0; elem < ttylist.count; elem++) + if (kp->kp_eproc.e_tdev == ttylist.l.ttys[elem]) + goto keepit; + } + if (uidlist.count > 0) { + for (elem = 0; elem < uidlist.count; elem++) + if (kp->kp_eproc.e_ucred.cr_uid == uidlist.l.uids[elem]) + goto keepit; + } + /* + * This process did not match any of the user's + * selector-options, so skip the process. + */ + continue; + + keepit: + next_KINFO = &kinfo[nkept]; + next_KINFO->ki_p = kp; + get_task_info(next_KINFO); +#ifndef __APPLE__ + next_KINFO->ki_pcpu = getpcpu(next_KINFO); + if (sortby == SORTMEM) + next_KINFO->ki_memsize = kp->ki_tsize + + kp->ki_dsize + kp->ki_ssize; +#endif /* !__APPLE__ */ + if (needuser) + saveuser(next_KINFO); + dynsizevars(next_KINFO); + nkept++; + } + } + + sizevars(); + + /* + * print header + */ + printheader(); + if (nkept == 0) + exit(1); + + /* + * sort proc list + */ + qsort(kinfo, nkept, sizeof(KINFO), pscomp); + /* + * For each process, call each variable output function. + */ + for (i = lineno = 0; i < nkept; i++) { + if(mflg) { + print_all_thread = 1; + for(j=0; j < kinfo[i].thread_count; j++) { + print_thread_num = j; + STAILQ_FOREACH(vent, &varlist, next_ve) { + (vent->var->oproc)(&kinfo[i], vent); + if (STAILQ_NEXT(vent, next_ve) != NULL) + (void)putchar(' '); + } + + (void)putchar('\n'); + if (prtheader && lineno++ == prtheader - 4) { + (void)putchar('\n'); + printheader(); + lineno = 0; + } + } + print_all_thread = 0; + } else { + STAILQ_FOREACH(vent, &varlist, next_ve) { + (vent->var->oproc)(&kinfo[i], vent); + if (STAILQ_NEXT(vent, next_ve) != NULL) + (void)putchar(' '); + } + + (void)putchar('\n'); + if (prtheader && lineno++ == prtheader - 4) { + (void)putchar('\n'); + printheader(); + lineno = 0; + } + } + } + for (i = 0; i < nkept; i++) { + if (kinfo[i].invalid_tinfo == 0 && kinfo[i].thread_count) + free(kinfo[i].thval); + } + free(kprocbuf); + free(kinfo); + free_list(&gidlist); + free_list(&pidlist); + free_list(&pgrplist); + free_list(&ruidlist); + free_list(&sesslist); + free_list(&ttylist); + free_list(&uidlist); + + exit(eval); +} + +static int +addelem_gid(struct listinfo *inf, const char *elem) +{ + struct group *grp; + const char *nameorID; + char *endp; + u_long bigtemp; + + if (*elem == '\0' || strlen(elem) >= MAXLOGNAME) { + if (*elem == '\0') + warnx("Invalid (zero-length) %s name", inf->lname); + else + warnx("%s name too long: %s", inf->lname, elem); + optfatal = 1; + return (0); /* Do not add this value. */ + } + + /* + * SUSv3 states that `ps -G grouplist' should match "real-group + * ID numbers", and does not mention group-names. I do want to + * also support group-names, so this tries for a group-id first, + * and only tries for a name if that doesn't work. This is the + * opposite order of what is done in addelem_uid(), but in + * practice the order would only matter for group-names which + * are all-numeric. + */ + grp = NULL; + nameorID = "named"; + errno = 0; + bigtemp = strtoul(elem, &endp, 10); + if (errno == 0 && *endp == '\0' && bigtemp <= GID_MAX) { + nameorID = "name or ID matches"; + grp = getgrgid((gid_t)bigtemp); + } + if (grp == NULL) + grp = getgrnam(elem); + if (grp == NULL) { + warnx("No %s %s '%s'", inf->lname, nameorID, elem); + optfatal = 1; + return (0); + } + if (inf->count >= inf->maxcount) + expand_list(inf); + inf->l.gids[(inf->count)++] = grp->gr_gid; + return (1); +} + +#define BSD_PID_MAX 99999 /* Copy of PID_MAX from sys/proc.h. */ +static int +addelem_pid(struct listinfo *inf, const char *elem) +{ + char *endp; + long tempid; + + if (*elem == '\0') { + warnx("Invalid (zero-length) process id"); + optfatal = 1; + return (0); /* Do not add this value. */ + } + + errno = 0; + tempid = strtol(elem, &endp, 10); + if (*endp != '\0' || tempid < 0 || elem == endp) { + warnx("Invalid %s: %s", inf->lname, elem); + errno = ERANGE; + } else if (errno != 0 || tempid > BSD_PID_MAX) { + warnx("%s too large: %s", inf->lname, elem); + errno = ERANGE; + } + if (errno == ERANGE) { + optfatal = 1; + return (0); + } + if (inf->count >= inf->maxcount) + expand_list(inf); + inf->l.pids[(inf->count)++] = tempid; + return (1); +} +#undef BSD_PID_MAX + +/*- + * The user can specify a device via one of three formats: + * 1) fully qualified, e.g.: /dev/ttyp0 /dev/console + * 2) missing "/dev", e.g.: ttyp0 console + * 3) two-letters, e.g.: p0 co + * (matching letters that would be seen in the "TT" column) + */ +static int +addelem_tty(struct listinfo *inf, const char *elem) +{ + const char *ttypath; + struct stat sb; + char pathbuf[PATH_MAX], pathbuf2[PATH_MAX]; + + ttypath = NULL; + pathbuf2[0] = '\0'; + switch (*elem) { + case '/': + ttypath = elem; + break; + case 'c': + if (strcmp(elem, "co") == 0) { + ttypath = _PATH_CONSOLE; + break; + } + /* FALLTHROUGH */ + default: + strlcpy(pathbuf, _PATH_DEV, sizeof(pathbuf)); + strlcat(pathbuf, elem, sizeof(pathbuf)); + ttypath = pathbuf; + if (strncmp(pathbuf, _PATH_TTY, strlen(_PATH_TTY)) == 0) + break; + if (strcmp(pathbuf, _PATH_CONSOLE) == 0) + break; + /* Check to see if /dev/tty${elem} exists */ + strlcpy(pathbuf2, _PATH_TTY, sizeof(pathbuf2)); + strlcat(pathbuf2, elem, sizeof(pathbuf2)); + if (stat(pathbuf2, &sb) == 0 && S_ISCHR(sb.st_mode)) { + /* No need to repeat stat() && S_ISCHR() checks */ + ttypath = NULL; + break; + } + break; + } + if (ttypath) { +#ifdef __APPLE__ + if (access(ttypath, F_OK) == -1 || stat(ttypath, &sb) == -1) { +#else + if (stat(ttypath, &sb) == -1) { +#endif + if (pathbuf2[0] != '\0') + warn("%s and %s", pathbuf2, ttypath); + else + warn("%s", ttypath); + optfatal = 1; + return (0); + } + if (!S_ISCHR(sb.st_mode)) { + if (pathbuf2[0] != '\0') + warnx("%s and %s: Not a terminal", pathbuf2, + ttypath); + else + warnx("%s: Not a terminal", ttypath); + optfatal = 1; + return (0); + } + } + if (inf->count >= inf->maxcount) + expand_list(inf); + inf->l.ttys[(inf->count)++] = sb.st_rdev; + return (1); +} + +static int +addelem_uid(struct listinfo *inf, const char *elem) +{ + struct passwd *pwd; + char *endp; + u_long bigtemp; + + if (*elem == '\0' || strlen(elem) >= MAXLOGNAME) { + if (*elem == '\0') + warnx("Invalid (zero-length) %s name", inf->lname); + else + warnx("%s name too long: %s", inf->lname, elem); + optfatal = 1; + return (0); /* Do not add this value. */ + } + + pwd = getpwnam(elem); + if (pwd == NULL) { + errno = 0; + bigtemp = strtoul(elem, &endp, 10); + if (errno != 0 || *endp != '\0' || bigtemp > UID_MAX) + warnx("No %s named '%s'", inf->lname, elem); + else { + /* The string is all digits, so it might be a userID. */ + pwd = getpwuid((uid_t)bigtemp); + if (pwd == NULL) + warnx("No %s name or ID matches '%s'", + inf->lname, elem); + } + } + if (pwd == NULL) { + /* + * These used to be treated as minor warnings (and the + * option was simply ignored), but now they are fatal + * errors (and the command will be aborted). + */ + optfatal = 1; + return (0); + } + if (inf->count >= inf->maxcount) + expand_list(inf); + inf->l.uids[(inf->count)++] = pwd->pw_uid; + return (1); +} + +static void +add_list(struct listinfo *inf, const char *argp) +{ + const char *savep; + char *cp, *endp; + int toolong; + char elemcopy[PATH_MAX]; + + if (*argp == 0) + inf->addelem(inf, elemcopy); + while (*argp != '\0') { + while (*argp != '\0' && strchr(W_SEP, *argp) != NULL) + argp++; + savep = argp; + toolong = 0; + cp = elemcopy; + if (strchr(T_SEP, *argp) == NULL) { + endp = elemcopy + sizeof(elemcopy) - 1; + while (*argp != '\0' && cp <= endp && + strchr(W_SEP T_SEP, *argp) == NULL) + *cp++ = *argp++; + if (cp > endp) + toolong = 1; + } + if (!toolong) { + *cp = '\0'; + /* + * Add this single element to the given list. + */ + inf->addelem(inf, elemcopy); + } else { + /* + * The string is too long to copy. Find the end + * of the string to print out the warning message. + */ + while (*argp != '\0' && strchr(W_SEP T_SEP, + *argp) == NULL) + argp++; + warnx("Value too long: %.*s", (int)(argp - savep), + savep); + optfatal = 1; + } + /* + * Skip over any number of trailing whitespace characters, + * but only one (at most) trailing element-terminating + * character. + */ + while (*argp != '\0' && strchr(W_SEP, *argp) != NULL) + argp++; + if (*argp != '\0' && strchr(T_SEP, *argp) != NULL) { + argp++; +#if 0 + /* Catch case where string ended with a comma. */ + if (*argp == '\0') + inf->addelem(inf, argp); +#endif /* 0 */ + } + } +} + +static void * +expand_list(struct listinfo *inf) +{ + void *newlist; + int newmax; + + newmax = (inf->maxcount + 1) << 1; + newlist = realloc(inf->l.ptr, newmax * inf->elemsize); + if (newlist == NULL) { + free(inf->l.ptr); + errx(1, "realloc to %d %ss failed", newmax, inf->lname); + } + inf->maxcount = newmax; + inf->l.ptr = newlist; + + return (newlist); +} + +static void +free_list(struct listinfo *inf) +{ + + inf->count = inf->elemsize = inf->maxcount = 0; + if (inf->l.ptr != NULL) + free(inf->l.ptr); + inf->addelem = NULL; + inf->lname = NULL; + inf->l.ptr = NULL; +} + +static void +init_list(struct listinfo *inf, addelem_rtn artn, int elemsize, + const char *lname) +{ + + inf->count = inf->maxcount = 0; + inf->elemsize = elemsize; + inf->addelem = artn; + inf->lname = lname; + inf->l.ptr = NULL; +} + +VARENT * +find_varentry(VAR *v) +{ + struct varent *vent; + + STAILQ_FOREACH(vent, &varlist, next_ve) { + if (strcmp(vent->var->name, v->name) == 0) + return vent; + } + return NULL; +} + +static void +scanvars(void) +{ + struct varent *vent; + VAR *v; + + STAILQ_FOREACH(vent, &varlist, next_ve) { + v = vent->var; + if (v->flag & DSIZ) { + v->dwidth = v->width; + v->width = 0; + } + if (v->flag & USER) + needuser = 1; + if (v->flag & COMM) + needcomm = 1; + } +} + +static void +dynsizevars(KINFO *ki) +{ + struct varent *vent; + VAR *v; + int i; + + STAILQ_FOREACH(vent, &varlist, next_ve) { + v = vent->var; + if (!(v->flag & DSIZ)) + continue; + i = (v->sproc)( ki); + if (v->width < i) + v->width = i; + if (v->width > v->dwidth) + v->width = v->dwidth; + } +} + +static void +sizevars(void) +{ + struct varent *vent; + VAR *v; + int i; + + STAILQ_FOREACH(vent, &varlist, next_ve) { + v = vent->var; + i = strlen(vent->header); + if (v->width < i) + v->width = i; + totwidth += v->width + 1; /* +1 for space */ + } + totwidth--; +} + +#ifndef __APPLE__ +static const char * +fmt(char **(*fn)(kvm_t *, const struct kinfo_proc *, int), KINFO *ki, + char *comm, int maxlen) +{ + const char *s; + + s = fmt_argv((*fn)(kd, ki->ki_p, termwidth), comm, maxlen); + return (s); +} +#endif /* !__APPLE__ */ + +#define UREADOK(ki) (forceuread || (KI_PROC(ki)->p_flag & P_INMEM)) + +static void +saveuser(KINFO *ki) +{ + struct usave *usp; +#if FIXME + struct user *u_addr = (struct user *)USRSTACK; +#endif /* FIXME */ + + usp = &ki->ki_u; +#if FIXME + if (UREADOK(ki) && kvm_uread(kd, KI_PROC(ki), (unsigned long)&u_addr->u_stats, + (char *)&pstats, sizeof(pstats)) == sizeof(pstats)) + { + /* + * The u-area might be swapped out, and we can't get + * at it because we have a crashdump and no swap. + * If it's here fill in these fields, otherwise, just + * leave them 0. + */ + usp->u_start = pstats.p_start; + usp->u_ru = pstats.p_ru; + usp->u_cru = pstats.p_cru; + usp->u_valid = 1; + } else + usp->u_valid = 0; +#else /* FIXME */ + usp->u_valid = 0; +#endif /* FIXME */ + /* + * save arguments if needed + */ +#if FIXME + if (needcomm && UREADOK(ki)) { + ki->ki_args = fmt(kvm_getargv, ki, KI_PROC(ki)->p_comm, + MAXCOMLEN); + } else if (needcomm) { + ki->ki_args = malloc(strlen(KI_PROC(ki)->p_comm) + 3); + sprintf(ki->ki_args, "(%s)", KI_PROC(ki)->p_comm); + } else { + ki->ki_args = NULL; + } +#else /* FIXME */ + ki->ki_args = malloc(strlen(KI_PROC(ki)->p_comm) + 3); + sprintf(ki->ki_args, "%s", KI_PROC(ki)->p_comm); + //ki->ki_args = malloc(10); + //strcpy(ki->ki_args, "()"); +#endif /* FIXME */ +#if FIXME + if (needenv && UREADOK(ki)) { + ki->ki_env = fmt(kvm_getenvv, ki, (char *)NULL, 0); + } else if (needenv) { + ki->ki_env = malloc(3); + strcpy(ki->ki_env, "()"); + } else { + ki->ki_env = NULL; + } +#else /* FIXME */ + ki->ki_env = malloc(10); + strcpy(ki->ki_env, ""); +#endif /* FIXME */ +} + +static int +pscomp(const void *a, const void *b) +{ + int i; +#if FIXME +#define VSIZE(k) (KI_EPROC(k)->e_vm.vm_dsize + KI_EPROC(k)->e_vm.vm_ssize + \ + KI_EPROC(k)->e_vm.vm_tsize) +#else /* FIXME */ +#define VSIZE(k) ((k)->tasks_info.resident_size) + +#endif /* FIXME */ + + if (sortby == SORTCPU) + return (getpcpu((KINFO *)b) - getpcpu((KINFO *)a)); + if (sortby == SORTMEM) + return (VSIZE((KINFO *)b) - VSIZE((KINFO *)a)); + i = KI_EPROC((KINFO *)a)->e_tdev - KI_EPROC((KINFO *)b)->e_tdev; + if (i == 0) + i = KI_PROC((KINFO *)a)->p_pid - KI_PROC((KINFO *)b)->p_pid; + return (i); +} + +/* + * ICK (all for getopt), would rather hide the ugliness + * here than taint the main code. + * + * ps foo -> ps -foo + * ps 34 -> ps -p34 + * + * The old convention that 't' with no trailing tty arg means the users + * tty, is only supported if argv[1] doesn't begin with a '-'. This same + * feature is available with the option 'T', which takes no argument. + */ +static char * +kludge_oldps_options(const char *optlist, char *origval, const char *nextarg, int *u03) +{ + size_t len; + char *argp, *cp, *newopts, *ns, *optp, *pidp; + + /* + * See if the original value includes any option which takes an + * argument (and will thus use up the remainder of the string). + */ + argp = NULL; + if (optlist != NULL) { + for (cp = origval; *cp != '\0'; cp++) { + optp = strchr(optlist, *cp); + if ((optp != NULL) && *(optp + 1) == ':') { + argp = cp; + break; + } + } + } + if (argp != NULL && *origval == '-') + return (origval); + + /* + * if last letter is a 't' flag with no argument (in the context + * of the oldps options -- option string NOT starting with a '-' -- + * then convert to 'T' (meaning *this* terminal, i.e. ttyname(0)). + * + * However, if a flag accepting a string argument is found earlier + * in the option string (including a possible `t' flag), then the + * remainder of the string must be the argument to that flag; so + * do not modify that argument. Note that a trailing `t' would + * cause argp to be set, if argp was not already set by some + * earlier option. + */ + len = strlen(origval); + cp = origval + len - 1; + pidp = NULL; + if (*cp == 't' && *origval != '-' && cp == argp) { + if (nextarg == NULL || *nextarg == '-' || isdigitch(*nextarg)) + *cp = 'T'; + } else if (argp == NULL) { + /* + * The original value did not include any option which takes + * an argument (and that would include `p' and `t'), so check + * the value for trailing number, or comma-separated list of + * numbers, which we will treat as a pid request. + */ + if (isdigitch(*cp)) { + while (cp >= origval && (*cp == ',' || isdigitch(*cp))) + --cp; + pidp = cp + 1; + } + } + + /* + * If nothing needs to be added to the string, then return + * the "original" (although possibly modified) value. + */ + if (*origval == '-' && pidp == NULL) + return (origval); + + /* + * Create a copy of the string to add '-' and/or 'p' to the + * original value. + */ + if ((newopts = ns = malloc(len + 3)) == NULL) + errx(1, "malloc failed"); + + if (*origval != '-') { + *ns++ = '-'; /* add option flag */ + *u03 = 0; + } + + if (pidp == NULL) + strcpy(ns, origval); + else { + /* + * Copy everything before the pid string, add the `p', + * and then copy the pid string. + */ + len = pidp - origval; + memcpy(ns, origval, len); + ns += len; + *ns++ = 'p'; + strcpy(ns, pidp); + } + + return (newopts); +} + +#ifndef __APPLE__ +static int +check_procfs(void) +{ + struct statfs mnt; + + if (statfs("/proc", &mnt) < 0) + return (0); + if (strcmp(mnt.f_fstypename, "procfs") != 0) + return (0); + return (1); +} +#endif /* !__APPLE__ */ + +static void +usage(int u03) +{ +#define SINGLE_OPTS "[-AaCcEefhjlMmrSTvwXx]" + + (void)fprintf(stderr, "%s\n%s\n%s\n%s\n", + "usage: ps " SINGLE_OPTS " [-O fmt | -o fmt] [-G gid[,gid...]]", + (u03 ? " [-g grp[,grp...]] [-u [uid,uid...]]" : " [-u]"), + " [-p pid[,pid...]] [-t tty[,tty...]] [-U user[,user...]]", + " ps [-L]"); + exit(1); +} diff --git a/adv_cmds/ps/ps.h b/adv_cmds/ps/ps.h new file mode 100644 index 0000000..a077eff --- /dev/null +++ b/adv_cmds/ps/ps.h @@ -0,0 +1,131 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ps.h 8.1 (Berkeley) 5/31/93 + * $FreeBSD: ps.h,v 1.6 1998/09/14 08:32:20 dfr Exp $ + */ + +#include <sys/queue.h> + +#include <mach/mach.h> +#include <mach/mach_error.h> +#include <mach/policy.h> +#include <mach/task_info.h> +#include <mach/thread_info.h> + +#define UNLIMITED 0 /* unlimited terminal width */ +enum type { CHAR, UCHAR, SHORT, USHORT, INT, UINT, LONG, ULONG, KPTR, PGTOK }; + +struct usave { + struct timeval u_start; + struct rusage u_ru; + struct rusage u_cru; + char u_acflag; + char u_valid; +}; + +#define KI_PROC(ki) (&(ki)->ki_p->kp_proc) +#define KI_EPROC(ki) (&(ki)->ki_p->kp_eproc) + +typedef struct thread_values { + struct thread_basic_info tb; + /* struct policy_infos schedinfo; */ + union { + struct policy_timeshare_info tshare; + struct policy_rr_info rr; + struct policy_fifo_info fifo; + } schedinfo; +} thread_values_t; + +typedef struct kinfo { + struct kinfo_proc *ki_p; /* kinfo_proc structure */ + struct usave ki_u; /* interesting parts of user */ + char *ki_args; /* exec args */ + char *ki_env; /* environment */ + task_port_t task; + int state; + int cpu_usage; + int curpri; + int basepri; + int swapped; + struct task_basic_info tasks_info; + struct task_thread_times_info times; + /* struct policy_infos schedinfo; */ + union { + struct policy_timeshare_info tshare; + struct policy_rr_info rr; + struct policy_fifo_info fifo; + } schedinfo; + int invalid_tinfo; + unsigned int thread_count; + thread_port_array_t thread_list; + thread_values_t *thval; + int invalid_thinfo; +} KINFO; + +/* Variables. */ +typedef struct varent { + STAILQ_ENTRY(varent) next_ve; + const char *header; + struct var *var; +} VARENT; + +typedef struct var { + const char *name; /* name(s) of variable */ + const char *header; /* default header */ + const char *alias; /* aliases */ +#define COMM 0x01 /* needs exec arguments and environment (XXX) */ +#define LJUST 0x02 /* left adjust on output (trailing blanks) */ +#define USER 0x04 /* needs user structure */ +#define DSIZ 0x08 /* field size is dynamic*/ +#define INF127 0x10 /* values >127 displayed as 127 */ + u_int flag; + /* output routine */ + void (*oproc)(struct kinfo *, struct varent *); + /* sizing routine*/ + int (*sproc)(struct kinfo *); + short width; /* printing width */ + /* + * The following (optional) elements are hooks for passing information + * to the generic output routine pvar (which prints simple elements + * from the well known kinfo_proc structure). + */ + size_t off; /* offset in structure */ + enum type type; /* type of element */ + const char *fmt; /* printf format */ + short dwidth; /* dynamic printing width */ + /* + * glue to link selected fields together + */ +} VAR; + +#include "extern.h" diff --git a/adv_cmds/ps/tasks.c b/adv_cmds/ps/tasks.c new file mode 100644 index 0000000..4548b56 --- /dev/null +++ b/adv_cmds/ps/tasks.c @@ -0,0 +1,246 @@ +#include <sys/param.h> +#include <sys/user.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <sys/sysctl.h> + +#include <ctype.h> +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <nlist.h> +#include <paths.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <locale.h> +#include <pwd.h> + +#include "ps.h" +#include <mach/shared_memory_server.h> + +extern kern_return_t task_for_pid(task_port_t task, pid_t pid, task_port_t *target); + +#define STATE_MAX 7 + +int +mach_state_order(s, sleep_time) +int s; +long sleep_time; +{ +switch (s) { +case TH_STATE_RUNNING: return(1); +case TH_STATE_UNINTERRUPTIBLE: + return(2); + case TH_STATE_WAITING: return((sleep_time > 20) ? 4 : 3); + case TH_STATE_STOPPED: return(5); + case TH_STATE_HALTED: return(6); + default: return(7); + } +} + /*01234567 */ +char mach_state_table[] = " RUSITH?"; + + +int +thread_schedinfo( + KINFO *ki, + thread_port_t thread, + policy_t pol, + void * buf) +{ + unsigned int count; + int ret = KERN_FAILURE; + + switch (pol) { + + case POLICY_TIMESHARE: + count = POLICY_TIMESHARE_INFO_COUNT; + ret = thread_info(thread, THREAD_SCHED_TIMESHARE_INFO, + (thread_info_t)buf, &count); + if((ret == KERN_SUCCESS) && (ki->curpri < (((struct policy_timeshare_info *)buf)->cur_priority))) + ki->curpri = ((struct policy_timeshare_info *)buf)->cur_priority; + break; + + case POLICY_FIFO: + count = POLICY_FIFO_INFO_COUNT; + ret = thread_info(thread, THREAD_SCHED_FIFO_INFO, + buf, &count); + if((ret == KERN_SUCCESS) && (ki->curpri < (((struct policy_fifo_info *)buf)->base_priority))) + ki->curpri = ((struct policy_fifo_info *)buf)->base_priority; + break; + + case POLICY_RR: + count = POLICY_RR_INFO_COUNT; + ret = thread_info(thread, THREAD_SCHED_RR_INFO, + buf, &count); + if((ret == KERN_SUCCESS) && (ki->curpri < (((struct policy_rr_info *)buf)->base_priority))) + ki->curpri = ((struct policy_rr_info *)buf)->base_priority; + break; + } + return(ret); +} + +int get_task_info (KINFO *ki) +{ + kern_return_t error; + unsigned int info_count = TASK_BASIC_INFO_COUNT; + unsigned int thread_info_count = THREAD_BASIC_INFO_COUNT; + pid_t pid; + int j, err = 0; + + ki->state = STATE_MAX; + + pid = KI_PROC(ki)->p_pid; + if (task_for_pid(mach_task_self(), pid, &ki->task) != KERN_SUCCESS) { + return(1); + } + info_count = TASK_BASIC_INFO_COUNT; + error = task_info(ki->task, TASK_BASIC_INFO, (task_info_t)&ki->tasks_info, &info_count); + if (error != KERN_SUCCESS) { + ki->invalid_tinfo=1; +#ifdef DEBUG + mach_error("Error calling task_info()", error); +#endif + return(1); + } + { + vm_region_basic_info_data_64_t b_info; + vm_address_t address = GLOBAL_SHARED_TEXT_SEGMENT; + vm_size_t size; + mach_port_t object_name; + + /* + * try to determine if this task has the split libraries + * mapped in... if so, adjust its virtual size down by + * the 2 segments that are used for split libraries + */ + info_count = VM_REGION_BASIC_INFO_COUNT_64; + error = vm_region_64(ki->task, &address, &size, VM_REGION_BASIC_INFO, + (vm_region_info_t)&b_info, &info_count, &object_name); + if (error == KERN_SUCCESS) { + if (b_info.reserved && size == (SHARED_TEXT_REGION_SIZE) && + ki->tasks_info.virtual_size > (SHARED_TEXT_REGION_SIZE + SHARED_DATA_REGION_SIZE)) + ki->tasks_info.virtual_size -= (SHARED_TEXT_REGION_SIZE + SHARED_DATA_REGION_SIZE); + } + } + info_count = TASK_THREAD_TIMES_INFO_COUNT; + error = task_info(ki->task, TASK_THREAD_TIMES_INFO, (task_info_t)&ki->times, &info_count); + if (error != KERN_SUCCESS) { + ki->invalid_tinfo=1; +#ifdef DEBUG + mach_error("Error calling task_info()", error); +#endif + return(1); + } + switch(ki->tasks_info.policy) { + case POLICY_TIMESHARE : + info_count = POLICY_TIMESHARE_INFO_COUNT; + error = task_info(ki->task, TASK_SCHED_TIMESHARE_INFO, (task_info_t)&ki->schedinfo.tshare, &info_count); + if (error != KERN_SUCCESS) { + ki->invalid_tinfo=1; +#ifdef DEBUG + mach_error("Error calling task_info()", error); +#endif + return(1); + } + + ki->curpri = ki->schedinfo.tshare.cur_priority; + ki->basepri = ki->schedinfo.tshare.base_priority; + break; + case POLICY_RR : + info_count = POLICY_RR_INFO_COUNT; + error = task_info(ki->task, TASK_SCHED_RR_INFO, (task_info_t)&ki->schedinfo.rr, &info_count); + if (error != KERN_SUCCESS) { + ki->invalid_tinfo=1; +#ifdef DEBUG + mach_error("Error calling task_info()", error); +#endif + return(1); + } + + ki->curpri = ki->schedinfo.rr.base_priority; + ki->basepri = ki->schedinfo.rr.base_priority; + break; + + case POLICY_FIFO : + info_count = POLICY_FIFO_INFO_COUNT; + error = task_info(ki->task, TASK_SCHED_FIFO_INFO, (task_info_t)&ki->schedinfo.fifo, &info_count); + if (error != KERN_SUCCESS) { + ki->invalid_tinfo=1; +#ifdef DEBUG + mach_error("Error calling task_info()", error); +#endif + return(1); + } + + ki->curpri = ki->schedinfo.fifo.base_priority; + ki->basepri = ki->schedinfo.fifo.base_priority; + break; + } + + ki->invalid_tinfo=0; + + ki->cpu_usage=0; + error = task_threads(ki->task, &ki->thread_list, &ki->thread_count); + if (error != KERN_SUCCESS) { + mach_port_deallocate(mach_task_self(),ki->task); +#ifdef DEBUG + mach_error("Call to task_threads() failed", error); +#endif + return(1); + } + err=0; + //ki->curpri = 255; + //ki->basepri = 255; + ki->swapped = 1; + ki->thval = calloc(ki->thread_count, sizeof(struct thread_values)); + for (j = 0; j < ki->thread_count; j++) { + int tstate; + thread_info_count = THREAD_BASIC_INFO_COUNT; + error = thread_info(ki->thread_list[j], THREAD_BASIC_INFO, + (thread_info_t)&ki->thval[j].tb, + &thread_info_count); + if (error != KERN_SUCCESS) { +#ifdef DEBUG + mach_error("Call to thread_info() failed", error); +#endif + err=1; + } else { + ki->cpu_usage += ki->thval[j].tb.cpu_usage; + } + error = thread_schedinfo(ki, ki->thread_list[j], + ki->thval[j].tb.policy, &ki->thval[j].schedinfo); + if (error != KERN_SUCCESS) { +#ifdef DEBUG + mach_error("Call to thread_schedinfo() failed", error); +#endif + err=1; + } + tstate = mach_state_order(ki->thval[j].tb.run_state, + ki->thval[j].tb.sleep_time); + if (tstate < ki->state) + ki->state = tstate; + if ((ki->thval[j].tb.flags & TH_FLAGS_SWAPPED ) == 0) + ki->swapped = 0; + mach_port_deallocate(mach_task_self(), + ki->thread_list[j]); + } + ki->invalid_thinfo = err; + /* Deallocate the list of threads. */ + error = vm_deallocate(mach_task_self(), + (vm_address_t)(ki->thread_list), + sizeof(*ki->thread_list) * ki->thread_count); + if (error != KERN_SUCCESS) { +#ifdef DEBUG + mach_error("Trouble freeing thread_list", error); +#endif + } + + mach_port_deallocate(mach_task_self(),ki->task); + return(0); +} diff --git a/adv_cmds/stty/cchar.c b/adv_cmds/stty/cchar.c new file mode 100644 index 0000000..da9d523 --- /dev/null +++ b/adv_cmds/stty/cchar.c @@ -0,0 +1,153 @@ +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)cchar.c 8.5 (Berkeley) 4/2/94"; +#endif +#endif /* not lint */ +#include <sys/cdefs.h> +__RCSID("$FreeBSD: src/bin/stty/cchar.c,v 1.13 2002/06/30 05:15:04 obrien Exp $"); + +#include <sys/types.h> + +#include <err.h> +#include <limits.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> + +#include "stty.h" +#include "extern.h" + +static int c_cchar(const void *, const void *); + +/* + * Special control characters. + * + * Cchars1 are the standard names, cchars2 are the old aliases. + * The first are displayed, but both are recognized on the + * command line. + */ +struct cchar cchars1[] = { + { "discard", VDISCARD, CDISCARD }, + { "dsusp", VDSUSP, CDSUSP }, + { "eof", VEOF, CEOF }, + { "eol", VEOL, CEOL }, + { "eol2", VEOL2, CEOL }, + { "erase", VERASE, CERASE }, +#ifndef __APPLE__ + { "erase2", VERASE2, CERASE2 }, +#endif + { "intr", VINTR, CINTR }, + { "kill", VKILL, CKILL }, + { "lnext", VLNEXT, CLNEXT }, + { "min", VMIN, CMIN }, + { "quit", VQUIT, CQUIT }, + { "reprint", VREPRINT, CREPRINT }, + { "start", VSTART, CSTART }, + { "status", VSTATUS, CSTATUS }, + { "stop", VSTOP, CSTOP }, + { "susp", VSUSP, CSUSP }, + { "time", VTIME, CTIME }, + { "werase", VWERASE, CWERASE }, + { NULL, 0, 0}, +}; + +struct cchar cchars2[] = { + { "brk", VEOL, CEOL }, + { "flush", VDISCARD, CDISCARD }, + { "rprnt", VREPRINT, CREPRINT }, + { NULL, 0, 0 }, +}; + +static int +c_cchar(const void *a, const void *b) +{ + + return (strcmp(((const struct cchar *)a)->name, ((const struct cchar *)b)->name)); +} + +int +csearch(char ***argvp, struct info *ip) +{ + struct cchar *cp, tmp; + long val; + char *arg, *ep, *name; + + name = **argvp; + + tmp.name = name; + if (!(cp = (struct cchar *)bsearch(&tmp, cchars1, + sizeof(cchars1)/sizeof(struct cchar) - 1, sizeof(struct cchar), + c_cchar)) && !(cp = (struct cchar *)bsearch(&tmp, cchars2, + sizeof(cchars2)/sizeof(struct cchar) - 1, sizeof(struct cchar), + c_cchar))) + return (0); + + arg = *++*argvp; + if (!arg) { + warnx("option requires an argument -- %s", name); + usage(); + } + +#define CHK(s) (*arg == s[0] && !strcmp(arg, s)) + if (CHK("undef") || CHK("<undef>")) + ip->t.c_cc[cp->sub] = _POSIX_VDISABLE; + else if (cp->sub == VMIN || cp->sub == VTIME) { + val = strtol(arg, &ep, 10); +#ifdef __APPLE__ + if (val == _POSIX_VDISABLE) { + warnx("value of %ld would disable the option -- %s", + val, name); + usage(); + } +#endif + if (val > UCHAR_MAX) { + warnx("maximum option value is %d -- %s", + UCHAR_MAX, name); + usage(); + } + if (*ep != '\0') { + warnx("option requires a numeric argument -- %s", name); + usage(); + } + ip->t.c_cc[cp->sub] = val; + } else if (arg[0] == '^') + ip->t.c_cc[cp->sub] = (arg[1] == '?') ? 0177 : + (arg[1] == '-') ? _POSIX_VDISABLE : arg[1] & 037; + else + ip->t.c_cc[cp->sub] = arg[0]; + ip->set = 1; + return (1); +} diff --git a/adv_cmds/stty/extern.h b/adv_cmds/stty/extern.h new file mode 100644 index 0000000..193142a --- /dev/null +++ b/adv_cmds/stty/extern.h @@ -0,0 +1,49 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)extern.h 8.1 (Berkeley) 5/31/93 + * $FreeBSD: src/bin/stty/extern.h,v 1.9 2002/02/02 06:50:56 imp Exp $ + */ + +int c_cchars(const void *, const void *); +int c_modes(const void *, const void *); +int csearch(char ***, struct info *); +void checkredirect(void); +void gprint(struct termios *, struct winsize *, int); +void gread(struct termios *, char *); +int ksearch(char ***, struct info *); +int msearch(char ***, struct info *); +void optlist(void); +void print(struct termios *, struct winsize *, int, enum FMT); +void usage(void); + +extern struct cchar cchars1[], cchars2[]; diff --git a/adv_cmds/stty/gfmt.c b/adv_cmds/stty/gfmt.c new file mode 100644 index 0000000..4e5203f --- /dev/null +++ b/adv_cmds/stty/gfmt.c @@ -0,0 +1,135 @@ +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)gfmt.c 8.6 (Berkeley) 4/2/94"; +#endif +#endif /* not lint */ +#include <sys/cdefs.h> +__RCSID("$FreeBSD: src/bin/stty/gfmt.c,v 1.18 2002/06/30 05:15:04 obrien Exp $"); + +#include <sys/types.h> + +#include <err.h> +#include <stdio.h> +#include <string.h> + +#include "stty.h" +#include "extern.h" + +static void gerr(const char *s); + +static void +gerr(const char *s) +{ + if (s) + errx(1, "illegal gfmt1 option -- %s", s); + else + errx(1, "illegal gfmt1 option"); +} + +void +#ifndef __APPLE__ +gprint(struct termios *tp, struct winsize *wp __unused, int ldisc __unused) +#else +gprint(struct termios *tp, struct winsize *wp, int ldisc) +#endif +{ + struct cchar *cp; + + (void)printf("gfmt1:cflag=%lx:iflag=%lx:lflag=%lx:oflag=%lx:", + (u_long)tp->c_cflag, (u_long)tp->c_iflag, (u_long)tp->c_lflag, + (u_long)tp->c_oflag); + for (cp = cchars1; cp->name; ++cp) + (void)printf("%s=%x:", cp->name, tp->c_cc[cp->sub]); + (void)printf("ispeed=%lu:ospeed=%lu\n", + (u_long)cfgetispeed(tp), (u_long)cfgetospeed(tp)); +} + +void +gread(struct termios *tp, char *s) +{ + struct cchar *cp; + char *ep, *p; + long tmp; + + if ((s = strchr(s, ':')) == NULL) + gerr(NULL); + for (++s; s != NULL;) { + p = strsep(&s, ":\0"); + if (!p || !*p) + break; + if (!(ep = strchr(p, '='))) + gerr(p); + *ep++ = '\0'; + (void)sscanf(ep, "%lx", &tmp); + +#define CHK(s) (*p == s[0] && !strcmp(p, s)) + if (CHK("cflag")) { + tp->c_cflag = tmp; + continue; + } + if (CHK("iflag")) { + tp->c_iflag = tmp; + continue; + } + if (CHK("ispeed")) { + (void)sscanf(ep, "%ld", &tmp); + tp->c_ispeed = tmp; + continue; + } + if (CHK("lflag")) { + tp->c_lflag = tmp; + continue; + } + if (CHK("oflag")) { + tp->c_oflag = tmp; + continue; + } + if (CHK("ospeed")) { + (void)sscanf(ep, "%ld", &tmp); + tp->c_ospeed = tmp; + continue; + } + for (cp = cchars1; cp->name != NULL; ++cp) + if (CHK(cp->name)) { + if (cp->sub == VMIN || cp->sub == VTIME) + (void)sscanf(ep, "%ld", &tmp); + tp->c_cc[cp->sub] = tmp; + break; + } + if (cp->name == NULL) + gerr(p); + } +} diff --git a/adv_cmds/stty/key.c b/adv_cmds/stty/key.c new file mode 100644 index 0000000..b38cab8 --- /dev/null +++ b/adv_cmds/stty/key.c @@ -0,0 +1,297 @@ +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)key.c 8.3 (Berkeley) 4/2/94"; +#endif +#endif /* not lint */ +#include <sys/cdefs.h> +__RCSID("$FreeBSD: src/bin/stty/key.c,v 1.17 2002/06/30 05:15:04 obrien Exp $"); + +#include <sys/types.h> + +#include <err.h> +#include <errno.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "stty.h" +#include "extern.h" + +__BEGIN_DECLS +static int c_key(const void *, const void *); +void f_all(struct info *); +void f_cbreak(struct info *); +void f_columns(struct info *); +void f_dec(struct info *); +void f_ek(struct info *); +void f_everything(struct info *); +void f_extproc(struct info *); +void f_ispeed(struct info *); +void f_nl(struct info *); +void f_ospeed(struct info *); +void f_raw(struct info *); +void f_rows(struct info *); +void f_sane(struct info *); +void f_size(struct info *); +void f_speed(struct info *); +void f_tty(struct info *); +__END_DECLS + +static struct key { + const char *name; /* name */ + void (*f)(struct info *); /* function */ +#define F_NEEDARG 0x01 /* needs an argument */ +#define F_OFFOK 0x02 /* can turn off */ + int flags; +} keys[] = { + { "all", f_all, 0 }, + { "cbreak", f_cbreak, F_OFFOK }, + { "cols", f_columns, F_NEEDARG }, + { "columns", f_columns, F_NEEDARG }, + { "cooked", f_sane, 0 }, + { "dec", f_dec, 0 }, + { "ek", f_ek, 0 }, + { "everything", f_everything, 0 }, + { "extproc", f_extproc, F_OFFOK }, + { "ispeed", f_ispeed, F_NEEDARG }, + { "new", f_tty, 0 }, + { "nl", f_nl, F_OFFOK }, + { "old", f_tty, 0 }, + { "ospeed", f_ospeed, F_NEEDARG }, + { "raw", f_raw, F_OFFOK }, + { "rows", f_rows, F_NEEDARG }, + { "sane", f_sane, 0 }, + { "size", f_size, 0 }, + { "speed", f_speed, 0 }, + { "tty", f_tty, 0 }, +}; + +static int +c_key(const void *a, const void *b) +{ + + return (strcmp(((const struct key *)a)->name, ((const struct key *)b)->name)); +} + +int +ksearch(char ***argvp, struct info *ip) +{ + char *name; + struct key *kp, tmp; + + name = **argvp; + if (*name == '-') { + ip->off = 1; + ++name; + } else + ip->off = 0; + + tmp.name = name; + if (!(kp = (struct key *)bsearch(&tmp, keys, + sizeof(keys)/sizeof(struct key), sizeof(struct key), c_key))) + return (0); + if (!(kp->flags & F_OFFOK) && ip->off) { + warnx("illegal option -- -%s", name); + usage(); + } + if (kp->flags & F_NEEDARG && !(ip->arg = *++*argvp)) { + warnx("option requires an argument -- %s", name); + usage(); + } + kp->f(ip); + return (1); +} + +void +f_all(struct info *ip) +{ + print(&ip->t, &ip->win, ip->ldisc, BSD); +} + +void +f_cbreak(struct info *ip) +{ + + if (ip->off) + f_sane(ip); + else { + ip->t.c_iflag |= BRKINT|IXON|IMAXBEL; + ip->t.c_oflag |= OPOST; + ip->t.c_lflag |= ISIG|IEXTEN; + ip->t.c_lflag &= ~ICANON; + ip->set = 1; + } +} + +void +f_columns(struct info *ip) +{ + + ip->win.ws_col = atoi(ip->arg); + ip->wset = 1; +} + +void +f_dec(struct info *ip) +{ + + ip->t.c_cc[VERASE] = (u_char)0177; + ip->t.c_cc[VKILL] = CTRL('u'); + ip->t.c_cc[VINTR] = CTRL('c'); + ip->t.c_lflag &= ~ECHOPRT; + ip->t.c_lflag |= ECHOE|ECHOKE|ECHOCTL; + ip->t.c_iflag &= ~IXANY; + ip->set = 1; +} + +void +f_ek(struct info *ip) +{ + + ip->t.c_cc[VERASE] = CERASE; + ip->t.c_cc[VKILL] = CKILL; + ip->set = 1; +} + +void +f_everything(struct info *ip) +{ + + print(&ip->t, &ip->win, ip->ldisc, BSD); +} + +void +f_extproc(struct info *ip) +{ + + if (ip->off) { + int tmp = 0; + (void)ioctl(ip->fd, TIOCEXT, &tmp); + } else { + int tmp = 1; + (void)ioctl(ip->fd, TIOCEXT, &tmp); + } +} + +void +f_ispeed(struct info *ip) +{ + + cfsetispeed(&ip->t, (speed_t)atoi(ip->arg)); + ip->set = 1; +} + +void +f_nl(struct info *ip) +{ + + if (ip->off) { + ip->t.c_iflag |= ICRNL; + ip->t.c_oflag |= ONLCR; + } else { + ip->t.c_iflag &= ~ICRNL; + ip->t.c_oflag &= ~ONLCR; + } + ip->set = 1; +} + +void +f_ospeed(struct info *ip) +{ + + cfsetospeed(&ip->t, (speed_t)atoi(ip->arg)); + ip->set = 1; +} + +void +f_raw(struct info *ip) +{ + + if (ip->off) + f_sane(ip); + else { + cfmakeraw(&ip->t); + ip->t.c_cflag &= ~(CSIZE|PARENB); + ip->t.c_cflag |= CS8; + ip->set = 1; + } +} + +void +f_rows(struct info *ip) +{ + + ip->win.ws_row = atoi(ip->arg); + ip->wset = 1; +} + +void +f_sane(struct info *ip) +{ + + ip->t.c_cflag = TTYDEF_CFLAG | (ip->t.c_cflag & CLOCAL); + ip->t.c_iflag = TTYDEF_IFLAG; + ip->t.c_iflag |= ICRNL; + /* preserve user-preference flags in lflag */ +#define LKEEP (ECHOKE|ECHOE|ECHOK|ECHOPRT|ECHOCTL|ALTWERASE|TOSTOP|NOFLSH) + ip->t.c_lflag = TTYDEF_LFLAG | (ip->t.c_lflag & LKEEP); + ip->t.c_oflag = TTYDEF_OFLAG; + ip->set = 1; +} + +void +f_size(struct info *ip) +{ + + (void)printf("%d %d\n", ip->win.ws_row, ip->win.ws_col); +} + +void +f_speed(struct info *ip) +{ + + (void)printf("%lu\n", (u_long)cfgetospeed(&ip->t)); +} + +void +f_tty(struct info *ip) +{ + int tmp; + + tmp = TTYDISC; + if (ioctl(ip->fd, TIOCSETD, &tmp) < 0) + err(1, "TIOCSETD"); +} diff --git a/adv_cmds/stty/modes.c b/adv_cmds/stty/modes.c new file mode 100644 index 0000000..0313c87 --- /dev/null +++ b/adv_cmds/stty/modes.c @@ -0,0 +1,308 @@ +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)modes.c 8.3 (Berkeley) 4/2/94"; +#endif +#endif /* not lint */ +#include <sys/cdefs.h> +__RCSID("$FreeBSD: src/bin/stty/modes.c,v 1.12 2002/06/30 05:15:04 obrien Exp $"); + +#include <sys/types.h> +#include <stddef.h> +#include <string.h> +#include "stty.h" + +#ifdef __APPLE__ +#include <get_compat.h> +#else +#define COMPAT_MODE(a,b) (1) +#endif /* __APPLE__ */ + +int msearch(char ***, struct info *); + +struct modes { + const char *name; + long set; + long unset; +}; + +/* + * The code in optlist() depends on minus options following regular + * options, i.e. "foo" must immediately precede "-foo". + */ +struct modes cmodes[] = { + { "cs5", CS5, CSIZE }, + { "cs6", CS6, CSIZE }, + { "cs7", CS7, CSIZE }, + { "cs8", CS8, CSIZE }, + { "cstopb", CSTOPB, 0 }, + { "-cstopb", 0, CSTOPB }, + { "cread", CREAD, 0 }, + { "-cread", 0, CREAD }, + { "parenb", PARENB, 0 }, + { "-parenb", 0, PARENB }, + { "parodd", PARODD, 0 }, + { "-parodd", 0, PARODD }, + { "parity", PARENB | CS7, PARODD | CSIZE }, + { "-parity", CS8, PARODD | PARENB | CSIZE }, + { "evenp", PARENB | CS7, PARODD | CSIZE }, + { "-evenp", CS8, PARODD | PARENB | CSIZE }, + { "oddp", PARENB | CS7 | PARODD, CSIZE }, + { "-oddp", CS8, PARODD | PARENB | CSIZE }, + { "pass8", CS8, PARODD | PARENB | CSIZE }, + { "-pass8", PARENB | CS7, PARODD | CSIZE }, + { "hupcl", HUPCL, 0 }, + { "-hupcl", 0, HUPCL }, + { "hup", HUPCL, 0 }, + { "-hup", 0, HUPCL }, + { "clocal", CLOCAL, 0 }, + { "-clocal", 0, CLOCAL }, + { "crtscts", CRTSCTS, 0 }, + { "-crtscts", 0, CRTSCTS }, + { "ctsflow", CCTS_OFLOW, 0 }, + { "-ctsflow", 0, CCTS_OFLOW }, + { "dsrflow", CDSR_OFLOW, 0 }, + { "-dsrflow", 0, CDSR_OFLOW }, + { "dtrflow", CDTR_IFLOW, 0 }, + { "-dtrflow", 0, CDTR_IFLOW }, + { "rtsflow", CRTS_IFLOW, 0 }, + { "-rtsflow", 0, CRTS_IFLOW }, + { "mdmbuf", MDMBUF, 0 }, + { "-mdmbuf", 0, MDMBUF }, + { NULL, 0, 0 }, +}; + +struct modes imodes[] = { + { "ignbrk", IGNBRK, 0 }, + { "-ignbrk", 0, IGNBRK }, + { "brkint", BRKINT, 0 }, + { "-brkint", 0, BRKINT }, + { "ignpar", IGNPAR, 0 }, + { "-ignpar", 0, IGNPAR }, + { "parmrk", PARMRK, 0 }, + { "-parmrk", 0, PARMRK }, + { "inpck", INPCK, 0 }, + { "-inpck", 0, INPCK }, + { "istrip", ISTRIP, 0 }, + { "-istrip", 0, ISTRIP }, + { "inlcr", INLCR, 0 }, + { "-inlcr", 0, INLCR }, + { "igncr", IGNCR, 0 }, + { "-igncr", 0, IGNCR }, + { "icrnl", ICRNL, 0 }, + { "-icrnl", 0, ICRNL }, + { "ixon", IXON, 0 }, + { "-ixon", 0, IXON }, + { "flow", IXON, 0 }, + { "-flow", 0, IXON }, + { "ixoff", IXOFF, 0 }, + { "-ixoff", 0, IXOFF }, + { "tandem", IXOFF, 0 }, + { "-tandem", 0, IXOFF }, + { "ixany", IXANY, 0 }, + { "-ixany", 0, IXANY }, + { "decctlq", 0, IXANY }, + { "-decctlq", IXANY, 0 }, + { "imaxbel", IMAXBEL, 0 }, + { "-imaxbel", 0, IMAXBEL }, + { "iutf8", IUTF8, 0 }, + { "-iutf8", 0, IUTF8 }, + { NULL, 0, 0 }, +}; + +struct modes lmodes[] = { + { "echo", ECHO, 0 }, + { "-echo", 0, ECHO }, + { "echoe", ECHOE, 0 }, + { "-echoe", 0, ECHOE }, + { "crterase", ECHOE, 0 }, + { "-crterase", 0, ECHOE }, + { "crtbs", ECHOE, 0 }, /* crtbs not supported, close enough */ + { "-crtbs", 0, ECHOE }, + { "echok", ECHOK, 0 }, + { "-echok", 0, ECHOK }, + { "echoke", ECHOKE, 0 }, + { "-echoke", 0, ECHOKE }, + { "crtkill", ECHOKE, 0 }, + { "-crtkill", 0, ECHOKE }, + { "altwerase", ALTWERASE, 0 }, + { "-altwerase", 0, ALTWERASE }, + { "iexten", IEXTEN, 0 }, + { "-iexten", 0, IEXTEN }, + { "echonl", ECHONL, 0 }, + { "-echonl", 0, ECHONL }, + { "echoctl", ECHOCTL, 0 }, + { "-echoctl", 0, ECHOCTL }, + { "ctlecho", ECHOCTL, 0 }, + { "-ctlecho", 0, ECHOCTL }, + { "echoprt", ECHOPRT, 0 }, + { "-echoprt", 0, ECHOPRT }, + { "prterase", ECHOPRT, 0 }, + { "-prterase", 0, ECHOPRT }, + { "isig", ISIG, 0 }, + { "-isig", 0, ISIG }, + { "icanon", ICANON, 0 }, + { "-icanon", 0, ICANON }, + { "noflsh", NOFLSH, 0 }, + { "-noflsh", 0, NOFLSH }, + { "tostop", TOSTOP, 0 }, + { "-tostop", 0, TOSTOP }, + { "flusho", FLUSHO, 0 }, + { "-flusho", 0, FLUSHO }, + { "pendin", PENDIN, 0 }, + { "-pendin", 0, PENDIN }, + { "crt", ECHOE|ECHOKE|ECHOCTL, ECHOK|ECHOPRT }, + { "-crt", ECHOK, ECHOE|ECHOKE|ECHOCTL }, + { "newcrt", ECHOE|ECHOKE|ECHOCTL, ECHOK|ECHOPRT }, + { "-newcrt", ECHOK, ECHOE|ECHOKE|ECHOCTL }, + { "nokerninfo", NOKERNINFO, 0 }, + { "-nokerninfo",0, NOKERNINFO }, + { "kerninfo", 0, NOKERNINFO }, + { "-kerninfo", NOKERNINFO, 0 }, + { NULL, 0, 0 }, +}; + +struct modes omodes[] = { + { "opost", OPOST, 0 }, + { "-opost", 0, OPOST }, + { "litout", 0, OPOST }, + { "-litout", OPOST, 0 }, + { "onlcr", ONLCR, 0 }, + { "-onlcr", 0, ONLCR }, +#ifndef __APPLE__ + { "ocrnl", OCRNL, 0 }, + { "-ocrnl", 0, OCRNL }, +#endif + { "tabs", 0, OXTABS }, /* "preserve" tabs */ + { "-tabs", OXTABS, 0 }, + { "oxtabs", OXTABS, 0 }, + { "-oxtabs", 0, OXTABS }, +#ifndef __APPLE__ + { "onocr", ONOCR, 0 }, + { "-onocr", 0, ONOCR }, + { "onlret", ONLRET, 0 }, + { "-onlret", 0, ONLRET }, +#endif + { NULL, 0, 0 }, +}; + +struct modes umodes[] = { /* For Unix conformance only */ + { "ocrnl", OCRNL, 0 }, + { "-ocrnl", 0, OCRNL }, + { "onocr", ONOCR, 0 }, + { "-onocr", 0, ONOCR }, + { "onlret", ONLRET, 0 }, + { "-onlret", 0, ONLRET }, + + { "ofill", OFILL, 0 }, + { "-ofill", 0, OFILL }, + + { "ofdel", OFDEL, 0 }, + { "-ofdel", 0, OFDEL }, + + { "bs0", BS0, 0 }, + { "bs1", BS1, 0 }, + + { "cr0", CR0, 0 }, + { "cr1", CR1, 0 }, + { "cr2", CR2, 0 }, + { "cr3", CR3, 0 }, + + { "ff0", FF0, 0 }, + { "ff1", FF1, 0 }, + + { "nl0", NL0, 0 }, + { "nl1", NL1, 0 }, + + { "tab0", TAB0, 0 }, + { "tab1", TAB1, 0 }, + { "tab2", TAB2, 0 }, + { "tab3", TAB3, 0 }, + + { "vt0", VT0, 0 }, + { "vt1", VT1, 0 }, + + { NULL, 0, 0 }, +}; + +#define CHK(s) (*name == s[0] && !strcmp(name, s)) + +int +msearch(char ***argvp, struct info *ip) +{ + struct modes *mp; + char *name; + + name = **argvp; + + for (mp = cmodes; mp->name; ++mp) + if (CHK(mp->name)) { + ip->t.c_cflag &= ~mp->unset; + ip->t.c_cflag |= mp->set; + ip->set = 1; + return (1); + } + for (mp = imodes; mp->name; ++mp) + if (CHK(mp->name)) { + ip->t.c_iflag &= ~mp->unset; + ip->t.c_iflag |= mp->set; + ip->set = 1; + return (1); + } + for (mp = lmodes; mp->name; ++mp) + if (CHK(mp->name)) { + ip->t.c_lflag &= ~mp->unset; + ip->t.c_lflag |= mp->set; + ip->set = 1; + return (1); + } + for (mp = omodes; mp->name; ++mp) + if (CHK(mp->name)) { + ip->t.c_oflag &= ~mp->unset; + ip->t.c_oflag |= mp->set; + ip->set = 1; + return (1); + } + if (COMPAT_MODE("bin/stty", "Unix2003")) { + for (mp = umodes; mp->name; ++mp) + if (CHK(mp->name)) { + ip->t.c_oflag &= ~mp->unset; + ip->t.c_oflag |= mp->set; + ip->set = 1; + return (1); + } + } + return (0); +} diff --git a/adv_cmds/stty/print.c b/adv_cmds/stty/print.c new file mode 100644 index 0000000..ef59bf1 --- /dev/null +++ b/adv_cmds/stty/print.c @@ -0,0 +1,291 @@ +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)print.c 8.6 (Berkeley) 4/16/94"; +#endif +#endif /* not lint */ +#include <sys/cdefs.h> +__RCSID("$FreeBSD: src/bin/stty/print.c,v 1.18 2002/06/30 05:15:04 obrien Exp $"); + +#include <sys/types.h> + +#include <stddef.h> +#include <stdio.h> +#include <string.h> + +#include "stty.h" +#include "extern.h" + +#include <sys/ioctl_compat.h> /* XXX NTTYDISC is too well hidden */ + +static void binit(const char *); +static void bput(const char *); +static const char *ccval(struct cchar *, int); + +void +print(struct termios *tp, struct winsize *wp, int ldisc, enum FMT fmt) +{ + struct cchar *p; + long tmp; + u_char *cc; + int cnt, ispeed, ospeed; + char buf1[100], buf2[100]; + + cnt = 0; + + /* Line discipline. */ + if (ldisc != TTYDISC) { + switch(ldisc) { + case NTTYDISC: + cnt += printf("new tty disc; "); + break; +#ifdef __APPLE__ + case TABLDISC: + cnt += printf("tablet disc; "); + break; +#endif + case SLIPDISC: + cnt += printf("slip disc; "); + break; + case PPPDISC: + cnt += printf("ppp disc; "); + break; + default: + cnt += printf("#%d disc; ", ldisc); + break; + } + } + + /* Line speed. */ + ispeed = cfgetispeed(tp); + ospeed = cfgetospeed(tp); + if (ispeed != ospeed) + cnt += + printf("ispeed %d baud; ospeed %d baud;", ispeed, ospeed); + else + cnt += printf("speed %d baud;", ispeed); + if (fmt >= BSD) + cnt += printf(" %d rows; %d columns;", wp->ws_row, wp->ws_col); + if (cnt) + (void)printf("\n"); + +#define on(f) ((tmp & (f)) != 0) +#define put(n, f, d) \ + if (fmt >= BSD || on(f) != (d)) \ + bput((n) + on(f)); + + /* "local" flags */ + tmp = tp->c_lflag; + binit("lflags"); + put("-icanon", ICANON, 1); + put("-isig", ISIG, 1); + put("-iexten", IEXTEN, 1); + put("-echo", ECHO, 1); + put("-echoe", ECHOE, 0); + put("-echok", ECHOK, 0); + put("-echoke", ECHOKE, 0); + put("-echonl", ECHONL, 0); + put("-echoctl", ECHOCTL, 0); + put("-echoprt", ECHOPRT, 0); + put("-altwerase", ALTWERASE, 0); + put("-noflsh", NOFLSH, 0); + put("-tostop", TOSTOP, 0); + put("-flusho", FLUSHO, 0); + put("-pendin", PENDIN, 0); + put("-nokerninfo", NOKERNINFO, 0); + put("-extproc", EXTPROC, 0); + + /* input flags */ + tmp = tp->c_iflag; + binit("iflags"); + put("-istrip", ISTRIP, 0); + put("-icrnl", ICRNL, 1); + put("-inlcr", INLCR, 0); + put("-igncr", IGNCR, 0); + put("-ixon", IXON, 1); + put("-ixoff", IXOFF, 0); + put("-ixany", IXANY, 1); + put("-imaxbel", IMAXBEL, 1); + put("-iutf8", IUTF8, 0); + put("-ignbrk", IGNBRK, 0); + put("-brkint", BRKINT, 1); + put("-inpck", INPCK, 0); + put("-ignpar", IGNPAR, 0); + put("-parmrk", PARMRK, 0); + + /* output flags */ + tmp = tp->c_oflag; + binit("oflags"); + put("-opost", OPOST, 1); + put("-onlcr", ONLCR, 1); +#ifndef __APPLE__ + put("-ocrnl", OCRNL, 0); +#endif + put("-oxtabs", OXTABS, 1); + put("-onocr", OXTABS, 0); + put("-onlret", OXTABS, 0); + + /* control flags (hardware state) */ + tmp = tp->c_cflag; + binit("cflags"); + put("-cread", CREAD, 1); + switch(tmp&CSIZE) { + case CS5: + bput("cs5"); + break; + case CS6: + bput("cs6"); + break; + case CS7: + bput("cs7"); + break; + case CS8: + bput("cs8"); + break; + } + bput("-parenb" + on(PARENB)); + put("-parodd", PARODD, 0); + put("-hupcl", HUPCL, 1); + put("-clocal", CLOCAL, 0); + put("-cstopb", CSTOPB, 0); + switch(tmp & (CCTS_OFLOW | CRTS_IFLOW)) { + case CCTS_OFLOW: + bput("ctsflow"); + break; + case CRTS_IFLOW: + bput("rtsflow"); + break; + default: + put("-crtscts", CCTS_OFLOW | CRTS_IFLOW, 0); + break; + } + put("-dsrflow", CDSR_OFLOW, 0); + put("-dtrflow", CDTR_IFLOW, 0); + put("-mdmbuf", MDMBUF, 0); /* XXX mdmbuf == dtrflow */ + + /* special control characters */ + cc = tp->c_cc; + if (fmt == POSIX) { + binit("cchars"); + for (p = cchars1; p->name; ++p) { + (void)snprintf(buf1, sizeof(buf1), "%s = %s;", + p->name, ccval(p, cc[p->sub])); + bput(buf1); + } + binit(NULL); + } else { + binit(NULL); + for (p = cchars1, cnt = 0; p->name; ++p) { + if (fmt != BSD && cc[p->sub] == p->def) + continue; +#define WD "%-8s" + (void)snprintf(buf1 + cnt * 8, sizeof(buf1) - cnt * 8, + WD, p->name); + (void)snprintf(buf2 + cnt * 8, sizeof(buf2) - cnt * 8, + WD, ccval(p, cc[p->sub])); + if (++cnt == LINELENGTH / 8) { + cnt = 0; + (void)printf("%s\n", buf1); + (void)printf("%s\n", buf2); + } + } + if (cnt) { + (void)printf("%s\n", buf1); + (void)printf("%s\n", buf2); + } + } +} + +static int col; +static const char *label; + +static void +binit(const char *lb) +{ + + if (col) { + (void)printf("\n"); + col = 0; + } + label = lb; +} + +static void +bput(const char *s) +{ + + if (col == 0) { + col = printf("%s: %s", label, s); + return; + } + if ((col + strlen(s)) > LINELENGTH) { + (void)printf("\n\t"); + col = printf("%s", s) + 8; + return; + } + col += printf(" %s", s); +} + +static const char * +ccval(struct cchar *p, int c) +{ + static char buf[5]; + char *bp; + + if (p->sub == VMIN || p->sub == VTIME) { + (void)snprintf(buf, sizeof(buf), "%d", c); + return (buf); + } + if (c == _POSIX_VDISABLE) + return ("<undef>"); + bp = buf; + if (c & 0200) { + *bp++ = 'M'; + *bp++ = '-'; + c &= 0177; + } + if (c == 0177) { + *bp++ = '^'; + *bp++ = '?'; + } + else if (c < 040) { + *bp++ = '^'; + *bp++ = c + '@'; + } + else + *bp++ = c; + *bp = '\0'; + return (buf); +} diff --git a/adv_cmds/stty/stty.1 b/adv_cmds/stty/stty.1 new file mode 100644 index 0000000..9a864b4 --- /dev/null +++ b/adv_cmds/stty/stty.1 @@ -0,0 +1,633 @@ +.\" Copyright (c) 1990, 1993, 1994 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the Institute of Electrical and Electronics Engineers, Inc. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)stty.1 8.4 (Berkeley) 4/18/94 +.\" $FreeBSD: src/bin/stty/stty.1,v 1.27 2001/11/29 15:46:54 green Exp $ +.\" +.Dd April 18, 1994 +.Dt STTY 1 +.Os +.Sh NAME +.Nm stty +.Nd set the options for a terminal device interface +.Sh SYNOPSIS +.Nm +.Op Fl a | Fl e | Fl g +.Op Fl f Ar file +.Op operands +.Sh DESCRIPTION +The +.Nm +utility sets or reports on terminal +characteristics for the device that is its standard input. +If no options or operands are specified, it reports the settings of a subset +of characteristics as well as additional ones if they differ from their +default values. +Otherwise it modifies +the terminal state according to the specified arguments. +Some combinations of arguments are mutually +exclusive on some terminal types. +.Pp +The following options are available: +.Bl -tag -width indent +.It Fl a +Display all the current settings for the terminal to standard output +as per +.St -p1003.2 . +.It Fl e +Display all the current settings for the terminal to standard output +in the traditional +.Bx +``all'' and ``everything'' formats. +.It Fl f +Open and use the terminal named by +.Ar file +rather than using standard input. The file is opened +using the +.Dv O_NONBLOCK +flag of +.Fn open , +making it possible to +set or display settings on a terminal that might otherwise +block on the open. +.It Fl g +Display all the current settings for the terminal to standard output +in a form that may be used as an argument to a subsequent invocation of +.Nm +to restore the current terminal state as per +.St -p1003.2 . +.El +.Pp +The following arguments are available to set the terminal +characteristics: +.Ss Control Modes: +.Pp +Control mode flags affect hardware characteristics associated with the +terminal. This corresponds to the c_cflag in the termios structure. +.Bl -tag -width Fl +.It Ar number +Set terminal baud rate to the number given, if possible. +If the baud rate is set to zero, +modem control is no longer asserted. +.It Cm clocal Pq Fl clocal +Assume a line without (with) modem control. +.It Cm cread Pq Fl cread +Enable (disable) the receiver. +.It Cm crtscts Pq Fl crtscts +Enable (disable) RTS/CTS flow control. +.It Cm cs5 cs6 cs7 cs8 +Select character size, if possible. +.It Cm cstopb Pq Fl cstopb +Use two (one) stop bits per character. +.It Cm hup Pq Fl hup +Same as +.Cm hupcl +.Pq Fl hupcl . +.It Cm hupcl Pq Fl hupcl +Stop asserting modem control +(do not stop asserting modem control) on last close. +.It Cm ispeed Ar number +Set terminal input baud rate to the number given, if possible. +If the input baud rate is set to zero, +the input baud rate is set to the value of the output baud rate. +.It Cm ospeed Ar number +Set terminal output baud rate to the number given, if possible. +If the output baud rate is set to zero, +modem control is no longer asserted. +.It Cm parenb Pq Fl parenb +Enable (disable) parity generation and detection. +.It Cm parodd Pq Fl parodd +Select odd (even) parity. +.It Cm speed Ar number +This sets both +.Cm ispeed +and +.Cm ospeed +to +.Ar number . +.El +.Ss Input Modes: +This corresponds to the c_iflag in the termios structure. +.Bl -tag -width Fl +.It Cm brkint Pq Fl brkint +Signal (do not signal) +.Dv INTR +on +break. +.It Cm icrnl Pq Fl icrnl +Map (do not map) +.Dv CR +to +.Dv NL +on input. +.It Cm ignbrk Pq Fl ignbrk +Ignore (do not ignore) break on input. +.It Cm igncr Pq Fl igncr +Ignore (do not ignore) +.Dv CR +on input. +.It Cm ignpar Pq Fl ignpar +Ignore (do not ignore) characters with parity errors. +.It Cm imaxbel Pq Fl imaxbel +The system imposes a limit of +.Dv MAX_INPUT +(currently 255) characters in the input queue. If +.Cm imaxbel +is set and the input queue limit has been reached, +subsequent input causes the system to send an ASCII BEL +character to the output queue (the terminal beeps at you). Otherwise, +if +.Cm imaxbel +is unset and the input queue is full, the next input character causes +the entire input and output queues to be discarded. +.It Cm inlcr Pq Fl inlcr +Map (do not map) +.Dv NL +to +.Dv CR +on input. +.It Cm inpck Pq Fl inpck +Enable (disable) input parity checking. +.It Cm istrip Pq Fl istrip +Strip (do not strip) input characters to seven bits. +.It Cm iutf8 Pq Fl iutf8 +Assume input characters are UTF-8 encoded. +.It Cm ixany Pq Fl ixany +Allow any character (allow only +.Dv START ) +to restart output. +.It Cm ixoff Pq Fl ixoff +Request that the system send (not send) +.Dv START/STOP +characters when the input queue is nearly empty/full. +.It Cm ixon Pq Fl ixon +Enable (disable) +.Dv START/STOP +output control. +Output from the system is stopped when the system receives +.Dv STOP +and started when the system receives +.Dv START , +or if +.Cm ixany +is set, any character restarts output. +.It Cm parmrk Pq Fl parmrk +Mark (do not mark) characters with parity errors. +.El +.Ss Output Modes: +This corresponds to the c_oflag of the termios structure. +.Bl -tag -width Fl +.It Cm bs0 bs1 +Select the style of delay for backspaces (e.g., set BSDLY to BS0). +.It Cm cr0 cr1 cr2 cr3 +Select the style of delay for carriage returns (e.g., set CRDLY to CR0). +.It Cm ff0 ff1 +Select the style of delay for form feeds (e.g., set FFDLY to FF0). +.It Cm nl0 nl1 +Select the style of delay for newlines (e.g., set NLDLY to NL0). +.It Cm ocrnl Pq Fl ocrnl +Map (do not map) carriage return to newline on output. +.It Cm ofdel Pq Fl odell +Use DELs (NULs) as fill characters. +.It Cm ofill Pq Fl ofill +Use fill characters (use timing) for delays. +.It Cm onlcr Pq Fl onlcr +Map (do not map) +.Dv NL +to +.Dv CR-NL +on output. +.It Cm onlret Pq Fl onlret +On the terminal, NL performs (does not perform) the CR function. +.It Cm onocr Pq Fl onocr +Do not (do) output CRs at column zero. +.It Cm opost Pq Fl opost +Post-process output (do not post-process output; +ignore all other output modes). +.It Cm oxtabs Pq Fl oxtabs +Expand (do not expand) tabs to spaces on output. +.It Cm tab0 tab1 tab2 tab3 +Select the style of delay for horizontal tabs (e.g., set TABDLY to TAB0). +.It Cm tabs Pq Fl tabs +Same as +.Cm tab0 +.Cm ( tab3 ) . +.It Cm vt0 vt1 +Select the style of delay for vertical tabs (e.g., set VTDLY to VT0). +.El +.Ss Local Modes: +.Pp +Local mode flags (lflags) affect various and sundry characteristics +of terminal processing. +Historically the term "local" pertained to new job control features +implemented by Jim Kulp on a +.Tn Pdp 11/70 +at +.Tn IIASA . +Later, the driver ran on the first +.Tn VAX +at Evans Hall, UC Berkeley, where the job control details +were greatly modified, +but the structure definitions and names remained essentially unchanged. +The second interpretation of the 'l' in lflag +is ``line discipline flag'', which corresponds to the +.Ar c_lflag +of the +.Ar termios +structure. +.Bl -tag -width Fl +.It Cm altwerase Pq Fl altwerase +Use (do not use) an alternate word erase algorithm when processing +.Dv WERASE +characters. +This alternate algorithm considers sequences of +alphanumeric/underscores as words. +It also skips the first preceding character in its classification +(as a convenience, since the one preceding character could have been +erased with simply an +.Dv ERASE +character.) +.It Cm echo Pq Fl echo +Echo back (do not echo back) every character typed. +.It Cm echoctl Pq Fl echoctl +If +.Cm echoctl +is set, echo control characters as ^X. +Otherwise, control characters echo as themselves. +.It Cm echoe Pq Fl echoe +The +.Dv ERASE +character shall (shall not) visually erase the last character +in the current line from the display, if possible. +.It Cm echok Pq Fl echok +Echo (do not echo) +.Dv NL +after +.Dv KILL +character. +.It Cm echoke Pq Fl echoke +The +.Dv KILL +character shall (shall +not) visually erase the +current line from the +display, if possible. +.It Cm echonl Pq Fl echonl +Echo (do not echo) +.Dv NL , +even if echo is disabled. +.It Cm echoprt Pq Fl echoprt +For printing terminals. +If set, echo erased characters backwards within ``\\'' and ``/''. +Otherwise, disable this feature. +.It Cm flusho Pq Fl flusho +Indicates output is (is not) being discarded. +.It Cm icanon Pq Fl icanon +Enable (disable) canonical input +.Pf ( Dv ERASE +and +.Dv KILL +processing). +.It Cm iexten Pq Fl iexten +Enable (disable) any implementation-defined special control characters +that are not currently controlled by +.Cm icanon , +.Cm isig , +.Cm ixoff , +or +.Cm ixon . +.It Cm isig Pq Fl isig +Enable (disable) the checking of characters +against the special control characters +.Dv INTR , QUIT , +and +.Dv SUSP . +.It Cm mdmbuf Pq Fl mdmbuf +If set, flow control output based on condition of Carrier Detect. +Otherwise, writes return an error if Carrier Detect is low +(and Carrier is not being ignored with the +.Dv CLOCAL +flag.) +.It Cm noflsh Pq Fl noflsh +Disable (enable) flush after +.Dv INTR , QUIT , +or +.Dv SUSP . +.It Cm pendin Pq Fl pendin +Indicates input is (is not) pending +after a switch from non-canonical to canonical mode +and will be re-input when a read becomes pending or more input arrives. +.It Cm tostop Pq Fl tostop +Send (do not send) +.Dv SIGTTOU +for background output. +This causes background jobs to stop if they attempt terminal output. +.El +.Ss Control Characters: +.Bl -tag -width Fl +.It Ar control-character Ar string +Set +.Ar control-character +to +.Ar string . +If string is a single character, +the control character is set to +that character. +If string is the +two character sequence "^-" or the +string "undef" the control character +is disabled (i.e. set to +.Pf { Dv _POSIX_VDISABLE Ns } . ) +.Pp +Recognized control-characters: +.Bd -ragged -offset indent +.Bl -column character Subscript +.It control- +.It character Ta Subscript Ta Description +.It _________ Ta _________ Ta _______________ +.It eof Ta Tn VEOF Ta EOF No character +.It eol Ta Tn VEOL Ta EOL No character +.It eol2 Ta Tn VEOL2 Ta EOL2 No character +.It erase Ta Tn VERASE Ta ERASE No character +.It erase2 Ta Tn VERASE2 Ta ERASE2 No character +.It werase Ta Tn VWERASE Ta WERASE No character +.It intr Ta Tn VINTR Ta INTR No character +.It kill Ta Tn VKILL Ta KILL No character +.It quit Ta Tn VQUIT Ta QUIT No character +.It susp Ta Tn VSUSP Ta SUSP No character +.It start Ta Tn VSTART Ta START No character +.It stop Ta Tn VSTOP Ta STOP No character +.It dsusp Ta Tn VDSUSP Ta DSUSP No character +.It lnext Ta Tn VLNEXT Ta LNEXT No character +.It reprint Ta Tn VREPRINT Ta REPRINT No character +.It status Ta Tn VSTATUS Ta STATUS No character +.El +.Ed +.It Cm min Ar number +.It Cm time Ar number +Set the value of min or time to number. +.Dv MIN +and +.Dv TIME +are used in Non-Canonical mode input processing (-icanon). +.El +.Ss Combination Modes: +.Pp +.Bl -tag -width Fl +.It Ar saved settings +Set the current terminal characteristics +to the saved settings produced by the +.Fl g +option. +.It Cm cols Ar number +Same as +.Cm columns . +.It Cm columns Ar number +The terminal size is recorded as having +.Ar number +columns. +.It Cm crt Pq Fl crt +Set (disable) all modes suitable for a CRT display device. +.It Cm dec +Set modes suitable for users of Digital Equipment Corporation systems +.Dv ( ERASE , +.Dv KILL , +and +.Dv INTR +characters are set to ^?, ^U, and ^C; +.Dv ixany +is disabled, and +.Dv crt +is enabled.) +.It Cm ek +Reset +.Dv ERASE , +.Dv ERASE2 , +and +.Dv KILL +characters +back to system defaults. +.It Fl evenp +Same as +.Fl oddp +and +.Fl parity . +.It Cm evenp +Enable +.Cm parenb +and +.Cm cs7 ; +disable +.Cm parodd . +.It Cm extproc Pq Fl extproc +If set, this flag indicates that some amount of terminal processing +is being performed by either the terminal hardware +or by the remote side connected to a pty. +.It Cm kerninfo Pq Fl kerninfo +Enable (disable) the system generated status line associated with +processing a +.Dv STATUS +character (usually set to ^T). The status line consists of the +system load average, the current command name, its process ID, the +event the process is waiting on (or the status of the process), the user +and system times, percent cpu, and current memory usage. +.It Cm \&nl Pq Fl \&nl +Enable (disable) +.Cm icrnl . +In addition, +.Fl nl +unsets +.Cm inlcr +and +.Cm igncr . +.It Fl oddp +Same as +.Fl evenp +and +.Fl parity . +.It Cm oddp +Enable +.Cm parenb , +.Cm cs7 , +and +.Cm parodd . +.It Fl parity +Disable +.Cm parenb ; +set +.Cm cs8 . +.It Cm parity +Same as +.Cm evenp . +.It Cm raw Pq Fl raw +If set, change the modes of the terminal +so that no input or output processing is performed. +If unset, change the modes of the terminal to some reasonable state +that performs input and output processing. +Note that since the terminal driver no longer has a single +.Dv RAW +bit, it is not possible to intuit what flags were set prior to setting +.Cm raw . +This means that unsetting +.Cm raw +may not put back all the setting that were previously in effect. +To set the terminal into a raw state and then accurately restore it, +the following shell code is recommended: +.Bd -literal +save_state=$(stty -g) +stty raw +\&... +stty "$save_state" +.Ed +.It Cm rows Ar number +The terminal size is recorded as having +.Ar number +rows. +.It Cm sane +Resets all modes to reasonable values for interactive terminal use. +.It Cm size +The size of the terminal is printed as two numbers on a single line, +first rows, then columns. +.It Cm tty +Set the line discipline to the standard terminal line discipline +.Dv TTYDISC . +.El +.Ss Compatibility Modes: +.Pp +These modes remain for compatibility with the previous version of +the +.Nm +command. +.Bl -tag -width Fl +.It Cm all +Reports all the terminal modes as with +.Cm stty Fl a , +except that the control characters are printed in a columnar format. +.It Cm brk Ar value +Same as the control character +.Cm eol . +.It Cm cbreak +If set, enables +.Cm brkint , ixon , imaxbel , opost , isig , iexten , +and +.Fl icanon . +If unset, same as +.Cm sane . +.It Cm cooked +Same as +.Cm sane . +.It Cm crtbs Pq Fl crtbs +Same as +.Cm echoe . +.It Cm crterase Pq Fl crterase +Same as +.Cm echoe . +.It Cm crtkill Pq Fl crtkill +Same as +.Cm echoke . +.It Cm ctlecho Pq Fl ctlecho +Same as +.Cm echoctl . +.It Cm decctlq Pq Fl decctlq +The converse of +.Cm ixany . +.It Cm everything +Same as +.Cm all . +.It Cm flush Ar value +Same as the control character +.Cm discard . +.It Cm litout Pq Fl litout +The converse of +.Cm opost . +.It Cm new +Same as +.Cm tty . +.It Cm newcrt Pq Fl newcrt +Same as +.Cm crt . +.It Cm old +Same as +.Cm tty . +.It Cm pass8 +The converse of +.Cm parity . +.It Cm prterase Pq Fl prterase +Same as +.Cm echoprt . +.It Cm rprnt Ar value +Same as the control character +.Cm reprint . +.It Cm tabs Pq Fl tabs +The converse of +.Cm oxtabs . +.It Cm tandem Pq Fl tandem +Same as +.Cm ixoff . +.El +.Sh DIAGNOSTICS +.Ex -std +.Sh LEGACY DESCRIPTION +In legacy operation, the +.Cm bs[01] , +.Cm cr[0-3] , +.Cm ff[01] , +.Cm nl[01] , +.Cm tab[0-3] , +and +.Cm vt[01] +control modes are not accepted, nor are +.Cm ocrnl Pq Fl ocrnl , +.Cm ofdel Pq Fl ofdel , +.Cm ofill Pq Fl ofill , +.Cm onlret Pq Fl onlret , +and +.Cm onocr Pq Fl onocr . +.Pp +For more information about legacy mode, see +.Xr compat 5 . +.Sh SEE ALSO +.Xr termios 4 , +.Xr compat 5 +.Sh STANDARDS +The +.Nm +utility is expected to be +.St -p1003.2 +compatible. The flags +.Fl e +and +.Fl f +are +extensions to the standard. diff --git a/adv_cmds/stty/stty.c b/adv_cmds/stty/stty.c new file mode 100644 index 0000000..a7feaf0 --- /dev/null +++ b/adv_cmds/stty/stty.c @@ -0,0 +1,164 @@ +/*- + * Copyright (c) 1989, 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char const copyright[] = +"@(#) Copyright (c) 1989, 1991, 1993, 1994\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)stty.c 8.3 (Berkeley) 4/2/94"; +#endif +#endif /* not lint */ +#include <sys/cdefs.h> +__RCSID("$FreeBSD: src/bin/stty/stty.c,v 1.20 2002/06/30 05:15:04 obrien Exp $"); + +#include <sys/types.h> + +#include <ctype.h> +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "stty.h" +#include "extern.h" + +int +main(int argc, char *argv[]) +{ + struct info i; + enum FMT fmt; + int ch; + + fmt = NOTSET; + i.fd = STDIN_FILENO; + + opterr = 0; + while (optind < argc && + strspn(argv[optind], "-aefg") == strlen(argv[optind]) && + (ch = getopt(argc, argv, "aef:g")) != -1) + switch(ch) { + case 'a': /* undocumented: POSIX compatibility */ + fmt = POSIX; + break; + case 'e': + fmt = BSD; + break; + case 'f': + if ((i.fd = open(optarg, O_RDONLY | O_NONBLOCK)) < 0) + err(1, "%s", optarg); + break; + case 'g': + fmt = GFLAG; + break; + case '?': + default: + goto args; + } + +args: argc -= optind; + argv += optind; + + if (tcgetattr(i.fd, &i.t) < 0) + errx(1, "stdin isn't a terminal"); + if (ioctl(i.fd, TIOCGETD, &i.ldisc) < 0) + err(1, "TIOCGETD"); + if (ioctl(i.fd, TIOCGWINSZ, &i.win) < 0) + warn("TIOCGWINSZ"); + + checkredirect(); /* conversion aid */ + + switch(fmt) { + case NOTSET: + if (*argv) + break; + /* FALLTHROUGH */ + case BSD: + case POSIX: + print(&i.t, &i.win, i.ldisc, fmt); + break; + case GFLAG: + gprint(&i.t, &i.win, i.ldisc); + break; + } + + for (i.set = i.wset = 0; *argv; ++argv) { + if (ksearch(&argv, &i)) + continue; + + if (csearch(&argv, &i)) + continue; + + if (msearch(&argv, &i)) + continue; + + if (isdigit(**argv)) { + speed_t speed; + + speed = atoi(*argv); + cfsetospeed(&i.t, speed); + cfsetispeed(&i.t, speed); + i.set = 1; + continue; + } + + if (!strncmp(*argv, "gfmt1", sizeof("gfmt1") - 1)) { + gread(&i.t, *argv + sizeof("gfmt1") - 1); + i.set = 1; + continue; + } + + warnx("illegal option -- %s", *argv); + usage(); + } + + if (i.set && tcsetattr(i.fd, 0, &i.t) < 0) + err(1, "tcsetattr"); + if (i.wset && ioctl(i.fd, TIOCSWINSZ, &i.win) < 0) + warn("TIOCSWINSZ"); + exit(0); +} + +void +usage(void) +{ + + (void)fprintf(stderr, "usage: stty [-a|-e|-g] [-f file] [options]\n"); + exit (1); +} diff --git a/adv_cmds/stty/stty.h b/adv_cmds/stty/stty.h new file mode 100644 index 0000000..91c710f --- /dev/null +++ b/adv_cmds/stty/stty.h @@ -0,0 +1,59 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)stty.h 8.1 (Berkeley) 5/31/93 + * $FreeBSD: src/bin/stty/stty.h,v 1.8 2001/05/18 11:04:19 kris Exp $ + */ + +#include <sys/ioctl.h> +#include <termios.h> + +struct info { + int fd; /* file descriptor */ + int ldisc; /* line discipline */ + int off; /* turn off */ + int set; /* need set */ + int wset; /* need window set */ + const char *arg; /* argument */ + struct termios t; /* terminal info */ + struct winsize win; /* window info */ +}; + +struct cchar { + const char *name; + int sub; + u_char def; +}; + +enum FMT { NOTSET, GFLAG, BSD, POSIX }; + +#define LINELENGTH 72 diff --git a/adv_cmds/stty/util.c b/adv_cmds/stty/util.c new file mode 100644 index 0000000..9695365 --- /dev/null +++ b/adv_cmds/stty/util.c @@ -0,0 +1,68 @@ +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)util.c 8.3 (Berkeley) 4/2/94"; +#endif +#endif /* not lint */ +#include <sys/cdefs.h> +__RCSID("$FreeBSD: src/bin/stty/util.c,v 1.10 2002/06/30 05:15:04 obrien Exp $"); + +#include <sys/types.h> +#include <sys/stat.h> + +#include <err.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include "stty.h" +#include "extern.h" + +/* + * Gross, but since we're changing the control descriptor from 1 to 0, most + * users will be probably be doing "stty > /dev/sometty" by accident. If 1 + * and 2 are both ttys, but not the same, assume that 1 was incorrectly + * redirected. + */ +void +checkredirect(void) +{ + struct stat sb1, sb2; + + if (isatty(STDOUT_FILENO) && isatty(STDERR_FILENO) && + !fstat(STDOUT_FILENO, &sb1) && !fstat(STDERR_FILENO, &sb2) && + (sb1.st_rdev != sb2.st_rdev)) +warnx("stdout appears redirected, but stdin is the control descriptor"); +} diff --git a/adv_cmds/tabs/tabs.1 b/adv_cmds/tabs/tabs.1 new file mode 100644 index 0000000..b2f8523 --- /dev/null +++ b/adv_cmds/tabs/tabs.1 @@ -0,0 +1,160 @@ +.\" Copyright (c) 2002 Tim J. Robbins. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD: src/usr.bin/tabs/tabs.1,v 1.7 2005/01/17 07:44:29 ru Exp $ +.\" +.Dd May 20, 2002 +.Dt TABS 1 +.Os +.Sh NAME +.Nm tabs +.Nd set terminal tabs +.Sh SYNOPSIS +.Nm +.Op Fl Ar n | Fl a | a2 | c | c2 | c3 | f | p | s | u +.Op Cm +m Ns Op Ar n +.Op Fl T Ar type +.Nm +.Op Fl T Ar type +.Op Cm + Ns Op Ar n +.Ar n1 Ns Op Ns , Ns Ar n2 , Ns ... +.Sh DESCRIPTION +The +.Nm +utility displays a series of characters that clear the hardware terminal +tab settings then initialises tab stops at specified positions, and +optionally adjusts the margin. +.Pp +In the first synopsis form, the tab stops set depend on the command line +options used, and may be one of the predefined formats or at regular +intervals. +.Pp +In the second synopsis form, tab stops are set at positions +.Ar n1 , n2 , +etc. +If a position is preceded by a +.Ql + , +it is relative to the previous position set. +No more than 20 positions may be specified. +.Pp +If no tab stops are specified, the +.Dq standard +.Ux +tab width of 8 is used. +.Pp +The options are as follows: +.Bl -tag -width indent +.It Fl Ar n +Set a tab stop every +.Ar n +columns. +If +.Ar n +is 0, the tab stops are cleared but no new ones are set. +.It Fl a +Assembler format (columns 1, 10, 16, 36, 72). +.It Fl a2 +Assembler format (columns 1, 10, 16, 40, 72). +.It Fl c +.Tn COBOL +normal format (columns 1, 8, 12, 16, 20, 55) +.It Fl c2 +.Tn COBOL +compact format (columns 1, 6, 10, 14, 49) +.It Fl c3 +.Tn COBOL +compact format (columns 1, 6, 10, 14, 18, 22, 26, 30, 34, 38, 42, 46, +50, 54, 58, 62, 67). +.It Fl f +.Tn FORTRAN +format (columns 1, 7, 11, 15, 19, 23). +.It Fl p +.Tn PL/1 +format (columns 1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 49, 53, +57, 61). +.It Fl s +.Tn SNOBOL +format (columns 1, 10, 55). +.It Fl u +Assembler format (columns 1, 12, 20, 44). +.It Xo +.Cm +m Ns Op Ar n , +.Cm + Ns Op Ar n +.Xc +Set an +.Ar n +character left margin, or 10 if +.Ar n +is omitted. +.It Fl T Ar type +Output escape sequence for the terminal type +.Ar type . +.El +.Sh ENVIRONMENT +The +.Ev LANG , LC_ALL , LC_CTYPE +and +.Ev TERM +environment variables affect the execution of +.Nm +as described in +.Xr environ 7 . +.Pp +The +.Fl T +option overrides the setting of the +.Ev TERM +environment variable. +If neither +.Ev TERM +nor the +.Fl T +option are present, +.Nm +will fail. +.Sh EXIT STATUS +.Ex -std +.Sh SEE ALSO +.Xr expand 1 , +.Xr stty 1 , +.Xr tput 1 , +.Xr unexpand 1 , +.Xr termcap 5 +.Sh STANDARDS +The +.Nm +utility conforms to +.St -p1003.1-2001 . +.Sh HISTORY +A +.Nm +utility appeared in PWB UNIX. +This implementation was introduced in +.Fx 5.0 . +.Sh BUGS +The current +.Xr termcap 5 +database does not define the +.Ql ML +(set left soft margin) capability for any terminals. diff --git a/adv_cmds/tabs/tabs.c b/adv_cmds/tabs/tabs.c new file mode 100644 index 0000000..8130b8b --- /dev/null +++ b/adv_cmds/tabs/tabs.c @@ -0,0 +1,240 @@ +/*- + * Copyright (c) 2002 Tim J. Robbins. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * tabs -- set terminal tabs + * + * This utility displays a series of characters that clears the terminal + * hardware tab settings, then initialises them to specified values, + * and optionally sets a soft margin. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD: src/usr.bin/tabs/tabs.c,v 1.3 2002/06/08 11:33:22 tjr Exp $"); + +#ifdef __APPLE__ +#include <sys/ioctl.h> +#endif +#include <sys/types.h> +#include <sys/tty.h> + +#include <ctype.h> +#include <err.h> +#include <errno.h> +#include <locale.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <term.h> +#include <unistd.h> + +/* Maximum number of tab stops allowed in table. */ +#define NSTOPS 20 + +#define NELEMS(a) (sizeof(a) / sizeof(a[0])) + +/* Predefined formats, taken from IEEE Std 1003.1-2001. */ +static const struct { + const char *name; /* Format name used on cmd. line */ + long stops[NSTOPS]; /* Column positions */ +} formats[] = { + { "a", { 1, 10, 16, 36, 72 } }, + { "a2", { 1, 10, 16, 40, 72 } }, + { "c", { 1, 8, 12, 16, 20, 55 } }, + { "c2", { 1, 6, 10, 14, 49 } }, + { "c3", { 1, 6, 10, 14, 18, 22, 26, 30, 34, 38, 42, 46, 50, 54, 58, + 62, 67 } }, + { "f", { 1, 7, 11, 15, 19, 23 } }, + { "p", { 1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 49, 53, 57, + 61 } }, + { "s", { 1, 10, 55 } }, + { "u", { 1, 12, 20, 44 } } +}; + +static void gettabs(char *, long *, long *); +static int ttywidth(void); +static void usage(void); + +int +main(int argc __unused, char *argv[]) +{ + long cols, i, inc, j, margin, nstops, stops[NSTOPS]; + const char *cr, *ct, *st, *ML; + char area[1024], *ap, *arg, *end; + + setlocale(LC_ALL, ""); + + inc = 8; + margin = 0; + nstops = -1; + while ((arg = *++argv) != NULL && (*arg == '-' || *arg == '+')) { + if (*arg == '+') { + /* +m[n] or +[n] */ + if (*++arg == 'm') + arg++; + if (*arg != '\0') { + errno = 0; + margin = strtol(arg, &end, 10); + if (errno != 0 || *end != '\0' || margin < 0) + errx(1, "%s: invalid margin width", + arg); + } else + margin = 10; + } else if (isdigit(arg[1])) { + /* -n */ + errno = 0; + inc = strtol(arg + 1, &end, 10); + if (errno != 0 || *end != '\0' || inc < 0) + errx(1, "%s: invalid increment", arg + 1); + } else if (arg[1] == 'T') { + /* -Ttype or -T type */ + if (arg[2] != '\0') + setenv("TERM", arg + 2, 1); + else { + if ((arg = *++argv) == NULL) + usage(); + setenv("TERM", arg, 1); + } + } else if (arg[1] == '-') { + arg = *++argv; + break; + } else { + /* Predefined format */ + for (i = 0; i < (int)NELEMS(formats); i++) + if (strcmp(formats[i].name, arg + 1) == 0) + break; + if (i == NELEMS(formats)) + usage(); + for (j = nstops = 0; j < NSTOPS && + formats[i].stops[j] != 0; j++) + stops[nstops++] = formats[i].stops[j]; + } + } + + if (arg != NULL) { + if (nstops != -1) + usage(); + gettabs(arg, stops, &nstops); + } + + /* Initialise terminal, get the strings we need */ + setupterm(NULL, 1, NULL); + ap = area; + if ((ct = tgetstr("ct", &ap)) == NULL) + errx(1, "terminal cannot clear tabs"); + if ((st = tgetstr("st", &ap)) == NULL) + errx(1, "terminal cannot set tabs"); + if ((cr = tgetstr("cr", &ap)) == NULL) + cr = "\r"; + ML = tgetstr("ML", &ap); + cols = ttywidth(); + + /* Clear all tabs. */ + putp(cr); + putp(ct); + + /* + * Set soft margin. + * XXX Does this actually work? + */ + if (ML != NULL) { + printf("%*s", (int)margin, ""); + putp(ML); + } else if (margin != 0) + warnx("terminal cannot set left margin"); + + /* Optionally output new tab stops. */ + if (nstops >= 0) { + printf("%*s", (int)stops[0] - 1, ""); + putp(st); + for (i = 1; i < nstops; i++) { + printf("%*s", (int)(stops[i] - stops[i - 1]), ""); + putp(st); + } + } else if (inc > 0) { + for (i = 0; i < cols / inc; i++) { + putp(st); + printf("%*s", (int)inc, ""); + } + putp(st); + } + putp(cr); + + exit(0); +} + +static void +usage(void) +{ + + fprintf(stderr, +"usage: tabs [-n|-a|-a2|-c|-c2|-c3|-f|-p|-s|-u] [+m[n]] [-T type]\n"); + fprintf(stderr, +" tabs [-T type] [+[n]] n1,[n2,...]\n"); + exit(1); +} + +static void +gettabs(char *arg, long stops[], long *nstops) +{ + char *tok, *end; + long last, stop; + + for (last = *nstops = 0, tok = strtok(arg, ","); tok != NULL; + tok = strtok(NULL, ",")) { + if (*nstops >= NSTOPS) + errx(1, "too many tab stops (limit %d)", NSTOPS); + errno = 0; + stop = strtol(tok, &end, 10); + if (errno != 0 || *end != '\0' || stop <= 0) + errx(1, "%s: invalid tab stop", tok); + if (*tok == '+') { + if (tok == arg) + errx(1, "%s: first tab may not be relative", + tok); + stop += last; + } + if (last > stop) + errx(1, "cannot go backwards"); + last = stops[(*nstops)++] = stop; + } +} + +static int +ttywidth(void) +{ + struct winsize ws; + int width; + + if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) != -1) + width = ws.ws_col; + else if ((width = tgetnum("co")) == 0) { + width = 80; + warnx("cannot find terminal width; defaulted to %d", width); + } + + return (width); +} diff --git a/adv_cmds/tty/tty.1 b/adv_cmds/tty/tty.1 new file mode 100644 index 0000000..1fd66b8 --- /dev/null +++ b/adv_cmds/tty/tty.1 @@ -0,0 +1,87 @@ +.\" Copyright (c) 1990, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the Institute of Electrical and Electronics Engineers, Inc. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)tty.1 8.1 (Berkeley) 6/6/93 +.\" $FreeBSD: src/usr.bin/tty/tty.1,v 1.9 2006/12/13 20:15:49 ru Exp $ +.\" +.Dd June 6, 1993 +.Dt TTY 1 +.Os +.Sh NAME +.Nm tty +.Nd return user's terminal name +.Sh SYNOPSIS +.Nm +.Op Fl s +.Sh DESCRIPTION +The +.Nm +utility writes the name of the terminal attached to standard input +to standard output. +The name that is written is the string returned by +.Xr ttyname 3 . +If the standard input is not a terminal, the message +.Dq Li "not a tty" +is written. +The options are as follows: +.Bl -tag -width indent +.It Fl s +Do not write the terminal name; only the exit status is affected +when this option is specified. +The +.Fl s +option is deprecated in favor of the +.Dq Li "test -t 0" +command. +.El +.Sh EXIT STATUS +The +.Nm +utility +exits 0 if the standard input is a terminal, 1 if the standard input is +not a terminal, and >1 if an error occurs. +.Sh SEE ALSO +.Xr test 1 , +.Xr ttyname 3 +.Sh STANDARDS +The +.Nm +utility is expected to be +.St -p1003.2 +compatible. +.Sh HISTORY +A +.Nm +command appeared in +.At v1 . diff --git a/adv_cmds/tty/tty.c b/adv_cmds/tty/tty.c new file mode 100644 index 0000000..806fe4b --- /dev/null +++ b/adv_cmds/tty/tty.c @@ -0,0 +1,83 @@ +/* + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static const char copyright[] = +"@(#) Copyright (c) 1988, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)tty.c 8.1 (Berkeley) 6/6/93"; +#endif +#endif /* not lint */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD: src/usr.bin/tty/tty.c,v 1.9 2002/05/29 17:12:30 jmallett Exp $"); + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +static void usage(void); + +int +main(int argc, char *argv[]) +{ + int ch, sflag; + char *t; + + sflag = 0; + while ((ch = getopt(argc, argv, "s")) != -1) + switch (ch) { + case 's': + sflag = 1; + break; + case '?': + default: + usage(); + } + + t = ttyname(0); + if (!sflag) + puts(t ? t : "not a tty"); + exit(t ? 0 : 1); +} + +static void +usage(void) +{ + fprintf(stderr, "usage: tty [-s]\n"); + exit(2); +} diff --git a/adv_cmds/whois/whois.1 b/adv_cmds/whois/whois.1 new file mode 100644 index 0000000..0177b48 --- /dev/null +++ b/adv_cmds/whois/whois.1 @@ -0,0 +1,287 @@ +.\" Copyright (c) 1985, 1990, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" From: @(#)whois.1 8.1 (Berkeley) 6/6/93 +.\" $FreeBSD$ +.\" +.Dd April 25, 2016 +.Dt WHOIS 1 +.Os +.Sh NAME +.Nm whois +.Nd "Internet domain name and network number directory service" +.Sh SYNOPSIS +.Nm +.Op Fl aAbfgiIklmPQrRS +.Op Fl c Ar TLD | Fl h Ar host +.Op Fl p Ar port +.Op Fl - +.Ar name ... +.Sh DESCRIPTION +The +.Nm +utility looks up records in the databases maintained by several +Network Information Centers +.Pq Tn NICs . +.Pp +By default +.Nm +starts by querying the Internet Assigned Numbers Authority (IANA) whois server, +and follows referrals to whois servers +that have more specific details about the query +.Ar name . +The IANA whois server knows about +IP address and AS numbers +as well as domain names. +.Pp +There are a few special cases where referrals do not work, so +.Nm +goes directly to the appropriate server. +These include point-of-contact handles for ARIN, +.Pa nic.at , +NORID, and RIPE, +and domain names under +.Pa ac.uk . +.Pp +The options are as follows: +.Bl -tag -width indent +.It Fl a +Use the American Registry for Internet Numbers +.Pq Tn ARIN +database. +It contains network numbers used in those parts of the world covered neither by +.Tn APNIC , AfriNIC , LACNIC , +nor by +.Tn RIPE . +The query syntax is documented at +.Pa https://www.arin.net/resources/whoisrws/whois_api.html#nicname +.It Fl A +Use the Asia/Pacific Network Information Center +.Pq Tn APNIC +database. +It contains network numbers used in East Asia, Australia, +New Zealand, and the Pacific islands. +Get query syntax documentation using +.Ic whois -A help +.It Fl b +Use the Network Abuse Clearinghouse database. +It contains addresses to which network abuse should be reported, +indexed by domain name. +.It Fl c Ar TLD +This is the equivalent of using the +.Fl h +option with an argument of +.Qq Ar TLD Ns Li .whois-servers.net . +This can be helpful for locating country-class TLD whois servers. +.It Fl f +Use the African Network Information Centre +.Pq Tn AfriNIC +database. +It contains network numbers used in Africa and the islands of the +western Indian Ocean. +Get query syntax documentation using +.Ic whois -f help +.It Fl g +Use the US non-military federal government database, which contains points of +contact for subdomains of +.Pa .GOV . +.It Fl h Ar host +Use the specified host instead of the default. +Either a host name or an IP address may be specified. +.It Fl i +Use the traditional Network Information Center (InterNIC) +.Pq Pa whois.internic.net +database. +This now contains only registrations for domain names under +.Pa .COM , +.Pa .NET , +.Pa .EDU . +You can specify the type of object to search for like +.Ic whois -i ' Ns Ar type Ar name Ns Ic ' +where +.Ar type +can be +.Nm domain , nameserver , registrar . +The +.Ar name +can contain +.Li * +wildcards. +.It Fl I +Use the Internet Assigned Numbers Authority +.Pq Tn IANA +database. +.It Fl k +Use the National Internet Development Agency of Korea's +.Pq Tn KRNIC +database. +It contains network numbers and domain contact information +for Korea. +.It Fl l +Use the Latin American and Caribbean IP address Regional Registry +.Pq Tn LACNIC +database. +It contains network numbers used in much of Latin America and the +Caribbean. +.It Fl m +Use the Route Arbiter Database +.Pq Tn RADB +database. +It contains route policy specifications for a large +number of operators' networks. +.It Fl p Ar port +Connect to the whois server on +.Ar port . +If this option is not specified, +.Nm +defaults to port 43. +.It Fl P +Use the PeeringDB database of AS numbers. +It contains details about presence at internet peering points +for many network operators. +.It Fl Q +Do a quick lookup; +.Nm +will not attempt to follow referrals to other whois servers. +This is the default if a server is explicitly specified +using one of the other options or in an environment variable. +See also the +.Fl R +option. +.It Fl r +Use the R\(aaeseaux IP Europ\(aaeens +.Pq Tn RIPE +database. +It contains network numbers and domain contact information +for Europe. +Get query syntax documentation using +.Ic whois -r help +.It Fl R +Do a recursive lookup; +.Nm +will attempt to follow referrals to other whois servers. +This is the default if no server is explicitly specified. +See also the +.Fl Q +option. +.It Fl S +By default +.Nm +adjusts simple queries (without spaces) to produce more useful output +from certain whois servers, +and it suppresses some uninformative output. +With the +.Fl S +option, +.Nm +sends the query and prints the output verbatim. +.El +.Pp +The operands specified to +.Nm +are treated independently and may be used +as queries on different whois servers. +.Sh ENVIRONMENT +.Bl -tag -width WHOIS_SERVER +.It Ev WHOIS_SERVER +The primary default whois server. +If this is unset, +.Nm +uses the +.Ev RA_SERVER +environment variable. +.It Ev RA_SERVER +The secondary default whois server. +If this is unset, +.Nm +will use +.Pa whois.iana.org . +.El +.Sh EXIT STATUS +.Ex -std +.Sh EXAMPLES +To obtain contact information about an +administrator located in the Russian +.Tn TLD +domain +.Qq Li RU , +use the +.Fl c +option as shown in the following example, where +.Ar CONTACT-ID +is substituted with the actual contact identifier. +.Pp +.Dl Ic whois -c RU CONTACT-ID +.Pp +(Note: This example is specific to the +.Tn TLD +.Qq Li RU , +but other +.Tn TLDs +can be queried by using a similar syntax.) +.Pp +The following example demonstrates how to query +a whois server using a non-standard port, where +.Dq Li query-data +is the query to be sent to +.Dq Li whois.example.com +on port +.Dq Li rwhois +(written numerically as 4321). +.Pp +.Dl Ic whois -h whois.example.com -p rwhois query-data +.Pp +Some whois servers support complex queries +with dash-letter options. +You can use the +.Fl - +option to separate +.Nm +command options from whois server query options. +A query containing spaces must be quoted as one +argument to the +.Nm +command. +The following example asks the RIPE whois server +to return a brief description of its +.Dq Li domain +object type: +.Pp +.Dl Ic whois -r -- '-t domain' +.Sh SEE ALSO +.Rs +.%A Ken Harrenstien +.%A Vic White +.%T NICNAME/WHOIS +.%D 1 March 1982 +.%O RFC 812 +.Re +.Sh HISTORY +The +.Nm +command appeared in +.Bx 4.3 . diff --git a/adv_cmds/whois/whois.c b/adv_cmds/whois/whois.c new file mode 100644 index 0000000..a6c4f6c --- /dev/null +++ b/adv_cmds/whois/whois.c @@ -0,0 +1,629 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static const char copyright[] = +"@(#) Copyright (c) 1980, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#if 0 +#ifndef lint +static char sccsid[] = "@(#)whois.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ +#endif + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/poll.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <ctype.h> +#include <err.h> +#include <netdb.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sysexits.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> + +#ifdef __APPLE__ +#ifndef SOCK_NONBLOCK +#define SOCK_NONBLOCK 0 +#endif +#ifndef INFTIM +#define INFTIM -1 +#endif +#endif + +#define ABUSEHOST "whois.abuse.net" +#define ANICHOST "whois.arin.net" +#define DENICHOST "whois.denic.de" +#define DKNICHOST "whois.dk-hostmaster.dk" +#define FNICHOST "whois.afrinic.net" +#define GNICHOST "whois.nic.gov" +#define IANAHOST "whois.iana.org" +#define INICHOST "whois.internic.net" +#define KNICHOST "whois.krnic.net" +#define LNICHOST "whois.lacnic.net" +#define MNICHOST "whois.ra.net" +#define PDBHOST "whois.peeringdb.com" +#define PNICHOST "whois.apnic.net" +#define QNICHOST_TAIL ".whois-servers.net" +#define RNICHOST "whois.ripe.net" +#define VNICHOST "whois.verisign-grs.com" + +#ifdef __APPLE__ +#define DEFAULT_PORT "nicname" +#else +#define DEFAULT_PORT "whois" +#endif + +#define WHOIS_RECURSE 0x01 +#define WHOIS_QUICK 0x02 +#define WHOIS_SPAM_ME 0x04 + +#define CHOPSPAM ">>> Last update of WHOIS database:" + +#define ishost(h) (isalnum((unsigned char)h) || h == '.' || h == '-') + +#define SCAN(p, end, check) \ + while ((p) < (end)) \ + if (check) ++(p); \ + else break + +static struct { + const char *suffix, *server; +} whoiswhere[] = { + /* Various handles */ + { "-ARIN", ANICHOST }, + { "-NICAT", "at" QNICHOST_TAIL }, + { "-NORID", "no" QNICHOST_TAIL }, + { "-RIPE", RNICHOST }, + /* Nominet's whois server doesn't return referrals to JANET */ + { ".ac.uk", "ac.uk" QNICHOST_TAIL }, + { ".gov.uk", "ac.uk" QNICHOST_TAIL }, + { "", IANAHOST }, /* default */ + { NULL, NULL } /* safety belt */ +}; + +#define WHOIS_REFERRAL(s) { s, sizeof(s) - 1 } +static struct { + const char *prefix; + size_t len; +} whois_referral[] = { + WHOIS_REFERRAL("whois:"), /* IANA */ + WHOIS_REFERRAL("Whois Server:"), + WHOIS_REFERRAL("Registrar WHOIS Server:"), /* corporatedomains.com */ + WHOIS_REFERRAL("ReferralServer: whois://"), /* ARIN */ + WHOIS_REFERRAL("descr: region. Please query"), /* AfriNIC */ + { NULL, 0 } +}; + +/* + * We have a list of patterns for RIRs that assert ignorance rather than + * providing referrals. If that happens, we guess that ARIN will be more + * helpful. But, before following a referral to an RIR, we check if we have + * asked that RIR already, and if so we make another guess. + */ +static const char *actually_arin[] = { + "netname: ERX-NETBLOCK\n", /* APNIC */ + "netname: NON-RIPE-NCC-MANAGED-ADDRESS-BLOCK\n", + NULL +}; + +static struct { + int loop; + const char *host; +} try_rir[] = { + { 0, ANICHOST }, + { 0, RNICHOST }, + { 0, PNICHOST }, + { 0, FNICHOST }, + { 0, LNICHOST }, + { 0, NULL } +}; + +static void +reset_rir(void) { + int i; + + for (i = 0; try_rir[i].host != NULL; i++) + try_rir[i].loop = 0; +} + +static const char *port = DEFAULT_PORT; + +static const char *choose_server(char *); +static struct addrinfo *gethostinfo(char const *host, int exitnoname); +#ifdef __APPLE__ +static void s_asprintf(char **ret, const char *format, ...) __attribute__((__format__(printf, 2, 3))); +#else +static void s_asprintf(char **ret, const char *format, ...) __printflike(2, 3); +#endif +static void usage(void); +static void whois(const char *, const char *, int); + +int +main(int argc, char *argv[]) +{ + const char *country, *host; + int ch, flags; + +#ifdef SOCKS + SOCKSinit(argv[0]); +#endif + + country = host = NULL; + flags = 0; + while ((ch = getopt(argc, argv, "aAbc:fgh:iIklmp:PQrRS")) != -1) { + switch (ch) { + case 'a': + host = ANICHOST; + break; + case 'A': + host = PNICHOST; + break; + case 'b': + host = ABUSEHOST; + break; + case 'c': + country = optarg; + break; + case 'f': + host = FNICHOST; + break; + case 'g': + host = GNICHOST; + break; + case 'h': + host = optarg; + break; + case 'i': + host = INICHOST; + break; + case 'I': + host = IANAHOST; + break; + case 'k': + host = KNICHOST; + break; + case 'l': + host = LNICHOST; + break; + case 'm': + host = MNICHOST; + break; + case 'p': + port = optarg; + break; + case 'P': + host = PDBHOST; + break; + case 'Q': + flags |= WHOIS_QUICK; + break; + case 'r': + host = RNICHOST; + break; + case 'R': + flags |= WHOIS_RECURSE; + break; + case 'S': + flags |= WHOIS_SPAM_ME; + break; + case '?': + default: + usage(); + /* NOTREACHED */ + } + } + argc -= optind; + argv += optind; + + if (!argc || (country != NULL && host != NULL)) + usage(); + + /* + * If no host or country is specified, rely on referrals from IANA. + */ + if (host == NULL && country == NULL) { + if ((host = getenv("WHOIS_SERVER")) == NULL && + (host = getenv("RA_SERVER")) == NULL) { + if (!(flags & WHOIS_QUICK)) + flags |= WHOIS_RECURSE; + } + } + while (argc-- > 0) { + if (country != NULL) { + char *qnichost; + s_asprintf(&qnichost, "%s%s", country, QNICHOST_TAIL); + whois(*argv, qnichost, flags); + free(qnichost); + } else + whois(*argv, host != NULL ? host : + choose_server(*argv), flags); + reset_rir(); + argv++; + } + exit(0); +} + +static const char * +choose_server(char *domain) +{ + size_t len = strlen(domain); + int i; + + for (i = 0; whoiswhere[i].suffix != NULL; i++) { + size_t suffix_len = strlen(whoiswhere[i].suffix); + if (len > suffix_len && + strcasecmp(domain + len - suffix_len, + whoiswhere[i].suffix) == 0) + return (whoiswhere[i].server); + } + errx(EX_SOFTWARE, "no default whois server"); +} + +static struct addrinfo * +gethostinfo(char const *host, int exit_on_noname) +{ + struct addrinfo hints, *res; + int error; + + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_CANONNAME; + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + res = NULL; + error = getaddrinfo(host, port, &hints, &res); + if (error && (exit_on_noname || error != EAI_NONAME)) + err(EX_NOHOST, "%s: %s", host, gai_strerror(error)); + return (res); +} + +/* + * Wrapper for asprintf(3) that exits on error. + */ +static void +s_asprintf(char **ret, const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + if (vasprintf(ret, format, ap) == -1) { + va_end(ap); + err(EX_OSERR, "vasprintf()"); + } + va_end(ap); +} + +static int +connect_to_any_host(struct addrinfo *hostres) +{ + struct addrinfo *res; + nfds_t i, j; + size_t count; + struct pollfd *fds; + int timeout = 180, s = -1; + + for (res = hostres, count = 0; res; res = res->ai_next) + count++; + fds = calloc(count, sizeof(*fds)); + if (fds == NULL) + err(EX_OSERR, "calloc()"); + + /* + * Traverse the result list elements and make non-block + * connection attempts. + */ + count = i = 0; + for (res = hostres; res != NULL; res = res->ai_next) { + s = socket(res->ai_family, res->ai_socktype | SOCK_NONBLOCK, + res->ai_protocol); + if (s < 0) + continue; +#ifdef __APPLE__ + int flags = fcntl(s, F_GETFL, 0); + if (flags < 0) { + close(s); + continue; + } + flags |= O_NONBLOCK; + if (fcntl(s, F_SETFL, flags) != 0) { + close(s); + continue; + } +#endif + if (connect(s, res->ai_addr, res->ai_addrlen) < 0) { + if (errno == EINPROGRESS) { + /* Add the socket to poll list */ + fds[i].fd = s; + fds[i].events = POLLERR | POLLHUP | + POLLIN | POLLOUT; + /* + * From here until a socket connects, the + * socket fd is owned by the fds[] poll array. + */ + s = -1; + count++; + i++; + } else { + close(s); + s = -1; + + /* + * Poll only if we have something to poll, + * otherwise just go ahead and try next + * address + */ + if (count == 0) + continue; + } + } else + goto done; + + /* + * If we are at the last address, poll until a connection is + * established or we failed all connection attempts. + */ + if (res->ai_next == NULL) + timeout = INFTIM; + + /* + * Poll the watched descriptors for successful connections: + * if we still have more untried resolved addresses, poll only + * once; otherwise, poll until all descriptors have errors, + * which will be considered as ETIMEDOUT later. + */ + do { + int n; + + n = poll(fds, i, timeout); + if (n == 0) { + /* + * No event reported in time. Try with a + * smaller timeout (but cap at 2-3ms) + * after a new host have been added. + */ + if (timeout >= 3) + timeout >>= 1; + + break; + } else if (n < 0) { + /* + * errno here can only be EINTR which we would + * want to clean up and bail out. + */ + s = -1; + goto done; + } + + /* + * Check for the event(s) we have seen. + */ + for (j = 0; j < i; j++) { + if (fds[j].fd == -1 || fds[j].events == 0 || + fds[j].revents == 0) + continue; + if (fds[j].revents & ~(POLLIN | POLLOUT)) { + close(fds[j].fd); + fds[j].fd = -1; + fds[j].events = 0; + count--; + continue; + } else if (fds[j].revents & (POLLIN | POLLOUT)) { + /* Connect succeeded. */ + s = fds[j].fd; + fds[j].fd = -1; + + goto done; + } + + } + } while (timeout == INFTIM && count != 0); + } + + /* All attempts were failed */ + s = -1; + if (count == 0) + errno = ETIMEDOUT; + +done: + /* Close all watched fds except the succeeded one */ + for (j = 0; j < i; j++) + if (fds[j].fd != -1) + close(fds[j].fd); + free(fds); + return (s); +} + +static void +whois(const char *query, const char *hostname, int flags) +{ + FILE *fp; + struct addrinfo *hostres; + char *buf, *host, *nhost, *p; + int comment, s, f; + size_t len, i; + + hostres = gethostinfo(hostname, 1); + s = connect_to_any_host(hostres); + if (s == -1) + err(EX_OSERR, "connect()"); + + /* Restore default blocking behavior. */ + if ((f = fcntl(s, F_GETFL)) == -1) + err(EX_OSERR, "fcntl()"); + f &= ~O_NONBLOCK; + if (fcntl(s, F_SETFL, f) == -1) + err(EX_OSERR, "fcntl()"); + + fp = fdopen(s, "r+"); + if (fp == NULL) + err(EX_OSERR, "fdopen()"); + + if (!(flags & WHOIS_SPAM_ME) && + (strcasecmp(hostname, DENICHOST) == 0 || + strcasecmp(hostname, "de" QNICHOST_TAIL) == 0)) { + const char *q; + int idn = 0; + for (q = query; *q != '\0'; q++) + if (!isascii(*q)) + idn = 1; + fprintf(fp, "-T dn%s %s\r\n", idn ? "" : ",ace", query); + } else if (!(flags & WHOIS_SPAM_ME) && + (strcasecmp(hostname, DKNICHOST) == 0 || + strcasecmp(hostname, "dk" QNICHOST_TAIL) == 0)) + fprintf(fp, "--show-handles %s\r\n", query); + else if ((flags & WHOIS_SPAM_ME) || + strchr(query, ' ') != NULL) + fprintf(fp, "%s\r\n", query); + else if (strcasecmp(hostname, ANICHOST) == 0) { + if (strncasecmp(query, "AS", 2) == 0 && + strspn(query+2, "0123456789") == strlen(query+2)) + fprintf(fp, "+ a %s\r\n", query+2); + else + fprintf(fp, "+ %s\r\n", query); + } else if (strcasecmp(hostres->ai_canonname, VNICHOST) == 0) + fprintf(fp, "domain %s\r\n", query); + else + fprintf(fp, "%s\r\n", query); + fflush(fp); + + comment = 0; + if (!(flags & WHOIS_SPAM_ME) && + (strcasecmp(hostname, ANICHOST) == 0 || + strcasecmp(hostname, RNICHOST) == 0)) { + comment = 2; + } + + nhost = NULL; + while ((buf = fgetln(fp, &len)) != NULL) { + /* Nominet */ + if (!(flags & WHOIS_SPAM_ME) && + len == 5 && strncmp(buf, "-- \r\n", 5) == 0) + break; + /* RIRs */ + if (comment == 1 && buf[0] == '#') + break; + else if (comment == 2) { + if (strchr("#%\r\n", buf[0]) != NULL) + continue; + else + comment = 1; + } + + printf("%.*s", (int)len, buf); + + if ((flags & WHOIS_RECURSE) && nhost == NULL) { + for (i = 0; whois_referral[i].prefix != NULL; i++) { + p = buf; + SCAN(p, buf+len, *p == ' '); + if (strncasecmp(p, whois_referral[i].prefix, + whois_referral[i].len) != 0) + continue; + p += whois_referral[i].len; + SCAN(p, buf+len, *p == ' '); + host = p; + SCAN(p, buf+len, ishost(*p)); + if (p > host) + s_asprintf(&nhost, "%.*s", + (int)(p - host), host); + break; + } + for (i = 0; actually_arin[i] != NULL; i++) { + if (strncmp(buf, actually_arin[i], len) == 0) { + s_asprintf(&nhost, "%s", ANICHOST); + break; + } + } + } + /* Verisign etc. */ + if (!(flags & WHOIS_SPAM_ME) && + len >= sizeof(CHOPSPAM)-1 && + (strncasecmp(buf, CHOPSPAM, sizeof(CHOPSPAM)-1) == 0 || + strncasecmp(buf, CHOPSPAM+4, sizeof(CHOPSPAM)-5) == 0)) { + printf("\n"); + break; + } + } + fclose(fp); + freeaddrinfo(hostres); + + f = 0; + for (i = 0; try_rir[i].host != NULL; i++) { + /* Remember visits to RIRs */ + if (try_rir[i].loop == 0 && + strcasecmp(try_rir[i].host, hostname) == 0) + try_rir[i].loop = 1; + /* Do we need to find an alternative RIR? */ + if (try_rir[i].loop != 0 && nhost != NULL && + strcasecmp(try_rir[i].host, nhost) == 0) { + free(nhost); + nhost = NULL; + f = 1; + } + } + if (f) { + /* Find a replacement RIR */ + for (i = 0; try_rir[i].host != NULL; i++) { + if (try_rir[i].loop == 0) { + s_asprintf(&nhost, "%s", + try_rir[i].host); + break; + } + } + } + if (nhost != NULL) { + /* Ignore self-referrals */ + if (strcasecmp(hostname, nhost) != 0) { + printf("# %s\n\n", nhost); + whois(query, nhost, flags); + } + free(nhost); + } +} + +static void +usage(void) +{ + fprintf(stderr, + "usage: whois [-aAbfgiIklmPQrRS] [-c country-code | -h hostname] " + "[-p port] name ...\n"); + exit(EX_USAGE); +} diff --git a/adv_cmds/xcodescripts/variant_links.sh b/adv_cmds/xcodescripts/variant_links.sh new file mode 100644 index 0000000..523c755 --- /dev/null +++ b/adv_cmds/xcodescripts/variant_links.sh @@ -0,0 +1,11 @@ +#!/bin/sh +# +# Variant links cannot be created in the actual target, because Strip/CodeSign/etc are +# after all other phases. Running it in the aggregate target guarantees that the variants +# are really linked to the actual stripped/signed binary. +# + +set -ex + +ln ${DSTROOT}/usr/bin/pkill ${DSTROOT}/usr/bin/pgrep +ln ${DSTROOT}/usr/share/man/man1/pkill.1 ${DSTROOT}/usr/share/man/man1/pgrep.1 |