aboutsummaryrefslogtreecommitdiffstats
path: root/shell_cmds
diff options
context:
space:
mode:
authorCameron Katri <me@cameronkatri.com>2021-05-09 14:20:58 -0400
committerCameron Katri <me@cameronkatri.com>2021-05-09 14:20:58 -0400
commit5fd83771641d15c418f747bd343ba6738d3875f7 (patch)
tree5abf0f78f680d9837dbd93d4d4c3933bb7509599 /shell_cmds
downloadapple_cmds-5fd83771641d15c418f747bd343ba6738d3875f7.tar.gz
apple_cmds-5fd83771641d15c418f747bd343ba6738d3875f7.tar.zst
apple_cmds-5fd83771641d15c418f747bd343ba6738d3875f7.zip
Import macOS userland
adv_cmds-176 basic_cmds-55 bootstrap_cmds-116.100.1 developer_cmds-66 diskdev_cmds-667.40.1 doc_cmds-53.60.1 file_cmds-321.40.3 mail_cmds-35 misc_cmds-34 network_cmds-606.40.1 patch_cmds-17 remote_cmds-63 shell_cmds-216.60.1 system_cmds-880.60.2 text_cmds-106
Diffstat (limited to 'shell_cmds')
-rw-r--r--shell_cmds/.upstream_base_commits4
-rw-r--r--shell_cmds/alias/alias.11
-rw-r--r--shell_cmds/alias/builtin.1333
-rw-r--r--shell_cmds/alias/generic.sh4
-rw-r--r--shell_cmds/apply/apply.1140
-rw-r--r--shell_cmds/apply/apply.c267
-rw-r--r--shell_cmds/basename/basename.1114
-rw-r--r--shell_cmds/basename/basename.c119
-rw-r--r--shell_cmds/basename/dirname.11
-rw-r--r--shell_cmds/chroot/chroot.8102
-rw-r--r--shell_cmds/chroot/chroot.c178
-rw-r--r--shell_cmds/date/date.1472
-rw-r--r--shell_cmds/date/date.c365
-rw-r--r--shell_cmds/date/date.plist.part22
-rw-r--r--shell_cmds/date/extern.h35
-rw-r--r--shell_cmds/date/netdate.c181
-rw-r--r--shell_cmds/date/vary.c506
-rw-r--r--shell_cmds/date/vary.h36
-rw-r--r--shell_cmds/dirname/dirname.c84
-rw-r--r--shell_cmds/echo/echo.1101
-rw-r--r--shell_cmds/echo/echo.c182
-rw-r--r--shell_cmds/env/env.1482
-rw-r--r--shell_cmds/env/env.c144
-rw-r--r--shell_cmds/env/envopts.c468
-rw-r--r--shell_cmds/env/envopts.h37
-rw-r--r--shell_cmds/expr/expr.1235
-rw-r--r--shell_cmds/expr/expr.y571
-rw-r--r--shell_cmds/false/false.160
-rw-r--r--shell_cmds/false/false.c2
-rw-r--r--shell_cmds/false/false.sh2
-rw-r--r--shell_cmds/find/extern.h124
-rw-r--r--shell_cmds/find/find.11078
-rw-r--r--shell_cmds/find/find.c323
-rw-r--r--shell_cmds/find/find.h145
-rw-r--r--shell_cmds/find/find.plist.part30
-rw-r--r--shell_cmds/find/function.c1772
-rw-r--r--shell_cmds/find/getdate.y961
-rw-r--r--shell_cmds/find/ls.c124
-rw-r--r--shell_cmds/find/main.c166
-rw-r--r--shell_cmds/find/misc.c106
-rw-r--r--shell_cmds/find/operator.c273
-rw-r--r--shell_cmds/find/option.c201
-rw-r--r--shell_cmds/getopt/getopt.1134
-rw-r--r--shell_cmds/getopt/getopt.c32
-rw-r--r--shell_cmds/hexdump/conv.c178
-rw-r--r--shell_cmds/hexdump/display.c417
-rw-r--r--shell_cmds/hexdump/hexdump.1342
-rw-r--r--shell_cmds/hexdump/hexdump.c86
-rw-r--r--shell_cmds/hexdump/hexdump.h108
-rw-r--r--shell_cmds/hexdump/hexsyntax.c147
-rw-r--r--shell_cmds/hexdump/od.1267
-rw-r--r--shell_cmds/hexdump/odsyntax.c447
-rw-r--r--shell_cmds/hexdump/parse.c523
-rw-r--r--shell_cmds/hostname/hostname.167
-rw-r--r--shell_cmds/hostname/hostname.c105
-rw-r--r--shell_cmds/id/groups.163
-rw-r--r--shell_cmds/id/id.1167
-rw-r--r--shell_cmds/id/id.c529
-rw-r--r--shell_cmds/id/open_directory.c229
-rw-r--r--shell_cmds/id/open_directory.h18
-rw-r--r--shell_cmds/id/whoami.160
-rw-r--r--shell_cmds/jot/jot.1251
-rw-r--r--shell_cmds/jot/jot.c490
-rw-r--r--shell_cmds/kill/kill.1152
-rw-r--r--shell_cmds/kill/kill.c230
-rw-r--r--shell_cmds/kill/kill.plist.part18
-rw-r--r--shell_cmds/killall/killall.1159
-rw-r--r--shell_cmds/killall/killall.c549
-rw-r--r--shell_cmds/lastcomm/lastcomm.1132
-rw-r--r--shell_cmds/lastcomm/lastcomm.c235
-rw-r--r--shell_cmds/lastcomm/pathnames.h36
-rw-r--r--shell_cmds/locate/bigram/locate.bigram.81
-rw-r--r--shell_cmds/locate/bigram/locate.bigram.c110
-rw-r--r--shell_cmds/locate/code/locate.code.823
-rw-r--r--shell_cmds/locate/code/locate.code.c279
-rw-r--r--shell_cmds/locate/locate/com.apple.locate.plist35
-rw-r--r--shell_cmds/locate/locate/concatdb.sh70
-rw-r--r--shell_cmds/locate/locate/fastfind.c338
-rw-r--r--shell_cmds/locate/locate/locate.1276
-rw-r--r--shell_cmds/locate/locate/locate.c389
-rw-r--r--shell_cmds/locate/locate/locate.h76
-rw-r--r--shell_cmds/locate/locate/locate.rc26
-rwxr-xr-xshell_cmds/locate/locate/locate.updatedb.875
-rw-r--r--shell_cmds/locate/locate/mklocatedb.sh92
-rw-r--r--shell_cmds/locate/locate/pathnames.h36
-rw-r--r--shell_cmds/locate/locate/updatedb.sh106
-rw-r--r--shell_cmds/locate/locate/util.c278
-rw-r--r--shell_cmds/logname/logname.178
-rw-r--r--shell_cmds/logname/logname.c92
-rw-r--r--shell_cmds/mktemp/mktemp.1215
-rw-r--r--shell_cmds/mktemp/mktemp.c182
-rw-r--r--shell_cmds/mktemp/mktemp.plist.part21
-rw-r--r--shell_cmds/nice/nice.1120
-rw-r--r--shell_cmds/nice/nice.c122
-rw-r--r--shell_cmds/nohup/nohup.1124
-rw-r--r--shell_cmds/nohup/nohup.c149
-rw-r--r--shell_cmds/path_helper/path_helper.876
-rw-r--r--shell_cmds/path_helper/path_helper.c201
-rw-r--r--shell_cmds/printenv/printenv.184
-rw-r--r--shell_cmds/printenv/printenv.c99
-rw-r--r--shell_cmds/printf/printf.1418
-rw-r--r--shell_cmds/printf/printf.c697
-rw-r--r--shell_cmds/printf/printf.plist.part18
-rw-r--r--shell_cmds/printf/tests/Makefile23
-rw-r--r--shell_cmds/printf/tests/Makefile.depend11
-rw-r--r--shell_cmds/printf/tests/legacy_test.sh6
-rw-r--r--shell_cmds/printf/tests/regress.b.out1
-rw-r--r--shell_cmds/printf/tests/regress.bwidth.out1
-rw-r--r--shell_cmds/printf/tests/regress.d.out1
-rw-r--r--shell_cmds/printf/tests/regress.f.out1
-rw-r--r--shell_cmds/printf/tests/regress.l1.out1
-rw-r--r--shell_cmds/printf/tests/regress.l2.out1
-rw-r--r--shell_cmds/printf/tests/regress.m1.outbin0 -> 7 bytes
-rw-r--r--shell_cmds/printf/tests/regress.m2.out2
-rw-r--r--shell_cmds/printf/tests/regress.m3.out4
-rw-r--r--shell_cmds/printf/tests/regress.m4.out1
-rw-r--r--shell_cmds/printf/tests/regress.m5.out1
-rw-r--r--shell_cmds/printf/tests/regress.missingpos1.out1
-rw-r--r--shell_cmds/printf/tests/regress.s.out1
-rw-r--r--shell_cmds/printf/tests/regress.sh32
-rw-r--r--shell_cmds/printf/tests/regress.zero.out1
-rw-r--r--shell_cmds/pwd/pwd.1103
-rw-r--r--shell_cmds/pwd/pwd.c127
-rw-r--r--shell_cmds/renice/renice.8138
-rw-r--r--shell_cmds/renice/renice.c203
-rw-r--r--shell_cmds/script/script.1217
-rw-r--r--shell_cmds/script/script.c546
-rw-r--r--shell_cmds/script/script.plist.part20
-rw-r--r--shell_cmds/seq/seq.1187
-rw-r--r--shell_cmds/seq/seq.c453
-rw-r--r--shell_cmds/sh/Makefile70
-rw-r--r--shell_cmds/sh/Makefile.depend19
-rw-r--r--shell_cmds/sh/TOUR301
-rw-r--r--shell_cmds/sh/alias.c256
-rw-r--r--shell_cmds/sh/alias.h45
-rw-r--r--shell_cmds/sh/arith.h37
-rw-r--r--shell_cmds/sh/arith_yacc.c381
-rw-r--r--shell_cmds/sh/arith_yacc.h93
-rw-r--r--shell_cmds/sh/arith_yylex.c248
-rw-r--r--shell_cmds/sh/bltin/bltin.h81
-rw-r--r--shell_cmds/sh/bltin/echo.c109
-rw-r--r--shell_cmds/sh/builtins.def96
-rw-r--r--shell_cmds/sh/cd.c430
-rw-r--r--shell_cmds/sh/cd.h32
-rw-r--r--shell_cmds/sh/error.c199
-rw-r--r--shell_cmds/sh/error.h95
-rw-r--r--shell_cmds/sh/eval.c1381
-rw-r--r--shell_cmds/sh/eval.h70
-rw-r--r--shell_cmds/sh/exec.c780
-rw-r--r--shell_cmds/sh/exec.h77
-rw-r--r--shell_cmds/sh/expand.c1550
-rw-r--r--shell_cmds/sh/expand.h62
-rw-r--r--shell_cmds/sh/funcs/cmv49
-rw-r--r--shell_cmds/sh/funcs/dirs73
-rw-r--r--shell_cmds/sh/funcs/login38
-rw-r--r--shell_cmds/sh/funcs/newgrp37
-rw-r--r--shell_cmds/sh/funcs/popd73
-rw-r--r--shell_cmds/sh/funcs/pushd73
-rw-r--r--shell_cmds/sh/funcs/suspend39
-rw-r--r--shell_cmds/sh/histedit.c502
-rw-r--r--shell_cmds/sh/input.c536
-rw-r--r--shell_cmds/sh/input.h65
-rw-r--r--shell_cmds/sh/jobs.c1552
-rw-r--r--shell_cmds/sh/jobs.h67
-rw-r--r--shell_cmds/sh/mail.c117
-rw-r--r--shell_cmds/sh/mail.h38
-rw-r--r--shell_cmds/sh/main.c351
-rw-r--r--shell_cmds/sh/main.h42
-rw-r--r--shell_cmds/sh/memalloc.c344
-rw-r--r--shell_cmds/sh/memalloc.h88
-rw-r--r--shell_cmds/sh/miscbltin.c534
-rwxr-xr-xshell_cmds/sh/mkbuiltins137
-rw-r--r--shell_cmds/sh/mknodes.c467
-rw-r--r--shell_cmds/sh/mksyntax.c331
-rw-r--r--shell_cmds/sh/mktokens93
-rw-r--r--shell_cmds/sh/myhistedit.h44
-rw-r--r--shell_cmds/sh/mystring.c100
-rw-r--r--shell_cmds/sh/mystring.h43
-rw-r--r--shell_cmds/sh/nodes.c.pat193
-rw-r--r--shell_cmds/sh/nodetypes145
-rw-r--r--shell_cmds/sh/options.c594
-rw-r--r--shell_cmds/sh/options.h115
-rw-r--r--shell_cmds/sh/output.c370
-rw-r--r--shell_cmds/sh/output.h85
-rw-r--r--shell_cmds/sh/parser.c2120
-rw-r--r--shell_cmds/sh/parser.h87
-rw-r--r--shell_cmds/sh/redir.c365
-rw-r--r--shell_cmds/sh/redir.h47
-rw-r--r--shell_cmds/sh/sh.12879
-rw-r--r--shell_cmds/sh/sh.plist.part23
-rw-r--r--shell_cmds/sh/shell.h79
-rw-r--r--shell_cmds/sh/show.c410
-rw-r--r--shell_cmds/sh/show.h42
-rw-r--r--shell_cmds/sh/tests/Makefile14
-rw-r--r--shell_cmds/sh/tests/Makefile.depend11
-rw-r--r--shell_cmds/sh/tests/builtins/Makefile185
-rw-r--r--shell_cmds/sh/tests/builtins/Makefile.depend11
-rw-r--r--shell_cmds/sh/tests/builtins/alias.09
-rw-r--r--shell_cmds/sh/tests/builtins/alias.0.stdout4
-rw-r--r--shell_cmds/sh/tests/builtins/alias.13
-rw-r--r--shell_cmds/sh/tests/builtins/alias.1.stderr1
-rw-r--r--shell_cmds/sh/tests/builtins/alias3.012
-rw-r--r--shell_cmds/sh/tests/builtins/alias3.0.stdout4
-rw-r--r--shell_cmds/sh/tests/builtins/alias4.04
-rw-r--r--shell_cmds/sh/tests/builtins/break1.016
-rw-r--r--shell_cmds/sh/tests/builtins/break2.012
-rw-r--r--shell_cmds/sh/tests/builtins/break2.0.stdout1
-rw-r--r--shell_cmds/sh/tests/builtins/break3.015
-rw-r--r--shell_cmds/sh/tests/builtins/break4.47
-rw-r--r--shell_cmds/sh/tests/builtins/break5.412
-rw-r--r--shell_cmds/sh/tests/builtins/break6.08
-rw-r--r--shell_cmds/sh/tests/builtins/builtin1.031
-rw-r--r--shell_cmds/sh/tests/builtins/case1.013
-rw-r--r--shell_cmds/sh/tests/builtins/case10.016
-rw-r--r--shell_cmds/sh/tests/builtins/case11.06
-rw-r--r--shell_cmds/sh/tests/builtins/case12.06
-rw-r--r--shell_cmds/sh/tests/builtins/case13.012
-rw-r--r--shell_cmds/sh/tests/builtins/case14.05
-rw-r--r--shell_cmds/sh/tests/builtins/case15.05
-rw-r--r--shell_cmds/sh/tests/builtins/case16.07
-rw-r--r--shell_cmds/sh/tests/builtins/case17.03
-rw-r--r--shell_cmds/sh/tests/builtins/case18.07
-rw-r--r--shell_cmds/sh/tests/builtins/case19.07
-rw-r--r--shell_cmds/sh/tests/builtins/case2.0106
-rw-r--r--shell_cmds/sh/tests/builtins/case20.09
-rw-r--r--shell_cmds/sh/tests/builtins/case21.010
-rw-r--r--shell_cmds/sh/tests/builtins/case22.010
-rw-r--r--shell_cmds/sh/tests/builtins/case3.095
-rw-r--r--shell_cmds/sh/tests/builtins/case4.06
-rw-r--r--shell_cmds/sh/tests/builtins/case5.057
-rw-r--r--shell_cmds/sh/tests/builtins/case6.052
-rw-r--r--shell_cmds/sh/tests/builtins/case7.024
-rw-r--r--shell_cmds/sh/tests/builtins/case8.032
-rw-r--r--shell_cmds/sh/tests/builtins/case9.039
-rw-r--r--shell_cmds/sh/tests/builtins/cd1.030
-rw-r--r--shell_cmds/sh/tests/builtins/cd10.06
-rw-r--r--shell_cmds/sh/tests/builtins/cd2.016
-rw-r--r--shell_cmds/sh/tests/builtins/cd3.021
-rw-r--r--shell_cmds/sh/tests/builtins/cd4.038
-rw-r--r--shell_cmds/sh/tests/builtins/cd5.023
-rw-r--r--shell_cmds/sh/tests/builtins/cd6.010
-rw-r--r--shell_cmds/sh/tests/builtins/cd7.015
-rw-r--r--shell_cmds/sh/tests/builtins/cd8.026
-rw-r--r--shell_cmds/sh/tests/builtins/cd9.08
-rw-r--r--shell_cmds/sh/tests/builtins/cd9.0.stdout2
-rw-r--r--shell_cmds/sh/tests/builtins/command1.05
-rw-r--r--shell_cmds/sh/tests/builtins/command10.014
-rw-r--r--shell_cmds/sh/tests/builtins/command11.014
-rw-r--r--shell_cmds/sh/tests/builtins/command12.07
-rw-r--r--shell_cmds/sh/tests/builtins/command2.03
-rw-r--r--shell_cmds/sh/tests/builtins/command3.014
-rw-r--r--shell_cmds/sh/tests/builtins/command3.0.stdout7
-rw-r--r--shell_cmds/sh/tests/builtins/command4.02
-rw-r--r--shell_cmds/sh/tests/builtins/command5.015
-rw-r--r--shell_cmds/sh/tests/builtins/command5.0.stdout8
-rw-r--r--shell_cmds/sh/tests/builtins/command6.022
-rw-r--r--shell_cmds/sh/tests/builtins/command6.0.stdout7
-rw-r--r--shell_cmds/sh/tests/builtins/command7.034
-rw-r--r--shell_cmds/sh/tests/builtins/command8.045
-rw-r--r--shell_cmds/sh/tests/builtins/command9.014
-rw-r--r--shell_cmds/sh/tests/builtins/dot1.021
-rw-r--r--shell_cmds/sh/tests/builtins/dot2.021
-rw-r--r--shell_cmds/sh/tests/builtins/dot3.010
-rw-r--r--shell_cmds/sh/tests/builtins/dot4.012
-rw-r--r--shell_cmds/sh/tests/builtins/echo1.06
-rw-r--r--shell_cmds/sh/tests/builtins/echo2.07
-rw-r--r--shell_cmds/sh/tests/builtins/echo3.05
-rw-r--r--shell_cmds/sh/tests/builtins/eval1.09
-rw-r--r--shell_cmds/sh/tests/builtins/eval2.07
-rw-r--r--shell_cmds/sh/tests/builtins/eval3.09
-rw-r--r--shell_cmds/sh/tests/builtins/eval4.05
-rw-r--r--shell_cmds/sh/tests/builtins/eval5.04
-rw-r--r--shell_cmds/sh/tests/builtins/eval6.05
-rw-r--r--shell_cmds/sh/tests/builtins/eval7.09
-rw-r--r--shell_cmds/sh/tests/builtins/eval8.77
-rw-r--r--shell_cmds/sh/tests/builtins/exec1.025
-rw-r--r--shell_cmds/sh/tests/builtins/exec2.025
-rw-r--r--shell_cmds/sh/tests/builtins/exit1.06
-rw-r--r--shell_cmds/sh/tests/builtins/exit2.87
-rw-r--r--shell_cmds/sh/tests/builtins/exit3.05
-rw-r--r--shell_cmds/sh/tests/builtins/export1.03
-rw-r--r--shell_cmds/sh/tests/builtins/fc1.027
-rw-r--r--shell_cmds/sh/tests/builtins/fc2.034
-rw-r--r--shell_cmds/sh/tests/builtins/for1.04
-rw-r--r--shell_cmds/sh/tests/builtins/for2.09
-rw-r--r--shell_cmds/sh/tests/builtins/for3.08
-rw-r--r--shell_cmds/sh/tests/builtins/getopts1.025
-rw-r--r--shell_cmds/sh/tests/builtins/getopts1.0.stdout8
-rw-r--r--shell_cmds/sh/tests/builtins/getopts10.011
-rw-r--r--shell_cmds/sh/tests/builtins/getopts2.06
-rw-r--r--shell_cmds/sh/tests/builtins/getopts2.0.stdout1
-rw-r--r--shell_cmds/sh/tests/builtins/getopts3.06
-rw-r--r--shell_cmds/sh/tests/builtins/getopts4.010
-rw-r--r--shell_cmds/sh/tests/builtins/getopts5.010
-rw-r--r--shell_cmds/sh/tests/builtins/getopts6.07
-rw-r--r--shell_cmds/sh/tests/builtins/getopts7.06
-rw-r--r--shell_cmds/sh/tests/builtins/getopts8.08
-rw-r--r--shell_cmds/sh/tests/builtins/getopts8.0.stdout5
-rw-r--r--shell_cmds/sh/tests/builtins/getopts9.09
-rw-r--r--shell_cmds/sh/tests/builtins/getopts9.0.stdout3
-rw-r--r--shell_cmds/sh/tests/builtins/hash1.05
-rw-r--r--shell_cmds/sh/tests/builtins/hash1.0.stdout1
-rw-r--r--shell_cmds/sh/tests/builtins/hash2.04
-rw-r--r--shell_cmds/sh/tests/builtins/hash2.0.stdout1
-rw-r--r--shell_cmds/sh/tests/builtins/hash3.03
-rw-r--r--shell_cmds/sh/tests/builtins/hash3.0.stdout2
-rw-r--r--shell_cmds/sh/tests/builtins/hash4.06
-rw-r--r--shell_cmds/sh/tests/builtins/jobid1.07
-rw-r--r--shell_cmds/sh/tests/builtins/jobid2.09
-rw-r--r--shell_cmds/sh/tests/builtins/kill1.08
-rw-r--r--shell_cmds/sh/tests/builtins/kill2.07
-rw-r--r--shell_cmds/sh/tests/builtins/lineno.016
-rw-r--r--shell_cmds/sh/tests/builtins/lineno.0.stdout9
-rw-r--r--shell_cmds/sh/tests/builtins/lineno2.010
-rw-r--r--shell_cmds/sh/tests/builtins/lineno3.06
-rw-r--r--shell_cmds/sh/tests/builtins/lineno3.0.stdout2
-rw-r--r--shell_cmds/sh/tests/builtins/local1.013
-rw-r--r--shell_cmds/sh/tests/builtins/local2.017
-rw-r--r--shell_cmds/sh/tests/builtins/local3.026
-rw-r--r--shell_cmds/sh/tests/builtins/local4.012
-rw-r--r--shell_cmds/sh/tests/builtins/local5.015
-rw-r--r--shell_cmds/sh/tests/builtins/local6.010
-rw-r--r--shell_cmds/sh/tests/builtins/local7.010
-rw-r--r--shell_cmds/sh/tests/builtins/locale1.0134
-rw-r--r--shell_cmds/sh/tests/builtins/locale2.05
-rw-r--r--shell_cmds/sh/tests/builtins/printf1.03
-rw-r--r--shell_cmds/sh/tests/builtins/printf2.03
-rw-r--r--shell_cmds/sh/tests/builtins/printf3.05
-rw-r--r--shell_cmds/sh/tests/builtins/printf4.05
-rw-r--r--shell_cmds/sh/tests/builtins/read1.026
-rw-r--r--shell_cmds/sh/tests/builtins/read1.0.stdout20
-rw-r--r--shell_cmds/sh/tests/builtins/read2.031
-rw-r--r--shell_cmds/sh/tests/builtins/read3.011
-rw-r--r--shell_cmds/sh/tests/builtins/read3.0.stdout9
-rw-r--r--shell_cmds/sh/tests/builtins/read4.010
-rw-r--r--shell_cmds/sh/tests/builtins/read4.0.stdout8
-rw-r--r--shell_cmds/sh/tests/builtins/read5.032
-rw-r--r--shell_cmds/sh/tests/builtins/read6.05
-rw-r--r--shell_cmds/sh/tests/builtins/read7.05
-rw-r--r--shell_cmds/sh/tests/builtins/read8.017
-rw-r--r--shell_cmds/sh/tests/builtins/read9.010
-rw-r--r--shell_cmds/sh/tests/builtins/return1.07
-rw-r--r--shell_cmds/sh/tests/builtins/return2.17
-rw-r--r--shell_cmds/sh/tests/builtins/return3.13
-rw-r--r--shell_cmds/sh/tests/builtins/return4.016
-rw-r--r--shell_cmds/sh/tests/builtins/return5.017
-rw-r--r--shell_cmds/sh/tests/builtins/return6.43
-rw-r--r--shell_cmds/sh/tests/builtins/return7.46
-rw-r--r--shell_cmds/sh/tests/builtins/return8.013
-rw-r--r--shell_cmds/sh/tests/builtins/set1.032
-rw-r--r--shell_cmds/sh/tests/builtins/set2.03
-rw-r--r--shell_cmds/sh/tests/builtins/set3.04
-rw-r--r--shell_cmds/sh/tests/builtins/trap1.022
-rw-r--r--shell_cmds/sh/tests/builtins/trap10.06
-rw-r--r--shell_cmds/sh/tests/builtins/trap11.08
-rw-r--r--shell_cmds/sh/tests/builtins/trap12.010
-rw-r--r--shell_cmds/sh/tests/builtins/trap13.08
-rw-r--r--shell_cmds/sh/tests/builtins/trap14.010
-rw-r--r--shell_cmds/sh/tests/builtins/trap15.05
-rw-r--r--shell_cmds/sh/tests/builtins/trap16.020
-rw-r--r--shell_cmds/sh/tests/builtins/trap17.010
-rw-r--r--shell_cmds/sh/tests/builtins/trap2.052
-rw-r--r--shell_cmds/sh/tests/builtins/trap3.011
-rw-r--r--shell_cmds/sh/tests/builtins/trap4.017
-rw-r--r--shell_cmds/sh/tests/builtins/trap5.019
-rw-r--r--shell_cmds/sh/tests/builtins/trap6.09
-rw-r--r--shell_cmds/sh/tests/builtins/trap7.03
-rw-r--r--shell_cmds/sh/tests/builtins/trap8.07
-rw-r--r--shell_cmds/sh/tests/builtins/trap9.03
-rw-r--r--shell_cmds/sh/tests/builtins/type1.08
-rw-r--r--shell_cmds/sh/tests/builtins/type1.0.stderr4
-rw-r--r--shell_cmds/sh/tests/builtins/type2.026
-rw-r--r--shell_cmds/sh/tests/builtins/type3.03
-rw-r--r--shell_cmds/sh/tests/builtins/unalias.021
-rw-r--r--shell_cmds/sh/tests/builtins/var-assign.055
-rw-r--r--shell_cmds/sh/tests/builtins/var-assign2.055
-rw-r--r--shell_cmds/sh/tests/builtins/wait1.023
-rw-r--r--shell_cmds/sh/tests/builtins/wait10.05
-rw-r--r--shell_cmds/sh/tests/builtins/wait2.015
-rw-r--r--shell_cmds/sh/tests/builtins/wait3.021
-rw-r--r--shell_cmds/sh/tests/builtins/wait4.012
-rw-r--r--shell_cmds/sh/tests/builtins/wait5.012
-rw-r--r--shell_cmds/sh/tests/builtins/wait6.03
-rw-r--r--shell_cmds/sh/tests/builtins/wait7.04
-rw-r--r--shell_cmds/sh/tests/builtins/wait8.07
-rw-r--r--shell_cmds/sh/tests/builtins/wait9.1273
-rw-r--r--shell_cmds/sh/tests/errors/Makefile35
-rw-r--r--shell_cmds/sh/tests/errors/Makefile.depend11
-rw-r--r--shell_cmds/sh/tests/errors/assignment-error1.030
-rw-r--r--shell_cmds/sh/tests/errors/assignment-error2.08
-rw-r--r--shell_cmds/sh/tests/errors/backquote-error1.04
-rw-r--r--shell_cmds/sh/tests/errors/backquote-error2.07
-rw-r--r--shell_cmds/sh/tests/errors/bad-binary1.12612
-rw-r--r--shell_cmds/sh/tests/errors/bad-keyword1.04
-rw-r--r--shell_cmds/sh/tests/errors/bad-parm-exp1.07
-rw-r--r--shell_cmds/sh/tests/errors/bad-parm-exp2.22
-rw-r--r--shell_cmds/sh/tests/errors/bad-parm-exp2.2.stderr1
-rw-r--r--shell_cmds/sh/tests/errors/bad-parm-exp3.22
-rw-r--r--shell_cmds/sh/tests/errors/bad-parm-exp3.2.stderr1
-rw-r--r--shell_cmds/sh/tests/errors/bad-parm-exp4.22
-rw-r--r--shell_cmds/sh/tests/errors/bad-parm-exp4.2.stderr1
-rw-r--r--shell_cmds/sh/tests/errors/bad-parm-exp5.22
-rw-r--r--shell_cmds/sh/tests/errors/bad-parm-exp5.2.stderr1
-rw-r--r--shell_cmds/sh/tests/errors/bad-parm-exp6.22
-rw-r--r--shell_cmds/sh/tests/errors/bad-parm-exp6.2.stderr1
-rw-r--r--shell_cmds/sh/tests/errors/bad-parm-exp7.04
-rw-r--r--shell_cmds/sh/tests/errors/bad-parm-exp8.04
-rw-r--r--shell_cmds/sh/tests/errors/option-error.046
-rw-r--r--shell_cmds/sh/tests/errors/redirection-error.053
-rw-r--r--shell_cmds/sh/tests/errors/redirection-error2.24
-rw-r--r--shell_cmds/sh/tests/errors/redirection-error3.054
-rw-r--r--shell_cmds/sh/tests/errors/redirection-error4.07
-rw-r--r--shell_cmds/sh/tests/errors/redirection-error5.05
-rw-r--r--shell_cmds/sh/tests/errors/redirection-error6.012
-rw-r--r--shell_cmds/sh/tests/errors/redirection-error7.07
-rw-r--r--shell_cmds/sh/tests/errors/redirection-error8.05
-rw-r--r--shell_cmds/sh/tests/errors/write-error1.03
-rw-r--r--shell_cmds/sh/tests/execution/Makefile57
-rw-r--r--shell_cmds/sh/tests/execution/Makefile.depend11
-rw-r--r--shell_cmds/sh/tests/execution/bg1.03
-rw-r--r--shell_cmds/sh/tests/execution/bg10.04
-rw-r--r--shell_cmds/sh/tests/execution/bg10.0.stdout1
-rw-r--r--shell_cmds/sh/tests/execution/bg2.05
-rw-r--r--shell_cmds/sh/tests/execution/bg3.05
-rw-r--r--shell_cmds/sh/tests/execution/bg4.06
-rw-r--r--shell_cmds/sh/tests/execution/bg5.04
-rw-r--r--shell_cmds/sh/tests/execution/bg6.04
-rw-r--r--shell_cmds/sh/tests/execution/bg6.0.stdout1
-rw-r--r--shell_cmds/sh/tests/execution/bg7.05
-rw-r--r--shell_cmds/sh/tests/execution/bg8.05
-rw-r--r--shell_cmds/sh/tests/execution/bg9.05
-rw-r--r--shell_cmds/sh/tests/execution/fork1.010
-rw-r--r--shell_cmds/sh/tests/execution/fork2.09
-rw-r--r--shell_cmds/sh/tests/execution/fork3.04
-rw-r--r--shell_cmds/sh/tests/execution/func1.04
-rw-r--r--shell_cmds/sh/tests/execution/func2.012
-rw-r--r--shell_cmds/sh/tests/execution/func3.07
-rw-r--r--shell_cmds/sh/tests/execution/hash1.012
-rw-r--r--shell_cmds/sh/tests/execution/int-cmd1.03
-rw-r--r--shell_cmds/sh/tests/execution/killed1.08
-rw-r--r--shell_cmds/sh/tests/execution/killed2.010
-rw-r--r--shell_cmds/sh/tests/execution/not1.04
-rw-r--r--shell_cmds/sh/tests/execution/not2.06
-rw-r--r--shell_cmds/sh/tests/execution/path1.015
-rw-r--r--shell_cmds/sh/tests/execution/redir1.027
-rw-r--r--shell_cmds/sh/tests/execution/redir2.029
-rw-r--r--shell_cmds/sh/tests/execution/redir3.03
-rw-r--r--shell_cmds/sh/tests/execution/redir4.04
-rw-r--r--shell_cmds/sh/tests/execution/redir5.03
-rw-r--r--shell_cmds/sh/tests/execution/redir6.021
-rw-r--r--shell_cmds/sh/tests/execution/redir7.021
-rw-r--r--shell_cmds/sh/tests/execution/set-C1.012
-rw-r--r--shell_cmds/sh/tests/execution/set-n1.07
-rw-r--r--shell_cmds/sh/tests/execution/set-n2.05
-rw-r--r--shell_cmds/sh/tests/execution/set-n3.04
-rw-r--r--shell_cmds/sh/tests/execution/set-n4.03
-rw-r--r--shell_cmds/sh/tests/execution/set-x1.08
-rw-r--r--shell_cmds/sh/tests/execution/set-x2.09
-rw-r--r--shell_cmds/sh/tests/execution/set-x3.09
-rw-r--r--shell_cmds/sh/tests/execution/set-x4.07
-rw-r--r--shell_cmds/sh/tests/execution/shellproc1.011
-rw-r--r--shell_cmds/sh/tests/execution/subshell1.06
-rw-r--r--shell_cmds/sh/tests/execution/subshell1.0.stdout2
-rw-r--r--shell_cmds/sh/tests/execution/subshell2.010
-rw-r--r--shell_cmds/sh/tests/execution/subshell3.04
-rw-r--r--shell_cmds/sh/tests/execution/subshell4.03
-rw-r--r--shell_cmds/sh/tests/execution/unknown1.029
-rw-r--r--shell_cmds/sh/tests/execution/var-assign1.03
-rw-r--r--shell_cmds/sh/tests/expansion/Makefile105
-rw-r--r--shell_cmds/sh/tests/expansion/Makefile.depend11
-rw-r--r--shell_cmds/sh/tests/expansion/arith1.030
-rw-r--r--shell_cmds/sh/tests/expansion/arith10.035
-rw-r--r--shell_cmds/sh/tests/expansion/arith11.012
-rw-r--r--shell_cmds/sh/tests/expansion/arith12.04
-rw-r--r--shell_cmds/sh/tests/expansion/arith13.06
-rw-r--r--shell_cmds/sh/tests/expansion/arith14.040
-rw-r--r--shell_cmds/sh/tests/expansion/arith2.077
-rw-r--r--shell_cmds/sh/tests/expansion/arith3.014
-rw-r--r--shell_cmds/sh/tests/expansion/arith4.020
-rw-r--r--shell_cmds/sh/tests/expansion/arith5.017
-rw-r--r--shell_cmds/sh/tests/expansion/arith6.016
-rw-r--r--shell_cmds/sh/tests/expansion/arith7.012
-rw-r--r--shell_cmds/sh/tests/expansion/arith8.04
-rw-r--r--shell_cmds/sh/tests/expansion/arith9.020
-rw-r--r--shell_cmds/sh/tests/expansion/assign1.037
-rw-r--r--shell_cmds/sh/tests/expansion/cmdsubst1.048
-rw-r--r--shell_cmds/sh/tests/expansion/cmdsubst10.051
-rw-r--r--shell_cmds/sh/tests/expansion/cmdsubst11.05
-rw-r--r--shell_cmds/sh/tests/expansion/cmdsubst12.06
-rw-r--r--shell_cmds/sh/tests/expansion/cmdsubst13.012
-rw-r--r--shell_cmds/sh/tests/expansion/cmdsubst14.05
-rw-r--r--shell_cmds/sh/tests/expansion/cmdsubst15.05
-rw-r--r--shell_cmds/sh/tests/expansion/cmdsubst16.05
-rw-r--r--shell_cmds/sh/tests/expansion/cmdsubst17.05
-rw-r--r--shell_cmds/sh/tests/expansion/cmdsubst18.06
-rw-r--r--shell_cmds/sh/tests/expansion/cmdsubst19.05
-rw-r--r--shell_cmds/sh/tests/expansion/cmdsubst2.043
-rw-r--r--shell_cmds/sh/tests/expansion/cmdsubst20.06
-rw-r--r--shell_cmds/sh/tests/expansion/cmdsubst21.06
-rw-r--r--shell_cmds/sh/tests/expansion/cmdsubst22.06
-rw-r--r--shell_cmds/sh/tests/expansion/cmdsubst23.05
-rw-r--r--shell_cmds/sh/tests/expansion/cmdsubst24.024
-rw-r--r--shell_cmds/sh/tests/expansion/cmdsubst25.07
-rw-r--r--shell_cmds/sh/tests/expansion/cmdsubst26.06
-rw-r--r--shell_cmds/sh/tests/expansion/cmdsubst3.023
-rw-r--r--shell_cmds/sh/tests/expansion/cmdsubst4.04
-rw-r--r--shell_cmds/sh/tests/expansion/cmdsubst5.05
-rw-r--r--shell_cmds/sh/tests/expansion/cmdsubst6.053
-rw-r--r--shell_cmds/sh/tests/expansion/cmdsubst7.031
-rw-r--r--shell_cmds/sh/tests/expansion/cmdsubst8.017
-rw-r--r--shell_cmds/sh/tests/expansion/cmdsubst9.011
-rw-r--r--shell_cmds/sh/tests/expansion/export1.013
-rw-r--r--shell_cmds/sh/tests/expansion/export2.024
-rw-r--r--shell_cmds/sh/tests/expansion/export3.030
-rw-r--r--shell_cmds/sh/tests/expansion/heredoc1.025
-rw-r--r--shell_cmds/sh/tests/expansion/heredoc2.015
-rw-r--r--shell_cmds/sh/tests/expansion/ifs1.035
-rw-r--r--shell_cmds/sh/tests/expansion/ifs2.024
-rw-r--r--shell_cmds/sh/tests/expansion/ifs3.021
-rw-r--r--shell_cmds/sh/tests/expansion/ifs4.039
-rw-r--r--shell_cmds/sh/tests/expansion/ifs5.04
-rw-r--r--shell_cmds/sh/tests/expansion/ifs6.06
-rw-r--r--shell_cmds/sh/tests/expansion/ifs7.05
-rw-r--r--shell_cmds/sh/tests/expansion/length1.012
-rw-r--r--shell_cmds/sh/tests/expansion/length2.04
-rw-r--r--shell_cmds/sh/tests/expansion/length3.010
-rw-r--r--shell_cmds/sh/tests/expansion/length4.011
-rw-r--r--shell_cmds/sh/tests/expansion/length5.027
-rw-r--r--shell_cmds/sh/tests/expansion/length6.08
-rw-r--r--shell_cmds/sh/tests/expansion/length7.014
-rw-r--r--shell_cmds/sh/tests/expansion/length8.014
-rw-r--r--shell_cmds/sh/tests/expansion/local1.028
-rw-r--r--shell_cmds/sh/tests/expansion/local2.034
-rw-r--r--shell_cmds/sh/tests/expansion/pathname1.065
-rw-r--r--shell_cmds/sh/tests/expansion/pathname2.035
-rw-r--r--shell_cmds/sh/tests/expansion/pathname3.029
-rw-r--r--shell_cmds/sh/tests/expansion/pathname4.028
-rw-r--r--shell_cmds/sh/tests/expansion/pathname5.03
-rw-r--r--shell_cmds/sh/tests/expansion/pathname6.029
-rw-r--r--shell_cmds/sh/tests/expansion/plus-minus1.076
-rw-r--r--shell_cmds/sh/tests/expansion/plus-minus2.04
-rw-r--r--shell_cmds/sh/tests/expansion/plus-minus3.044
-rw-r--r--shell_cmds/sh/tests/expansion/plus-minus4.038
-rw-r--r--shell_cmds/sh/tests/expansion/plus-minus5.031
-rw-r--r--shell_cmds/sh/tests/expansion/plus-minus6.034
-rw-r--r--shell_cmds/sh/tests/expansion/plus-minus7.026
-rw-r--r--shell_cmds/sh/tests/expansion/plus-minus8.05
-rw-r--r--shell_cmds/sh/tests/expansion/question1.022
-rw-r--r--shell_cmds/sh/tests/expansion/readonly1.07
-rw-r--r--shell_cmds/sh/tests/expansion/redir1.026
-rw-r--r--shell_cmds/sh/tests/expansion/set-u1.029
-rw-r--r--shell_cmds/sh/tests/expansion/set-u2.012
-rw-r--r--shell_cmds/sh/tests/expansion/set-u3.06
-rw-r--r--shell_cmds/sh/tests/expansion/tilde1.056
-rw-r--r--shell_cmds/sh/tests/expansion/tilde2.090
-rw-r--r--shell_cmds/sh/tests/expansion/trim1.085
-rw-r--r--shell_cmds/sh/tests/expansion/trim2.055
-rw-r--r--shell_cmds/sh/tests/expansion/trim3.046
-rw-r--r--shell_cmds/sh/tests/expansion/trim4.015
-rw-r--r--shell_cmds/sh/tests/expansion/trim5.028
-rw-r--r--shell_cmds/sh/tests/expansion/trim6.022
-rw-r--r--shell_cmds/sh/tests/expansion/trim7.016
-rw-r--r--shell_cmds/sh/tests/expansion/trim8.075
-rw-r--r--shell_cmds/sh/tests/expansion/trim9.061
-rwxr-xr-xshell_cmds/sh/tests/functional_test.sh72
-rw-r--r--shell_cmds/sh/tests/invocation/Makefile16
-rw-r--r--shell_cmds/sh/tests/invocation/Makefile.depend11
-rw-r--r--shell_cmds/sh/tests/invocation/sh-ac1.07
-rw-r--r--shell_cmds/sh/tests/invocation/sh-c-missing1.03
-rw-r--r--shell_cmds/sh/tests/invocation/sh-c1.04
-rw-r--r--shell_cmds/sh/tests/invocation/sh-ca1.07
-rw-r--r--shell_cmds/sh/tests/invocation/sh-fca1.07
-rw-r--r--shell_cmds/sh/tests/parameters/Makefile29
-rw-r--r--shell_cmds/sh/tests/parameters/Makefile.depend11
-rw-r--r--shell_cmds/sh/tests/parameters/env1.011
-rw-r--r--shell_cmds/sh/tests/parameters/exitstatus1.09
-rw-r--r--shell_cmds/sh/tests/parameters/ifs1.010
-rw-r--r--shell_cmds/sh/tests/parameters/mail1.015
-rw-r--r--shell_cmds/sh/tests/parameters/mail2.015
-rw-r--r--shell_cmds/sh/tests/parameters/optind1.03
-rw-r--r--shell_cmds/sh/tests/parameters/optind2.03
-rw-r--r--shell_cmds/sh/tests/parameters/positional1.013
-rw-r--r--shell_cmds/sh/tests/parameters/positional2.065
-rw-r--r--shell_cmds/sh/tests/parameters/positional3.04
-rw-r--r--shell_cmds/sh/tests/parameters/positional4.04
-rw-r--r--shell_cmds/sh/tests/parameters/positional5.014
-rw-r--r--shell_cmds/sh/tests/parameters/positional6.07
-rw-r--r--shell_cmds/sh/tests/parameters/positional7.08
-rw-r--r--shell_cmds/sh/tests/parameters/positional8.031
-rw-r--r--shell_cmds/sh/tests/parameters/positional9.018
-rw-r--r--shell_cmds/sh/tests/parameters/pwd1.011
-rw-r--r--shell_cmds/sh/tests/parameters/pwd2.024
-rw-r--r--shell_cmds/sh/tests/parser/Makefile88
-rw-r--r--shell_cmds/sh/tests/parser/Makefile.depend11
-rw-r--r--shell_cmds/sh/tests/parser/alias1.05
-rw-r--r--shell_cmds/sh/tests/parser/alias10.09
-rw-r--r--shell_cmds/sh/tests/parser/alias11.06
-rw-r--r--shell_cmds/sh/tests/parser/alias12.06
-rw-r--r--shell_cmds/sh/tests/parser/alias13.06
-rw-r--r--shell_cmds/sh/tests/parser/alias14.06
-rw-r--r--shell_cmds/sh/tests/parser/alias15.012
-rw-r--r--shell_cmds/sh/tests/parser/alias15.0.stdout4
-rw-r--r--shell_cmds/sh/tests/parser/alias16.07
-rw-r--r--shell_cmds/sh/tests/parser/alias17.07
-rw-r--r--shell_cmds/sh/tests/parser/alias18.08
-rw-r--r--shell_cmds/sh/tests/parser/alias2.06
-rw-r--r--shell_cmds/sh/tests/parser/alias3.06
-rw-r--r--shell_cmds/sh/tests/parser/alias4.05
-rw-r--r--shell_cmds/sh/tests/parser/alias5.05
-rw-r--r--shell_cmds/sh/tests/parser/alias6.06
-rw-r--r--shell_cmds/sh/tests/parser/alias7.04
-rw-r--r--shell_cmds/sh/tests/parser/alias8.04
-rw-r--r--shell_cmds/sh/tests/parser/alias9.06
-rw-r--r--shell_cmds/sh/tests/parser/and-pipe-not.02
-rw-r--r--shell_cmds/sh/tests/parser/case1.014
-rw-r--r--shell_cmds/sh/tests/parser/case2.032
-rw-r--r--shell_cmds/sh/tests/parser/comment1.03
-rw-r--r--shell_cmds/sh/tests/parser/comment2.424
-rw-r--r--shell_cmds/sh/tests/parser/dollar-quote1.012
-rw-r--r--shell_cmds/sh/tests/parser/dollar-quote10.010
-rw-r--r--shell_cmds/sh/tests/parser/dollar-quote11.08
-rw-r--r--shell_cmds/sh/tests/parser/dollar-quote12.07
-rw-r--r--shell_cmds/sh/tests/parser/dollar-quote13.08
-rw-r--r--shell_cmds/sh/tests/parser/dollar-quote2.05
-rw-r--r--shell_cmds/sh/tests/parser/dollar-quote3.022
-rw-r--r--shell_cmds/sh/tests/parser/dollar-quote4.019
-rw-r--r--shell_cmds/sh/tests/parser/dollar-quote5.012
-rw-r--r--shell_cmds/sh/tests/parser/dollar-quote6.05
-rw-r--r--shell_cmds/sh/tests/parser/dollar-quote7.06
-rw-r--r--shell_cmds/sh/tests/parser/dollar-quote8.011
-rw-r--r--shell_cmds/sh/tests/parser/dollar-quote9.08
-rw-r--r--shell_cmds/sh/tests/parser/empty-braces1.07
-rw-r--r--shell_cmds/sh/tests/parser/empty-cmd1.03
-rw-r--r--shell_cmds/sh/tests/parser/for1.029
-rw-r--r--shell_cmds/sh/tests/parser/for2.015
-rw-r--r--shell_cmds/sh/tests/parser/func1.025
-rw-r--r--shell_cmds/sh/tests/parser/func2.06
-rw-r--r--shell_cmds/sh/tests/parser/func3.06
-rw-r--r--shell_cmds/sh/tests/parser/heredoc1.085
-rw-r--r--shell_cmds/sh/tests/parser/heredoc10.049
-rw-r--r--shell_cmds/sh/tests/parser/heredoc11.026
-rw-r--r--shell_cmds/sh/tests/parser/heredoc12.047
-rw-r--r--shell_cmds/sh/tests/parser/heredoc13.021
-rw-r--r--shell_cmds/sh/tests/parser/heredoc2.039
-rw-r--r--shell_cmds/sh/tests/parser/heredoc3.07
-rw-r--r--shell_cmds/sh/tests/parser/heredoc4.044
-rw-r--r--shell_cmds/sh/tests/parser/heredoc5.056
-rw-r--r--shell_cmds/sh/tests/parser/heredoc6.05
-rw-r--r--shell_cmds/sh/tests/parser/heredoc7.019
-rw-r--r--shell_cmds/sh/tests/parser/heredoc8.020
-rw-r--r--shell_cmds/sh/tests/parser/heredoc9.058
-rw-r--r--shell_cmds/sh/tests/parser/line-cont1.016
-rw-r--r--shell_cmds/sh/tests/parser/line-cont10.018
-rw-r--r--shell_cmds/sh/tests/parser/line-cont11.023
-rw-r--r--shell_cmds/sh/tests/parser/line-cont2.04
-rw-r--r--shell_cmds/sh/tests/parser/line-cont3.07
-rw-r--r--shell_cmds/sh/tests/parser/line-cont4.08
-rw-r--r--shell_cmds/sh/tests/parser/line-cont5.014
-rw-r--r--shell_cmds/sh/tests/parser/line-cont6.023
-rw-r--r--shell_cmds/sh/tests/parser/line-cont7.07
-rw-r--r--shell_cmds/sh/tests/parser/line-cont8.06
-rw-r--r--shell_cmds/sh/tests/parser/line-cont9.06
-rw-r--r--shell_cmds/sh/tests/parser/no-space1.018
-rw-r--r--shell_cmds/sh/tests/parser/no-space2.07
-rw-r--r--shell_cmds/sh/tests/parser/nul1.012
-rw-r--r--shell_cmds/sh/tests/parser/only-redir1.03
-rw-r--r--shell_cmds/sh/tests/parser/only-redir2.02
-rw-r--r--shell_cmds/sh/tests/parser/only-redir3.02
-rw-r--r--shell_cmds/sh/tests/parser/only-redir4.02
-rw-r--r--shell_cmds/sh/tests/parser/pipe-not1.03
-rw-r--r--shell_cmds/sh/tests/parser/set-v1.08
-rw-r--r--shell_cmds/sh/tests/parser/set-v1.0.stderr5
-rw-r--r--shell_cmds/sh/tests/parser/var-assign1.019
-rw-r--r--shell_cmds/sh/tests/set-e/Makefile46
-rw-r--r--shell_cmds/sh/tests/set-e/Makefile.depend11
-rw-r--r--shell_cmds/sh/tests/set-e/and1.03
-rw-r--r--shell_cmds/sh/tests/set-e/and2.14
-rw-r--r--shell_cmds/sh/tests/set-e/and3.04
-rw-r--r--shell_cmds/sh/tests/set-e/and4.04
-rw-r--r--shell_cmds/sh/tests/set-e/background1.03
-rw-r--r--shell_cmds/sh/tests/set-e/cmd1.03
-rw-r--r--shell_cmds/sh/tests/set-e/cmd2.14
-rw-r--r--shell_cmds/sh/tests/set-e/elif1.07
-rw-r--r--shell_cmds/sh/tests/set-e/elif2.07
-rw-r--r--shell_cmds/sh/tests/set-e/eval1.03
-rw-r--r--shell_cmds/sh/tests/set-e/eval2.14
-rw-r--r--shell_cmds/sh/tests/set-e/for1.09
-rw-r--r--shell_cmds/sh/tests/set-e/func1.07
-rw-r--r--shell_cmds/sh/tests/set-e/func2.17
-rw-r--r--shell_cmds/sh/tests/set-e/if1.05
-rw-r--r--shell_cmds/sh/tests/set-e/if2.07
-rw-r--r--shell_cmds/sh/tests/set-e/if3.05
-rw-r--r--shell_cmds/sh/tests/set-e/not1.04
-rw-r--r--shell_cmds/sh/tests/set-e/not2.04
-rw-r--r--shell_cmds/sh/tests/set-e/or1.03
-rw-r--r--shell_cmds/sh/tests/set-e/or2.03
-rw-r--r--shell_cmds/sh/tests/set-e/or3.14
-rw-r--r--shell_cmds/sh/tests/set-e/pipe1.14
-rw-r--r--shell_cmds/sh/tests/set-e/pipe2.03
-rw-r--r--shell_cmds/sh/tests/set-e/return1.011
-rw-r--r--shell_cmds/sh/tests/set-e/semi1.14
-rw-r--r--shell_cmds/sh/tests/set-e/semi2.14
-rw-r--r--shell_cmds/sh/tests/set-e/subshell1.03
-rw-r--r--shell_cmds/sh/tests/set-e/subshell2.14
-rw-r--r--shell_cmds/sh/tests/set-e/until1.05
-rw-r--r--shell_cmds/sh/tests/set-e/until2.05
-rw-r--r--shell_cmds/sh/tests/set-e/until3.09
-rw-r--r--shell_cmds/sh/tests/set-e/while1.05
-rw-r--r--shell_cmds/sh/tests/set-e/while2.05
-rw-r--r--shell_cmds/sh/tests/set-e/while3.09
-rw-r--r--shell_cmds/sh/trap.c556
-rw-r--r--shell_cmds/sh/trap.h50
-rw-r--r--shell_cmds/sh/var.c971
-rw-r--r--shell_cmds/sh/var.h132
-rw-r--r--shell_cmds/shell_cmds.xcodeproj/project.pbxproj5903
-rw-r--r--shell_cmds/shell_cmds.xcodeproj/project.xcworkspace/contents.xcworkspacedata7
-rw-r--r--shell_cmds/shlock/shlock.1147
-rw-r--r--shell_cmds/shlock/shlock.c364
-rw-r--r--shell_cmds/sleep/sleep.1124
-rw-r--r--shell_cmds/sleep/sleep.c131
-rw-r--r--shell_cmds/su/su.1213
-rw-r--r--shell_cmds/su/su.c737
-rw-r--r--shell_cmds/su/su.pam7
-rw-r--r--shell_cmds/su/su_entitlements.plist10
-rw-r--r--shell_cmds/systime/systime.176
-rw-r--r--shell_cmds/systime/systime.c365
-rw-r--r--shell_cmds/tee/tee.190
-rw-r--r--shell_cmds/tee/tee.c156
-rw-r--r--shell_cmds/test/[.11
-rw-r--r--shell_cmds/test/test.1390
-rw-r--r--shell_cmds/test/test.c611
-rw-r--r--shell_cmds/test/test.plist.part19
-rw-r--r--shell_cmds/test/tests/Makefile15
-rw-r--r--shell_cmds/test/tests/legacy_test.sh203
-rw-r--r--shell_cmds/tests/regress.m459
-rw-r--r--shell_cmds/tests/shell_cmds.plist53
-rwxr-xr-xshell_cmds/time/tests/test_time.sh60
-rw-r--r--shell_cmds/time/time.1116
-rw-r--r--shell_cmds/time/time.c245
-rw-r--r--shell_cmds/true/true.160
-rw-r--r--shell_cmds/true/true.c2
-rw-r--r--shell_cmds/true/true.sh2
-rw-r--r--shell_cmds/uname/uname.187
-rw-r--r--shell_cmds/uname/uname.c208
-rw-r--r--shell_cmds/users/users.161
-rw-r--r--shell_cmds/users/users.c123
-rw-r--r--shell_cmds/w/extern.h44
-rw-r--r--shell_cmds/w/fmt.c129
-rw-r--r--shell_cmds/w/pr_time.c117
-rw-r--r--shell_cmds/w/proc_compare.c144
-rw-r--r--shell_cmds/w/uptime.152
-rw-r--r--shell_cmds/w/w.1127
-rw-r--r--shell_cmds/w/w.c776
-rw-r--r--shell_cmds/what/what.170
-rw-r--r--shell_cmds/what/what.c97
-rw-r--r--shell_cmds/whereis/whereis.170
-rw-r--r--shell_cmds/whereis/whereis.c128
-rw-r--r--shell_cmds/which/which.185
-rw-r--r--shell_cmds/which/which.c146
-rw-r--r--shell_cmds/who/utmpentry.c348
-rw-r--r--shell_cmds/who/utmpentry.h78
-rw-r--r--shell_cmds/who/who.1130
-rw-r--r--shell_cmds/who/who.c453
-rw-r--r--shell_cmds/xargs/pathnames.h36
-rw-r--r--shell_cmds/xargs/strnsubst.c109
-rw-r--r--shell_cmds/xargs/xargs.1389
-rw-r--r--shell_cmds/xargs/xargs.c840
-rw-r--r--shell_cmds/xcconfigs/base.xcconfig59
-rw-r--r--shell_cmds/xcconfigs/sh.xcconfig33
-rw-r--r--shell_cmds/xcodescripts/builtins-manpages.txt85
-rw-r--r--shell_cmds/xcodescripts/builtins.txt14
-rw-r--r--shell_cmds/xcodescripts/install-files.sh66
-rw-r--r--shell_cmds/yes/yes.156
-rw-r--r--shell_cmds/yes/yes.c63
774 files changed, 68459 insertions, 0 deletions
diff --git a/shell_cmds/.upstream_base_commits b/shell_cmds/.upstream_base_commits
new file mode 100644
index 0000000..23f2adb
--- /dev/null
+++ b/shell_cmds/.upstream_base_commits
@@ -0,0 +1,4 @@
+xargs/pathname.h freebsd usr.bin/xargs/pathname.h 872b698bd4a1bfc0bf008c09228e6fd238809c75
+xargs/strnsubst.c freebsd usr.bin/xargs/strnsubst.c 56640efcbe39386a0152f14fb18a314b85e7e014
+xargs/xargs.1 freebsd usr.bin/xargs/xargs.1 7e6cabd06e6caa6a02eeb86308dc0cb3f27e10da
+xargs/xargs.c freebsd usr.bin/xargs/xargs.c 872b698bd4a1bfc0bf008c09228e6fd238809c75
diff --git a/shell_cmds/alias/alias.1 b/shell_cmds/alias/alias.1
new file mode 100644
index 0000000..5a811f4
--- /dev/null
+++ b/shell_cmds/alias/alias.1
@@ -0,0 +1 @@
+.so man1/builtin.1
diff --git a/shell_cmds/alias/builtin.1 b/shell_cmds/alias/builtin.1
new file mode 100644
index 0000000..0fae99a
--- /dev/null
+++ b/shell_cmds/alias/builtin.1
@@ -0,0 +1,333 @@
+.\"
+.\" Copyright (c) 1999 Sheldon Hearn
+.\"
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: /repoman/r/ncvs/src/share/man/man1/builtin.1,v 1.25 2005/09/09 17:02:08 garys Exp $
+.\"
+.Dd February 23, 2005
+.Dt BUILTIN 1
+.Os
+.Sh NAME
+.Nm builtin ,
+.Nm \&! ,
+.Nm \&% ,
+.Nm \&. ,
+.Nm \&: ,
+.Nm \&@ ,
+.Nm \&{ ,
+.Nm \&} ,
+.Nm alias ,
+.Nm alloc ,
+.Nm bg ,
+.Nm bind ,
+.Nm bindkey ,
+.Nm break ,
+.Nm breaksw ,
+.Nm builtins ,
+.Nm case ,
+.Nm cd ,
+.Nm chdir ,
+.Nm command ,
+.Nm complete ,
+.Nm continue ,
+.Nm default ,
+.Nm dirs ,
+.Nm do ,
+.Nm done ,
+.Nm echo ,
+.Nm echotc ,
+.Nm elif ,
+.Nm else ,
+.Nm end ,
+.Nm endif ,
+.Nm endsw ,
+.Nm esac ,
+.Nm eval ,
+.Nm exec ,
+.Nm exit ,
+.Nm export ,
+.Nm false ,
+.Nm fc ,
+.Nm fg ,
+.Nm filetest ,
+.Nm fi ,
+.Nm for ,
+.Nm foreach ,
+.Nm getopts ,
+.Nm glob ,
+.Nm goto ,
+.Nm hash ,
+.Nm hashstat ,
+.Nm history ,
+.Nm hup ,
+.Nm if ,
+.Nm jobid ,
+.Nm jobs ,
+.Nm kill ,
+.Nm limit ,
+.Nm local ,
+.Nm log ,
+.Nm login ,
+.Nm logout ,
+.Nm ls-F ,
+.Nm nice ,
+.Nm nohup ,
+.Nm notify ,
+.Nm onintr ,
+.Nm popd ,
+.Nm printenv ,
+.Nm pushd ,
+.Nm pwd ,
+.Nm read ,
+.Nm readonly ,
+.Nm rehash ,
+.Nm repeat ,
+.Nm return ,
+.Nm sched ,
+.Nm set ,
+.Nm setenv ,
+.Nm settc ,
+.Nm setty ,
+.Nm setvar ,
+.Nm shift ,
+.Nm source ,
+.Nm stop ,
+.Nm suspend ,
+.Nm switch ,
+.Nm telltc ,
+.Nm test ,
+.Nm then ,
+.Nm time ,
+.Nm times ,
+.Nm trap ,
+.Nm true ,
+.Nm type ,
+.Nm ulimit ,
+.Nm umask ,
+.Nm unalias ,
+.Nm uncomplete ,
+.Nm unhash ,
+.Nm unlimit ,
+.Nm unset ,
+.Nm unsetenv ,
+.Nm until ,
+.Nm wait ,
+.Nm where ,
+.Nm which ,
+.Nm while
+.Nd shell built-in commands
+.Sh SYNOPSIS
+.Nm
+.Op Fl options
+.Op Ar args ...
+.Sh DESCRIPTION
+Shell builtin commands are commands that can be executed within the
+running shell's process.
+Note that, in the case of
+.Xr csh 1
+builtin commands, the command is executed in a subshell if it occurs as
+any component of a pipeline except the last.
+.Pp
+If a command specified to the shell contains a slash
+.Dq \&/ ,
+the shell will not execute a builtin command, even if the last component
+of the specified command matches the name of a builtin command.
+Thus, while specifying
+.Dq Ic echo
+causes a builtin command to be executed under shells that support the
+.Nm echo
+builtin command,
+specifying
+.Dq Ic /bin/echo
+or
+.Dq Ic ./echo
+does not.
+.Pp
+While some builtin commands may exist in more than one shell, their
+operation may be different under each shell which supports them.
+Below is a table which lists shell builtin commands, the standard shells
+that support them and whether they exist as standalone utilities.
+.Pp
+Only builtin commands for the
+.Xr csh 1
+and
+.Xr sh 1
+shells are listed here.
+Consult a shell's manual page for
+details on the operation of its builtin commands.
+Beware that the
+.Xr sh 1
+manual page, at least, calls some of these commands
+.Dq built-in commands
+and some of them
+.Dq reserved words .
+Users of other shells may need to consult an
+.Xr info 1
+page or other sources of documentation.
+.Pp
+Commands marked
+.Dq Li No**
+under
+.Em External
+do exist externally,
+but are implemented as scripts using a builtin command of the same name.
+.Bl -column ".Ic uncomplete" ".Em External" ".Xr csh 1" ".Xr sh 1" -offset indent
+.It Xo
+.Em "Command External" Ta Xr csh 1 Ta Xr sh 1
+.Xc
+.It Ic ! Ta \&No Ta \&No Ta \&Yes
+.It Ic % Ta \&No Ta Yes Ta \&No
+.It Ic . Ta \&No Ta \&No Ta Yes
+.It Ic : Ta \&No Ta Yes Ta Yes
+.It Ic @ Ta \&No Ta Yes Ta Yes
+.It Ic { Ta \&No Ta \&No Ta \&Yes
+.It Ic } Ta \&No Ta \&No Ta \&Yes
+.It Ic alias Ta \&No** Ta Yes Ta Yes
+.It Ic alloc Ta \&No Ta Yes Ta \&No
+.It Ic bg Ta No** Ta Yes Ta Yes
+.It Ic bind Ta \&No Ta \&No Ta Yes
+.It Ic bindkey Ta \&No Ta Yes Ta \&No
+.It Ic break Ta \&No Ta Yes Ta \&Yes
+.It Ic breaksw Ta \&No Ta Yes Ta \&No
+.It Ic builtin Ta \&No Ta \&No Ta Yes
+.It Ic builtins Ta \&No Ta Yes Ta \&No
+.It Ic case Ta \&No Ta Yes Ta Yes
+.It Ic cd Ta \&No** Ta Yes Ta Yes
+.It Ic chdir Ta \&No Ta Yes Ta \&Yes
+.It Ic command Ta \&No** Ta \&No Ta Yes
+.It Ic complete Ta \&No Ta Yes Ta \&No
+.It Ic continue Ta \&No Ta Yes Ta \&Yes
+.It Ic default Ta \&No Ta Yes Ta \&No
+.It Ic dirs Ta \&No Ta Yes Ta \&No
+.It Ic do Ta \&No Ta \&No Ta Yes
+.It Ic done Ta \&No Ta \&No Ta Yes
+.It Ic echo Ta Yes Ta Yes Ta Yes
+.It Ic echotc Ta \&No Ta Yes Ta \&No
+.It Ic elif Ta \&No Ta \&No Ta Yes
+.It Ic else Ta \&No Ta Yes Ta \&Yes
+.It Ic end Ta \&No Ta Yes Ta \&No
+.It Ic endif Ta \&No Ta Yes Ta \&No
+.It Ic endsw Ta \&No Ta Yes Ta \&No
+.It Ic esac Ta \&No Ta \&No Ta Yes
+.It Ic eval Ta \&No Ta Yes Ta Yes
+.It Ic exec Ta \&No Ta Yes Ta Yes
+.It Ic exit Ta \&No Ta Yes Ta Yes
+.It Ic export Ta \&No Ta \&No Ta Yes
+.It Ic false Ta Yes Ta \&No Ta Yes
+.It Ic fc Ta \&No** Ta \&No Ta Yes
+.It Ic fg Ta \&No** Ta Yes Ta Yes
+.It Ic filetest Ta \&No Ta Yes Ta \&No
+.It Ic fi Ta \&No Ta \&No Ta Yes
+.It Ic for Ta \&No Ta \&No Ta Yes
+.It Ic foreach Ta \&No Ta Yes Ta \&No
+.It Ic getopts Ta \&No** Ta \&No Ta Yes
+.It Ic glob Ta \&No Ta Yes Ta \&No
+.It Ic goto Ta \&No Ta Yes Ta \&No
+.It Ic hash Ta \&No Ta \&No Ta Yes
+.It Ic hashstat Ta \&No Ta Yes Ta \&No
+.It Ic history Ta \&No Ta Yes Ta \&No
+.It Ic hup Ta \&No Ta Yes Ta \&No
+.It Ic if Ta \&No Ta Yes Ta \&Yes
+.It Ic jobid Ta \&No Ta \&No Ta Yes
+.It Ic jobs Ta \&No** Ta Yes Ta Yes
+.It Ic kill Ta Yes Ta Yes Ta \&No
+.It Ic limit Ta \&No Ta Yes Ta \&No
+.It Ic local Ta \&No Ta \&No Ta Yes
+.It Ic log Ta \&No Ta Yes Ta \&No
+.It Ic login Ta Yes Ta Yes Ta \&No
+.It Ic logout Ta \&No Ta Yes Ta \&No
+.It Ic ls-F Ta \&No Ta Yes Ta \&No
+.It Ic nice Ta Yes Ta Yes Ta \&No
+.It Ic nohup Ta Yes Ta Yes Ta \&No
+.It Ic notify Ta \&No Ta Yes Ta \&No
+.It Ic onintr Ta \&No Ta Yes Ta \&No
+.It Ic popd Ta \&No Ta Yes Ta \&No
+.It Ic printenv Ta Yes Ta Yes Ta \&No
+.It Ic pushd Ta \&No Ta Yes Ta \&No
+.It Ic pwd Ta Yes Ta \&No Ta Yes
+.It Ic read Ta \&No** Ta \&No Ta Yes
+.It Ic readonly Ta \&No Ta \&No Ta Yes
+.It Ic rehash Ta \&No Ta Yes Ta \&No
+.It Ic repeat Ta \&No Ta Yes Ta \&No
+.It Ic return Ta \&No Ta \&No Ta Yes
+.It Ic sched Ta \&No Ta Yes Ta \&No
+.It Ic set Ta \&No Ta Yes Ta \&Yes
+.It Ic setenv Ta \&No Ta Yes Ta \&No
+.It Ic settc Ta \&No Ta Yes Ta \&No
+.It Ic setty Ta \&No Ta Yes Ta \&No
+.It Ic setvar Ta \&No Ta \&No Ta Yes
+.It Ic shift Ta \&No Ta Yes Ta Yes
+.It Ic source Ta \&No Ta Yes Ta \&No
+.It Ic stop Ta \&No Ta Yes Ta \&No
+.It Ic suspend Ta \&No Ta Yes Ta \&No
+.It Ic switch Ta \&No Ta Yes Ta \&No
+.It Ic telltc Ta \&No Ta Yes Ta \&No
+.It Ic test Ta Yes Ta \&No Ta Yes
+.It Ic then Ta \&No Ta \&No Ta Yes
+.It Ic time Ta Yes Ta Yes Ta \&No
+.It Ic times Ta \&No Ta \&No Ta Yes
+.It Ic trap Ta \&No Ta \&No Ta Yes
+.It Ic true Ta Yes Ta \&No Ta Yes
+.It Ic type Ta \&No Ta \&No Ta Yes
+.It Ic ulimit Ta \&No Ta \&No Ta Yes
+.It Ic umask Ta \&No** Ta Yes Ta Yes
+.It Ic unalias Ta \&No** Ta Yes Ta Yes
+.It Ic uncomplete Ta \&No Ta Yes Ta \&No
+.It Ic unhash Ta \&No Ta Yes Ta \&No
+.It Ic unlimit Ta \&No Ta Yes Ta \&No
+.It Ic unset Ta \&No Ta Yes Ta Yes
+.It Ic unsetenv Ta \&No Ta Yes Ta \&No
+.It Ic until Ta \&No Ta \&No Ta Yes
+.It Ic wait Ta \&No** Ta Yes Ta Yes
+.It Ic where Ta \&No Ta Yes Ta \&No
+.It Ic which Ta Yes Ta Yes Ta \&No
+.It Ic while Ta \&No Ta Yes Ta \&Yes
+.El
+.Sh SEE ALSO
+.Xr csh 1 ,
+.Xr dash 1 ,
+.Xr echo 1 ,
+.Xr false 1 ,
+.Xr info 1 ,
+.Xr kill 1 ,
+.Xr login 1 ,
+.Xr nice 1 ,
+.Xr nohup 1 ,
+.Xr printenv 1 ,
+.Xr pwd 1 ,
+.Xr sh 1 ,
+.Xr test 1 ,
+.Xr time 1 ,
+.Xr true 1 ,
+.Xr which 1 ,
+.Xr zsh 1
+.Sh HISTORY
+The
+.Nm
+manual page first appeared in
+.Fx 3.4 .
+.Sh AUTHORS
+This manual page was written by
+.An Sheldon Hearn Aq sheldonh@FreeBSD.org .
diff --git a/shell_cmds/alias/generic.sh b/shell_cmds/alias/generic.sh
new file mode 100644
index 0000000..5948cc9
--- /dev/null
+++ b/shell_cmds/alias/generic.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+# $FreeBSD: src/usr.bin/alias/generic.sh,v 1.2 2005/10/24 22:32:19 cperciva Exp $
+# This file is in the public domain.
+builtin `echo ${0##*/} | tr \[:upper:] \[:lower:]` ${1+"$@"}
diff --git a/shell_cmds/apply/apply.1 b/shell_cmds/apply/apply.1
new file mode 100644
index 0000000..2eb1516
--- /dev/null
+++ b/shell_cmds/apply/apply.1
@@ -0,0 +1,140 @@
+.\" Copyright (c) 1983, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)apply.1 8.2 (Berkeley) 4/4/94
+.\" $FreeBSD: src/usr.bin/apply/apply.1,v 1.14 2002/04/19 23:16:06 charnier Exp $
+.\"
+.Dd April 4, 1994
+.Dt APPLY 1
+.Os
+.Sh NAME
+.Nm apply
+.Nd apply a command to a set of arguments
+.Sh SYNOPSIS
+.Nm
+.Op Fl a Ar c
+.Op Fl d
+.Op Fl #
+.Ar command argument ...
+.Sh DESCRIPTION
+The
+.Nm
+utility runs the named
+.Ar command
+on each
+argument
+.Ar argument
+in turn.
+.Pp
+Character sequences of the form
+.Dq Li \&%d
+in
+.Ar command ,
+where
+.Sq Li d
+is a digit from 1 to 9, are replaced by the
+.Li d Ns \'th
+following unused
+.Ar argument .
+In this case, the largest digit number of arguments are discarded for
+each execution of
+.Ar command .
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl #
+Normally arguments are taken singly; the optional number
+.Fl #
+specifies the number of arguments to be passed to
+.Ar command .
+If the number is zero,
+.Ar command
+is run, without arguments, once for each
+.Ar argument .
+.Pp
+If any sequences of
+.Dq Li \&%d
+occur in
+.Ar command ,
+the
+.Fl #
+option is ignored.
+.It Fl a Ar c
+The use of the character
+.Sq Li %
+as a magic character may be changed with the
+.Fl a
+option.
+.It Fl d
+Display the commands that would have been executed, but do not actually
+execute them.
+.El
+.Sh ENVIRONMENT
+The following environment variable affects the execution of
+.Nm :
+.Bl -tag -width SHELL
+.It Ev SHELL
+Pathname of shell to use.
+If this variable is not defined, the Bourne shell is used.
+.El
+.Sh EXAMPLES
+.Bl -tag -width apply -compact
+.It Li "apply echo a*"
+is similar to
+.Xr ls 1 ;
+.It Li "apply \-2 cmp a1 b1 a2 b2 a3 b3"
+compares the `a' files to the `b' files;
+.It Li "apply \-0 who 1 2 3 4 5"
+runs
+.Xr who 1
+5 times; and
+.It Li "apply \'ln %1 /usr/joe\'" *
+links all files in the current directory to the directory
+.Pa /usr/joe .
+.El
+.Sh FILES
+.Bl -tag -width /bin/sh -compact
+.It Pa /bin/sh
+default shell
+.El
+.Sh AUTHORS
+.An Rob Pike
+.Sh BUGS
+Shell metacharacters in
+.Ar command
+may have bizarre effects; it is best to enclose complicated
+commands in single quotes
+.Pq '' .
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.2 .
diff --git a/shell_cmds/apply/apply.c b/shell_cmds/apply/apply.c
new file mode 100644
index 0000000..cf4e9c1
--- /dev/null
+++ b/shell_cmds/apply/apply.c
@@ -0,0 +1,267 @@
+/*-
+ * Copyright (c) 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)apply.c 8.4 (Berkeley) 4/4/94";
+#endif
+#endif
+
+#include <sys/cdefs.h>
+__RCSID("$FreeBSD: src/usr.bin/apply/apply.c,v 1.22 2002/07/14 18:22:12 alfred Exp $");
+
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <paths.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define EXEC "exec "
+
+static int exec_shell(const char *, char *, char *);
+static void usage(void);
+
+int
+main(int argc, char *argv[]) {
+ int ch, debug, i, magic, n, nargs, offset, rval;
+ size_t clen, cmdsize, l;
+ char *c, *cmd, *name, *p, *q, *shell, *slashp, *tmpshell;
+
+ debug = 0;
+ magic = '%'; /* Default magic char is `%'. */
+ nargs = -1;
+ while ((ch = getopt(argc, argv, "a:d0123456789")) != -1)
+ switch (ch) {
+ case 'a':
+ if (optarg[1] != '\0')
+ errx(1,
+ "illegal magic character specification");
+ magic = optarg[0];
+ break;
+ case 'd':
+ debug = 1;
+ break;
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ if (nargs != -1)
+ errx(1,
+ "only one -# argument may be specified");
+ nargs = optopt - '0';
+ break;
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 2)
+ usage();
+
+ /*
+ * The command to run is argv[0], and the args are argv[1..].
+ * Look for %digit references in the command, remembering the
+ * largest one.
+ */
+ for (n = 0, p = argv[0]; *p != '\0'; ++p)
+ if (p[0] == magic && isdigit(p[1]) && p[1] != '0') {
+ ++p;
+ if (p[0] - '0' > n)
+ n = p[0] - '0';
+ }
+
+ /*
+ * Figure out the shell and name arguments to pass to execl()
+ * in exec_shell(). Always malloc() shell and just set name
+ * to point at the last part of shell if there are any backslashes,
+ * otherwise just set it to point at the space malloc()'d. If
+ * SHELL environment variable exists, replace contents of
+ * shell with it.
+ */
+ shell = name = NULL;
+ tmpshell = getenv("SHELL");
+ shell = (tmpshell != NULL) ? strdup(tmpshell) : strdup(_PATH_BSHELL);
+ if (shell == NULL)
+ err(1, "strdup() failed");
+ slashp = strrchr(shell, '/');
+ name = (slashp != NULL) ? slashp + 1 : shell;
+
+ /*
+ * If there were any %digit references, then use those, otherwise
+ * build a new command string with sufficient %digit references at
+ * the end to consume (nargs) arguments each time round the loop.
+ * Allocate enough space to hold the maximum command. Save the
+ * size to pass to snprintf().
+ */
+ cmdsize = sizeof(EXEC) - 1 + strlen(argv[0])
+ + 9 * (sizeof(" %1") - 1) + 1;
+ if ((cmd = malloc(cmdsize)) == NULL)
+ err(1, NULL);
+
+ if (n == 0) {
+ /* If nargs not set, default to a single argument. */
+ if (nargs == -1)
+ nargs = 1;
+
+ p = cmd;
+ offset = snprintf(cmd, cmdsize, EXEC "%s", argv[0]);
+ if ((size_t)offset >= cmdsize)
+ err(1, "snprintf() failed");
+ p += offset;
+ cmdsize -= offset;
+ for (i = 1; i <= nargs; i++) {
+ offset = snprintf(p, cmdsize, " %c%d", magic, i);
+ if ((size_t)offset >= cmdsize)
+ err(1, "snprintf() failed");
+ p += offset;
+ cmdsize -= offset;
+ }
+
+ /*
+ * If nargs set to the special value 0, eat a single
+ * argument for each command execution.
+ */
+ if (nargs == 0)
+ nargs = 1;
+ } else {
+ offset = snprintf(cmd, cmdsize, EXEC "%s", argv[0]);
+ if ((size_t)offset >= cmdsize)
+ err(1, "snprintf() failed");
+ nargs = n;
+ }
+
+ /*
+ * Grab some space in which to build the command. Allocate
+ * as necessary later, but no reason to build it up slowly
+ * for the normal case.
+ */
+ if ((c = malloc(clen = 1024)) == NULL)
+ err(1, NULL);
+
+ /*
+ * (argc) and (argv) are still offset by one to make it simpler to
+ * expand %digit references. At the end of the loop check for (argc)
+ * equals 1 means that all the (argv) has been consumed.
+ */
+ for (rval = 0; argc > nargs; argc -= nargs, argv += nargs) {
+ /*
+ * Find a max value for the command length, and ensure
+ * there's enough space to build it.
+ */
+ for (l = strlen(cmd), i = 0; i < nargs; i++)
+ l += strlen(argv[i+1]);
+ if (l > clen && (c = realloc(c, clen = l)) == NULL)
+ err(1, NULL);
+
+ /* Expand command argv references. */
+ for (p = cmd, q = c; *p != '\0'; ++p)
+ if (p[0] == magic && isdigit(p[1]) && p[1] != '0') {
+ offset = snprintf(q, l, "%s",
+ argv[(++p)[0] - '0']);
+ if ((size_t)offset >= l)
+ err(1, "snprintf() failed");
+ q += offset;
+ l -= offset;
+ } else
+ *q++ = *p;
+
+ /* Terminate the command string. */
+ *q = '\0';
+
+ /* Run the command. */
+ if (debug)
+ (void)printf("%s\n", c);
+ else
+ if (exec_shell(c, shell, name))
+ rval = 1;
+ }
+
+ if (argc != 1)
+ errx(1, "expecting additional argument%s after \"%s\"",
+ (nargs - argc) ? "s" : "", argv[argc - 1]);
+ free(cmd);
+ free(c);
+ free(shell);
+ exit(rval);
+}
+
+/*
+ * exec_shell --
+ * Execute a shell command using passed use_shell and use_name
+ * arguments.
+ */
+static int
+exec_shell(const char *command, char *use_shell, char *use_name)
+{
+ pid_t pid;
+ int omask, pstat;
+ sig_t intsave, quitsave;
+
+ if (!command) /* just checking... */
+ return(1);
+
+ omask = sigblock(sigmask(SIGCHLD));
+ switch(pid = vfork()) {
+ case -1: /* error */
+ err(1, "vfork");
+ case 0: /* child */
+ (void)sigsetmask(omask);
+ execl(use_shell, use_name, "-c", command, (char *)NULL);
+ warn("%s", use_shell);
+ _exit(1);
+ }
+ intsave = signal(SIGINT, SIG_IGN);
+ quitsave = signal(SIGQUIT, SIG_IGN);
+ pid = waitpid(pid, &pstat, 0);
+ (void)sigsetmask(omask);
+ (void)signal(SIGINT, intsave);
+ (void)signal(SIGQUIT, quitsave);
+ return(pid == -1 ? -1 : pstat);
+}
+
+void
+usage(void)
+{
+
+ (void)fprintf(stderr,
+ "usage: apply [-a magic] [-d] [-0123456789] command arguments ...\n");
+ exit(1);
+}
diff --git a/shell_cmds/basename/basename.1 b/shell_cmds/basename/basename.1
new file mode 100644
index 0000000..835d21a
--- /dev/null
+++ b/shell_cmds/basename/basename.1
@@ -0,0 +1,114 @@
+.\" Copyright (c) 1990, 1993, 1994
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)basename.1 8.2 (Berkeley) 4/18/94
+.\" $FreeBSD: src/usr.bin/basename/basename.1,v 1.13 2002/06/30 13:40:35 jmallett Exp $
+.\"
+.Dd April 18, 1994
+.Dt BASENAME 1
+.Os
+.Sh NAME
+.Nm basename , dirname
+.Nd return filename or directory portion of pathname
+.Sh SYNOPSIS
+.Nm
+.Ar string
+.Op Ar suffix
+.Nm
+.Op Fl a
+.Op Fl s Ar suffix
+.Ar string
+.Op Ar ...
+.Nm dirname
+.Ar string
+.Sh DESCRIPTION
+The
+.Nm
+utility deletes any prefix ending with the last slash
+.Ql \&/
+character present in
+.Ar string
+(after first stripping trailing slashes),
+and a
+.Ar suffix ,
+if given.
+The
+.Ar suffix
+is not stripped if it is identical to the remaining characters in
+.Ar string .
+The resulting filename is written to the standard output.
+A non-existent suffix is ignored.
+If
+.Fl a
+is specified, then every argument is treated as a
+.Ar string
+as if
+.Nm
+were invoked with just one argument.
+If
+.Fl s
+is specified, then the
+.Ar suffix
+is taken as its argument, and all other arguments are treated as a
+.Ar string .
+.Pp
+The
+.Nm dirname
+utility deletes the filename portion, beginning
+with the last slash
+.Ql \&/
+character to the end of
+.Ar string
+(after first stripping trailing slashes),
+and writes the result to the standard output.
+.Sh EXAMPLES
+The following line sets the shell variable
+.Ev FOO
+to
+.Pa /usr/bin .
+.Pp
+.Dl FOO=`dirname /usr/bin/trail`
+.Sh DIAGNOSTICS
+.Ex -std basename dirname
+.Sh SEE ALSO
+.Xr csh 1 ,
+.Xr sh 1
+.Sh STANDARDS
+The
+.Nm
+and
+.Nm dirname
+utilities are expected to be
+.St -p1003.2
+compatible.
diff --git a/shell_cmds/basename/basename.c b/shell_cmds/basename/basename.c
new file mode 100644
index 0000000..6bde858
--- /dev/null
+++ b/shell_cmds/basename/basename.c
@@ -0,0 +1,119 @@
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1991, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)basename.c 8.4 (Berkeley) 5/4/95";
+#endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+__RCSID("$FreeBSD: src/usr.bin/basename/basename.c,v 1.14 2002/09/04 23:28:52 dwmalone Exp $");
+
+#include <err.h>
+#include <libgen.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+void usage(void);
+
+int
+main(int argc, char **argv)
+{
+ char *p, *q, *suffix;
+ size_t suffixlen;
+ int aflag, ch;
+
+ aflag = 0;
+ suffix = NULL;
+ suffixlen = 0;
+
+ while ((ch = getopt(argc, argv, "as:")) != -1)
+ switch(ch) {
+ case 'a':
+ aflag = 1;
+ break;
+ case 's':
+ suffix = optarg;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1)
+ usage();
+
+ if (!*argv[0]) {
+ printf("\n");
+ exit(0);
+ }
+ if ((p = basename(argv[0])) == NULL)
+ err(1, "%s", argv[0]);
+ if ((suffix == NULL && !aflag) && argc == 2) {
+ suffix = argv[1];
+ argc--;
+ }
+ if (suffix != NULL)
+ suffixlen = strlen(suffix);
+ while (argc--) {
+ if ((p = basename(*argv)) == NULL)
+ err(1, "%s", argv[0]);
+ if (suffixlen && (q = strchr(p, '\0') - suffixlen) > p &&
+ strcmp(suffix, q) == 0)
+ *q = '\0';
+ argv++;
+ (void)printf("%s\n", p);
+ }
+ exit(0);
+}
+
+void
+usage(void)
+{
+
+ (void)fprintf(stderr,
+"usage: basename string [suffix]\n"
+" basename [-a] [-s suffix] string [...]\n");
+ exit(1);
+}
diff --git a/shell_cmds/basename/dirname.1 b/shell_cmds/basename/dirname.1
new file mode 100644
index 0000000..ee3bc6f
--- /dev/null
+++ b/shell_cmds/basename/dirname.1
@@ -0,0 +1 @@
+.so man1/basename.1
diff --git a/shell_cmds/chroot/chroot.8 b/shell_cmds/chroot/chroot.8
new file mode 100644
index 0000000..fce026b
--- /dev/null
+++ b/shell_cmds/chroot/chroot.8
@@ -0,0 +1,102 @@
+.\" Copyright (c) 1988, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" from: @(#)chroot.8 8.1 (Berkeley) 6/9/93
+.\" $NetBSD: chroot.8,v 1.7 1998/10/06 03:47:50 mrg Exp $
+.\"
+.Dd October 6, 1998
+.Dt CHROOT 8
+.Os BSD 4.3
+.Sh NAME
+.Nm chroot
+.Nd change root directory
+.Sh SYNOPSIS
+.Nm
+.Op Fl u user
+.Op Fl g group
+.Op Fl G group,group,...
+.Ar newroot
+.Op Ar command
+.Sh DESCRIPTION
+The
+.Nm
+command changes its root directory to the supplied directory
+.Ar newroot
+and exec's
+.Ar command ,
+if supplied, or an interactive copy of your shell.
+.Pp
+If the
+.Fl u ,
+.Fl g
+or
+.Fl G
+options are given, the user, group and group list of the process are
+set to these values after the chroot has taken place. See
+.Xr setgid 2 ,
+.Xr setgroups 2 ,
+.Xr setuid 2 ,
+.Xr getgrnam 3
+and
+.Xr getpwnam 3 .
+.Pp
+Note,
+.Ar command
+or the shell are run as your real-user-id.
+.Sh ENVIRONMENT
+The following environment variable is referenced by
+.Nm :
+.Bl -tag -width SHELL
+.It Ev SHELL
+If set,
+the string specified by
+.Ev SHELL
+is interpreted as the name of
+the shell to exec.
+If the variable
+.Ev SHELL
+is not set,
+.Pa /bin/sh
+is used.
+.El
+.Sh SEE ALSO
+.Xr chdir 2 ,
+.Xr chroot 2 ,
+.Xr environ 7
+.Sh HISTORY
+The
+.Nm
+utility first appeared in
+.Bx 4.4 .
+.Sh SECURITY CONSIDERATIONS
+.Nm
+should never be installed setuid root, as it would then be possible
+to exploit the program to gain root privileges.
diff --git a/shell_cmds/chroot/chroot.c b/shell_cmds/chroot/chroot.c
new file mode 100644
index 0000000..c9c38f5
--- /dev/null
+++ b/shell_cmds/chroot/chroot.c
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1988, 1993\n\
+ The Regents of the University of California. All rights reserved.\n");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)chroot.c 8.1 (Berkeley) 6/9/93";
+#else
+__RCSID("$NetBSD: chroot.c,v 1.7 1998/10/06 03:47:51 mrg Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <grp.h>
+#include <paths.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+int main __P((int, char **));
+void usage __P((void)) __attribute__((__noreturn__));
+
+char *user; /* user to switch to before running program */
+char *group; /* group to switch to ... */
+char *grouplist; /* group list to switch to ... */
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ struct group *gp;
+ struct passwd *pw;
+ char *shell, *endp, *comma;
+ gid_t gid = 0, gidlist[NGROUPS_MAX];
+ uid_t uid = 0;
+ int ch, gids;
+
+ while ((ch = getopt(argc, argv, "G:g:u:")) != -1)
+ switch(ch) {
+ case 'u':
+ user = optarg;
+ break;
+ case 'g':
+ group = optarg;
+ break;
+ case 'G':
+ grouplist = optarg;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1)
+ usage();
+
+ if (group) {
+ if (isdigit(*group)) {
+ gid = (gid_t)strtol(group, &endp, 0);
+ if (endp == group)
+ goto getgroup;
+ } else {
+getgroup:
+ if ((gp = getgrnam(group)))
+ gid = gp->gr_gid;
+ else
+ errx(1, "no such group %s", group);
+ }
+ }
+
+ for (gids = 0; grouplist; ) {
+ comma = strchr(grouplist, ',');
+
+ if (comma)
+ *comma++ = '\0';
+
+ if (isdigit(*grouplist)) {
+ gidlist[gids] = (gid_t)strtol(grouplist, &endp, 0);
+ if (endp == grouplist)
+ goto getglist;
+ } else {
+getglist:
+ if ((gp = getgrnam(grouplist)))
+ gidlist[gids] = gp->gr_gid;
+ else
+ errx(1, "no such group %s", group);
+ }
+ gids++;
+ grouplist = comma;
+ }
+
+ if (user) {
+ if (isdigit(*user)) {
+ uid = (uid_t)strtol(user, &endp, 0);
+ if (endp == user)
+ goto getuser;
+ } else {
+getuser:
+ if ((pw = getpwnam(user)))
+ uid = pw->pw_uid;
+ else
+ errx(1, "no such user %s", user);
+ }
+ }
+
+ if (chdir(argv[0]) || chroot("."))
+ err(1, "%s", argv[0]);
+
+ if (gids && setgroups(gids, gidlist) < 0)
+ err(1, "setgroups");
+ if (group && setgid(gid) < 0)
+ err(1, "setgid");
+ if (user && setuid(uid) < 0)
+ err(1, "setuid");
+
+ if (argv[1]) {
+ execvp(argv[1], &argv[1]);
+ err(1, "%s", argv[1]);
+ }
+
+ if (!(shell = getenv("SHELL")))
+ shell = _PATH_BSHELL;
+ execlp(shell, shell, "-i", NULL);
+ err(1, "%s", shell);
+ /* NOTREACHED */
+}
+
+void
+usage()
+{
+ (void)fprintf(stderr, "usage: chroot [-g group] [-G group,group,...] "
+ "[-u user] newroot [command]\n");
+ exit(1);
+}
diff --git a/shell_cmds/date/date.1 b/shell_cmds/date/date.1
new file mode 100644
index 0000000..0cabb01
--- /dev/null
+++ b/shell_cmds/date/date.1
@@ -0,0 +1,472 @@
+.\"-
+.\" Copyright (c) 1980, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)date.1 8.3 (Berkeley) 4/28/95
+.\" $FreeBSD$
+.\"
+.Dd May 7, 2015
+.Dt DATE 1
+.Os
+.Sh NAME
+.Nm date
+.Nd display or set date and time
+.Sh SYNOPSIS
+.Nm
+.Op Fl jRu
+.Op Fl r Ar seconds | Ar filename
+.Oo
+.Fl v
+.Sm off
+.Op Cm + | -
+.Ar val Op Ar ymwdHMS
+.Sm on
+.Oc
+.Ar ...
+.Op Cm + Ns Ar output_fmt
+.Nm
+.Op Fl jnu
+.Sm off
+.Op Oo Oo Ar mm Oc Ar dd Oc Ar HH
+.Ar MM Oo Oo Ar cc Oc Ar yy Oc Op Ar .ss
+.Sm on
+.Nm
+.Op Fl jnRu
+.Fl f Ar input_fmt new_date
+.Op Cm + Ns Ar output_fmt
+.Nm
+.Op Fl d Ar dst
+.Op Fl t Ar minutes_west
+.Sh DESCRIPTION
+When invoked without arguments, the
+.Nm
+utility displays the current date and time.
+Otherwise, depending on the options specified,
+.Nm
+will set the date and time or print it in a user-defined way.
+.Pp
+The
+.Nm
+utility displays the date and time read from the kernel clock.
+When used to set the date and time,
+both the kernel clock and the hardware clock are updated.
+.Pp
+Only the superuser may set the date,
+and if the system securelevel (see
+.Xr securelevel 7 )
+is greater than 1,
+the time may not be changed by more than 1 second.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl d Ar dst
+Set the kernel's value for daylight saving time.
+If
+.Ar dst
+is non-zero, future calls
+to
+.Xr gettimeofday 2
+will return a non-zero for
+.Fa tz_dsttime .
+.It Fl f
+Use
+.Ar input_fmt
+as the format string to parse the
+.Ar new_date
+provided rather than using the default
+.Sm off
+.Oo Oo Oo
+.Ar mm Oc
+.Ar dd Oc
+.Ar HH Oc
+.Ar MM
+.Oo Oo
+.Ar cc Oc
+.Ar yy Oc Oo
+.Ar .ss Oc
+.Sm on
+format.
+Parsing is done using
+.Xr strptime 3 .
+.It Fl j
+Do not try to set the date.
+This allows you to use the
+.Fl f
+flag in addition to the
+.Cm +
+option to convert one date format to another.
+.It Fl n
+By default, if the
+.Xr timed 8
+daemon is running,
+.Nm
+sets the time on all of the machines in the local group.
+The
+.Fl n
+option suppresses this behavior and causes the time to be set only on the
+current machine.
+.It Fl R
+Use RFC 2822 date and time output format. This is equivalent to use
+.Dq Li %a, %d %b %Y \&%T %z
+as
+.Ar output_fmt
+while
+.Ev LC_TIME
+is set to the
+.Dq C
+locale .
+.It Fl r Ar seconds
+Print the date and time represented by
+.Ar seconds ,
+where
+.Ar seconds
+is the number of seconds since the Epoch
+(00:00:00 UTC, January 1, 1970;
+see
+.Xr time 3 ) ,
+and can be specified in decimal, octal, or hex.
+.It Fl r Ar filename
+Print the date and time of the last modification of
+.Ar filename .
+.It Fl t Ar minutes_west
+Set the system's value for minutes west of
+.Tn GMT .
+.Ar minutes_west
+specifies the number of minutes returned in
+.Fa tz_minuteswest
+by future calls to
+.Xr gettimeofday 2 .
+.It Fl u
+Display or set the date in
+.Tn UTC
+(Coordinated Universal) time.
+.It Fl v
+Adjust (i.e., take the current date and display the result of the
+adjustment; not actually set the date) the second, minute, hour, month
+day, week day, month or year according to
+.Ar val .
+If
+.Ar val
+is preceded with a plus or minus sign,
+the date is adjusted forwards or backwards according to the remaining string,
+otherwise the relevant part of the date is set.
+The date can be adjusted as many times as required using these flags.
+Flags are processed in the order given.
+.Pp
+When setting values
+(rather than adjusting them),
+seconds are in the range 0-59, minutes are in the range 0-59, hours are
+in the range 0-23, month days are in the range 1-31, week days are in the
+range 0-6 (Sun-Sat),
+months are in the range 1-12 (Jan-Dec)
+and years are in the range 80-38 or 1980-2038.
+.Pp
+If
+.Ar val
+is numeric, one of either
+.Ar y ,
+.Ar m ,
+.Ar w ,
+.Ar d ,
+.Ar H ,
+.Ar M
+or
+.Ar S
+must be used to specify which part of the date is to be adjusted.
+.Pp
+The week day or month may be specified using a name rather than a
+number.
+If a name is used with the plus
+(or minus)
+sign, the date will be put forwards
+(or backwards)
+to the next
+(previous)
+date that matches the given week day or month.
+This will not adjust the date,
+if the given week day or month is the same as the current one.
+.Pp
+When a date is adjusted to a specific value or in units greater than hours,
+daylight savings time considerations are ignored.
+Adjustments in units of hours or less honor daylight saving time.
+So, assuming the current date is March 26, 0:30 and that the DST adjustment
+means that the clock goes forward at 01:00 to 02:00, using
+.Fl v No +1H
+will adjust the date to March 26, 2:30.
+Likewise, if the date is October 29, 0:30 and the DST adjustment means that
+the clock goes back at 02:00 to 01:00, using
+.Fl v No +3H
+will be necessary to reach October 29, 2:30.
+.Pp
+When the date is adjusted to a specific value that does not actually exist
+(for example March 26, 1:30 BST 2000 in the Europe/London timezone),
+the date will be silently adjusted forwards in units of one hour until it
+reaches a valid time.
+When the date is adjusted to a specific value that occurs twice
+(for example October 29, 1:30 2000),
+the resulting timezone will be set so that the date matches the earlier of
+the two times.
+.Pp
+It is not possible to adjust a date to an invalid absolute day, so using
+the switches
+.Fl v No 31d Fl v No 12m
+will simply fail five months of the year.
+It is therefore usual to set the month before setting the day; using
+.Fl v No 12m Fl v No 31d
+always works.
+.Pp
+Adjusting the date by months is inherently ambiguous because
+a month is a unit of variable length depending on the current date.
+This kind of date adjustment is applied in the most intuitive way.
+First of all,
+.Nm
+tries to preserve the day of the month.
+If it is impossible because the target month is shorter than the present one,
+the last day of the target month will be the result.
+For example, using
+.Fl v No +1m
+on May 31 will adjust the date to June 30, while using the same option
+on January 30 will result in the date adjusted to the last day of February.
+This approach is also believed to make the most sense for shell scripting.
+Nevertheless, be aware that going forth and back by the same number of
+months may take you to a different date.
+.Pp
+Refer to the examples below for further details.
+.El
+.Pp
+An operand with a leading plus
+.Pq Sq +
+sign signals a user-defined format string
+which specifies the format in which to display the date and time.
+The format string may contain any of the conversion specifications
+described in the
+.Xr strftime 3
+manual page, as well as any arbitrary text.
+A newline
+.Pq Ql \en
+character is always output after the characters specified by
+the format string.
+The format string for the default display is
+.Dq +%+ .
+.Pp
+If an operand does not have a leading plus sign, it is interpreted as
+a value for setting the system's notion of the current date and time.
+The canonical representation for setting the date and time is:
+.Pp
+.Bl -tag -width Ds -compact -offset indent
+.It Ar cc
+Century
+(either 19 or 20)
+prepended to the abbreviated year.
+.It Ar yy
+Year in abbreviated form
+(e.g., 89 for 1989, 06 for 2006).
+.It Ar mm
+Numeric month, a number from 1 to 12.
+.It Ar dd
+Day, a number from 1 to 31.
+.It Ar HH
+Hour, a number from 0 to 23.
+.It Ar MM
+Minutes, a number from 0 to 59.
+.It Ar ss
+Seconds, a number from 0 to 61
+(59 plus a maximum of two leap seconds).
+.El
+.Pp
+Everything but the minutes is optional.
+.Pp
+Time changes for Daylight Saving Time, standard time, leap seconds,
+and leap years are handled automatically.
+.Sh ENVIRONMENT
+The following environment variables affect the execution of
+.Nm :
+.Bl -tag -width Ds
+.It Ev TZ
+The timezone to use when displaying dates.
+The normal format is a pathname relative to
+.Pa /usr/share/zoneinfo .
+For example, the command
+.Dq TZ=America/Los_Angeles date
+displays the current time in California.
+See
+.Xr environ 7
+for more information.
+.El
+.Sh FILES
+.Bl -tag -width /var/log/messages -compact
+.It Pa /var/log/messages
+record of the user setting the time
+.El
+.Sh EXIT STATUS
+The
+.Nm
+utility exits 0 on success, 1 if unable to set the date, and 2
+if able to set the local date, but unable to set it globally.
+.Sh EXAMPLES
+The command:
+.Pp
+.Dl "date ""+DATE: %Y-%m-%d%nTIME: %H:%M:%S"""
+.Pp
+will display:
+.Bd -literal -offset indent
+DATE: 1987-11-21
+TIME: 13:36:16
+.Ed
+.Pp
+In the Europe/London timezone, the command:
+.Pp
+.Dl "date -v1m -v+1y"
+.Pp
+will display:
+.Pp
+.Dl "Sun Jan 4 04:15:24 GMT 1998"
+.Pp
+where it is currently
+.Li "Mon Aug 4 04:15:24 BST 1997" .
+.Pp
+The command:
+.Pp
+.Dl "date -v1d -v3m -v0y -v-1d"
+.Pp
+will display the last day of February in the year 2000:
+.Pp
+.Dl "Tue Feb 29 03:18:00 GMT 2000"
+.Pp
+So will the command:
+.Pp
+.Dl "date -v3m -v30d -v0y -v-1m"
+.Pp
+because there is no such date as the 30th of February.
+.Pp
+The command:
+.Pp
+.Dl "date -v1d -v+1m -v-1d -v-fri"
+.Pp
+will display the last Friday of the month:
+.Pp
+.Dl "Fri Aug 29 04:31:11 BST 1997"
+.Pp
+where it is currently
+.Li "Mon Aug 4 04:31:11 BST 1997" .
+.Pp
+The command:
+.Pp
+.Dl "date 0613162785"
+.Pp
+sets the date to
+.Dq Li "June 13, 1985, 4:27 PM" .
+.Pp
+.Dl "date ""+%m%d%H%M%Y.%S"""
+.Pp
+may be used on one machine to print out the date
+suitable for setting on another.
+.Pp
+The command:
+.Pp
+.Dl "date 1432"
+.Pp
+sets the time to
+.Li "2:32 PM" ,
+without modifying the date.
+.Pp
+Finally the command:
+.Pp
+.Dl "date -j -f ""%a %b %d %T %Z %Y"" ""`date`"" ""+%s"""
+.Pp
+can be used to parse the output from
+.Nm
+and express it in Epoch time.
+.Sh DIAGNOSTICS
+Occasionally, when
+.Xr timed 8
+synchronizes the time on many hosts, the setting of a new time value may
+require more than a few seconds.
+On these occasions,
+.Nm
+prints:
+.Ql Network time being set .
+The message
+.Ql Communication error with timed
+occurs when the communication
+between
+.Nm
+and
+.Xr timed 8
+fails.
+.Sh LEGACY SYNOPSIS
+As above, except for the second line, which is:
+.Pp
+.Nm
+.Op Fl jnu
+.Sm off
+.Op Oo Oo Oo Oo Ar cc Oc Ar yy Oc Ar mm Oc Ar dd Oc Ar HH
+.Ar MM Op Ar .ss
+.Sm on
+.Sh LEGACY DIAGNOSTICS
+When invoked in legacy mode, the following exit values are returned:
+.Bl -tag -width X -compact
+.It 0
+The date was written successfully
+.It 1
+Unable to set the date
+.It 2
+Able to set the local date, but unable to set it globally
+.El
+.Pp
+For more information about legacy mode, see
+.Xr compat 5 .
+.Sh SEE ALSO
+.Xr locale 1 ,
+.Xr gettimeofday 2 ,
+.Xr getutxent 3 ,
+.Xr strftime 3 ,
+.Xr strptime 3 ,
+.Xr timed 8
+.Rs
+.%T "TSP: The Time Synchronization Protocol for UNIX 4.3BSD"
+.%A R. Gusella
+.%A S. Zatti
+.Re
+.Sh STANDARDS
+The
+.Nm
+utility is expected to be compatible with
+.St -p1003.2 .
+The
+.Fl d , f , j , n , r , t ,
+and
+.Fl v
+options are all extensions to the standard.
+.Sh HISTORY
+A
+.Nm
+command appeared in
+.At v1 .
diff --git a/shell_cmds/date/date.c b/shell_cmds/date/date.c
new file mode 100644
index 0000000..a45e110
--- /dev/null
+++ b/shell_cmds/date/date.c
@@ -0,0 +1,365 @@
+/*-
+ * Copyright (c) 1985, 1987, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char const copyright[] =
+"@(#) Copyright (c) 1985, 1987, 1988, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)date.c 8.2 (Berkeley) 4/28/95";
+#endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <utmpx.h>
+
+#ifdef __APPLE__
+#include <get_compat.h>
+#else
+#define COMPAT_MODE(a,b) (1)
+#endif /* __APPLE__ */
+
+#include "extern.h"
+#include "vary.h"
+
+#ifndef TM_YEAR_BASE
+#define TM_YEAR_BASE 1900
+#endif
+
+#ifdef __APPLE__
+#define st_mtim st_mtimespec
+#endif
+
+static time_t tval;
+int retval;
+static int unix2003_std; /* to determine legacy vs std mode */
+
+static void setthetime(const char *, const char *, int, int);
+static void badformat(void);
+static void usage(void);
+
+static const char *rfc2822_format = "%a, %d %b %Y %T %z";
+
+int
+main(int argc, char *argv[])
+{
+ struct timezone tz;
+ int ch, rflag;
+ int jflag, nflag, Rflag;
+ const char *format;
+ char buf[1024];
+ char *endptr, *fmt;
+ char *tmp;
+ int set_timezone;
+ struct vary *v;
+ const struct vary *badv;
+ struct tm lt;
+ struct stat sb;
+
+ unix2003_std = COMPAT_MODE("bin/date", "unix2003"); /* Determine the STD */
+
+ v = NULL;
+ fmt = NULL;
+ (void) setlocale(LC_TIME, "");
+ tz.tz_dsttime = tz.tz_minuteswest = 0;
+ rflag = 0;
+ jflag = nflag = Rflag = 0;
+ set_timezone = 0;
+ while ((ch = getopt(argc, argv, "d:f:jnRr:t:uv:")) != -1)
+ switch((char)ch) {
+ case 'd': /* daylight savings time */
+ tz.tz_dsttime = strtol(optarg, &endptr, 10) ? 1 : 0;
+ if (endptr == optarg || *endptr != '\0')
+ usage();
+ set_timezone = 1;
+ break;
+ case 'f':
+ fmt = optarg;
+ break;
+ case 'j':
+ jflag = 1; /* don't set time */
+ break;
+ case 'n': /* don't set network */
+ nflag = 1;
+ break;
+ case 'R': /* RFC 2822 datetime format */
+ Rflag = 1;
+ break;
+ case 'r': /* user specified seconds */
+ rflag = 1;
+ tval = strtoq(optarg, &tmp, 0);
+ if (*tmp != 0) {
+ if (stat(optarg, &sb) == 0)
+ tval = sb.st_mtim.tv_sec;
+ else
+ usage();
+ }
+ break;
+ case 't': /* minutes west of UTC */
+ /* error check; don't allow "PST" */
+ tz.tz_minuteswest = strtol(optarg, &endptr, 10);
+ if (endptr == optarg || *endptr != '\0')
+ usage();
+ set_timezone = 1;
+ break;
+ case 'u': /* do everything in UTC */
+ (void)setenv("TZ", "UTC0", 1);
+ break;
+ case 'v':
+ v = vary_append(v, optarg);
+ break;
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ /*
+ * If -d or -t, set the timezone or daylight savings time; this
+ * doesn't belong here; the kernel should not know about either.
+ */
+ if (set_timezone && settimeofday(NULL, &tz) != 0)
+ err(1, "settimeofday (timezone)");
+
+ if (!rflag && time(&tval) == -1)
+ err(1, "time");
+
+ format = "%+";
+
+ if (Rflag)
+ format = rfc2822_format;
+
+ /* allow the operands in any order */
+ if (*argv && **argv == '+') {
+ format = *argv + 1;
+ ++argv;
+ }
+
+ if (*argv) {
+ setthetime(fmt, *argv, jflag, nflag);
+ ++argv;
+ } else if (fmt != NULL)
+ usage();
+
+ if (*argv && **argv == '+')
+ format = *argv + 1;
+
+#ifdef __APPLE__
+ /* 7999711 */
+ struct tm *ltp = localtime(&tval);
+ if (ltp == NULL) {
+ err(1, "localtime");
+ }
+ lt = *ltp;
+#else
+ lt = *localtime(&tval);
+#endif
+ badv = vary_apply(v, &lt);
+ if (badv) {
+ fprintf(stderr, "%s: Cannot apply date adjustment\n",
+ badv->arg);
+ vary_destroy(v);
+ usage();
+ }
+ vary_destroy(v);
+
+ if (format == rfc2822_format)
+ /*
+ * When using RFC 2822 datetime format, don't honor the
+ * locale.
+ */
+ setlocale(LC_TIME, "C");
+
+ (void)strftime(buf, sizeof(buf), format, &lt);
+ (void)printf("%s\n", buf);
+ if (fflush(stdout))
+ err(1, "stdout");
+ /*
+ * If date/time could not be set/notified in the other hosts as
+ * determined by netsetval(), a return value 2 is set, which is
+ * only propagated back to shell in legacy mode.
+ */
+ if (unix2003_std)
+ exit(0);
+ exit(retval);
+}
+
+#define ATOI2(s) ((s) += 2, ((s)[-2] - '0') * 10 + ((s)[-1] - '0'))
+#define ATOI2_OFFSET(s, o) (((s)[o] - '0') * 10 + ((s)[o + 1] - '0'))
+
+static void
+setthetime(const char *fmt, const char *p, int jflag, int nflag)
+{
+ struct utmpx utx;
+ struct tm *lt;
+ struct timeval tv;
+ const char *dot, *t;
+ int century;
+ size_t length;
+
+ lt = localtime(&tval);
+ lt->tm_isdst = -1; /* divine correct DST */
+
+ if (fmt != NULL) {
+ t = strptime(p, fmt, lt);
+ if (t == NULL) {
+ fprintf(stderr, "Failed conversion of ``%s''"
+ " using format ``%s''\n", p, fmt);
+ badformat();
+ } else if (*t != '\0')
+ fprintf(stderr, "Warning: Ignoring %ld extraneous"
+ " characters in date string (%s)\n",
+ (long) strlen(t), t);
+ } else {
+ for (t = p, dot = NULL; *t; ++t) {
+ if (isdigit(*t))
+ continue;
+ if (*t == '.' && dot == NULL) {
+ dot = t;
+ continue;
+ }
+ badformat();
+ }
+
+ if (dot != NULL) { /* .ss */
+ dot++; /* *dot++ = '\0'; */
+ if (strlen(dot) != 2)
+ badformat();
+ lt->tm_sec = ATOI2(dot);
+ if (lt->tm_sec > 61)
+ badformat();
+ } else
+ lt->tm_sec = 0;
+
+ century = 0;
+ /* if p has a ".ss" field then let's pretend it's not there */
+ switch (length = strlen(p) - ((dot != NULL) ? 3 : 0)) {
+ case 12: /* cc */
+ lt->tm_year = (unix2003_std ? ATOI2_OFFSET(p, length - 4) : ATOI2(p)) * 100 - TM_YEAR_BASE;
+ century = 1;
+ /* FALLTHROUGH */
+ case 10: /* yy */
+ if (century)
+ lt->tm_year += (unix2003_std ? ATOI2_OFFSET(p, length - 2) : ATOI2(p));
+ else {
+ lt->tm_year = (unix2003_std ? ATOI2_OFFSET(p, length - 2) : ATOI2(p));
+ if (lt->tm_year < 69) /* hack for 2000 ;-} */
+ lt->tm_year += 2000 - TM_YEAR_BASE;
+ else
+ lt->tm_year += 1900 - TM_YEAR_BASE;
+ }
+ /* FALLTHROUGH */
+ case 8: /* mm */
+ lt->tm_mon = ATOI2(p);
+ if (lt->tm_mon > 12)
+ badformat();
+ --lt->tm_mon; /* time struct is 0 - 11 */
+ /* FALLTHROUGH */
+ case 6: /* dd */
+ lt->tm_mday = ATOI2(p);
+ if (lt->tm_mday > 31)
+ badformat();
+ /* FALLTHROUGH */
+ case 4: /* HH */
+ lt->tm_hour = ATOI2(p);
+ if (lt->tm_hour > 23)
+ badformat();
+ /* FALLTHROUGH */
+ case 2: /* MM */
+ lt->tm_min = ATOI2(p);
+ if (lt->tm_min > 59)
+ badformat();
+ break;
+ default:
+ badformat();
+ }
+ }
+
+ /* convert broken-down time to GMT clock time */
+ if ((tval = mktime(lt)) == -1)
+ errx(1, "nonexistent time");
+
+ if (!jflag) {
+ /* set the time */
+ if (nflag || netsettime(tval)) {
+ utx.ut_type = OLD_TIME;
+ (void)gettimeofday(&utx.ut_tv, NULL);
+ pututxline(&utx);
+ tv.tv_sec = tval;
+ tv.tv_usec = 0;
+ if (settimeofday(&tv, NULL) != 0)
+ err(1, "settimeofday (timeval)");
+ utx.ut_type = NEW_TIME;
+ (void)gettimeofday(&utx.ut_tv, NULL);
+ pututxline(&utx);
+ }
+
+ if ((p = getlogin()) == NULL)
+ p = "???";
+ syslog(LOG_AUTH | LOG_NOTICE, "date set by %s", p);
+ }
+}
+
+static void
+badformat(void)
+{
+ warnx("illegal time format");
+ usage();
+}
+
+static void
+usage(void)
+{
+ (void)fprintf(stderr, "%s\n%s\n",
+ "usage: date [-jnRu] [-d dst] [-r seconds] [-t west] "
+ "[-v[+|-]val[ymwdHMS]] ... ",
+ unix2003_std ?
+ " "
+ "[-f fmt date | [[[mm]dd]HH]MM[[cc]yy][.ss]] [+format]" :
+ " "
+ "[-f fmt date | [[[[[cc]yy]mm]dd]HH]MM[.ss]] [+format]");
+ exit(1);
+}
diff --git a/shell_cmds/date/date.plist.part b/shell_cmds/date/date.plist.part
new file mode 100644
index 0000000..da97d84
--- /dev/null
+++ b/shell_cmds/date/date.plist.part
@@ -0,0 +1,22 @@
+ <dict>
+ <key>OpenSourceProject</key>
+ <string>date</string>
+ <key>OpenSourceVersion</key>
+ <string>2015-05-07</string>
+ <key>OpenSourceWebsiteURL</key>
+ <string>http://svnweb.freebsd.org/base/head/bin/date/</string>
+ <key>OpenSourceSCM</key>
+ <string>svn co http://svn.freebsd.org/base/head/bin/date/</string>
+ <key>OpenSourceImportDate</key>
+ <string>2015-11-06</string>
+ <key>OpenSourceModifications</key>
+ <array>
+ <string>date.1: discuss conformance changes</string>
+ <string>date.1: remove bogus utmpx path</string>
+ <string>date.c: conformance changes for date format and exit value</string>
+ <string>date.c: fix crash on invalid dates (7999711)</string>
+ <string>date.c: st_mtim compatibility</string>
+ </array>
+ <key>OpenSourceLicense</key>
+ <string>bsd</string>
+ </dict>
diff --git a/shell_cmds/date/extern.h b/shell_cmds/date/extern.h
new file mode 100644
index 0000000..91aeab2
--- /dev/null
+++ b/shell_cmds/date/extern.h
@@ -0,0 +1,35 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)extern.h 8.1 (Berkeley) 5/31/93
+ * $FreeBSD$
+ */
+
+extern int retval;
+
+int netsettime(time_t);
diff --git a/shell_cmds/date/netdate.c b/shell_cmds/date/netdate.c
new file mode 100644
index 0000000..e506e6d
--- /dev/null
+++ b/shell_cmds/date/netdate.c
@@ -0,0 +1,181 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)netdate.c 8.1 (Berkeley) 5/31/93";
+#endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <netdb.h>
+#define TSPTYPES
+#include <protocols/timed.h>
+
+#include <err.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "extern.h"
+
+#define WAITACK 2 /* seconds */
+#define WAITDATEACK 5 /* seconds */
+
+/*
+ * Set the date in the machines controlled by timedaemons by communicating the
+ * new date to the local timedaemon. If the timedaemon is in the master state,
+ * it performs the correction on all slaves. If it is in the slave state, it
+ * notifies the master that a correction is needed.
+ * Returns 0 on success. Returns > 0 on failure, setting retval to 2;
+ */
+int
+netsettime(time_t tval)
+{
+ struct timeval tout;
+ struct servent *sp;
+ struct tsp msg;
+ struct sockaddr_in lsin, dest, from;
+ fd_set ready;
+ long waittime;
+ int s, port, timed_ack, found, lerr;
+ socklen_t length;
+ char hostname[MAXHOSTNAMELEN];
+
+ if ((sp = getservbyname("timed", "udp")) == NULL) {
+ warnx("timed/udp: unknown service");
+ return (retval = 2);
+ }
+
+ dest.sin_port = sp->s_port;
+ dest.sin_family = AF_INET;
+ dest.sin_addr.s_addr = htonl((u_long)INADDR_ANY);
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ if (errno != EAFNOSUPPORT)
+ warn("timed");
+ return (retval = 2);
+ }
+
+ memset(&lsin, 0, sizeof(lsin));
+ lsin.sin_family = AF_INET;
+ for (port = IPPORT_RESERVED - 1; port > IPPORT_RESERVED / 2; port--) {
+ lsin.sin_port = htons((u_short)port);
+ if (bind(s, (struct sockaddr *)&lsin, sizeof(lsin)) >= 0)
+ break;
+ if (errno == EADDRINUSE)
+ continue;
+ if (errno != EADDRNOTAVAIL)
+ warn("bind");
+ goto bad;
+ }
+ if (port == IPPORT_RESERVED / 2) {
+ warnx("all ports in use");
+ goto bad;
+ }
+ memset(&msg, 0, sizeof(msg));
+ msg.tsp_type = TSP_SETDATE;
+ msg.tsp_vers = TSPVERSION;
+ if (gethostname(hostname, sizeof(hostname))) {
+ warn("gethostname");
+ goto bad;
+ }
+ (void)strlcpy(msg.tsp_name, hostname, sizeof(msg.tsp_name));
+ msg.tsp_seq = htons((u_short)0);
+ msg.tsp_time.tv_sec = htonl((u_long)tval);
+ msg.tsp_time.tv_usec = htonl((u_long)0);
+ length = sizeof(struct sockaddr_in);
+ if (connect(s, (struct sockaddr *)&dest, length) < 0) {
+ warn("connect");
+ goto bad;
+ }
+ if (send(s, (char *)&msg, sizeof(struct tsp), 0) < 0) {
+ if (errno != ECONNREFUSED)
+ warn("send");
+ goto bad;
+ }
+
+ timed_ack = -1;
+ waittime = WAITACK;
+loop:
+ tout.tv_sec = waittime;
+ tout.tv_usec = 0;
+
+ FD_ZERO(&ready);
+ FD_SET(s, &ready);
+ found = select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, &tout);
+
+ length = sizeof(lerr);
+ if (!getsockopt(s,
+ SOL_SOCKET, SO_ERROR, (char *)&lerr, &length) && lerr) {
+ if (lerr != ECONNREFUSED)
+ warnc(lerr, "send (delayed error)");
+ goto bad;
+ }
+
+ if (found > 0 && FD_ISSET(s, &ready)) {
+ length = sizeof(struct sockaddr_in);
+ if (recvfrom(s, &msg, sizeof(struct tsp), 0,
+ (struct sockaddr *)&from, &length) < 0) {
+ if (errno != ECONNREFUSED)
+ warn("recvfrom");
+ goto bad;
+ }
+ msg.tsp_seq = ntohs(msg.tsp_seq);
+ msg.tsp_time.tv_sec = ntohl(msg.tsp_time.tv_sec);
+ msg.tsp_time.tv_usec = ntohl(msg.tsp_time.tv_usec);
+ switch (msg.tsp_type) {
+ case TSP_ACK:
+ timed_ack = TSP_ACK;
+ waittime = WAITDATEACK;
+ goto loop;
+ case TSP_DATEACK:
+ (void)close(s);
+ return (0);
+ default:
+ warnx("wrong ack received from timed: %s",
+ tsptype[msg.tsp_type]);
+ timed_ack = -1;
+ break;
+ }
+ }
+ if (timed_ack == -1)
+ warnx("can't reach time daemon, time set locally");
+
+bad:
+ (void)close(s);
+ return (retval = 2);
+}
diff --git a/shell_cmds/date/vary.c b/shell_cmds/date/vary.c
new file mode 100644
index 0000000..5f01231
--- /dev/null
+++ b/shell_cmds/date/vary.c
@@ -0,0 +1,506 @@
+/*-
+ * Copyright (c) 1997 Brian Somers <brian@Awfulhak.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <err.h>
+#include <time.h>
+#include <string.h>
+#include <stdlib.h>
+#include "vary.h"
+
+struct trans {
+ int val;
+ const char *str;
+};
+
+static struct trans trans_mon[] = {
+ { 1, "january" }, { 2, "february" }, { 3, "march" }, { 4, "april" },
+ { 5, "may"}, { 6, "june" }, { 7, "july" }, { 8, "august" },
+ { 9, "september" }, { 10, "october" }, { 11, "november" }, { 12, "december" },
+ { -1, NULL }
+};
+
+static struct trans trans_wday[] = {
+ { 0, "sunday" }, { 1, "monday" }, { 2, "tuesday" }, { 3, "wednesday" },
+ { 4, "thursday" }, { 5, "friday" }, { 6, "saturday" },
+ { -1, NULL }
+};
+
+static char digits[] = "0123456789";
+static int adjhour(struct tm *, char, int, int);
+
+static int
+domktime(struct tm *t, char type)
+{
+ time_t ret;
+
+ while ((ret = mktime(t)) == -1 && t->tm_year > 68 && t->tm_year < 138)
+ /* While mktime() fails, adjust by an hour */
+ adjhour(t, type == '-' ? type : '+', 1, 0);
+
+ return ret;
+}
+
+static int
+trans(const struct trans t[], const char *arg)
+{
+ int f;
+
+ for (f = 0; t[f].val != -1; f++)
+ if (!strncasecmp(t[f].str, arg, 3) ||
+ !strncasecmp(t[f].str, arg, strlen(t[f].str)))
+ return t[f].val;
+
+ return -1;
+}
+
+struct vary *
+vary_append(struct vary *v, char *arg)
+{
+ struct vary *result, **nextp;
+
+ if (v) {
+ result = v;
+ while (v->next)
+ v = v->next;
+ nextp = &v->next;
+ } else
+ nextp = &result;
+
+ if ((*nextp = (struct vary *)malloc(sizeof(struct vary))) == NULL)
+ err(1, "malloc");
+ (*nextp)->arg = arg;
+ (*nextp)->next = NULL;
+ return result;
+}
+
+static int mdays[12] = { 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+
+static int
+daysinmonth(const struct tm *t)
+{
+ int year;
+
+ year = t->tm_year + 1900;
+
+ if (t->tm_mon == 1)
+ if (!(year % 400))
+ return 29;
+ else if (!(year % 100))
+ return 28;
+ else if (!(year % 4))
+ return 29;
+ else
+ return 28;
+ else if (t->tm_mon >= 0 && t->tm_mon < 12)
+ return mdays[t->tm_mon];
+
+ return 0;
+}
+
+
+static int
+adjyear(struct tm *t, char type, int val, int mk)
+{
+ switch (type) {
+ case '+':
+ t->tm_year += val;
+ break;
+ case '-':
+ t->tm_year -= val;
+ break;
+ default:
+ t->tm_year = val;
+ if (t->tm_year < 69)
+ t->tm_year += 100; /* as per date.c */
+ else if (t->tm_year > 1900)
+ t->tm_year -= 1900; /* struct tm holds years since 1900 */
+ break;
+ }
+ return !mk || domktime(t, type) != -1;
+}
+
+static int
+adjmon(struct tm *t, char type, int val, int istext, int mk)
+{
+ int lmdays;
+
+ if (val < 0)
+ return 0;
+
+ switch (type) {
+ case '+':
+ if (istext) {
+ if (val <= t->tm_mon)
+ val += 11 - t->tm_mon; /* early next year */
+ else
+ val -= t->tm_mon + 1; /* later this year */
+ }
+ if (val) {
+ if (!adjyear(t, '+', (t->tm_mon + val) / 12, 0))
+ return 0;
+ val %= 12;
+ t->tm_mon += val;
+ if (t->tm_mon > 11)
+ t->tm_mon -= 12;
+ }
+ break;
+
+ case '-':
+ if (istext) {
+ if (val-1 > t->tm_mon)
+ val = 13 - val + t->tm_mon; /* later last year */
+ else
+ val = t->tm_mon - val + 1; /* early this year */
+ }
+ if (val) {
+ if (!adjyear(t, '-', val / 12, 0))
+ return 0;
+ val %= 12;
+ if (val > t->tm_mon) {
+ if (!adjyear(t, '-', 1, 0))
+ return 0;
+ val -= 12;
+ }
+ t->tm_mon -= val;
+ }
+ break;
+
+ default:
+ if (val > 12 || val < 1)
+ return 0;
+ t->tm_mon = --val;
+ }
+
+ /* e.g., -v-1m on March, 31 is the last day of February in common sense */
+ lmdays = daysinmonth(t);
+ if (t->tm_mday > lmdays)
+ t->tm_mday = lmdays;
+
+ return !mk || domktime(t, type) != -1;
+}
+
+static int
+adjday(struct tm *t, char type, int val, int mk)
+{
+ int lmdays;
+
+ switch (type) {
+ case '+':
+ while (val) {
+ lmdays = daysinmonth(t);
+ if (val > lmdays - t->tm_mday) {
+ val -= lmdays - t->tm_mday + 1;
+ t->tm_mday = 1;
+ if (!adjmon(t, '+', 1, 0, 0))
+ return 0;
+ } else {
+ t->tm_mday += val;
+ val = 0;
+ }
+ }
+ break;
+ case '-':
+ while (val)
+ if (val >= t->tm_mday) {
+ val -= t->tm_mday;
+ t->tm_mday = 1;
+ if (!adjmon(t, '-', 1, 0, 0))
+ return 0;
+ t->tm_mday = daysinmonth(t);
+ } else {
+ t->tm_mday -= val;
+ val = 0;
+ }
+ break;
+ default:
+ if (val > 0 && val <= daysinmonth(t))
+ t->tm_mday = val;
+ else
+ return 0;
+ break;
+ }
+
+ return !mk || domktime(t, type) != -1;
+}
+
+static int
+adjwday(struct tm *t, char type, int val, int istext, int mk)
+{
+ if (val < 0)
+ return 0;
+
+ switch (type) {
+ case '+':
+ if (istext)
+ if (val < t->tm_wday)
+ val = 7 - t->tm_wday + val; /* early next week */
+ else
+ val -= t->tm_wday; /* later this week */
+ else
+ val *= 7; /* "-v+5w" == "5 weeks in the future" */
+ return !val || adjday(t, '+', val, mk);
+ case '-':
+ if (istext) {
+ if (val > t->tm_wday)
+ val = 7 - val + t->tm_wday; /* later last week */
+ else
+ val = t->tm_wday - val; /* early this week */
+ } else
+ val *= 7; /* "-v-5w" == "5 weeks ago" */
+ return !val || adjday(t, '-', val, mk);
+ default:
+ if (val < t->tm_wday)
+ return adjday(t, '-', t->tm_wday - val, mk);
+ else if (val > 6)
+ return 0;
+ else if (val > t->tm_wday)
+ return adjday(t, '+', val - t->tm_wday, mk);
+ }
+ return 1;
+}
+
+static int
+adjhour(struct tm *t, char type, int val, int mk)
+{
+ if (val < 0)
+ return 0;
+
+ switch (type) {
+ case '+':
+ if (val) {
+ int days;
+
+ days = (t->tm_hour + val) / 24;
+ val %= 24;
+ t->tm_hour += val;
+ t->tm_hour %= 24;
+ if (!adjday(t, '+', days, 0))
+ return 0;
+ }
+ break;
+
+ case '-':
+ if (val) {
+ int days;
+
+ days = val / 24;
+ val %= 24;
+ if (val > t->tm_hour) {
+ days++;
+ val -= 24;
+ }
+ t->tm_hour -= val;
+ if (!adjday(t, '-', days, 0))
+ return 0;
+ }
+ break;
+
+ default:
+ if (val > 23)
+ return 0;
+ t->tm_hour = val;
+ }
+
+ return !mk || domktime(t, type) != -1;
+}
+
+static int
+adjmin(struct tm *t, char type, int val, int mk)
+{
+ if (val < 0)
+ return 0;
+
+ switch (type) {
+ case '+':
+ if (val) {
+ if (!adjhour(t, '+', (t->tm_min + val) / 60, 0))
+ return 0;
+ val %= 60;
+ t->tm_min += val;
+ if (t->tm_min > 59)
+ t->tm_min -= 60;
+ }
+ break;
+
+ case '-':
+ if (val) {
+ if (!adjhour(t, '-', val / 60, 0))
+ return 0;
+ val %= 60;
+ if (val > t->tm_min) {
+ if (!adjhour(t, '-', 1, 0))
+ return 0;
+ val -= 60;
+ }
+ t->tm_min -= val;
+ }
+ break;
+
+ default:
+ if (val > 59)
+ return 0;
+ t->tm_min = val;
+ }
+
+ return !mk || domktime(t, type) != -1;
+}
+
+static int
+adjsec(struct tm *t, char type, int val, int mk)
+{
+ if (val < 0)
+ return 0;
+
+ switch (type) {
+ case '+':
+ if (val) {
+ if (!adjmin(t, '+', (t->tm_sec + val) / 60, 0))
+ return 0;
+ val %= 60;
+ t->tm_sec += val;
+ if (t->tm_sec > 59)
+ t->tm_sec -= 60;
+ }
+ break;
+
+ case '-':
+ if (val) {
+ if (!adjmin(t, '-', val / 60, 0))
+ return 0;
+ val %= 60;
+ if (val > t->tm_sec) {
+ if (!adjmin(t, '-', 1, 0))
+ return 0;
+ val -= 60;
+ }
+ t->tm_sec -= val;
+ }
+ break;
+
+ default:
+ if (val > 59)
+ return 0;
+ t->tm_sec = val;
+ }
+
+ return !mk || domktime(t, type) != -1;
+}
+
+const struct vary *
+vary_apply(const struct vary *v, struct tm *t)
+{
+ char type;
+ char which;
+ char *arg;
+ size_t len;
+ int val;
+
+ for (; v; v = v->next) {
+ type = *v->arg;
+ arg = v->arg;
+ if (type == '+' || type == '-')
+ arg++;
+ else
+ type = '\0';
+ len = strlen(arg);
+ if (len < 2)
+ return v;
+
+ if (type == '\0')
+ t->tm_isdst = -1;
+
+ if (strspn(arg, digits) != len-1) {
+ val = trans(trans_wday, arg);
+ if (val != -1) {
+ if (!adjwday(t, type, val, 1, 1))
+ return v;
+ } else {
+ val = trans(trans_mon, arg);
+ if (val != -1) {
+ if (!adjmon(t, type, val, 1, 1))
+ return v;
+ } else
+ return v;
+ }
+ } else {
+ val = atoi(arg);
+ which = arg[len-1];
+
+ switch (which) {
+ case 'S':
+ if (!adjsec(t, type, val, 1))
+ return v;
+ break;
+ case 'M':
+ if (!adjmin(t, type, val, 1))
+ return v;
+ break;
+ case 'H':
+ if (!adjhour(t, type, val, 1))
+ return v;
+ break;
+ case 'd':
+ t->tm_isdst = -1;
+ if (!adjday(t, type, val, 1))
+ return v;
+ break;
+ case 'w':
+ t->tm_isdst = -1;
+ if (!adjwday(t, type, val, 0, 1))
+ return v;
+ break;
+ case 'm':
+ t->tm_isdst = -1;
+ if (!adjmon(t, type, val, 0, 1))
+ return v;
+ break;
+ case 'y':
+ t->tm_isdst = -1;
+ if (!adjyear(t, type, val, 1))
+ return v;
+ break;
+ default:
+ return v;
+ }
+ }
+ }
+ return 0;
+}
+
+void
+vary_destroy(struct vary *v)
+{
+ struct vary *n;
+
+ while (v) {
+ n = v->next;
+ free(v);
+ v = n;
+ }
+}
diff --git a/shell_cmds/date/vary.h b/shell_cmds/date/vary.h
new file mode 100644
index 0000000..b39306a
--- /dev/null
+++ b/shell_cmds/date/vary.h
@@ -0,0 +1,36 @@
+/*-
+ * Copyright (c) 1997 Brian Somers <brian@Awfulhak.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+struct vary {
+ char *arg;
+ struct vary *next;
+};
+
+extern struct vary *vary_append(struct vary *v, char *arg);
+extern const struct vary *vary_apply(const struct vary *v, struct tm *t);
+extern void vary_destroy(struct vary *v);
diff --git a/shell_cmds/dirname/dirname.c b/shell_cmds/dirname/dirname.c
new file mode 100644
index 0000000..11b19b2
--- /dev/null
+++ b/shell_cmds/dirname/dirname.c
@@ -0,0 +1,84 @@
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1991, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static const char sccsid[] = "@(#)dirname.c 8.4 (Berkeley) 5/4/95";
+#endif /* not lint */
+#include <sys/cdefs.h>
+__RCSID("$FreeBSD: src/usr.bin/dirname/dirname.c,v 1.11 2002/07/28 15:43:56 dwmalone Exp $");
+
+#include <err.h>
+#include <libgen.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+void usage(void);
+
+int
+main(int argc, char **argv)
+{
+ char *p;
+ int ch;
+
+ while ((ch = getopt(argc, argv, "")) != -1)
+ switch(ch) {
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc != 1)
+ usage();
+
+ if ((p = dirname(*argv)) == NULL)
+ err(1, "%s", *argv);
+ (void)printf("%s\n", p);
+ exit(0);
+}
+
+void
+usage(void)
+{
+
+ (void)fprintf(stderr, "usage: dirname path\n");
+ exit(1);
+}
diff --git a/shell_cmds/echo/echo.1 b/shell_cmds/echo/echo.1
new file mode 100644
index 0000000..87bcc34
--- /dev/null
+++ b/shell_cmds/echo/echo.1
@@ -0,0 +1,101 @@
+.\"-
+.\" Copyright (c) 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)echo.1 8.1 (Berkeley) 7/22/93
+.\" $FreeBSD: src/bin/echo/echo.1,v 1.19 2005/01/16 16:41:56 ru Exp $
+.\"
+.Dd April 12, 2003
+.Dt ECHO 1
+.Os
+.Sh NAME
+.Nm echo
+.Nd write arguments to the standard output
+.Sh SYNOPSIS
+.Nm
+.Op Fl n
+.Op Ar string ...
+.Sh DESCRIPTION
+The
+.Nm
+utility writes any specified operands, separated by single blank
+.Pq Ql "\ "
+characters and followed by a newline
+.Pq Ql \en
+character, to the standard
+output.
+.Pp
+The following option is available:
+.Bl -tag -width flag
+.It Fl n
+Do not print the trailing newline character.
+This may also be achieved by appending
+.Ql \ec
+to the end of the string, as is done
+by iBCS2 compatible systems.
+Note that this option as well as the effect of
+.Ql \ec
+are implementation-defined in
+.St -p1003.1-2001
+as amended by Cor.\& 1-2002.
+Applications aiming for maximum
+portability are strongly encouraged to use
+.Xr printf 1
+to suppress the newline character.
+.El
+.Pp
+Some shells may provide a builtin
+.Nm
+command which is similar or identical to this utility.
+.\" 4874742
+Most notably, the builtin
+.Nm
+in
+.Xr sh 1
+does not accept the
+.Fl n
+option.
+.\" 4874742
+Consult the
+.Xr builtin 1
+manual page.
+.Sh EXIT STATUS
+.Ex -std
+.Sh SEE ALSO
+.Xr builtin 1 ,
+.Xr csh 1 ,
+.Xr printf 1 ,
+.Xr sh 1
+.Sh STANDARDS
+The
+.Nm
+utility conforms to
+.St -p1003.1-2001
+as amended by Cor.\& 1-2002.
diff --git a/shell_cmds/echo/echo.c b/shell_cmds/echo/echo.c
new file mode 100644
index 0000000..a994e6d
--- /dev/null
+++ b/shell_cmds/echo/echo.c
@@ -0,0 +1,182 @@
+/*-
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static char const copyright[] =
+"@(#) Copyright (c) 1989, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)echo.c 8.1 (Berkeley) 5/31/93";
+#endif /* not lint */
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/bin/echo/echo.c,v 1.18 2005/01/10 08:39:22 imp Exp $");
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+
+static void
+flush_and_exit(void)
+{
+ if (fflush(stdout) != 0)
+ err(1, "fflush");
+ exit(0);
+}
+
+static char *
+print_one_char(char *cur, int posix, int *bytes_len_out)
+{
+ char *next;
+ wchar_t wc;
+ int bytes_len = mbtowc(&wc, cur, MB_CUR_MAX);
+ if (bytes_len <= 0) {
+ putchar(*cur);
+ bytes_len = 1;
+ goto out;
+ }
+
+ /* If this is not an escape sequence, just print the character */
+ if (wc != '\\') {
+ putwchar(wc);
+ goto out;
+ }
+
+ next = cur + bytes_len;
+
+ if (!posix) {
+ /* In non-POSIX mode, the only valid escape sequence is \c */
+ if (*next == 'c') {
+ flush_and_exit();
+ } else {
+ putchar(wc);
+ goto out;
+ }
+ } else {
+ cur = next;
+ bytes_len = 1;
+ }
+
+ switch (*cur) {
+ case 'a':
+ putchar('\a');
+ goto out;
+
+ case 'b':
+ putchar('\b');
+ goto out;
+
+ case 'c':
+ flush_and_exit();
+
+ case 'f':
+ putchar('\f');
+ goto out;
+
+ case 'n':
+ putchar('\n');
+ goto out;
+
+ case 'r':
+ putchar('\r');
+ goto out;
+
+ case 't':
+ putchar('\t');
+ goto out;
+
+ case 'v':
+ putchar('\v');
+ goto out;
+
+ case '\\':
+ putchar('\\');
+ goto out;
+
+ case '0': {
+ int j = 0, num = 0;
+ while ((*++cur >= '0' && *cur <= '7') &&
+ j++ < 3) {
+ num <<= 3;
+ num |= (*cur - '0');
+ }
+ putchar(num);
+ --cur;
+ goto out;
+ }
+ default:
+ --cur;
+ putchar(*cur);
+ goto out;
+ }
+
+ out:
+ if (bytes_len_out)
+ *bytes_len_out = bytes_len;
+ return cur;
+}
+
+int
+main(int argc, char *argv[])
+{
+ int nflag = 0;
+ int posix = (getenv("POSIXLY_CORRECT") != NULL || getenv("POSIX_PEDANTIC") != NULL);
+
+ if (!posix && argv[1] && strcmp(argv[1], "-n") == 0)
+ nflag = 1;
+
+ for (int i = 0; i < argc; i++) {
+ /* argv[0] == progname */
+ int ignore_arg = (i == 0 || (i == 1 && nflag == 1));
+ int last_arg = (i == (argc - 1));
+ if (!ignore_arg) {
+ char *cur = argv[i];
+ size_t arg_len = strlen(cur);
+ int bytes_len = 0;
+
+ for (const char *end = cur + arg_len; cur < end; cur += bytes_len) {
+ cur = print_one_char(cur, posix, &bytes_len);
+ }
+ }
+ if (last_arg && !nflag)
+ putchar('\n');
+ else if (!last_arg && !ignore_arg)
+ putchar(' ');
+
+ if (fflush(stdout) != 0)
+ err(1, "fflush");
+ }
+
+ return 0;
+}
diff --git a/shell_cmds/env/env.1 b/shell_cmds/env/env.1
new file mode 100644
index 0000000..101f4eb
--- /dev/null
+++ b/shell_cmds/env/env.1
@@ -0,0 +1,482 @@
+.\" Copyright (c) 1980, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" From @(#)printenv.1 8.1 (Berkeley) 6/6/93
+.\" From FreeBSD: src/usr.bin/printenv/printenv.1,v 1.17 2002/11/26 17:33:35 ru Exp
+.\" $FreeBSD$
+.\"
+.Dd April 17, 2008
+.Dt ENV 1
+.Os
+.Sh NAME
+.Nm env
+.Nd set environment and execute command, or print environment
+.Sh SYNOPSIS
+.Nm
+.Op Fl iv
+.Op Fl P Ar altpath
+.Op Fl S Ar string
+.Op Fl u Ar name
+.Op Ar name Ns = Ns Ar value ...
+.Op Ar utility Op Ar argument ...
+.Sh DESCRIPTION
+The
+.Nm
+utility executes another
+.Ar utility
+after modifying the environment as
+specified on the command line.
+Each
+.Ar name Ns = Ns Ar value
+option specifies the setting of an environment variable,
+.Ar name ,
+with a value of
+.Ar value .
+All such environment variables are set before the
+.Ar utility
+is executed.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl i
+Execute the
+.Ar utility
+with only those environment variables specified by
+.Ar name Ns = Ns Ar value
+options.
+The environment inherited
+by
+.Nm
+is ignored completely.
+.\" -P
+.It Fl P Ar altpath
+Search the set of directories as specified by
+.Ar altpath
+to locate the specified
+.Ar utility
+program, instead of using the value of the
+.Ev PATH
+environment variable.
+.\" -S
+.It Fl S Ar string
+Split apart the given
+.Ar string
+into multiple strings, and process each of the resulting strings
+as separate arguments to the
+.Nm
+utility.
+The
+.Fl S
+option recognizes some special character escape sequences and
+also supports environment-variable substitution, as described
+below.
+.\" -u
+.It Fl u Ar name
+If the environment variable
+.Ar name
+is in the environment, then remove it before processing the
+remaining options.
+This is similar to the
+.Ic unset
+command in
+.Xr sh 1 .
+The value for
+.Ar name
+must not include the
+.Ql =
+character.
+.\" -v
+.It Fl v
+Print verbose information for each step of processing done by the
+.Nm
+utility.
+Additional information will be printed if
+.Fl v
+is specified multiple times.
+.El
+.Pp
+The above options are only recognized when they are specified
+before any
+.Ar name Ns = Ns Ar value
+options.
+.Pp
+If no
+.Ar utility
+is specified,
+.Nm
+prints out the names and values
+of the variables in the environment, with one name/value pair per line.
+.\"
+.Ss Details of Fl S Ss (split-string) processing
+The processing of the
+.Fl S
+option will split the given
+.Ar string
+into separate arguments based on any space or <tab> characters found in the
+.Ar string .
+Each of those new arguments will then be treated as if it had been
+specified as a separate argument on the original
+.Nm
+command.
+.Pp
+Spaces and tabs may be embedded in one of those new arguments by using
+single
+.Pq Dq Li '
+or double
+.Pq Ql \&"
+quotes, or backslashes
+.Pq Ql \e .
+Single quotes will escape all non-single quote characters, up to
+the matching single quote.
+Double quotes will escape all non-double quote characters, up to
+the matching double quote.
+It is an error if the end of the
+.Ar string
+is reached before the matching quote character.
+.Pp
+If
+.Fl S
+would create a new argument that starts with the
+.Ql #
+character, then that argument and the remainder of the
+.Ar string
+will be ignored.
+The
+.Ql \e#
+sequence can be used when you want a new argument to start
+with a
+.Ql #
+character, without causing the remainder of the
+.Ar string
+to be skipped.
+.Pp
+While processing the
+.Ar string
+value,
+.Fl S
+processing will treat certain character combinations as escape
+sequences which represent some action to take.
+The character escape sequences are in backslash notation.
+The characters and their meanings are as follows:
+.Pp
+.Bl -tag -width indent -offset indent -compact
+.It Cm \ec
+Ignore the remaining characters in the
+.Ar string .
+This must not appear inside a double-quoted string.
+.It Cm \ef
+Replace with a <form-feed> character.
+.It Cm \en
+Replace with a <new-line> character.
+.It Cm \er
+Replace with a <carriage return> character.
+.It Cm \et
+Replace with a <tab> character.
+.It Cm \ev
+Replace with a <vertical tab> character.
+.It Cm \e#
+Replace with a
+.Ql #
+character.
+This would be useful when you need a
+.Ql #
+as the first character in one of the arguments created
+by splitting apart the given
+.Ar string .
+.It Cm \e$
+Replace with a
+.Ql $
+character.
+.It Cm \e_
+If this is found inside of a double-quoted string, then replace it
+with a single blank.
+If this is found outside of a quoted string, then treat this as the
+separator character between new arguments in the original
+.Ar string .
+.It Cm \e"
+Replace with a <double quote> character.
+.It Cm \e\'
+Replace with a <single quote> character.
+.It Cm \e\e
+Replace with a backslash character.
+.El
+.Pp
+The sequences for <single-quote> and backslash are the only sequences
+which are recognized inside of a single-quoted string.
+The other sequences have no special meaning inside a single-quoted
+string.
+All escape sequences are recognized inside of a double-quoted string.
+It is an error if a single
+.Ql \e
+character is followed by a character other than the ones listed above.
+.Pp
+The processing of
+.Fl S
+also supports substitution of values from environment variables.
+To do this, the name of the environment variable must be inside of
+.Ql ${} ,
+such as:
+.Li ${SOMEVAR} .
+The common shell syntax of
+.Li $SOMEVAR
+is not supported.
+All values substituted will be the values of the environment variables
+as they were when the
+.Nm
+utility was originally invoked.
+Those values will not be checked for any of the escape sequences as
+described above.
+And any settings of
+.Ar name Ns = Ns Ar value
+will not effect the values used for substitution in
+.Fl S
+processing.
+.Pp
+Also,
+.Fl S
+processing can not reference the value of the special parameters
+which are defined by most shells.
+For instance,
+.Fl S
+can not recognize special parameters such as:
+.Ql $* ,
+.Ql $@ ,
+.Ql $# ,
+.Ql $?
+or
+.Ql $$
+if they appear inside the given
+.Ar string .
+.\"
+.Ss Use in shell-scripts
+The
+.Nm
+utility is often used as the
+.Ar interpreter
+on the first line of interpreted scripts, as
+described in
+.Xr execve 2 .
+.Pp
+Note that the way the kernel parses the
+.Ql #!
+(first line) of an interpreted script has changed as of
+.Fx 6.0 .
+Prior to that, the
+.Fx
+kernel would split that first line into separate arguments based
+on any whitespace (space or <tab> characters) found in the line.
+So, if a script named
+.Pa /usr/local/bin/someport
+had a first line of:
+.Pp
+.Dl "#!/usr/local/bin/php -n -q -dsafe_mode=0"
+.Pp
+then the
+.Pa /usr/local/bin/php
+program would have been started with the arguments of:
+.Bd -literal -offset indent
+arg[0] = '/usr/local/bin/php'
+arg[1] = '-n'
+arg[2] = '-q'
+arg[3] = '-dsafe_mode=0'
+arg[4] = '/usr/local/bin/someport'
+.Ed
+.Pp
+plus any arguments the user specified when executing
+.Pa someport .
+However, this processing of multiple options on the
+.Ql #!
+line is not the way any other operating system parses the
+first line of an interpreted script.
+So after a change which was made for
+.Fx 6.0
+release, that script will result in
+.Pa /usr/local/bin/php
+being started with the arguments of:
+.Bd -literal -offset indent
+arg[0] = '/usr/local/bin/php'
+arg[1] = '-n -q -dsafe_mode=0'
+arg[2] = '/usr/local/bin/someport'
+.Ed
+.Pp
+plus any arguments the user specified.
+This caused a significant change in the behavior of a few scripts.
+In the case of above script, to have it behave the same way under
+.Fx 6.0
+as it did under earlier releases, the first line should be
+changed to:
+.Pp
+.Dl "#!/usr/bin/env -S /usr/local/bin/php -n -q -dsafe_mode=0"
+.Pp
+The
+.Nm
+utility will be started with the entire line as a single
+argument:
+.Pp
+.Dl "arg[1] = '-S /usr/local/bin/php -n -q -dsafe_mode=0'"
+.Pp
+and then
+.Fl S
+processing will split that line into separate arguments before
+executing
+.Pa /usr/local/bin/php .
+.\"
+.Sh ENVIRONMENT
+The
+.Nm
+utility uses the
+.Ev PATH
+environment variable to locate the requested
+.Ar utility
+if the name contains no
+.Ql /
+characters, unless the
+.Fl P
+option has been specified.
+.Sh EXIT STATUS
+.Ex -std
+An exit status of 126 indicates that
+.Ar utility
+was found, but could not be executed.
+An exit status of 127 indicates that
+.Ar utility
+could not be found.
+.Sh EXAMPLES
+Since the
+.Nm
+utility is often used as part of the first line of an interpreted script,
+the following examples show a number of ways that the
+.Nm
+utility can be useful in scripts.
+.Pp
+The kernel processing of an interpreted script does not allow a script
+to directly reference some other script as its own interpreter.
+As a way around this, the main difference between
+.Pp
+.Dl #!/usr/local/bin/foo
+and
+.Dl "#!/usr/bin/env /usr/local/bin/foo"
+.Pp
+is that the latter works even if
+.Pa /usr/local/bin/foo
+is itself an interpreted script.
+.Pp
+Probably the most common use of
+.Nm
+is to find the correct interpreter for a script, when the interpreter
+may be in different directories on different systems.
+The following example will find the
+.Ql perl
+interpreter by searching through the directories specified by
+.Ev PATH .
+.Pp
+.Dl "#!/usr/bin/env perl"
+.Pp
+One limitation of that example is that it assumes the user's value
+for
+.Ev PATH
+is set to a value which will find the interpreter you want
+to execute.
+The
+.Fl P
+option can be used to make sure a specific list of directories is
+used in the search for
+.Ar utility .
+Note that the
+.Fl S
+option is also required for this example to work correctly.
+.Pp
+.Dl "#!/usr/bin/env -S -P/usr/local/bin:/usr/bin perl"
+.Pp
+The above finds
+.Ql perl
+only if it is in
+.Pa /usr/local/bin
+or
+.Pa /usr/bin .
+That could be combined with the present value of
+.Ev PATH ,
+to provide more flexibility.
+Note that spaces are not required between the
+.Fl S
+and
+.Fl P
+options:
+.Pp
+.Dl "#!/usr/bin/env -S-P/usr/local/bin:/usr/bin:${PATH} perl"
+.Sh COMPATIBILITY
+The
+.Nm
+utility accepts the
+.Fl
+option as a synonym for
+.Fl i .
+.Sh SEE ALSO
+.Xr printenv 1 ,
+.Xr sh 1 ,
+.Xr execvp 3 ,
+.Xr environ 7
+.Sh STANDARDS
+The
+.Nm
+utility conforms to
+.St -p1003.1-2001 .
+The
+.Fl P , S , u
+and
+.Fl v
+options are non-standard extensions supported by
+.Fx ,
+but which may not be available on other operating systems.
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.4 .
+The
+.Fl P , S
+and
+.Fl v
+options were added in
+.Fx 6.0 .
+.Sh BUGS
+The
+.Nm
+utility does not handle values of
+.Ar utility
+which have an equals sign
+.Pq Ql =
+in their name, for obvious reasons.
+.Pp
+The
+.Nm
+utility does not take multibyte characters into account when
+processing the
+.Fl S
+option, which may lead to incorrect results in some locales.
diff --git a/shell_cmds/env/env.c b/shell_cmds/env/env.c
new file mode 100644
index 0000000..3dc152a
--- /dev/null
+++ b/shell_cmds/env/env.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 1988, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1988, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)env.c 8.3 (Berkeley) 4/2/94";
+#endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "envopts.h"
+
+extern char **environ;
+
+int env_verbosity;
+
+static void usage(void);
+
+int
+main(int argc, char **argv)
+{
+ char *altpath, **ep, *p, **parg;
+ char *cleanenv[1];
+ int ch, want_clear;
+ int rtrn;
+
+ altpath = NULL;
+ want_clear = 0;
+ while ((ch = getopt(argc, argv, "-iP:S:u:v")) != -1)
+ switch(ch) {
+ case '-':
+ case 'i':
+ want_clear = 1;
+ break;
+ case 'P':
+ altpath = strdup(optarg);
+ break;
+ case 'S':
+ /*
+ * The -S option, for "split string on spaces, with
+ * support for some simple substitutions"...
+ */
+ split_spaces(optarg, &optind, &argc, &argv);
+ break;
+ case 'u':
+ if (env_verbosity)
+ fprintf(stderr, "#env unset:\t%s\n", optarg);
+ rtrn = unsetenv(optarg);
+ if (rtrn == -1)
+ err(EXIT_FAILURE, "unsetenv %s", optarg);
+ break;
+ case 'v':
+ env_verbosity++;
+ if (env_verbosity > 1)
+ fprintf(stderr, "#env verbosity now at %d\n",
+ env_verbosity);
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ if (want_clear) {
+ environ = cleanenv;
+ cleanenv[0] = NULL;
+ if (env_verbosity)
+ fprintf(stderr, "#env clearing environ\n");
+ }
+ for (argv += optind; *argv && (p = strchr(*argv, '=')); ++argv) {
+ if (env_verbosity)
+ fprintf(stderr, "#env setenv:\t%s\n", *argv);
+ *p = '\0';
+ rtrn = setenv(*argv, p + 1, 1);
+ *p = '=';
+ if (rtrn == -1)
+ err(EXIT_FAILURE, "setenv %s", *argv);
+ }
+ if (*argv) {
+ if (altpath)
+ search_paths(altpath, argv);
+ if (env_verbosity) {
+ fprintf(stderr, "#env executing:\t%s\n", *argv);
+ for (parg = argv, argc = 0; *parg; parg++, argc++)
+ fprintf(stderr, "#env arg[%d]=\t'%s'\n",
+ argc, *parg);
+ if (env_verbosity > 1)
+ sleep(1);
+ }
+ execvp(*argv, argv);
+ err(errno == ENOENT ? 127 : 126, "%s", *argv);
+ }
+ for (ep = environ; *ep; ep++)
+ (void)printf("%s\n", *ep);
+ exit(0);
+}
+
+static void
+usage(void)
+{
+ (void)fprintf(stderr,
+ "usage: env [-iv] [-P utilpath] [-S string] [-u name]\n"
+ " [name=value ...] [utility [argument ...]]\n");
+ exit(1);
+}
diff --git a/shell_cmds/env/envopts.c b/shell_cmds/env/envopts.c
new file mode 100644
index 0000000..f821430
--- /dev/null
+++ b/shell_cmds/env/envopts.c
@@ -0,0 +1,468 @@
+/*-
+ * Copyright (c) 2005 - Garance Alistair Drosehn <gad@FreeBSD.org>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * official policies, either expressed or implied, of the FreeBSD Project.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <err.h>
+#include <errno.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "envopts.h"
+
+static const char *
+ expand_vars(int in_thisarg, char **thisarg_p, char **dest_p,
+ const char **src_p);
+static int is_there(char *candidate);
+
+/*
+ * The is*() routines take a parameter of 'int', but expect values in the range
+ * of unsigned char. Define some wrappers which take a value of type 'char',
+ * whether signed or unsigned, and ensure the value ends up in the right range.
+ */
+#define isalnumch(Anychar) isalnum((u_char)(Anychar))
+#define isalphach(Anychar) isalpha((u_char)(Anychar))
+#define isspacech(Anychar) isspace((u_char)(Anychar))
+
+/*
+ * Routine to determine if a given fully-qualified filename is executable.
+ * This is copied almost verbatim from FreeBSD's usr.bin/which/which.c.
+ */
+static int
+is_there(char *candidate)
+{
+ struct stat fin;
+
+ /* XXX work around access(2) false positives for superuser */
+ if (access(candidate, X_OK) == 0 &&
+ stat(candidate, &fin) == 0 &&
+ S_ISREG(fin.st_mode) &&
+ (getuid() != 0 ||
+ (fin.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0)) {
+ if (env_verbosity > 1)
+ fprintf(stderr, "#env matched:\t'%s'\n", candidate);
+ return (1);
+ }
+ return (0);
+}
+
+/**
+ * Routine to search through an alternate path-list, looking for a given
+ * filename to execute. If the file is found, replace the original
+ * unqualified name with a fully-qualified path. This allows `env' to
+ * execute programs from a specific strict list of possible paths, without
+ * changing the value of PATH seen by the program which will be executed.
+ * E.G.:
+ * #!/usr/bin/env -S-P/usr/local/bin:/usr/bin perl
+ * will execute /usr/local/bin/perl or /usr/bin/perl (whichever is found
+ * first), no matter what the current value of PATH is, and without
+ * changing the value of PATH that the script will see when it runs.
+ *
+ * This is similar to the print_matches() routine in usr.bin/which/which.c.
+ */
+void
+search_paths(char *path, char **argv)
+{
+ char candidate[PATH_MAX];
+ const char *d;
+ char *filename, *fqname;
+
+ /* If the file has a `/' in it, then no search is done */
+ filename = *argv;
+ if (strchr(filename, '/') != NULL)
+ return;
+
+ if (env_verbosity > 1) {
+ fprintf(stderr, "#env Searching:\t'%s'\n", path);
+ fprintf(stderr, "#env for file:\t'%s'\n", filename);
+ }
+
+ fqname = NULL;
+ while ((d = strsep(&path, ":")) != NULL) {
+ if (*d == '\0')
+ d = ".";
+ if (snprintf(candidate, sizeof(candidate), "%s/%s", d,
+ filename) >= (int)sizeof(candidate))
+ continue;
+ if (is_there(candidate)) {
+ fqname = candidate;
+ break;
+ }
+ }
+
+ if (fqname == NULL) {
+ errno = ENOENT;
+ err(127, "%s", filename);
+ }
+ *argv = strdup(candidate);
+}
+
+/**
+ * Routine to split a string into multiple parameters, while recognizing a
+ * few special characters. It recognizes both single and double-quoted
+ * strings. This processing is designed entirely for the benefit of the
+ * parsing of "#!"-lines (aka "shebang" lines == the first line of an
+ * executable script). Different operating systems parse that line in very
+ * different ways, and this split-on-spaces processing is meant to provide
+ * ways to specify arbitrary arguments on that line, no matter how the OS
+ * parses it.
+ *
+ * Within a single-quoted string, the two characters "\'" are treated as
+ * a literal "'" character to add to the string, and "\\" are treated as
+ * a literal "\" character to add. Other than that, all characters are
+ * copied until the processing gets to a terminating "'".
+ *
+ * Within a double-quoted string, many more "\"-style escape sequences
+ * are recognized, mostly copied from what is recognized in the `printf'
+ * command. Some OS's will not allow a literal blank character to be
+ * included in the one argument that they recognize on a shebang-line,
+ * so a few additional escape-sequences are defined to provide ways to
+ * specify blanks.
+ *
+ * Within a double-quoted string "\_" is turned into a literal blank.
+ * (Inside of a single-quoted string, the two characters are just copied)
+ * Outside of a quoted string, "\_" is treated as both a blank, and the
+ * end of the current argument. So with a shelbang-line of:
+ * #!/usr/bin/env -SA=avalue\_perl
+ * the -S value would be broken up into arguments "A=avalue" and "perl".
+ */
+void
+split_spaces(const char *str, int *origind, int *origc, char ***origv)
+{
+ static const char *nullarg = "";
+ const char *bq_src, *copystr, *src;
+ char *dest, **newargv, *newstr, **nextarg, **oldarg;
+ int addcount, bq_destlen, copychar, found_sep, in_arg, in_dq, in_sq;
+
+ /*
+ * Ignore leading space on the string, and then malloc enough room
+ * to build a copy of it. The copy might end up shorter than the
+ * original, due to quoted strings and '\'-processing.
+ */
+ while (isspacech(*str))
+ str++;
+ if (*str == '\0')
+ return;
+ newstr = malloc(strlen(str) + 1);
+
+ /*
+ * Allocate plenty of space for the new array of arg-pointers,
+ * and start that array off with the first element of the old
+ * array.
+ */
+ newargv = malloc((*origc + (strlen(str) / 2) + 2) * sizeof(char *));
+ nextarg = newargv;
+ *nextarg++ = **origv;
+
+ /* Come up with the new args by splitting up the given string. */
+ addcount = 0;
+ bq_destlen = in_arg = in_dq = in_sq = 0;
+ bq_src = NULL;
+ for (src = str, dest = newstr; *src != '\0'; src++) {
+ /*
+ * This switch will look at a character in *src, and decide
+ * what should be copied to *dest. It only decides what
+ * character(s) to copy, it should not modify *dest. In some
+ * cases, it will look at multiple characters from *src.
+ */
+ copychar = found_sep = 0;
+ copystr = NULL;
+ switch (*src) {
+ case '"':
+ if (in_sq)
+ copychar = *src;
+ else if (in_dq)
+ in_dq = 0;
+ else {
+ /*
+ * Referencing nullarg ensures that a new
+ * argument is created, even if this quoted
+ * string ends up with zero characters.
+ */
+ copystr = nullarg;
+ in_dq = 1;
+ bq_destlen = dest - *(nextarg - 1);
+ bq_src = src;
+ }
+ break;
+ case '$':
+ if (in_sq)
+ copychar = *src;
+ else {
+ copystr = expand_vars(in_arg, (nextarg - 1),
+ &dest, &src);
+ }
+ break;
+ case '\'':
+ if (in_dq)
+ copychar = *src;
+ else if (in_sq)
+ in_sq = 0;
+ else {
+ /*
+ * Referencing nullarg ensures that a new
+ * argument is created, even if this quoted
+ * string ends up with zero characters.
+ */
+ copystr = nullarg;
+ in_sq = 1;
+ bq_destlen = dest - *(nextarg - 1);
+ bq_src = src;
+ }
+ break;
+ case '\\':
+ if (in_sq) {
+ /*
+ * Inside single-quoted strings, only the
+ * "\'" and "\\" are recognized as special
+ * strings.
+ */
+ copychar = *(src + 1);
+ if (copychar == '\'' || copychar == '\\')
+ src++;
+ else
+ copychar = *src;
+ break;
+ }
+ src++;
+ switch (*src) {
+ case '"':
+ case '#':
+ case '$':
+ case '\'':
+ case '\\':
+ copychar = *src;
+ break;
+ case '_':
+ /*
+ * Alternate way to get a blank, which allows
+ * that blank be used to separate arguments
+ * when it is not inside a quoted string.
+ */
+ if (in_dq)
+ copychar = ' ';
+ else {
+ found_sep = 1;
+ src++;
+ }
+ break;
+ case 'c':
+ /*
+ * Ignore remaining characters in the -S string.
+ * This would not make sense if found in the
+ * middle of a quoted string.
+ */
+ if (in_dq)
+ errx(1, "Sequence '\\%c' is not allowed"
+ " in quoted strings", *src);
+ goto str_done;
+ case 'f':
+ copychar = '\f';
+ break;
+ case 'n':
+ copychar = '\n';
+ break;
+ case 'r':
+ copychar = '\r';
+ break;
+ case 't':
+ copychar = '\t';
+ break;
+ case 'v':
+ copychar = '\v';
+ break;
+ default:
+ if (isspacech(*src))
+ copychar = *src;
+ else
+ errx(1, "Invalid sequence '\\%c' in -S",
+ *src);
+ }
+ break;
+ default:
+ if ((in_dq || in_sq) && in_arg)
+ copychar = *src;
+ else if (isspacech(*src))
+ found_sep = 1;
+ else {
+ /*
+ * If the first character of a new argument
+ * is `#', then ignore the remaining chars.
+ */
+ if (!in_arg && *src == '#')
+ goto str_done;
+ copychar = *src;
+ }
+ }
+ /*
+ * Now that the switch has determined what (if anything)
+ * needs to be copied, copy whatever that is to *dest.
+ */
+ if (copychar || copystr != NULL) {
+ if (!in_arg) {
+ /* This is the first byte of a new argument */
+ *nextarg++ = dest;
+ addcount++;
+ in_arg = 1;
+ }
+ if (copychar)
+ *dest++ = (char)copychar;
+ else if (copystr != NULL)
+ while (*copystr != '\0')
+ *dest++ = *copystr++;
+ } else if (found_sep) {
+ *dest++ = '\0';
+ while (isspacech(*src))
+ src++;
+ --src;
+ in_arg = 0;
+ }
+ }
+str_done:
+ *dest = '\0';
+ *nextarg = NULL;
+ if (in_dq || in_sq) {
+ errx(1, "No terminating quote for string: %.*s%s",
+ bq_destlen, *(nextarg - 1), bq_src);
+ }
+ if (env_verbosity > 1) {
+ fprintf(stderr, "#env split -S:\t'%s'\n", str);
+ oldarg = newargv + 1;
+ fprintf(stderr, "#env into:\t'%s'\n", *oldarg);
+ for (oldarg++; *oldarg; oldarg++)
+ fprintf(stderr, "#env &\t'%s'\n", *oldarg);
+ }
+
+ /* Copy the unprocessed arg-pointers from the original array */
+ for (oldarg = *origv + *origind; *oldarg; oldarg++)
+ *nextarg++ = *oldarg;
+ *nextarg = NULL;
+
+ /* Update optind/argc/argv in the calling routine */
+ *origind = 1;
+ *origc += addcount;
+ *origv = newargv;
+}
+
+/**
+ * Routine to split expand any environment variables referenced in the string
+ * that -S is processing. For now it only supports the form ${VARNAME}. It
+ * explicitly does not support $VARNAME, and obviously can not handle special
+ * shell-variables such as $?, $*, $1, etc. It is called with *src_p pointing
+ * at the initial '$', and if successful it will update *src_p, *dest_p, and
+ * possibly *thisarg_p in the calling routine.
+ */
+static const char *
+expand_vars(int in_thisarg, char **thisarg_p, char **dest_p, const char **src_p)
+{
+ const char *vbegin, *vend, *vvalue;
+ char *newstr, *vname;
+ int bad_reference;
+ size_t namelen, newlen;
+
+ bad_reference = 1;
+ vbegin = vend = (*src_p) + 1;
+ if (*vbegin++ == '{')
+ if (*vbegin == '_' || isalphach(*vbegin)) {
+ vend = vbegin + 1;
+ while (*vend == '_' || isalnumch(*vend))
+ vend++;
+ if (*vend == '}')
+ bad_reference = 0;
+ }
+ if (bad_reference)
+ errx(1, "Only ${VARNAME} expansion is supported, error at: %s",
+ *src_p);
+
+ /*
+ * We now know we have a valid environment variable name, so update
+ * the caller's source-pointer to the last character in that reference,
+ * and then pick up the matching value. If the variable is not found,
+ * or if it has a null value, then our work here is done.
+ */
+ *src_p = vend;
+ namelen = vend - vbegin + 1;
+ vname = malloc(namelen);
+ strlcpy(vname, vbegin, namelen);
+ vvalue = getenv(vname);
+ if (vvalue == NULL || *vvalue == '\0') {
+ if (env_verbosity > 2)
+ fprintf(stderr,
+ "#env replacing ${%s} with null string\n",
+ vname);
+ free(vname);
+ return (NULL);
+ }
+
+ if (env_verbosity > 2)
+ fprintf(stderr, "#env expanding ${%s} into '%s'\n", vname,
+ vvalue);
+
+ /*
+ * There is some value to copy to the destination. If the value is
+ * shorter than the ${VARNAME} reference that it replaces, then our
+ * caller can just copy the value to the existing destination.
+ */
+ if (strlen(vname) + 3 >= strlen(vvalue)) {
+ free(vname);
+ return (vvalue);
+ }
+
+ /*
+ * The value is longer than the string it replaces, which means the
+ * present destination area is too small to hold it. Create a new
+ * destination area, and update the caller's 'dest' variable to match.
+ * If the caller has already started copying some info for 'thisarg'
+ * into the present destination, then the new destination area must
+ * include a copy of that data, and the pointer to 'thisarg' must also
+ * be updated. Note that it is still the caller which copies this
+ * vvalue to the new *dest.
+ */
+ newlen = strlen(vvalue) + strlen(*src_p) + 1;
+ if (in_thisarg) {
+ **dest_p = '\0'; /* Provide terminator for 'thisarg' */
+ newlen += strlen(*thisarg_p);
+ newstr = malloc(newlen);
+ strcpy(newstr, *thisarg_p);
+ *thisarg_p = newstr;
+ } else {
+ newstr = malloc(newlen);
+ *newstr = '\0';
+ }
+ *dest_p = strchr(newstr, '\0');
+ free(vname);
+ return (vvalue);
+}
diff --git a/shell_cmds/env/envopts.h b/shell_cmds/env/envopts.h
new file mode 100644
index 0000000..1f15c69
--- /dev/null
+++ b/shell_cmds/env/envopts.h
@@ -0,0 +1,37 @@
+/*-
+ * Copyright (c) 2005 - Garance Alistair Drosehn <gad@FreeBSD.org>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * official policies, either expressed or implied, of the FreeBSD Project.
+ *
+ * $FreeBSD$
+ */
+
+void search_paths(char *path, char **argv);
+void split_spaces(const char *str, int *origind, int *origc,
+ char ***origv);
+
+extern int env_verbosity;
diff --git a/shell_cmds/expr/expr.1 b/shell_cmds/expr/expr.1
new file mode 100644
index 0000000..9c8090c
--- /dev/null
+++ b/shell_cmds/expr/expr.1
@@ -0,0 +1,235 @@
+.\" -*- nroff -*-
+.\"-
+.\" Copyright (c) 1993 Winning Strategies, Inc.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by Winning Strategies, Inc.
+.\" 4. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/bin/expr/expr.1,v 1.31 2011/07/09 12:05:53 se Exp $
+.\"
+.Dd September 9, 2010
+.Dt EXPR 1
+.Os
+.Sh NAME
+.Nm expr
+.Nd evaluate expression
+.Sh SYNOPSIS
+.Nm
+.Ar expression
+.Sh DESCRIPTION
+The
+.Nm
+utility evaluates
+.Ar expression
+and writes the result on standard output.
+.Pp
+All operators and operands must be passed as separate arguments.
+Several of the operators have special meaning to command interpreters
+and must therefore be quoted appropriately.
+All integer operands are interpreted in base 10 and must consist of only
+an optional leading minus sign followed by one or more digits.
+.Pp
+Arithmetic operations are performed using signed integer math with a
+range according to the C
+.Vt intmax_t
+data type (the largest signed integral type available).
+All conversions and operations are checked for overflow.
+Overflow results in program termination with an error message on stdout
+and with an error status.
+.Pp
+Operators are listed below in order of increasing precedence; all
+are left-associative.
+Operators with equal precedence are grouped within symbols
+.Ql {
+and
+.Ql } .
+.Bl -tag -width indent
+.It Ar expr1 Li | Ar expr2
+Return the evaluation of
+.Ar expr1
+if it is neither an empty string nor zero;
+otherwise, returns the evaluation of
+.Ar expr2
+if it is not an empty string;
+otherwise, returns zero.
+.It Ar expr1 Li & Ar expr2
+Return the evaluation of
+.Ar expr1
+if neither expression evaluates to an empty string or zero;
+otherwise, returns zero.
+.It Ar expr1 Li "{=, >, >=, <, <=, !=}" Ar expr2
+Return the results of integer comparison if both arguments are integers;
+otherwise, returns the results of string comparison using the locale-specific
+collation sequence.
+The result of each comparison is 1 if the specified relation is true,
+or 0 if the relation is false.
+.It Ar expr1 Li "{+, -}" Ar expr2
+Return the results of addition or subtraction of integer-valued arguments.
+.It Ar expr1 Li "{*, /, %}" Ar expr2
+Return the results of multiplication, integer division, or remainder of integer-valued arguments.
+.It Ar expr1 Li : Ar expr2
+The
+.Dq Li \&:
+operator matches
+.Ar expr1
+against
+.Ar expr2 ,
+which must be a basic regular expression.
+The regular expression is anchored
+to the beginning of the string with an implicit
+.Dq Li ^ .
+.Pp
+If the match succeeds and the pattern contains at least one regular
+expression subexpression
+.Dq Li "\e(...\e)" ,
+the string corresponding to
+.Dq Li \e1
+is returned;
+otherwise the matching operator returns the number of characters matched.
+If the match fails and the pattern contains a regular expression subexpression
+the null string is returned;
+otherwise 0.
+.El
+.Pp
+Parentheses are used for grouping in the usual manner.
+.Pp
+The
+.Nm
+utility makes no lexical distinction between arguments which may be
+operators and arguments which may be operands.
+An operand which is lexically identical to an operator will be considered a
+syntax error.
+See the examples below for a work-around.
+.Pp
+The syntax of the
+.Nm
+command in general is historic and inconvenient.
+New applications are advised to use shell arithmetic rather than
+.Nm .
+.Sh EXIT STATUS
+The
+.Nm
+utility exits with one of the following values:
+.Bl -tag -width indent -compact
+.It 0
+the expression is neither an empty string nor 0.
+.It 1
+the expression is an empty string or 0.
+.It 2
+the expression is invalid.
+.El
+.Sh EXAMPLES
+.Bl -bullet
+.It
+The following example (in
+.Xr sh 1
+syntax) adds one to the variable
+.Va a :
+.Dl "a=$(expr $a + 1)"
+.It
+This will fail if the value of
+.Va a
+is a negative number.
+To protect negative values of
+.Va a
+from being interpreted as options to the
+.Nm
+command, one might rearrange the expression:
+.Dl "a=$(expr 1 + $a)"
+.It
+More generally, parenthesize possibly-negative values:
+.Dl "a=$(expr \e( $a \e) + 1)"
+.It
+With shell arithmetic, no escaping is required:
+.Dl "a=$((a + 1))"
+.It
+This example prints the filename portion of a pathname stored
+in variable
+.Va a .
+Since
+.Va a
+might represent the path
+.Pa / ,
+it is necessary to prevent it from being interpreted as the division operator.
+The
+.Li //
+characters resolve this ambiguity.
+.Dl "expr \*q//$a\*q \&: '.*/\e(.*\e)'"
+.It
+With modern
+.Xr sh 1
+syntax,
+.Dl "\*q${a##*/}\*q"
+expands to the same value.
+.El
+.Pp
+The following examples output the number of characters in variable
+.Va a .
+Again, if
+.Va a
+might begin with a hyphen, it is necessary to prevent it from being
+interpreted as an option to
+.Nm ,
+and
+.Va a
+might be interpreted as an operator.
+.Bl -bullet
+.It
+To deal with all of this, a complicated command
+is required:
+.Dl "expr \e( \*qX$a\*q \&: \*q.*\*q \e) - 1"
+.It
+With modern
+.Xr sh 1
+syntax, this can be done much more easily:
+.Dl "${#a}"
+expands to the required number.
+.El
+.Sh SEE ALSO
+.Xr sh 1 ,
+.Xr test 1
+.Sh STANDARDS
+The
+.Nm
+utility conforms to
+.St -p1003.1-2008 .
+.Pp
+The extended arithmetic range and overflow checks do not conflict with
+POSIX's requirement that arithmetic be done using signed longs, since
+they only make a difference to the result in cases where using signed
+longs would give undefined behavior.
+.Pp
+According to the
+.Tn POSIX
+standard, the use of string arguments
+.Va length ,
+.Va substr ,
+.Va index ,
+or
+.Va match
+produces undefined results. In this version of
+.Nm ,
+these arguments are treated just as their respective string values.
diff --git a/shell_cmds/expr/expr.y b/shell_cmds/expr/expr.y
new file mode 100644
index 0000000..1aa9474
--- /dev/null
+++ b/shell_cmds/expr/expr.y
@@ -0,0 +1,571 @@
+%{
+/*-
+ * Written by Pace Willisson (pace@blitz.com)
+ * and placed in the public domain.
+ *
+ * Largely rewritten by J.T. Conklin (jtc@wimsey.com)
+ *
+ * $FreeBSD: src/bin/expr/expr.y,v 1.28 2011/07/09 12:20:15 se Exp $
+ */
+
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <regex.h>
+#include <unistd.h>
+
+/*
+ * POSIX specifies a specific error code for syntax errors. We exit
+ * with this code for all errors.
+ */
+#define ERR_EXIT 2
+
+enum valtype {
+ integer, numeric_string, string
+} ;
+
+struct val {
+ enum valtype type;
+ union {
+ char *s;
+ intmax_t i;
+ } u;
+} ;
+
+char **av;
+int nonposix;
+struct val *result;
+
+void assert_to_integer(struct val *);
+void assert_div(intmax_t, intmax_t);
+void assert_minus(intmax_t, intmax_t, intmax_t);
+void assert_plus(intmax_t, intmax_t, intmax_t);
+void assert_times(intmax_t, intmax_t, intmax_t);
+int compare_vals(struct val *, struct val *);
+void free_value(struct val *);
+int is_integer(const char *);
+int is_string(struct val *);
+int is_zero_or_null(struct val *);
+struct val *make_integer(intmax_t);
+struct val *make_str(const char *);
+struct val *op_and(struct val *, struct val *);
+struct val *op_colon(struct val *, struct val *);
+struct val *op_div(struct val *, struct val *);
+struct val *op_eq(struct val *, struct val *);
+struct val *op_ge(struct val *, struct val *);
+struct val *op_gt(struct val *, struct val *);
+struct val *op_le(struct val *, struct val *);
+struct val *op_lt(struct val *, struct val *);
+struct val *op_minus(struct val *, struct val *);
+struct val *op_ne(struct val *, struct val *);
+struct val *op_or(struct val *, struct val *);
+struct val *op_plus(struct val *, struct val *);
+struct val *op_rem(struct val *, struct val *);
+struct val *op_times(struct val *, struct val *);
+int to_integer(struct val *);
+void to_string(struct val *);
+int yyerror(const char *);
+int yylex(void);
+int yyparse(void);
+
+%}
+
+%union
+{
+ struct val *val;
+}
+
+%left <val> '|'
+%left <val> '&'
+%left <val> '=' '>' '<' GE LE NE
+%left <val> '+' '-'
+%left <val> '*' '/' '%'
+%left <val> ':'
+
+%token <val> TOKEN
+%type <val> start expr
+
+%%
+
+start: expr { result = $$; }
+
+expr: TOKEN
+ | '(' expr ')' { $$ = $2; }
+ | expr '|' expr { $$ = op_or($1, $3); }
+ | expr '&' expr { $$ = op_and($1, $3); }
+ | expr '=' expr { $$ = op_eq($1, $3); }
+ | expr '>' expr { $$ = op_gt($1, $3); }
+ | expr '<' expr { $$ = op_lt($1, $3); }
+ | expr GE expr { $$ = op_ge($1, $3); }
+ | expr LE expr { $$ = op_le($1, $3); }
+ | expr NE expr { $$ = op_ne($1, $3); }
+ | expr '+' expr { $$ = op_plus($1, $3); }
+ | expr '-' expr { $$ = op_minus($1, $3); }
+ | expr '*' expr { $$ = op_times($1, $3); }
+ | expr '/' expr { $$ = op_div($1, $3); }
+ | expr '%' expr { $$ = op_rem($1, $3); }
+ | expr ':' expr { $$ = op_colon($1, $3); }
+ ;
+
+%%
+
+struct val *
+make_integer(intmax_t i)
+{
+ struct val *vp;
+
+ vp = (struct val *)malloc(sizeof(*vp));
+ if (vp == NULL)
+ errx(ERR_EXIT, "malloc() failed");
+
+ vp->type = integer;
+ vp->u.i = i;
+ return (vp);
+}
+
+struct val *
+make_str(const char *s)
+{
+ struct val *vp;
+
+ vp = (struct val *)malloc(sizeof(*vp));
+ if (vp == NULL || ((vp->u.s = strdup(s)) == NULL))
+ errx(ERR_EXIT, "malloc() failed");
+
+ if (is_integer(s))
+ vp->type = numeric_string;
+ else
+ vp->type = string;
+
+ return (vp);
+}
+
+void
+free_value(struct val *vp)
+{
+ if (vp->type == string || vp->type == numeric_string)
+ free(vp->u.s);
+}
+
+int
+to_integer(struct val *vp)
+{
+ intmax_t i;
+
+ /* we can only convert numeric_string to integer, here */
+ if (vp->type == numeric_string) {
+ errno = 0;
+ i = strtoimax(vp->u.s, (char **)NULL, 10);
+ /* just keep as numeric_string, if the conversion fails */
+ if (errno != ERANGE) {
+ free(vp->u.s);
+ vp->u.i = i;
+ vp->type = integer;
+ }
+ }
+ return (vp->type == integer);
+}
+
+void
+assert_to_integer(struct val *vp)
+{
+ if (vp->type == string)
+ errx(ERR_EXIT, "not a decimal number: '%s'", vp->u.s);
+ if (!to_integer(vp))
+ errx(ERR_EXIT, "operand too large: '%s'", vp->u.s);
+}
+
+void
+to_string(struct val *vp)
+{
+ char *tmp;
+
+ if (vp->type == string || vp->type == numeric_string)
+ return;
+
+ /*
+ * log_10(x) ~= 0.3 * log_2(x). Rounding up gives the number
+ * of digits; add one each for the sign and terminating null
+ * character, respectively.
+ */
+#define NDIGITS(x) (3 * (sizeof(x) * CHAR_BIT) / 10 + 1 + 1 + 1)
+ tmp = malloc(NDIGITS(vp->u.i));
+ if (tmp == NULL)
+ errx(ERR_EXIT, "malloc() failed");
+
+ sprintf(tmp, "%jd", vp->u.i);
+ vp->type = string;
+ vp->u.s = tmp;
+}
+
+int
+is_integer(const char *s)
+{
+ if (nonposix) {
+ if (*s == '\0')
+ return (1);
+ while (isspace((unsigned char)*s))
+ s++;
+ }
+ if (*s == '-' || (nonposix && *s == '+'))
+ s++;
+ if (*s == '\0')
+ return (0);
+ while (isdigit((unsigned char)*s))
+ s++;
+ return (*s == '\0');
+}
+
+int
+is_string(struct val *vp)
+{
+ /* only TRUE if this string is not a valid integer */
+ return (vp->type == string);
+}
+
+int
+yylex(void)
+{
+ char *p;
+
+ if (*av == NULL)
+ return (0);
+
+ p = *av++;
+
+ if (strlen(p) == 1) {
+ if (strchr("|&=<>+-*/%:()", *p))
+ return (*p);
+ } else if (strlen(p) == 2 && p[1] == '=') {
+ switch (*p) {
+ case '>': return (GE);
+ case '<': return (LE);
+ case '!': return (NE);
+ }
+ }
+
+ yylval.val = make_str(p);
+ return (TOKEN);
+}
+
+int
+is_zero_or_null(struct val *vp)
+{
+ if (vp->type == integer)
+ return (vp->u.i == 0);
+
+ return (*vp->u.s == 0 || (to_integer(vp) && vp->u.i == 0));
+}
+
+int
+main(int argc, char *argv[])
+{
+#ifndef __APPLE__
+ int c;
+#endif
+
+ setlocale(LC_ALL, "");
+#ifdef __APPLE__
+ av = argv + 1;
+ if (*av && !strcmp(*av, "--"))
+ av++;
+#else
+ if (getenv("EXPR_COMPAT") != NULL
+ || check_utility_compat("expr")) {
+ av = argv + 1;
+ nonposix = 1;
+ } else {
+ while ((c = getopt(argc, argv, "e")) != -1) {
+ switch (c) {
+ case 'e':
+ nonposix = 1;
+ break;
+ default:
+ errx(ERR_EXIT,
+ "usage: expr [-e] expression\n");
+ }
+ }
+ av = argv + optind;
+ }
+#endif
+
+ yyparse();
+
+#ifdef __APPLE__
+ if (to_integer(result))
+#else
+ if (result->type == integer)
+#endif
+ printf("%jd\n", result->u.i);
+ else
+ printf("%s\n", result->u.s);
+
+ return (is_zero_or_null(result));
+}
+
+int
+yyerror(const char *s __unused)
+{
+ errx(ERR_EXIT, "syntax error");
+}
+
+struct val *
+op_or(struct val *a, struct val *b)
+{
+ if (!is_zero_or_null(a)) {
+ free_value(b);
+ return (a);
+ }
+ free_value(a);
+ if (!is_zero_or_null(b))
+ return (b);
+ free_value(b);
+ return (make_integer((intmax_t)0));
+}
+
+struct val *
+op_and(struct val *a, struct val *b)
+{
+ if (is_zero_or_null(a) || is_zero_or_null(b)) {
+ free_value(a);
+ free_value(b);
+ return (make_integer((intmax_t)0));
+ } else {
+ free_value(b);
+ return (a);
+ }
+}
+
+int
+compare_vals(struct val *a, struct val *b)
+{
+ int r;
+
+ if (is_string(a) || is_string(b)) {
+ to_string(a);
+ to_string(b);
+ r = strcoll(a->u.s, b->u.s);
+ } else {
+ assert_to_integer(a);
+ assert_to_integer(b);
+ if (a->u.i > b->u.i)
+ r = 1;
+ else if (a->u.i < b->u.i)
+ r = -1;
+ else
+ r = 0;
+ }
+
+ free_value(a);
+ free_value(b);
+ return (r);
+}
+
+struct val *
+op_eq(struct val *a, struct val *b)
+{
+ return (make_integer((intmax_t)(compare_vals(a, b) == 0)));
+}
+
+struct val *
+op_gt(struct val *a, struct val *b)
+{
+ return (make_integer((intmax_t)(compare_vals(a, b) > 0)));
+}
+
+struct val *
+op_lt(struct val *a, struct val *b)
+{
+ return (make_integer((intmax_t)(compare_vals(a, b) < 0)));
+}
+
+struct val *
+op_ge(struct val *a, struct val *b)
+{
+ return (make_integer((intmax_t)(compare_vals(a, b) >= 0)));
+}
+
+struct val *
+op_le(struct val *a, struct val *b)
+{
+ return (make_integer((intmax_t)(compare_vals(a, b) <= 0)));
+}
+
+struct val *
+op_ne(struct val *a, struct val *b)
+{
+ return (make_integer((intmax_t)(compare_vals(a, b) != 0)));
+}
+
+void
+assert_plus(intmax_t a, intmax_t b, intmax_t r)
+{
+ /*
+ * sum of two positive numbers must be positive,
+ * sum of two negative numbers must be negative
+ */
+ if ((a > 0 && b > 0 && r <= 0) ||
+ (a < 0 && b < 0 && r >= 0))
+ errx(ERR_EXIT, "overflow");
+}
+
+struct val *
+op_plus(struct val *a, struct val *b)
+{
+ struct val *r;
+
+ assert_to_integer(a);
+ assert_to_integer(b);
+ r = make_integer(a->u.i + b->u.i);
+ assert_plus(a->u.i, b->u.i, r->u.i);
+
+ free_value(a);
+ free_value(b);
+ return (r);
+}
+
+void
+assert_minus(intmax_t a, intmax_t b, intmax_t r)
+{
+ /* special case subtraction of INTMAX_MIN */
+ if (b == INTMAX_MIN && a < 0)
+ errx(ERR_EXIT, "overflow");
+ /* check addition of negative subtrahend */
+ assert_plus(a, -b, r);
+}
+
+struct val *
+op_minus(struct val *a, struct val *b)
+{
+ struct val *r;
+
+ assert_to_integer(a);
+ assert_to_integer(b);
+ r = make_integer(a->u.i - b->u.i);
+ assert_minus(a->u.i, b->u.i, r->u.i);
+
+ free_value(a);
+ free_value(b);
+ return (r);
+}
+
+void
+assert_times(intmax_t a, intmax_t b, intmax_t r)
+{
+ /*
+ * if first operand is 0, no overflow is possible,
+ * else result of division test must match second operand
+ */
+ if (a != 0 && r / a != b)
+ errx(ERR_EXIT, "overflow");
+}
+
+struct val *
+op_times(struct val *a, struct val *b)
+{
+ struct val *r;
+
+ assert_to_integer(a);
+ assert_to_integer(b);
+ r = make_integer(a->u.i * b->u.i);
+ assert_times(a->u.i, b->u.i, r->u.i);
+
+ free_value(a);
+ free_value(b);
+ return (r);
+}
+
+void
+assert_div(intmax_t a, intmax_t b)
+{
+ if (b == 0)
+ errx(ERR_EXIT, "division by zero");
+ /* only INTMAX_MIN / -1 causes overflow */
+ if (a == INTMAX_MIN && b == -1)
+ errx(ERR_EXIT, "overflow");
+}
+
+struct val *
+op_div(struct val *a, struct val *b)
+{
+ struct val *r;
+
+ assert_to_integer(a);
+ assert_to_integer(b);
+ /* assert based on operands only, not on result */
+ assert_div(a->u.i, b->u.i);
+ r = make_integer(a->u.i / b->u.i);
+
+ free_value(a);
+ free_value(b);
+ return (r);
+}
+
+struct val *
+op_rem(struct val *a, struct val *b)
+{
+ struct val *r;
+
+ assert_to_integer(a);
+ assert_to_integer(b);
+ /* pass a=1 to only check for div by zero */
+ assert_div(1, b->u.i);
+ r = make_integer(a->u.i % b->u.i);
+
+ free_value(a);
+ free_value(b);
+ return (r);
+}
+
+struct val *
+op_colon(struct val *a, struct val *b)
+{
+ regex_t rp;
+ regmatch_t rm[2];
+ char errbuf[256];
+ int eval;
+ struct val *v;
+
+ /* coerce both arguments to strings */
+ to_string(a);
+ to_string(b);
+
+ /* compile regular expression */
+ if ((eval = regcomp(&rp, b->u.s, 0)) != 0) {
+ regerror(eval, &rp, errbuf, sizeof(errbuf));
+ errx(ERR_EXIT, "%s", errbuf);
+ }
+
+ /* compare string against pattern */
+ /* remember that patterns are anchored to the beginning of the line */
+ if (regexec(&rp, a->u.s, (size_t)2, rm, 0) == 0 && rm[0].rm_so == 0)
+ if (rm[1].rm_so >= 0) {
+ *(a->u.s + rm[1].rm_eo) = '\0';
+ v = make_str(a->u.s + rm[1].rm_so);
+#ifdef __APPLE__
+ v->type = string; /* 8319378 */
+#endif
+
+ } else
+ v = make_integer((intmax_t)(rm[0].rm_eo - rm[0].rm_so));
+ else
+ if (rp.re_nsub == 0)
+ v = make_integer((intmax_t)0);
+ else
+ v = make_str("");
+
+ /* free arguments and pattern buffer */
+ free_value(a);
+ free_value(b);
+ regfree(&rp);
+
+ return (v);
+}
diff --git a/shell_cmds/false/false.1 b/shell_cmds/false/false.1
new file mode 100644
index 0000000..f7b07eb
--- /dev/null
+++ b/shell_cmds/false/false.1
@@ -0,0 +1,60 @@
+.\" $NetBSD: false.1,v 1.5 1997/10/18 14:46:54 lukem Exp $
+.\"
+.\" Copyright (c) 1983, 1990 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" from: @(#)false.1 6.6 (Berkeley) 7/24/91
+.\" $NetBSD: false.1,v 1.5 1997/10/18 14:46:54 lukem Exp $
+.\"
+.Dd July 24, 1991
+.Dt FALSE 1
+.Os BSD 4.2
+.Sh NAME
+.Nm false
+.Nd Return false value.
+.Sh SYNOPSIS
+.Nm
+.Sh DESCRIPTION
+The
+.Nm
+utility always exits with a nonzero exit code.
+.Sh SEE ALSO
+.Xr csh 1 ,
+.Xr sh 1 ,
+.Xr true 1
+.Sh STANDARDS
+The
+.Nm
+utility conforms to
+.St -p1003.2-92 .
diff --git a/shell_cmds/false/false.c b/shell_cmds/false/false.c
new file mode 100644
index 0000000..3883d89
--- /dev/null
+++ b/shell_cmds/false/false.c
@@ -0,0 +1,2 @@
+#include <stdlib.h>
+int main () { exit(1); }
diff --git a/shell_cmds/false/false.sh b/shell_cmds/false/false.sh
new file mode 100644
index 0000000..2526efb
--- /dev/null
+++ b/shell_cmds/false/false.sh
@@ -0,0 +1,2 @@
+#! /bin/sh
+exit 1
diff --git a/shell_cmds/find/extern.h b/shell_cmds/find/extern.h
new file mode 100644
index 0000000..f4282f7
--- /dev/null
+++ b/shell_cmds/find/extern.h
@@ -0,0 +1,124 @@
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)extern.h 8.3 (Berkeley) 4/16/94
+ * $FreeBSD: src/usr.bin/find/extern.h,v 1.26 2010/12/11 08:32:16 joel Exp $
+ */
+
+#include <sys/cdefs.h>
+
+void brace_subst(char *, char **, char *, int);
+PLAN *find_create(char ***);
+int find_execute(PLAN *, char **);
+PLAN *find_formplan(char **);
+PLAN *not_squish(PLAN *);
+PLAN *or_squish(PLAN *);
+PLAN *paren_squish(PLAN *);
+time_t get_date(char *);
+struct stat;
+void printlong(char *, char *, struct stat *);
+int queryuser(char **);
+OPTION *lookup_option(const char *);
+void finish_execplus(void);
+
+creat_f c_Xmin;
+creat_f c_Xtime;
+creat_f c_acl;
+creat_f c_and;
+creat_f c_delete;
+creat_f c_depth;
+creat_f c_empty;
+creat_f c_exec;
+creat_f c_flags;
+creat_f c_follow;
+creat_f c_fstype;
+creat_f c_group;
+creat_f c_inum;
+creat_f c_links;
+creat_f c_ls;
+creat_f c_mXXdepth;
+creat_f c_name;
+creat_f c_newer;
+creat_f c_nogroup;
+creat_f c_nouser;
+creat_f c_perm;
+creat_f c_print;
+creat_f c_regex;
+creat_f c_samefile;
+creat_f c_simple;
+creat_f c_size;
+creat_f c_type;
+creat_f c_user;
+creat_f c_xdev;
+
+exec_f f_Xmin;
+exec_f f_Xtime;
+exec_f f_acl;
+exec_f f_always_true;
+exec_f f_closeparen;
+exec_f f_delete;
+exec_f f_depth;
+exec_f f_empty;
+exec_f f_exec;
+exec_f f_expr;
+exec_f f_false;
+exec_f f_flags;
+exec_f f_fstype;
+exec_f f_group;
+exec_f f_inum;
+exec_f f_links;
+exec_f f_ls;
+exec_f f_name;
+exec_f f_newer;
+exec_f f_nogroup;
+exec_f f_not;
+exec_f f_nouser;
+exec_f f_openparen;
+exec_f f_or;
+exec_f f_path;
+exec_f f_perm;
+exec_f f_print;
+exec_f f_print0;
+exec_f f_prune;
+exec_f f_quit;
+exec_f f_regex;
+exec_f f_size;
+exec_f f_type;
+exec_f f_user;
+#ifdef __APPLE__
+exec_f f_xattr;
+exec_f f_xattrname;
+#endif /* __APPLE__ */
+
+extern int ftsoptions, isdeprecated, isdepth, isoutput, issort, isxargs;
+extern int mindepth, maxdepth;
+extern int regexp_flags;
+extern time_t now;
+extern int dotfd;
+extern FTS *tree;
+extern int execplus_error;
diff --git a/shell_cmds/find/find.1 b/shell_cmds/find/find.1
new file mode 100644
index 0000000..c6bb28f
--- /dev/null
+++ b/shell_cmds/find/find.1
@@ -0,0 +1,1078 @@
+.\" Copyright (c) 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)find.1 8.7 (Berkeley) 5/9/95
+.\" $FreeBSD: src/usr.bin/find/find.1,v 1.91 2011/09/28 18:53:36 ed Exp $
+.\"
+.Dd September 28, 2011
+.Dt FIND 1
+.Os
+.Sh NAME
+.Nm find
+.Nd walk a file hierarchy
+.Sh SYNOPSIS
+.Nm
+.Op Fl H | Fl L | Fl P
+.Op Fl EXdsx
+.Op Fl f Ar path
+.Ar path ...
+.Op Ar expression
+.Nm
+.Op Fl H | Fl L | Fl P
+.Op Fl EXdsx
+.Fl f Ar path
+.Op Ar path ...
+.Op Ar expression
+.Sh DESCRIPTION
+The
+.Nm
+utility recursively descends the directory tree for each
+.Ar path
+listed, evaluating an
+.Ar expression
+(composed of the
+.Dq primaries
+and
+.Dq operands
+listed below) in terms
+of each file in the tree.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl E
+Interpret regular expressions followed by
+.Ic -regex
+and
+.Ic -iregex
+primaries as extended (modern) regular expressions rather than basic
+regular expressions (BRE's).
+The
+.Xr re_format 7
+manual page fully describes both formats.
+.It Fl H
+Cause the file information and file type (see
+.Xr stat 2 )
+returned for each symbolic link specified on the command line to be
+those of the file referenced by the link, not the link itself.
+If the referenced file does not exist, the file information and type will
+be for the link itself.
+File information of all symbolic links not on
+the command line is that of the link itself.
+.It Fl L
+Cause the file information and file type (see
+.Xr stat 2 )
+returned for each symbolic link to be those of the file referenced by the
+link, not the link itself.
+If the referenced file does not exist, the file information and type will
+be for the link itself.
+.Pp
+This option is equivalent to the deprecated
+.Ic -follow
+primary.
+.It Fl P
+Cause the file information and file type (see
+.Xr stat 2 )
+returned for each symbolic link to be those of the link itself.
+This is the default.
+.It Fl X
+Permit
+.Nm
+to be safely used in conjunction with
+.Xr xargs 1 .
+If a file name contains any of the delimiting characters used by
+.Xr xargs 1 ,
+a diagnostic message is displayed on standard error, and the file
+is skipped.
+The delimiting characters include single
+.Pq Dq Li " ' "
+and double
+.Pq Dq Li " \*q "
+quotes, backslash
+.Pq Dq Li \e ,
+space, tab and newline characters.
+.Pp
+However, you may wish to consider the
+.Fl print0
+primary in conjunction with
+.Dq Nm xargs Fl 0
+as an effective alternative.
+.It Fl d
+Cause
+.Nm
+to perform a depth-first traversal, i.e., directories
+are visited in post-order and all entries in a directory will be acted
+on before the directory itself.
+By default,
+.Nm
+visits directories in pre-order, i.e., before their contents.
+Note, the default is
+.Em not
+a breadth-first traversal.
+.Pp
+This option is equivalent to the
+.Ic -depth
+primary of
+.St -p1003.1-2001 .
+The
+.Fl d
+option
+can be useful when
+.Nm
+is used with
+.Xr cpio 1
+to process files that are contained in directories with unusual permissions.
+It ensures that you have write permission while you are placing files in a
+directory, then sets the directory's permissions as the last thing.
+.It Fl f
+Specify a file hierarchy for
+.Nm
+to traverse.
+File hierarchies may also be specified as the operands immediately
+following the options.
+.It Fl s
+Cause
+.Nm
+to traverse the file hierarchies in lexicographical order,
+i.e., alphabetical order within each directory.
+Note:
+.Ql find -s
+and
+.Ql "find | sort"
+may give different results.
+.It Fl x
+Prevent
+.Nm
+from descending into directories that have a device number different
+than that of the file from which the descent began.
+.Pp
+This option is equivalent to the deprecated
+.Ic -xdev
+primary.
+.El
+.Sh PRIMARIES
+.Pp
+All primaries which take a numeric argument allow the number to be
+preceded by a plus sign
+.Pq Dq Li +
+or a minus sign
+.Pq Dq Li - .
+A preceding plus sign means
+.Dq more than n ,
+a preceding minus sign means
+.Dq less than n
+and neither means
+.Dq exactly n .
+.Bl -tag -width indent
+.It Ic -Bmin Ar n
+True if the difference between the time of a file's inode creation
+and the time
+.Nm
+was started, rounded up to the next full minute, is
+.Ar n
+minutes.
+.It Ic -Bnewer Ar file
+Same as
+.Ic -newerBm .
+.It Ic -Btime Ar n Ns Op Cm smhdw
+If no units are specified, this primary evaluates to
+true if the difference between the time of a file's inode creation
+and the time
+.Nm
+was started, rounded up to the next full 24-hour period, is
+.Ar n
+24-hour periods.
+.Pp
+If units are specified, this primary evaluates to
+true if the difference between the time of a file's inode creation
+and the time
+.Nm
+was started is exactly
+.Ar n
+units.
+Please refer to the
+.Ic -atime
+primary description for information on supported time units.
+.It Ic -acl
+May be used in conjunction with other primaries to locate
+files with extended ACLs.
+See
+.Xr acl 3
+for more information.
+.It Ic -amin Ar n
+True if the difference between the file last access time and the time
+.Nm
+was started, rounded up to the next full minute, is
+.Ar n
+minutes.
+.It Ic -anewer Ar file
+Same as
+.Ic -neweram .
+.It Ic -atime Ar n Ns Op Cm smhdw
+If no units are specified, this primary evaluates to
+true if the difference between the file last access time and the time
+.Nm
+was started, rounded up to the next full 24-hour period, is
+.Ar n
+24-hour periods.
+.Pp
+If units are specified, this primary evaluates to
+true if the difference between the file last access time and the time
+.Nm
+was started is exactly
+.Ar n
+units.
+Possible time units are as follows:
+.Pp
+.Bl -tag -width indent -compact
+.It Cm s
+second
+.It Cm m
+minute (60 seconds)
+.It Cm h
+hour (60 minutes)
+.It Cm d
+day (24 hours)
+.It Cm w
+week (7 days)
+.El
+.Pp
+Any number of units may be combined in one
+.Ic -atime
+argument, for example,
+.Dq Li "-atime -1h30m" .
+Units are probably only useful when used in conjunction with the
+.Cm +
+or
+.Cm -
+modifier.
+.It Ic -cmin Ar n
+True if the difference between the time of last change of file status
+information and the time
+.Nm
+was started, rounded up to the next full minute, is
+.Ar n
+minutes.
+.It Ic -cnewer Ar file
+Same as
+.Ic -newercm .
+.It Ic -ctime Ar n Ns Op Cm smhdw
+If no units are specified, this primary evaluates to
+true if the difference between the time of last change of file status
+information and the time
+.Nm
+was started, rounded up to the next full 24-hour period, is
+.Ar n
+24-hour periods.
+.Pp
+If units are specified, this primary evaluates to
+true if the difference between the time of last change of file status
+information and the time
+.Nm
+was started is exactly
+.Ar n
+units.
+Please refer to the
+.Ic -atime
+primary description for information on supported time units.
+.It Ic -d
+Same as
+.Ic depth .
+GNU find implements this as a primary in mistaken emulation of
+.Fx
+.Xr find 1 .
+.It Ic -delete
+Delete found files and/or directories.
+Always returns true.
+This executes
+from the current working directory as
+.Nm
+recurses down the tree.
+It will not attempt to delete a filename with a
+.Dq Pa /
+character in its pathname relative to
+.Dq Pa \&.
+for security reasons.
+Depth-first traversal processing is implied by this option.
+Following symlinks is incompatible with this option.
+.It Ic -depth
+Always true;
+same as the
+.Fl d
+option.
+.It Ic -depth Ar n
+True if the depth of the file relative to the starting point of the traversal
+is
+.Ar n .
+.It Ic -empty
+True if the current file or directory is empty.
+.It Ic -exec Ar utility Oo Ar argument ... Oc Li \&;
+True if the program named
+.Ar utility
+returns a zero value as its exit status.
+Optional
+.Ar arguments
+may be passed to the utility.
+The expression must be terminated by a semicolon
+.Pq Dq Li \&; .
+If you invoke
+.Nm
+from a shell you may need to quote the semicolon if the shell would
+otherwise treat it as a control operator.
+If the string
+.Dq Li {}
+appears anywhere in the utility name or the
+arguments it is replaced by the pathname of the current file.
+.Ar Utility
+will be executed from the directory from which
+.Nm
+was executed.
+.Ar Utility
+and
+.Ar arguments
+are not subject to the further expansion of shell patterns
+and constructs.
+.It Ic -exec Ar utility Oo Ar argument ... Oc Li {} +
+Same as
+.Ic -exec ,
+except that
+.Dq Li {}
+is replaced with as many pathnames as possible for each invocation of
+.Ar utility .
+This behaviour is similar to that of
+.Xr xargs 1 .
+.It Ic -execdir Ar utility Oo Ar argument ... Oc Li \&;
+The
+.Ic -execdir
+primary is identical to the
+.Ic -exec
+primary with the exception that
+.Ar utility
+will be executed from the directory that holds
+the current file.
+The filename substituted for
+the string
+.Dq Li {}
+is not qualified.
+.It Ic -execdir Ar utility Oo Ar argument ... Oc Li {} +
+Same as
+.Ic -execdir ,
+except that
+.Dq Li {}
+is replaced with as many pathnames as possible for each invocation of
+.Ar utility .
+This behaviour is similar to that of
+.Xr xargs 1 .
+.It Ic -flags Oo Cm - Ns | Ns Cm + Oc Ns Ar flags , Ns Ar notflags
+The flags are specified using symbolic names (see
+.Xr chflags 1 ) .
+Those with the
+.Qq Li no
+prefix (except
+.Qq Li nodump )
+are said to be
+.Ar notflags .
+Flags in
+.Ar flags
+are checked to be set, and flags in
+.Ar notflags
+are checked to be not set.
+Note that this is different from
+.Ic -perm ,
+which only allows the user to specify mode bits that are set.
+.Pp
+If flags are preceded by a dash
+.Pq Dq Li - ,
+this primary evaluates to true
+if at least all of the bits in
+.Ar flags
+and none of the bits in
+.Ar notflags
+are set in the file's flags bits.
+If flags are preceded by a plus
+.Pq Dq Li + ,
+this primary evaluates to true
+if any of the bits in
+.Ar flags
+is set in the file's flags bits,
+or any of the bits in
+.Ar notflags
+is not set in the file's flags bits.
+Otherwise,
+this primary evaluates to true
+if the bits in
+.Ar flags
+exactly match the file's flags bits,
+and none of the
+.Ar flags
+bits match those of
+.Ar notflags .
+.It Ic -fstype Ar type
+True if the file is contained in a file system of type
+.Ar type .
+The
+.Xr lsvfs 1
+command can be used to find out the types of file systems
+that are available on the system.
+In addition, there are two pseudo-types,
+.Dq Li local
+and
+.Dq Li rdonly .
+The former matches any file system physically mounted on the system where
+the
+.Nm
+is being executed and the latter matches any file system which is
+mounted read-only.
+.It Ic -gid Ar gname
+The same thing as
+.Ar -group Ar gname
+for compatibility with GNU find.
+GNU find imposes a restriction that
+.Ar gname
+is numeric, while
+.Xr find 1
+does not.
+.It Ic -group Ar gname
+True if the file belongs to the group
+.Ar gname .
+If
+.Ar gname
+is numeric and there is no such group name, then
+.Ar gname
+is treated as a group ID.
+.It Ic -ignore_readdir_race
+This option is for GNU find compatibility and is ignored.
+.It Ic -ilname Ar pattern
+Like
+.Ic -lname ,
+but the match is case insensitive.
+This is a GNU find extension.
+.It Ic -iname Ar pattern
+Like
+.Ic -name ,
+but the match is case insensitive.
+.It Ic -inum Ar n
+True if the file has inode number
+.Ar n .
+.It Ic -ipath Ar pattern
+Like
+.Ic -path ,
+but the match is case insensitive.
+.It Ic -iregex Ar pattern
+Like
+.Ic -regex ,
+but the match is case insensitive.
+.It Ic -iwholename Ar pattern
+The same thing as
+.Ic -ipath ,
+for GNU find compatibility.
+.It Ic -links Ar n
+True if the file has
+.Ar n
+links.
+.It Ic -lname Ar pattern
+Like
+.Ic -name ,
+but the contents of the symbolic link are matched instead of the file
+name.
+Note that this only matches broken symbolic links
+if symbolic links are being followed.
+This is a GNU find extension.
+.It Ic -ls
+This primary always evaluates to true.
+The following information for the current file is written to standard output:
+its inode number, size in 512-byte blocks, file permissions, number of hard
+links, owner, group, size in bytes, last modification time, and pathname.
+If the file is a block or character special file, the device number
+will be displayed instead of the size in bytes.
+If the file is a symbolic link, the pathname of the linked-to file will be
+displayed preceded by
+.Dq Li -> .
+The format is identical to that produced by
+.Bk -words
+.Dq Nm ls Fl dgils .
+.Ek
+.It Ic -maxdepth Ar n
+Always true; descend at most
+.Ar n
+directory levels below the command line arguments.
+If any
+.Ic -maxdepth
+primary is specified, it applies to the entire expression even if it would
+not normally be evaluated.
+.Dq Ic -maxdepth Li 0
+limits the whole search to the command line arguments.
+.It Ic -mindepth Ar n
+Always true; do not apply any tests or actions at levels less than
+.Ar n .
+If any
+.Ic -mindepth
+primary is specified, it applies to the entire expression even if it would
+not normally be evaluated.
+.Dq Ic -mindepth Li 1
+processes all but the command line arguments.
+.It Ic -mmin Ar n
+True if the difference between the file last modification time and the time
+.Nm
+was started, rounded up to the next full minute, is
+.Ar n
+minutes.
+.It Ic -mnewer Ar file
+Same as
+.Ic -newer .
+.It Ic -mount
+The same thing as
+.Ic -xdev ,
+for GNU find compatibility.
+.It Ic -mtime Ar n Ns Op Cm smhdw
+If no units are specified, this primary evaluates to
+true if the difference between the file last modification time and the time
+.Nm
+was started, rounded up to the next full 24-hour period, is
+.Ar n
+24-hour periods.
+.Pp
+If units are specified, this primary evaluates to
+true if the difference between the file last modification time and the time
+.Nm
+was started is exactly
+.Ar n
+units.
+Please refer to the
+.Ic -atime
+primary description for information on supported time units.
+.It Ic -name Ar pattern
+True if the last component of the pathname being examined matches
+.Ar pattern .
+Special shell pattern matching characters
+.Dq ( Li \&[ ,
+.Dq Li \&] ,
+.Dq Li * ,
+and
+.Dq Li \&? )
+may be used as part of
+.Ar pattern .
+These characters may be matched explicitly by escaping them with a
+backslash
+.Pq Dq Li \e .
+.It Ic -newer Ar file
+True if the current file has a more recent last modification time than
+.Ar file .
+.It Ic -newer Ns Ar X Ns Ar Y Ar file
+True if the current file has a more recent last access time
+.Pq Ar X Ns = Ns Cm a ,
+inode creation time
+.Pq Ar X Ns = Ns Cm B ,
+change time
+.Pq Ar X Ns = Ns Cm c ,
+or modification time
+.Pq Ar X Ns = Ns Cm m
+than the last access time
+.Pq Ar Y Ns = Ns Cm a ,
+inode creation time
+.Pq Ar Y Ns = Ns Cm B ,
+change time
+.Pq Ar Y Ns = Ns Cm c ,
+or modification time
+.Pq Ar Y Ns = Ns Cm m
+of
+.Ar file .
+In addition, if
+.Ar Y Ns = Ns Cm t ,
+then
+.Ar file
+is instead interpreted as a direct date specification of the form
+understood by
+.Xr cvs 1 .
+Note that
+.Ic -newermm
+is equivalent to
+.Ic -newer .
+.It Ic -nogroup
+True if the file belongs to an unknown group.
+.It Ic -noignore_readdir_race
+This option is for GNU find compatibility and is ignored.
+.It Ic -noleaf
+This option is for GNU find compatibility.
+In GNU find it disables an optimization not relevant to
+.Xr find 1 ,
+so it is ignored.
+.It Ic -nouser
+True if the file belongs to an unknown user.
+.It Ic -ok Ar utility Oo Ar argument ... Oc Li \&;
+The
+.Ic -ok
+primary is identical to the
+.Ic -exec
+primary with the exception that
+.Nm
+requests user affirmation for the execution of the
+.Ar utility
+by printing
+a message to the terminal and reading a response.
+If the response is not affirmative
+.Ql ( y
+in the
+.Dq Li POSIX
+locale),
+the command is not executed and the
+value of the
+.Ic -ok
+expression is false.
+.It Ic -okdir Ar utility Oo Ar argument ... Oc Li \&;
+The
+.Ic -okdir
+primary is identical to the
+.Ic -execdir
+primary with the same exception as described for the
+.Ic -ok
+primary.
+.It Ic -path Ar pattern
+True if the pathname being examined matches
+.Ar pattern .
+Special shell pattern matching characters
+.Dq ( Li \&[ ,
+.Dq Li \&] ,
+.Dq Li * ,
+and
+.Dq Li \&? )
+may be used as part of
+.Ar pattern .
+These characters may be matched explicitly by escaping them with a
+backslash
+.Pq Dq Li \e .
+Slashes
+.Pq Dq Li /
+are treated as normal characters and do not have to be
+matched explicitly.
+.It Ic -perm Oo Cm - Ns | Ns Cm + Oc Ns Ar mode
+The
+.Ar mode
+may be either symbolic (see
+.Xr chmod 1 )
+or an octal number.
+If the
+.Ar mode
+is symbolic, a starting value of zero is assumed and the
+.Ar mode
+sets or clears permissions without regard to the process' file mode
+creation mask.
+If the
+.Ar mode
+is octal, only bits 07777
+.Pq Dv S_ISUID | S_ISGID | S_ISTXT | S_IRWXU | S_IRWXG | S_IRWXO
+of the file's mode bits participate
+in the comparison.
+If the
+.Ar mode
+is preceded by a dash
+.Pq Dq Li - ,
+this primary evaluates to true
+if at least all of the bits in the
+.Ar mode
+are set in the file's mode bits.
+If the
+.Ar mode
+is preceded by a plus
+.Pq Dq Li + ,
+this primary evaluates to true
+if any of the bits in the
+.Ar mode
+are set in the file's mode bits.
+Otherwise, this primary evaluates to true if
+the bits in the
+.Ar mode
+exactly match the file's mode bits.
+Note, the first character of a symbolic mode may not be a dash
+.Pq Dq Li - .
+.It Ic -print
+This primary always evaluates to true.
+It prints the pathname of the current file to standard output.
+If none of
+.\" 4772561
+.Ic -exec , -ls , -print , -print0 ,
+or
+.Ic -ok
+is specified, the given expression shall be effectively replaced by
+.Cm \&( Ar "given expression" Cm \&) Ic -print .
+.It Ic -print0
+This primary always evaluates to true.
+It prints the pathname of the current file to standard output, followed by an
+.Tn ASCII
+.Dv NUL
+character (character code 0).
+.It Ic -prune
+This primary always evaluates to true.
+It causes
+.Nm
+to not descend into the current file.
+Note, the
+.Ic -prune
+primary has no effect if the
+.Fl d
+option was specified.
+.It Ic -regex Ar pattern
+True if the whole path of the file matches
+.Ar pattern
+using regular expression.
+To match a file named
+.Dq Pa ./foo/xyzzy ,
+you can use the regular expression
+.Dq Li ".*/[xyz]*"
+or
+.Dq Li ".*/foo/.*" ,
+but not
+.Dq Li xyzzy
+or
+.Dq Li /foo/ .
+.It Ic -samefile Ar name
+True if the file is a hard link to
+.Ar name .
+If the command option
+.Ic -L
+is specified, it is also true if the file is a symbolic link and
+points to
+.Ar name .
+.It Ic -size Ar n Ns Op Cm ckMGTP
+True if the file's size, rounded up, in 512-byte blocks is
+.Ar n .
+If
+.Ar n
+is followed by a
+.Cm c ,
+then the primary is true if the
+file's size is
+.Ar n
+bytes (characters).
+Similarly if
+.Ar n
+is followed by a scale indicator then the file's size is compared to
+.Ar n
+scaled as:
+.Pp
+.Bl -tag -width indent -compact
+.It Cm k
+kilobytes (1024 bytes)
+.It Cm M
+megabytes (1024 kilobytes)
+.It Cm G
+gigabytes (1024 megabytes)
+.It Cm T
+terabytes (1024 gigabytes)
+.It Cm P
+petabytes (1024 terabytes)
+.El
+.It Ic -type Ar t
+True if the file is of the specified type.
+Possible file types are as follows:
+.Pp
+.Bl -tag -width indent -compact
+.It Cm b
+block special
+.It Cm c
+character special
+.It Cm d
+directory
+.It Cm f
+regular file
+.It Cm l
+symbolic link
+.It Cm p
+FIFO
+.It Cm s
+socket
+.El
+.It Ic -uid Ar uname
+The same thing as
+.Ar -user Ar uname
+for compatibility with GNU find.
+GNU find imposes a restriction that
+.Ar uname
+is numeric, while
+.Xr find 1
+does not.
+.It Ic -user Ar uname
+True if the file belongs to the user
+.Ar uname .
+If
+.Ar uname
+is numeric and there is no such user name, then
+.Ar uname
+is treated as a user ID.
+.It Ic -wholename Ar pattern
+The same thing as
+.Ic -path ,
+for GNU find compatibility.
+.It Ic -xattr
+True if the file has any extended attributes.
+.It Ic -xattrname Ar name
+True if the file has an extended attribute with the specified
+.Ar name .
+.El
+.Sh OPERATORS
+The primaries may be combined using the following operators.
+The operators are listed in order of decreasing precedence.
+.Pp
+.Bl -tag -width indent -compact
+.It Cm \&( Ar expression Cm \&)
+This evaluates to true if the parenthesized expression evaluates to
+true.
+.Pp
+.It Cm \&! Ar expression
+.It Cm -not Ar expression
+This is the unary
+.Tn NOT
+operator.
+It evaluates to true if the expression is false.
+.Pp
+.It Cm -false
+Always false.
+.It Cm -true
+Always true.
+.Pp
+.It Ar expression Cm -and Ar expression
+.It Ar expression expression
+The
+.Cm -and
+operator is the logical
+.Tn AND
+operator.
+As it is implied by the juxtaposition of two expressions it does not
+have to be specified.
+The expression evaluates to true if both expressions are true.
+The second expression is not evaluated if the first expression is false.
+.Pp
+.It Ar expression Cm -or Ar expression
+The
+.Cm -or
+operator is the logical
+.Tn OR
+operator.
+The expression evaluates to true if either the first or the second expression
+is true.
+The second expression is not evaluated if the first expression is true.
+.El
+.Pp
+All operands and primaries must be separate arguments to
+.Nm .
+Primaries which themselves take arguments expect each argument
+to be a separate argument to
+.Nm .
+.Sh ENVIRONMENT
+The
+.Ev LANG , LC_ALL , LC_COLLATE , LC_CTYPE , LC_MESSAGES
+and
+.Ev LC_TIME
+environment variables affect the execution of the
+.Nm
+utility as described in
+.Xr environ 7 .
+.Sh EXAMPLES
+The following examples are shown as given to the shell:
+.Bl -tag -width indent
+.It Li "find / \e! -name \*q*.c\*q -print"
+Print out a list of all the files whose names do not end in
+.Pa .c .
+.It Li "find / -newer ttt -user wnj -print"
+Print out a list of all the files owned by user
+.Dq wnj
+that are newer
+than the file
+.Pa ttt .
+.It Li "find / \e! \e( -newer ttt -user wnj \e) -print"
+Print out a list of all the files which are not both newer than
+.Pa ttt
+and owned by
+.Dq wnj .
+.It Li "find / \e( -newer ttt -or -user wnj \e) -print"
+Print out a list of all the files that are either owned by
+.Dq wnj
+or that are newer than
+.Pa ttt .
+.It Li "find / -newerct '1 minute ago' -print"
+Print out a list of all the files whose inode change time is more
+recent than the current time minus one minute.
+.It Li "find / -type f -exec echo {} \e;"
+Use the
+.Xr echo 1
+command to print out a list of all the files.
+.It Li "find -L /usr/ports/packages -type l -exec rm -- {} +"
+Delete all broken symbolic links in
+.Pa /usr/ports/packages .
+.It Li "find /usr/src -name CVS -prune -o -depth +6 -print"
+Find files and directories that are at least seven levels deep
+in the working directory
+.Pa /usr/src .
+.It Li "find /usr/src -name CVS -prune -o -mindepth 7 -print"
+Is not equivalent to the previous example, since
+.Ic -prune
+is not evaluated below level seven.
+.El
+.Sh COMPATIBILITY
+The
+.Ic -follow
+primary is deprecated; the
+.Fl L
+option should be used instead.
+See the
+.Sx STANDARDS
+section below for details.
+.Sh SEE ALSO
+.Xr chflags 1 ,
+.Xr chmod 1 ,
+.Xr cvs 1 ,
+.Xr locate 1 ,
+.Xr lsvfs 1 ,
+.Xr whereis 1 ,
+.Xr which 1 ,
+.Xr xargs 1 ,
+.Xr stat 2 ,
+.Xr acl 3 ,
+.Xr fts 3 ,
+.Xr getgrent 3 ,
+.Xr getpwent 3 ,
+.Xr strmode 3 ,
+.Xr re_format 7 ,
+.Xr symlink 7
+.Sh STANDARDS
+The
+.Nm
+utility syntax is a superset of the syntax specified by the
+.St -p1003.1-2001
+standard.
+.Pp
+All the single character options except
+.Fl H
+and
+.Fl L
+as well as
+.Ic -amin , -anewer , -cmin , -cnewer , -delete , -empty , -fstype ,
+.Ic -iname , -inum , -iregex , -ls , -maxdepth , -mindepth , -mmin ,
+.Ic -path , -print0 , -regex
+and all of the
+.Ic -B*
+birthtime related primaries are extensions to
+.St -p1003.1-2001 .
+.Pp
+Historically, the
+.Fl d , L
+and
+.Fl x
+options were implemented using the primaries
+.Ic -depth , -follow ,
+and
+.Ic -xdev .
+These primaries always evaluated to true.
+As they were really global variables that took effect before the traversal
+began, some legal expressions could have unexpected results.
+An example is the expression
+.Ic -print Cm -o Ic -depth .
+As
+.Ic -print
+always evaluates to true, the standard order of evaluation
+implies that
+.Ic -depth
+would never be evaluated.
+This is not the case.
+.Pp
+The operator
+.Cm -or
+was implemented as
+.Cm -o ,
+and the operator
+.Cm -and
+was implemented as
+.Cm -a .
+.Pp
+Historic implementations of the
+.Ic -exec
+and
+.Ic -ok
+primaries did not replace the string
+.Dq Li {}
+in the utility name or the
+utility arguments if it had preceding or following non-whitespace characters.
+This version replaces it no matter where in the utility name or arguments
+it appears.
+.Pp
+The
+.Fl E
+option was inspired by the equivalent
+.Xr grep 1
+and
+.Xr sed 1
+options.
+.Sh HISTORY
+A
+.Nm
+command appeared in
+.At v1 .
+.Sh BUGS
+The special characters used by
+.Nm
+are also special characters to many shell programs.
+In particular, the characters
+.Dq Li * ,
+.Dq Li \&[ ,
+.Dq Li \&] ,
+.Dq Li \&? ,
+.Dq Li \&( ,
+.Dq Li \&) ,
+.Dq Li \&! ,
+.Dq Li \e
+and
+.Dq Li \&;
+may have to be escaped from the shell.
+.Pp
+As there is no delimiter separating options and file names or file
+names and the
+.Ar expression ,
+it is difficult to specify files named
+.Pa -xdev
+or
+.Pa \&! .
+These problems are handled by the
+.Fl f
+option and the
+.Xr getopt 3
+.Dq Fl Fl
+construct.
+.Pp
+The
+.Ic -delete
+primary does not interact well with other options that cause the file system
+tree traversal options to be changed.
+.Pp
+The
+.Ic -mindepth
+and
+.Ic -maxdepth
+primaries are actually global options (as documented above).
+They should
+probably be replaced by options which look like options.
diff --git a/shell_cmds/find/find.c b/shell_cmds/find/find.c
new file mode 100644
index 0000000..c59a75a
--- /dev/null
+++ b/shell_cmds/find/find.c
@@ -0,0 +1,323 @@
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Cimarron D. Taylor of the University of California, Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)find.c 8.5 (Berkeley) 8/5/94";
+#else
+#endif
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/find/find.c,v 1.23 2010/12/11 08:32:16 joel Exp $");
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fts.h>
+#include <regex.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef __APPLE__
+#include <get_compat.h>
+#include <unistd.h>
+#else
+#define COMPAT_MODE(func, mode) 1
+#endif
+
+#include "find.h"
+
+#ifdef __APPLE__
+static int find_compare(const FTSENT **s1, const FTSENT **s2);
+#else /* !__APPLE__ */
+static int find_compare(const FTSENT * const *s1, const FTSENT * const *s2);
+#endif /* __APPLE__ */
+
+/*
+ * find_compare --
+ * tell fts_open() how to order the traversal of the hierarchy.
+ * This variant gives lexicographical order, i.e., alphabetical
+ * order within each directory.
+ */
+static int
+#ifdef __APPLE__
+find_compare(const FTSENT **s1, const FTSENT **s2)
+#else /* !__APPLE__ */
+find_compare(const FTSENT * const *s1, const FTSENT * const *s2)
+#endif /* __APPLE__ */
+{
+
+ return (strcoll((*s1)->fts_name, (*s2)->fts_name));
+}
+
+/*
+ * find_formplan --
+ * process the command line and create a "plan" corresponding to the
+ * command arguments.
+ */
+PLAN *
+find_formplan(char *argv[])
+{
+ PLAN *plan, *tail, *new;
+
+ /*
+ * for each argument in the command line, determine what kind of node
+ * it is, create the appropriate node type and add the new plan node
+ * to the end of the existing plan. The resulting plan is a linked
+ * list of plan nodes. For example, the string:
+ *
+ * % find . -name foo -newer bar -print
+ *
+ * results in the plan:
+ *
+ * [-name foo]--> [-newer bar]--> [-print]
+ *
+ * in this diagram, `[-name foo]' represents the plan node generated
+ * by c_name() with an argument of foo and `-->' represents the
+ * plan->next pointer.
+ */
+ for (plan = tail = NULL; *argv;) {
+ if (!(new = find_create(&argv)))
+ continue;
+ if (plan == NULL)
+ tail = plan = new;
+ else {
+ tail->next = new;
+ tail = new;
+ }
+ }
+
+ /*
+ * if the user didn't specify one of -print, -ok or -exec, then -print
+ * is assumed so we bracket the current expression with parens, if
+ * necessary, and add a -print node on the end.
+ */
+ if (!isoutput) {
+ OPTION *p;
+ char **argv1 = 0;
+
+ if (plan == NULL) {
+ p = lookup_option("-print");
+ new = (p->create)(p, &argv1);
+ tail = plan = new;
+ } else {
+ p = lookup_option("(");
+ new = (p->create)(p, &argv1);
+ new->next = plan;
+ plan = new;
+ p = lookup_option(")");
+ new = (p->create)(p, &argv1);
+ tail->next = new;
+ tail = new;
+ p = lookup_option("-print");
+ new = (p->create)(p, &argv1);
+ tail->next = new;
+ tail = new;
+ }
+ }
+
+ /*
+ * the command line has been completely processed into a search plan
+ * except for the (, ), !, and -o operators. Rearrange the plan so
+ * that the portions of the plan which are affected by the operators
+ * are moved into operator nodes themselves. For example:
+ *
+ * [!]--> [-name foo]--> [-print]
+ *
+ * becomes
+ *
+ * [! [-name foo] ]--> [-print]
+ *
+ * and
+ *
+ * [(]--> [-depth]--> [-name foo]--> [)]--> [-print]
+ *
+ * becomes
+ *
+ * [expr [-depth]-->[-name foo] ]--> [-print]
+ *
+ * operators are handled in order of precedence.
+ */
+
+ plan = paren_squish(plan); /* ()'s */
+ plan = not_squish(plan); /* !'s */
+ plan = or_squish(plan); /* -o's */
+ return (plan);
+}
+
+/* addPath - helper function used to build a list of paths that were
+ * specified on the command line that we are allowed to search.
+ */
+static char **addPath(char **array, char *newPath)
+{
+ static int pathCounter = 0;
+
+ if (newPath == NULL) { /* initialize array */
+ if ((array = malloc(sizeof(char *))) == NULL)
+ err(2, "out of memory");
+ array[0] = NULL;
+ }
+ else {
+ array = realloc(array, (++pathCounter + 1) * sizeof(char *));
+ if (array == NULL)
+ err(2, "out of memory");
+ else {
+ array[pathCounter - 1] = newPath;
+ array[pathCounter] = NULL; /* ensure array is null terminated */
+ }
+ }
+ return (array);
+}
+
+FTS *tree; /* pointer to top of FTS hierarchy */
+
+/*
+ * find_execute --
+ * take a search plan and an array of search paths and executes the plan
+ * over all FTSENT's returned for the given search paths.
+ */
+int
+find_execute(PLAN *plan, char *paths[])
+{
+ FTSENT *entry;
+ PLAN *p;
+ int rval;
+ char **myPaths;
+ int nonSearchableDirFound = 0;
+ int pathIndex;
+ struct stat statInfo;
+
+ /* special-case directories specified on command line - explicitly examine
+ * mode bits, to ensure failure if the directory cannot be searched
+ * (whether or not it's empty). UNIX conformance... <sigh>
+ */
+
+ int strict_symlinks = (ftsoptions & (FTS_COMFOLLOW|FTS_LOGICAL))
+ && COMPAT_MODE("bin/find", "unix2003");
+
+ myPaths = addPath(NULL, NULL);
+ for (pathIndex = 0; paths[pathIndex] != NULL; ++pathIndex) {
+ int stat_ret = stat(paths[pathIndex], &statInfo);
+ int stat_errno = errno;
+ if (strict_symlinks && stat_ret < 0) {
+ if (stat_errno == ELOOP) {
+ errx(1, "Symlink loop resolving %s", paths[pathIndex]);
+ }
+ }
+
+ /* retrieve mode bits, and examine "searchable" bit of
+ directories, exempt root from POSIX conformance */
+ if (COMPAT_MODE("bin/find", "unix2003") && getuid()
+ && stat_ret == 0
+ && ((statInfo.st_mode & S_IFMT) == S_IFDIR)) {
+ if (access(paths[pathIndex], X_OK) == 0) {
+ myPaths = addPath(myPaths, paths[pathIndex]);
+ } else {
+ if (stat_errno != ENAMETOOLONG) { /* if name is too long, just let existing logic handle it */
+ warnx("%s: Permission denied", paths[pathIndex]);
+ nonSearchableDirFound = 1;
+ }
+ }
+ } else {
+ /* not a directory, so add path to array */
+ myPaths = addPath(myPaths, paths[pathIndex]);
+ }
+ }
+ if (myPaths[0] == NULL) { /* were any directories searchable? */
+ free(myPaths);
+ return(nonSearchableDirFound); /* no... */
+ }
+
+ tree = fts_open(myPaths, ftsoptions, (issort ? find_compare : NULL));
+ if (tree == NULL)
+ err(1, "ftsopen");
+
+ for (rval = nonSearchableDirFound; (entry = fts_read(tree)) != NULL;) {
+ if (maxdepth != -1 && entry->fts_level >= maxdepth) {
+ if (fts_set(tree, entry, FTS_SKIP))
+ err(1, "%s", entry->fts_path);
+ }
+
+ switch (entry->fts_info) {
+ case FTS_D:
+ if (isdepth)
+ continue;
+ break;
+ case FTS_DP:
+ if (!isdepth)
+ continue;
+ break;
+ case FTS_DNR:
+ case FTS_ERR:
+ case FTS_NS:
+ (void)fflush(stdout);
+ warnx("%s: %s",
+ entry->fts_path, strerror(entry->fts_errno));
+ rval = 1;
+ continue;
+#ifdef FTS_W
+ case FTS_W:
+ continue;
+#endif /* FTS_W */
+ }
+#define BADCH " \t\n\\'\""
+ if (isxargs && strpbrk(entry->fts_path, BADCH)) {
+ (void)fflush(stdout);
+ warnx("%s: illegal path", entry->fts_path);
+ rval = 1;
+ continue;
+ }
+
+ if (mindepth != -1 && entry->fts_level < mindepth)
+ continue;
+
+ /*
+ * Call all the functions in the execution plan until one is
+ * false or all have been executed. This is where we do all
+ * the work specified by the user on the command line.
+ */
+ for (p = plan; p && (p->execute)(p, entry); p = p->next);
+ }
+ free (myPaths);
+ finish_execplus();
+ if (execplus_error) {
+ exit(execplus_error);
+ }
+ if (errno)
+ err(1, "fts_read");
+ fts_close(tree);
+ return (rval);
+}
diff --git a/shell_cmds/find/find.h b/shell_cmds/find/find.h
new file mode 100644
index 0000000..8960a0b
--- /dev/null
+++ b/shell_cmds/find/find.h
@@ -0,0 +1,145 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Cimarron D. Taylor of the University of California, Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)find.h 8.1 (Berkeley) 6/6/93
+ * $FreeBSD: src/usr.bin/find/find.h,v 1.21 2010/12/11 08:32:16 joel Exp $
+ */
+
+#include <regex.h>
+
+/* forward declarations */
+struct _plandata;
+struct _option;
+
+/* execute function */
+typedef int exec_f(struct _plandata *, FTSENT *);
+/* create function */
+typedef struct _plandata *creat_f(struct _option *, char ***);
+
+/* function modifiers */
+#define F_NEEDOK 0x00000001 /* -ok vs. -exec */
+#define F_EXECDIR 0x00000002 /* -execdir vs. -exec */
+#define F_TIME_A 0x00000004 /* one of -atime, -anewer, -newera* */
+#define F_TIME_C 0x00000008 /* one of -ctime, -cnewer, -newerc* */
+#define F_TIME2_A 0x00000010 /* one of -newer?a */
+#define F_TIME2_C 0x00000020 /* one of -newer?c */
+#define F_TIME2_T 0x00000040 /* one of -newer?t */
+#define F_MAXDEPTH F_TIME_A /* maxdepth vs. mindepth */
+#define F_DEPTH F_TIME_A /* -depth n vs. -d */
+/* command line function modifiers */
+#define F_EQUAL 0x00000000 /* [acm]min [acm]time inum links size */
+#define F_LESSTHAN 0x00000100
+#define F_GREATER 0x00000200
+#define F_ELG_MASK 0x00000300
+#define F_ATLEAST 0x00000400 /* flags perm */
+#define F_ANY 0x00000800 /* perm */
+#define F_MTMASK 0x00003000
+#define F_MTFLAG 0x00000000 /* fstype */
+#define F_MTTYPE 0x00001000
+#define F_MTUNKNOWN 0x00002000
+#define F_IGNCASE 0x00010000 /* iname ipath iregex */
+#define F_EXACTTIME F_IGNCASE /* -[acm]time units syntax */
+#define F_EXECPLUS 0x00020000 /* -exec ... {} + */
+#define F_TIME_B 0x00040000 /* one of -Btime, -Bnewer, -newerB* */
+#define F_TIME2_B 0x00080000 /* one of -newer?B */
+#define F_LINK 0x00100000 /* lname or ilname */
+
+/* node definition */
+typedef struct _plandata {
+ struct _plandata *next; /* next node */
+ exec_f *execute; /* node evaluation function */
+ int flags; /* private flags */
+ union {
+ gid_t _g_data; /* gid */
+ ino_t _i_data; /* inode */
+ mode_t _m_data; /* mode mask */
+ struct {
+ u_long _f_flags;
+ u_long _f_notflags;
+ } fl;
+ nlink_t _l_data; /* link count */
+ short _d_data; /* level depth (-1 to N) */
+ off_t _o_data; /* file size */
+ time_t _t_data; /* time value */
+ uid_t _u_data; /* uid */
+ short _mt_data; /* mount flags */
+ struct _plandata *_p_data[2]; /* PLAN trees */
+ struct _ex {
+ char **_e_argv; /* argv array */
+ char **_e_orig; /* original strings */
+ int *_e_len; /* allocated length */
+ int _e_pbnum; /* base num. of args. used */
+ int _e_ppos; /* number of arguments used */
+ int _e_pnummax; /* max. number of arguments */
+ int _e_psize; /* number of bytes of args. */
+ int _e_pbsize; /* base num. of bytes of args */
+ int _e_psizemax; /* max num. of bytes of args */
+ struct _plandata *_e_next;/* next F_EXECPLUS in tree */
+ } ex;
+ char *_a_data[2]; /* array of char pointers */
+ char *_c_data; /* char pointer */
+ regex_t *_re_data; /* regex */
+ } p_un;
+} PLAN;
+#define a_data p_un._a_data
+#define c_data p_un._c_data
+#define d_data p_un._d_data
+#define fl_flags p_un.fl._f_flags
+#define fl_notflags p_un.fl._f_notflags
+#define g_data p_un._g_data
+#define i_data p_un._i_data
+#define l_data p_un._l_data
+#define m_data p_un._m_data
+#define mt_data p_un._mt_data
+#define o_data p_un._o_data
+#define p_data p_un._p_data
+#define t_data p_un._t_data
+#define u_data p_un._u_data
+#define re_data p_un._re_data
+#define e_argv p_un.ex._e_argv
+#define e_orig p_un.ex._e_orig
+#define e_len p_un.ex._e_len
+#define e_pbnum p_un.ex._e_pbnum
+#define e_ppos p_un.ex._e_ppos
+#define e_pnummax p_un.ex._e_pnummax
+#define e_psize p_un.ex._e_psize
+#define e_pbsize p_un.ex._e_pbsize
+#define e_psizemax p_un.ex._e_psizemax
+#define e_next p_un.ex._e_next
+
+typedef struct _option {
+ const char *name; /* option name */
+ creat_f *create; /* create function */
+ exec_f *execute; /* execute function */
+ int flags;
+} OPTION;
+
+#include "extern.h"
diff --git a/shell_cmds/find/find.plist.part b/shell_cmds/find/find.plist.part
new file mode 100644
index 0000000..0148f95
--- /dev/null
+++ b/shell_cmds/find/find.plist.part
@@ -0,0 +1,30 @@
+ <dict>
+ <key>OpenSourceProject</key>
+ <string>find</string>
+ <key>OpenSourceVersion</key>
+ <string>2011-12-10</string>
+ <key>OpenSourceWebsiteURL</key>
+ <string>http://svnweb.freebsd.org/base/head/usr.bin/find/</string>
+ <key>OpenSourceSCM</key>
+ <string>svn co http://svn.freebsd.org/base/head/usr.bin/find/</string>
+ <key>OpenSourceImportDate</key>
+ <string>2012-01-06</string>
+ <key>OpenSourceModifications</key>
+ <array>
+ <string>Add -xattr and -xattrname options.</string>
+ <string>execplus conformance fixes.</string>
+ <string>Man page fix (4772561).</string>
+ <string>Adjust FTS usage due to API differences.</string>
+ <string>Avoid searching unsearchable directories (3849245).</string>
+ <string>Add missing call to fts_close (4608460).</string>
+ <string>Conformance fixes related to F_EXACTTIME.</string>
+ <string>Apple-specific implementation of -acl primary.</string>
+ <string>Conformance fix for f_name (6591280).</string>
+ <string>setmode conformance fix (3936046).</string>
+ <string>Use a saner MAXLOGNAME definition.</string>
+ <string>Workaround for lack of rpmatch function.</string>
+ <string>FreeBSD revisions 260336, 260355.</string>
+ </array>
+ <key>OpenSourceLicense</key>
+ <string>bsd</string>
+ </dict>
diff --git a/shell_cmds/find/function.c b/shell_cmds/find/function.c
new file mode 100644
index 0000000..a673a02
--- /dev/null
+++ b/shell_cmds/find/function.c
@@ -0,0 +1,1772 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Cimarron D. Taylor of the University of California, Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static const char sccsid[] = "@(#)function.c 8.10 (Berkeley) 5/4/95";
+#endif
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/find/function.c,v 1.71 2011/06/13 05:22:07 avatar Exp $");
+
+#include <sys/param.h>
+#include <sys/ucred.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/acl.h>
+#include <sys/wait.h>
+#include <sys/mount.h>
+
+#include <dirent.h>
+#include <err.h>
+#include <errno.h>
+#include <fnmatch.h>
+#include <fts.h>
+#include <grp.h>
+#include <limits.h>
+#include <pwd.h>
+#include <regex.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+
+#ifdef __APPLE__
+#include <sys/sysctl.h>
+#include <sys/xattr.h>
+#include <libgen.h>
+#include <get_compat.h>
+#else
+#define COMPAT_MODE(func, mode) 1
+#endif
+
+#include "find.h"
+
+static PLAN *palloc(OPTION *);
+static long long find_parsenum(PLAN *, const char *, char *, char *);
+static long long find_parsetime(PLAN *, const char *, char *);
+static char *nextarg(OPTION *, char ***);
+
+extern char **environ;
+
+static PLAN *lastexecplus = NULL;
+int execplus_error;
+
+#define COMPARE(a, b) do { \
+ switch (plan->flags & F_ELG_MASK) { \
+ case F_EQUAL: \
+ return (a == b); \
+ case F_LESSTHAN: \
+ return (a < b); \
+ case F_GREATER: \
+ return (a > b); \
+ default: \
+ abort(); \
+ } \
+} while(0)
+
+static PLAN *
+palloc(OPTION *option)
+{
+ PLAN *new;
+
+ if ((new = malloc(sizeof(PLAN))) == NULL)
+ err(1, NULL);
+ new->execute = option->execute;
+ new->flags = option->flags;
+ new->next = NULL;
+ return new;
+}
+
+/*
+ * find_parsenum --
+ * Parse a string of the form [+-]# and return the value.
+ */
+static long long
+find_parsenum(PLAN *plan, const char *option, char *vp, char *endch)
+{
+ long long value;
+ char *endchar, *str; /* Pointer to character ending conversion. */
+
+ /* Determine comparison from leading + or -. */
+ str = vp;
+ switch (*str) {
+ case '+':
+ ++str;
+ plan->flags |= F_GREATER;
+ break;
+ case '-':
+ ++str;
+ plan->flags |= F_LESSTHAN;
+ break;
+ default:
+ plan->flags |= F_EQUAL;
+ break;
+ }
+
+ /*
+ * Convert the string with strtoq(). Note, if strtoq() returns zero
+ * and endchar points to the beginning of the string we know we have
+ * a syntax error.
+ */
+ value = strtoq(str, &endchar, 10);
+ if (value == 0 && endchar == str)
+ errx(1, "%s: %s: illegal numeric value", option, vp);
+ if (endchar[0] && endch == NULL)
+ errx(1, "%s: %s: illegal trailing character", option, vp);
+ if (endch)
+ *endch = endchar[0];
+ return value;
+}
+
+/*
+ * find_parsetime --
+ * Parse a string of the form [+-]([0-9]+[smhdw]?)+ and return the value.
+ */
+static long long
+find_parsetime(PLAN *plan, const char *option, char *vp)
+{
+ long long secs, value;
+ char *str, *unit; /* Pointer to character ending conversion. */
+
+ /* Determine comparison from leading + or -. */
+ str = vp;
+ switch (*str) {
+ case '+':
+ ++str;
+ plan->flags |= F_GREATER;
+ break;
+ case '-':
+ ++str;
+ plan->flags |= F_LESSTHAN;
+ break;
+ default:
+ plan->flags |= F_EQUAL;
+ break;
+ }
+
+ value = strtoq(str, &unit, 10);
+ if (value == 0 && unit == str) {
+ errx(1, "%s: %s: illegal time value", option, vp);
+ /* NOTREACHED */
+ }
+ if (*unit == '\0')
+ return value;
+
+ /* Units syntax. */
+ secs = 0;
+ for (;;) {
+ switch(*unit) {
+ case 's': /* seconds */
+ secs += value;
+ break;
+ case 'm': /* minutes */
+ secs += value * 60;
+ break;
+ case 'h': /* hours */
+ secs += value * 3600;
+ break;
+ case 'd': /* days */
+ secs += value * 86400;
+ break;
+ case 'w': /* weeks */
+ secs += value * 604800;
+ break;
+ default:
+ errx(1, "%s: %s: bad unit '%c'", option, vp, *unit);
+ /* NOTREACHED */
+ }
+ str = unit + 1;
+ if (*str == '\0') /* EOS */
+ break;
+ value = strtoq(str, &unit, 10);
+ if (value == 0 && unit == str) {
+ errx(1, "%s: %s: illegal time value", option, vp);
+ /* NOTREACHED */
+ }
+ if (*unit == '\0') {
+ errx(1, "%s: %s: missing trailing unit", option, vp);
+ /* NOTREACHED */
+ }
+ }
+ plan->flags |= F_EXACTTIME;
+ return secs;
+}
+
+/*
+ * nextarg --
+ * Check that another argument still exists, return a pointer to it,
+ * and increment the argument vector pointer.
+ */
+static char *
+nextarg(OPTION *option, char ***argvp)
+{
+ char *arg;
+
+ if ((arg = **argvp) == 0)
+ errx(1, "%s: requires additional arguments", option->name);
+ (*argvp)++;
+ return arg;
+} /* nextarg() */
+
+/*
+ * The value of n for the inode times (atime, birthtime, ctime, mtime) is a
+ * range, i.e. n matches from (n - 1) to n 24 hour periods. This interacts
+ * with -n, such that "-mtime -1" would be less than 0 days, which isn't what
+ * the user wanted. Correct so that -1 is "less than 1".
+ */
+#define TIME_CORRECT(p) \
+ if (((p)->flags & F_ELG_MASK) == F_LESSTHAN) \
+ ++((p)->t_data);
+
+/*
+ * -[acm]min n functions --
+ *
+ * True if the difference between the
+ * file access time (-amin)
+ * file birth time (-Bmin)
+ * last change of file status information (-cmin)
+ * file modification time (-mmin)
+ * and the current time is n min periods.
+ */
+int
+f_Xmin(PLAN *plan, FTSENT *entry)
+{
+ if (plan->flags & F_TIME_C) {
+ COMPARE((now - entry->fts_statp->st_ctime +
+ 60 - 1) / 60, plan->t_data);
+ } else if (plan->flags & F_TIME_A) {
+ COMPARE((now - entry->fts_statp->st_atime +
+ 60 - 1) / 60, plan->t_data);
+ } else if (plan->flags & F_TIME_B) {
+ COMPARE((now - entry->fts_statp->st_birthtime +
+ 60 - 1) / 60, plan->t_data);
+ } else {
+ COMPARE((now - entry->fts_statp->st_mtime +
+ 60 - 1) / 60, plan->t_data);
+ }
+}
+
+PLAN *
+c_Xmin(OPTION *option, char ***argvp)
+{
+ char *nmins;
+ PLAN *new;
+
+ nmins = nextarg(option, argvp);
+ ftsoptions &= ~FTS_NOSTAT;
+
+ new = palloc(option);
+ new->t_data = find_parsenum(new, option->name, nmins, NULL);
+ TIME_CORRECT(new);
+ return new;
+}
+
+/*
+ * -[acm]time n functions --
+ *
+ * True if the difference between the
+ * file access time (-atime)
+ * file birth time (-Btime)
+ * last change of file status information (-ctime)
+ * file modification time (-mtime)
+ * and the current time is n 24 hour periods.
+ */
+
+int
+f_Xtime(PLAN *plan, FTSENT *entry)
+{
+ time_t xtime;
+
+ if (plan->flags & F_TIME_A)
+ xtime = entry->fts_statp->st_atime;
+ else if (plan->flags & F_TIME_B)
+ xtime = entry->fts_statp->st_birthtime;
+ else if (plan->flags & F_TIME_C)
+ xtime = entry->fts_statp->st_ctime;
+ else
+ xtime = entry->fts_statp->st_mtime;
+
+ if (plan->flags & F_EXACTTIME)
+ COMPARE(now - xtime, plan->t_data);
+ else
+ COMPARE((now - xtime + (COMPAT_MODE("bin/find", "unix2003") ? 0 : 86400 - 1)) / 86400, plan->t_data);
+}
+
+PLAN *
+c_Xtime(OPTION *option, char ***argvp)
+{
+ char *value;
+ PLAN *new;
+
+ value = nextarg(option, argvp);
+ ftsoptions &= ~FTS_NOSTAT;
+
+ new = palloc(option);
+ new->t_data = find_parsetime(new, option->name, value);
+ if (!(new->flags & F_EXACTTIME) && !COMPAT_MODE("bin/find", "unix2003"))
+ TIME_CORRECT(new);
+ return new;
+}
+
+/*
+ * -maxdepth/-mindepth n functions --
+ *
+ * Does the same as -prune if the level of the current file is
+ * greater/less than the specified maximum/minimum depth.
+ *
+ * Note that -maxdepth and -mindepth are handled specially in
+ * find_execute() so their f_* functions are set to f_always_true().
+ */
+PLAN *
+c_mXXdepth(OPTION *option, char ***argvp)
+{
+ char *dstr;
+ PLAN *new;
+
+ dstr = nextarg(option, argvp);
+ if (dstr[0] == '-')
+ /* all other errors handled by find_parsenum() */
+ errx(1, "%s: %s: value must be positive", option->name, dstr);
+
+ new = palloc(option);
+ if (option->flags & F_MAXDEPTH)
+ maxdepth = find_parsenum(new, option->name, dstr, NULL);
+ else
+ mindepth = find_parsenum(new, option->name, dstr, NULL);
+ return new;
+}
+
+/*
+ * -acl function --
+ *
+ * Show files with EXTENDED ACL attributes.
+ */
+#ifdef __APPLE__
+int
+f_acl(PLAN *plan __unused, FTSENT *entry)
+{
+ acl_t facl;
+ int match;
+ acl_entry_t ae;
+
+ match = 0;
+ if ((facl = acl_get_link_np(entry->fts_accpath, ACL_TYPE_EXTENDED)) != NULL) {
+ if (acl_get_entry(facl, ACL_FIRST_ENTRY, &ae) == 0) {
+ match = 1;
+ }
+ acl_free(facl);
+ }
+ return match;
+}
+#else /* !__APPLE__ */
+int
+f_acl(PLAN *plan __unused, FTSENT *entry)
+{
+ acl_t facl;
+ acl_type_t acl_type;
+ int acl_supported = 0, ret, trivial;
+
+ if (S_ISLNK(entry->fts_statp->st_mode))
+ return 0;
+ ret = pathconf(entry->fts_accpath, _PC_ACL_NFS4);
+ if (ret > 0) {
+ acl_supported = 1;
+ acl_type = ACL_TYPE_NFS4;
+ } else if (ret < 0 && errno != EINVAL) {
+ warn("%s", entry->fts_accpath);
+ return (0);
+ }
+ if (acl_supported == 0) {
+ ret = pathconf(entry->fts_accpath, _PC_ACL_EXTENDED);
+ if (ret > 0) {
+ acl_supported = 1;
+ acl_type = ACL_TYPE_ACCESS;
+ } else if (ret < 0 && errno != EINVAL) {
+ warn("%s", entry->fts_accpath);
+ return (0);
+ }
+ }
+ if (acl_supported == 0)
+ return (0);
+
+ facl = acl_get_file(entry->fts_accpath, acl_type);
+ if (facl == NULL) {
+ warn("%s", entry->fts_accpath);
+ return (0);
+ }
+ ret = acl_is_trivial_np(facl, &trivial);
+ acl_free(facl);
+ if (ret) {
+ warn("%s", entry->fts_accpath);
+ acl_free(facl);
+ return (0);
+ }
+ if (trivial)
+ return (0);
+ return (1);
+}
+#endif /* __APPLE__ */
+
+PLAN *
+c_acl(OPTION *option, char ***argvp __unused)
+{
+#ifndef __APPLE__
+ ftsoptions &= ~FTS_NOSTAT;
+#endif /* !__APPLE__ */
+ return (palloc(option));
+}
+
+#ifdef __APPLE__
+int
+f_xattr(PLAN *plan __unused, FTSENT *entry)
+{
+ ssize_t xattr;
+ int match;
+
+ match = 0;
+ xattr = listxattr(entry->fts_accpath, NULL, 0, XATTR_NOFOLLOW);
+ if (xattr > 0) {
+ match = 1;
+ }
+ return match;
+}
+
+int
+f_xattrname(PLAN *plan, FTSENT *entry)
+{
+ ssize_t xattr;
+ int match;
+
+ match = 0;
+ xattr = getxattr(entry->fts_accpath, plan->c_data, NULL, 0, 0, XATTR_NOFOLLOW);
+ if (xattr > 0) {
+ match = 1;
+ }
+ return match;
+}
+#endif /* __APPLE__ */
+
+/*
+ * -delete functions --
+ *
+ * True always. Makes its best shot and continues on regardless.
+ */
+int
+f_delete(PLAN *plan __unused, FTSENT *entry)
+{
+ /* ignore these from fts */
+ if (strcmp(entry->fts_accpath, ".") == 0 ||
+ strcmp(entry->fts_accpath, "..") == 0)
+ return 1;
+
+ /* sanity check */
+ if (isdepth == 0 || /* depth off */
+ (ftsoptions & FTS_NOSTAT)) /* not stat()ing */
+ errx(1, "-delete: insecure options got turned on");
+
+ if (!(ftsoptions & FTS_PHYSICAL) || /* physical off */
+ (ftsoptions & FTS_LOGICAL)) /* or finally, logical on */
+ errx(1, "-delete: forbidden when symlinks are followed");
+
+ /* Potentially unsafe - do not accept relative paths whatsoever */
+ if (strchr(entry->fts_accpath, '/') != NULL)
+ errx(1, "-delete: %s: relative path potentially not safe",
+ entry->fts_accpath);
+
+ /* Turn off user immutable bits if running as root */
+ if ((entry->fts_statp->st_flags & (UF_APPEND|UF_IMMUTABLE)) &&
+ !(entry->fts_statp->st_flags & (SF_APPEND|SF_IMMUTABLE)) &&
+ geteuid() == 0)
+ lchflags(entry->fts_accpath,
+ entry->fts_statp->st_flags &= ~(UF_APPEND|UF_IMMUTABLE));
+
+ /* rmdir directories, unlink everything else */
+ if (S_ISDIR(entry->fts_statp->st_mode)) {
+ if (rmdir(entry->fts_accpath) < 0 && errno != ENOTEMPTY)
+ warn("-delete: rmdir(%s)", entry->fts_path);
+ } else {
+ if (unlink(entry->fts_accpath) < 0)
+ warn("-delete: unlink(%s)", entry->fts_path);
+ }
+
+ /* "succeed" */
+ return 1;
+}
+
+PLAN *
+c_delete(OPTION *option, char ***argvp __unused)
+{
+
+ ftsoptions &= ~FTS_NOSTAT; /* no optimise */
+ isoutput = 1; /* possible output */
+ isdepth = 1; /* -depth implied */
+
+ return palloc(option);
+}
+
+
+/*
+ * always_true --
+ *
+ * Always true, used for -maxdepth, -mindepth, -xdev, -follow, and -true
+ */
+int
+f_always_true(PLAN *plan __unused, FTSENT *entry __unused)
+{
+ return 1;
+}
+
+/*
+ * -depth functions --
+ *
+ * With argument: True if the file is at level n.
+ * Without argument: Always true, causes descent of the directory hierarchy
+ * to be done so that all entries in a directory are acted on before the
+ * directory itself.
+ */
+int
+f_depth(PLAN *plan, FTSENT *entry)
+{
+ if (plan->flags & F_DEPTH)
+ COMPARE(entry->fts_level, plan->d_data);
+ else
+ return 1;
+}
+
+PLAN *
+c_depth(OPTION *option, char ***argvp)
+{
+ PLAN *new;
+ char *str;
+
+ new = palloc(option);
+
+ str = **argvp;
+ if (str && !(new->flags & F_DEPTH)) {
+ /* skip leading + or - */
+ if (*str == '+' || *str == '-')
+ str++;
+ /* skip sign */
+ if (*str == '+' || *str == '-')
+ str++;
+ if (isdigit(*str))
+ new->flags |= F_DEPTH;
+ }
+
+ if (new->flags & F_DEPTH) { /* -depth n */
+ char *ndepth;
+
+ ndepth = nextarg(option, argvp);
+ new->d_data = find_parsenum(new, option->name, ndepth, NULL);
+ } else { /* -d */
+ isdepth = 1;
+ }
+
+ return new;
+}
+
+/*
+ * -empty functions --
+ *
+ * True if the file or directory is empty
+ */
+int
+f_empty(PLAN *plan __unused, FTSENT *entry)
+{
+ if (S_ISREG(entry->fts_statp->st_mode) &&
+ entry->fts_statp->st_size == 0)
+ return 1;
+ if (S_ISDIR(entry->fts_statp->st_mode)) {
+ struct dirent *dp;
+ int empty;
+ DIR *dir;
+
+ empty = 1;
+ dir = opendir(entry->fts_accpath);
+ if (dir == NULL)
+ return 0;
+ for (dp = readdir(dir); dp; dp = readdir(dir))
+ if (dp->d_name[0] != '.' ||
+ (dp->d_name[1] != '\0' &&
+ (dp->d_name[1] != '.' || dp->d_name[2] != '\0'))) {
+ empty = 0;
+ break;
+ }
+ closedir(dir);
+ return empty;
+ }
+ return 0;
+}
+
+PLAN *
+c_empty(OPTION *option, char ***argvp __unused)
+{
+ ftsoptions &= ~FTS_NOSTAT;
+
+ return palloc(option);
+}
+
+/*
+ * [-exec | -execdir | -ok] utility [arg ... ] ; functions --
+ *
+ * True if the executed utility returns a zero value as exit status.
+ * The end of the primary expression is delimited by a semicolon. If
+ * "{}" occurs anywhere, it gets replaced by the current pathname,
+ * or, in the case of -execdir, the current basename (filename
+ * without leading directory prefix). For -exec and -ok,
+ * the current directory for the execution of utility is the same as
+ * the current directory when the find utility was started, whereas
+ * for -execdir, it is the directory the file resides in.
+ *
+ * The primary -ok differs from -exec in that it requests affirmation
+ * of the user before executing the utility.
+ */
+int
+f_exec(PLAN *plan, FTSENT *entry)
+{
+ int cnt;
+ pid_t pid;
+ int status;
+ char *file;
+
+ if (entry == NULL && plan->flags & F_EXECPLUS) {
+ if (plan->e_ppos == plan->e_pbnum)
+ return (1);
+ plan->e_argv[plan->e_ppos] = NULL;
+ goto doexec;
+ }
+
+ /* XXX - if file/dir ends in '/' this will not work -- can it? */
+ if ((plan->flags & F_EXECDIR) && \
+ (file = strrchr(entry->fts_path, '/')))
+ file++;
+ else
+ file = entry->fts_path;
+
+ if (plan->flags & F_EXECPLUS) {
+ if ((plan->e_argv[plan->e_ppos] = strdup(file)) == NULL)
+ err(1, NULL);
+ plan->e_len[plan->e_ppos] = strlen(file);
+ plan->e_psize += plan->e_len[plan->e_ppos];
+ if (++plan->e_ppos < plan->e_pnummax &&
+ plan->e_psize < plan->e_psizemax)
+ return (1);
+ plan->e_argv[plan->e_ppos] = NULL;
+ } else {
+ for (cnt = 0; plan->e_argv[cnt]; ++cnt)
+ if (plan->e_len[cnt])
+ brace_subst(plan->e_orig[cnt],
+ &plan->e_argv[cnt], file,
+ plan->e_len[cnt]);
+ }
+
+doexec: if ((plan->flags & F_NEEDOK) && !queryuser(plan->e_argv))
+ return 0;
+
+ /* make sure find output is interspersed correctly with subprocesses */
+ fflush(stdout);
+ fflush(stderr);
+
+ switch (pid = fork()) {
+ case -1:
+ err(1, "fork");
+ /* NOTREACHED */
+ case 0:
+ /* change dir back from where we started */
+ if (!(plan->flags & F_EXECDIR) && fchdir(dotfd)) {
+ warn("chdir");
+ _exit(1);
+ }
+ execvp(plan->e_argv[0], plan->e_argv);
+ warn("%s", plan->e_argv[0]);
+ _exit(1);
+ }
+ if (plan->flags & F_EXECPLUS) {
+ while (--plan->e_ppos >= plan->e_pbnum)
+ free(plan->e_argv[plan->e_ppos]);
+ plan->e_ppos = plan->e_pbnum;
+ plan->e_psize = plan->e_pbsize;
+ }
+ pid = waitpid(pid, &status, 0);
+ if (plan->flags & F_EXECPLUS && WIFEXITED(status) && WEXITSTATUS(status) && !execplus_error) {
+ /* Test 140 (8907531, 10656525) */
+ execplus_error = WEXITSTATUS(status);
+ }
+ return (pid != -1 && WIFEXITED(status) && !WEXITSTATUS(status));
+}
+
+/*
+ * c_exec, c_execdir, c_ok --
+ * build three parallel arrays, one with pointers to the strings passed
+ * on the command line, one with (possibly duplicated) pointers to the
+ * argv array, and one with integer values that are lengths of the
+ * strings, but also flags meaning that the string has to be massaged.
+ */
+PLAN *
+c_exec(OPTION *option, char ***argvp)
+{
+ PLAN *new; /* node returned */
+ long argmax;
+ int cnt, i;
+ char **argv, **ap, **ep, *p;
+
+ /* XXX - was in c_execdir, but seems unnecessary!?
+ ftsoptions &= ~FTS_NOSTAT;
+ */
+ isoutput = 1;
+
+ /* XXX - this is a change from the previous coding */
+ new = palloc(option);
+
+ for (ap = argv = *argvp;; ++ap) {
+ if (!*ap)
+ errx(1,
+ "%s: no terminating \";\" or \"+\"", option->name);
+ if (**ap == ';')
+ break;
+ if (**ap == '+' && ap != argv && strcmp(*(ap - 1), "{}") == 0) {
+ new->flags |= F_EXECPLUS;
+ break;
+ }
+ }
+
+ if (ap == argv)
+ errx(1, "%s: no command specified", option->name);
+
+ cnt = ap - *argvp + 1;
+ if (new->flags & F_EXECPLUS) {
+ new->e_ppos = new->e_pbnum = cnt - 2;
+ if ((argmax = sysconf(_SC_ARG_MAX)) == -1) {
+ warn("sysconf(_SC_ARG_MAX)");
+ argmax = _POSIX_ARG_MAX;
+ }
+ argmax -= 1024;
+ for (ep = environ; *ep != NULL; ep++)
+ argmax -= strlen(*ep) + 1 + sizeof(*ep);
+ argmax -= 1 + sizeof(*ep);
+ new->e_pnummax = argmax / 16;
+ argmax -= sizeof(char *) * new->e_pnummax;
+ if (argmax <= 0)
+ errx(1, "no space for arguments");
+ new->e_psizemax = argmax;
+ new->e_pbsize = 0;
+ cnt += new->e_pnummax + 1;
+ new->e_next = lastexecplus;
+ lastexecplus = new;
+ }
+ if ((new->e_argv = malloc(cnt * sizeof(char *))) == NULL)
+ err(1, NULL);
+ if ((new->e_orig = malloc(cnt * sizeof(char *))) == NULL)
+ err(1, NULL);
+ if ((new->e_len = malloc(cnt * sizeof(int))) == NULL)
+ err(1, NULL);
+
+ for (argv = *argvp, cnt = 0; argv < ap; ++argv, ++cnt) {
+ new->e_orig[cnt] = *argv;
+ if (new->flags & F_EXECPLUS)
+ new->e_pbsize += strlen(*argv) + 1;
+ for (p = *argv; *p; ++p)
+ if (!(new->flags & F_EXECPLUS) && p[0] == '{' &&
+ p[1] == '}') {
+ if ((new->e_argv[cnt] =
+ malloc(MAXPATHLEN)) == NULL)
+ err(1, NULL);
+ new->e_len[cnt] = MAXPATHLEN;
+ break;
+ }
+ if (!*p) {
+ new->e_argv[cnt] = *argv;
+ new->e_len[cnt] = 0;
+ }
+ }
+ if (new->flags & F_EXECPLUS) {
+ new->e_psize = new->e_pbsize;
+ cnt--;
+ for (i = 0; i < new->e_pnummax; i++) {
+ new->e_argv[cnt] = NULL;
+ new->e_len[cnt] = 0;
+ cnt++;
+ }
+ argv = ap;
+ goto done;
+ }
+ new->e_argv[cnt] = new->e_orig[cnt] = NULL;
+
+done: *argvp = argv + 1;
+ return new;
+}
+
+/* Finish any pending -exec ... {} + functions. */
+void
+finish_execplus(void)
+{
+ PLAN *p;
+
+ p = lastexecplus;
+ while (p != NULL) {
+ (p->execute)(p, NULL);
+ p = p->e_next;
+ }
+}
+
+int
+f_flags(PLAN *plan, FTSENT *entry)
+{
+ u_long flags;
+
+ flags = entry->fts_statp->st_flags;
+ if (plan->flags & F_ATLEAST)
+ return (flags | plan->fl_flags) == flags &&
+ !(flags & plan->fl_notflags);
+ else if (plan->flags & F_ANY)
+ return (flags & plan->fl_flags) ||
+ (flags | plan->fl_notflags) != flags;
+ else
+ return flags == plan->fl_flags &&
+ !(plan->fl_flags & plan->fl_notflags);
+}
+
+PLAN *
+c_flags(OPTION *option, char ***argvp)
+{
+ char *flags_str;
+ PLAN *new;
+ u_long flags, notflags;
+
+ flags_str = nextarg(option, argvp);
+ ftsoptions &= ~FTS_NOSTAT;
+
+ new = palloc(option);
+
+ if (*flags_str == '-') {
+ new->flags |= F_ATLEAST;
+ flags_str++;
+ } else if (*flags_str == '+') {
+ new->flags |= F_ANY;
+ flags_str++;
+ }
+ if (strtofflags(&flags_str, &flags, &notflags) == 1)
+ errx(1, "%s: %s: illegal flags string", option->name, flags_str);
+
+ new->fl_flags = flags;
+ new->fl_notflags = notflags;
+ return new;
+}
+
+/*
+ * -follow functions --
+ *
+ * Always true, causes symbolic links to be followed on a global
+ * basis.
+ */
+PLAN *
+c_follow(OPTION *option, char ***argvp __unused)
+{
+ ftsoptions &= ~FTS_PHYSICAL;
+ ftsoptions |= FTS_LOGICAL;
+
+ return palloc(option);
+}
+
+/*
+ * -fstype functions --
+ *
+ * True if the file is of a certain type.
+ */
+int
+f_fstype(PLAN *plan, FTSENT *entry)
+{
+ static dev_t curdev; /* need a guaranteed illegal dev value */
+ static int first = 1;
+ struct statfs sb;
+ static int val_flags;
+ static char fstype[sizeof(sb.f_fstypename)];
+ char *p, save[2] = {0,0};
+
+ if ((plan->flags & F_MTMASK) == F_MTUNKNOWN)
+ return 0;
+
+ /* Only check when we cross mount point. */
+ if (first || curdev != entry->fts_statp->st_dev) {
+ curdev = entry->fts_statp->st_dev;
+
+ /*
+ * Statfs follows symlinks; find wants the link's filesystem,
+ * not where it points.
+ */
+ if (entry->fts_info == FTS_SL ||
+ entry->fts_info == FTS_SLNONE) {
+ if ((p = strrchr(entry->fts_accpath, '/')) != NULL)
+ ++p;
+ else
+ p = entry->fts_accpath;
+ save[0] = p[0];
+ p[0] = '.';
+ save[1] = p[1];
+ p[1] = '\0';
+ } else
+ p = NULL;
+
+ if (statfs(entry->fts_accpath, &sb))
+ err(1, "%s", entry->fts_accpath);
+
+ if (p) {
+ p[0] = save[0];
+ p[1] = save[1];
+ }
+
+ first = 0;
+
+ /*
+ * Further tests may need both of these values, so
+ * always copy both of them.
+ */
+ val_flags = sb.f_flags;
+ strlcpy(fstype, sb.f_fstypename, sizeof(fstype));
+ }
+ switch (plan->flags & F_MTMASK) {
+ case F_MTFLAG:
+ return val_flags & plan->mt_data;
+ case F_MTTYPE:
+ return (strncmp(fstype, plan->c_data, sizeof(fstype)) == 0);
+ default:
+ abort();
+ }
+}
+
+PLAN *
+c_fstype(OPTION *option, char ***argvp)
+{
+ char *fsname;
+ PLAN *new;
+
+ fsname = nextarg(option, argvp);
+ ftsoptions &= ~FTS_NOSTAT;
+
+ new = palloc(option);
+ switch (*fsname) {
+ case 'l':
+ if (!strcmp(fsname, "local")) {
+ new->flags |= F_MTFLAG;
+ new->mt_data = MNT_LOCAL;
+ return new;
+ }
+ break;
+ case 'r':
+ if (!strcmp(fsname, "rdonly")) {
+ new->flags |= F_MTFLAG;
+ new->mt_data = MNT_RDONLY;
+ return new;
+ }
+ break;
+ }
+
+ new->flags |= F_MTTYPE;
+ new->c_data = fsname;
+ return new;
+}
+
+/*
+ * -group gname functions --
+ *
+ * True if the file belongs to the group gname. If gname is numeric and
+ * an equivalent of the getgrnam() function does not return a valid group
+ * name, gname is taken as a group ID.
+ */
+int
+f_group(PLAN *plan, FTSENT *entry)
+{
+ COMPARE(entry->fts_statp->st_gid, plan->g_data);
+}
+
+PLAN *
+c_group(OPTION *option, char ***argvp)
+{
+ char *gname;
+ PLAN *new;
+ struct group *g;
+ gid_t gid;
+
+ gname = nextarg(option, argvp);
+ ftsoptions &= ~FTS_NOSTAT;
+
+ new = palloc(option);
+ g = getgrnam(gname);
+ if (g == NULL) {
+ char* cp = gname;
+ if (gname[0] == '-' || gname[0] == '+')
+ gname++;
+ gid = atoi(gname);
+ if (gid == 0 && gname[0] != '0')
+ errx(1, "%s: %s: no such group", option->name, gname);
+ gid = find_parsenum(new, option->name, cp, NULL);
+ } else
+ gid = g->gr_gid;
+
+ new->g_data = gid;
+ return new;
+}
+
+/*
+ * -inum n functions --
+ *
+ * True if the file has inode # n.
+ */
+int
+f_inum(PLAN *plan, FTSENT *entry)
+{
+ COMPARE(entry->fts_statp->st_ino, plan->i_data);
+}
+
+PLAN *
+c_inum(OPTION *option, char ***argvp)
+{
+ char *inum_str;
+ PLAN *new;
+
+ inum_str = nextarg(option, argvp);
+ ftsoptions &= ~FTS_NOSTAT;
+
+ new = palloc(option);
+ new->i_data = find_parsenum(new, option->name, inum_str, NULL);
+ return new;
+}
+
+/*
+ * -samefile FN
+ *
+ * True if the file has the same inode (eg hard link) FN
+ */
+
+/* f_samefile is just f_inum */
+PLAN *
+c_samefile(OPTION *option, char ***argvp)
+{
+ char *fn;
+ PLAN *new;
+ struct stat sb;
+
+ fn = nextarg(option, argvp);
+ ftsoptions &= ~FTS_NOSTAT;
+
+ new = palloc(option);
+ if (stat(fn, &sb))
+ err(1, "%s", fn);
+ new->i_data = sb.st_ino;
+ return new;
+}
+
+/*
+ * -links n functions --
+ *
+ * True if the file has n links.
+ */
+int
+f_links(PLAN *plan, FTSENT *entry)
+{
+ COMPARE(entry->fts_statp->st_nlink, plan->l_data);
+}
+
+PLAN *
+c_links(OPTION *option, char ***argvp)
+{
+ char *nlinks;
+ PLAN *new;
+
+ nlinks = nextarg(option, argvp);
+ ftsoptions &= ~FTS_NOSTAT;
+
+ new = palloc(option);
+ new->l_data = (nlink_t)find_parsenum(new, option->name, nlinks, NULL);
+ return new;
+}
+
+/*
+ * -ls functions --
+ *
+ * Always true - prints the current entry to stdout in "ls" format.
+ */
+int
+f_ls(PLAN *plan __unused, FTSENT *entry)
+{
+ printlong(entry->fts_path, entry->fts_accpath, entry->fts_statp);
+ return 1;
+}
+
+PLAN *
+c_ls(OPTION *option, char ***argvp __unused)
+{
+ ftsoptions &= ~FTS_NOSTAT;
+ isoutput = 1;
+
+ return palloc(option);
+}
+
+/*
+ * -name functions --
+ *
+ * True if the basename of the filename being examined
+ * matches pattern using Pattern Matching Notation S3.14
+ */
+int
+f_name(PLAN *plan, FTSENT *entry)
+{
+ char fn[PATH_MAX];
+ const char *name;
+ ssize_t len;
+
+ if (plan->flags & F_LINK) {
+ /*
+ * The below test both avoids obviously useless readlink()
+ * calls and ensures that symlinks with existent target do
+ * not match if symlinks are being followed.
+ * Assumption: fts will stat all symlinks that are to be
+ * followed and will return the stat information.
+ */
+ if (entry->fts_info != FTS_NSOK && entry->fts_info != FTS_SL &&
+ entry->fts_info != FTS_SLNONE)
+ return 0;
+ len = readlink(entry->fts_accpath, fn, sizeof(fn) - 1);
+ if (len == -1)
+ return 0;
+ fn[len] = '\0';
+ name = fn;
+ } else if (entry->fts_namelen == 0) {
+ name = basename(entry->fts_path);
+ } else
+ name = entry->fts_name;
+ return !fnmatch(plan->c_data, name,
+ plan->flags & F_IGNCASE ? FNM_CASEFOLD : 0);
+}
+
+PLAN *
+c_name(OPTION *option, char ***argvp)
+{
+ char *pattern;
+ PLAN *new;
+
+ pattern = nextarg(option, argvp);
+ new = palloc(option);
+ new->c_data = pattern;
+ return new;
+}
+
+/*
+ * -newer file functions --
+ *
+ * True if the current file has been modified more recently
+ * then the modification time of the file named by the pathname
+ * file.
+ */
+int
+f_newer(PLAN *plan, FTSENT *entry)
+{
+ if (plan->flags & F_TIME_C)
+ return entry->fts_statp->st_ctime > plan->t_data;
+ else if (plan->flags & F_TIME_A)
+ return entry->fts_statp->st_atime > plan->t_data;
+ else if (plan->flags & F_TIME_B)
+ return entry->fts_statp->st_birthtime > plan->t_data;
+ else
+ return entry->fts_statp->st_mtime > plan->t_data;
+}
+
+PLAN *
+c_newer(OPTION *option, char ***argvp)
+{
+ char *fn_or_tspec;
+ PLAN *new;
+ struct stat sb;
+
+ fn_or_tspec = nextarg(option, argvp);
+ ftsoptions &= ~FTS_NOSTAT;
+
+ new = palloc(option);
+ /* compare against what */
+ if (option->flags & F_TIME2_T) {
+ new->t_data = get_date(fn_or_tspec);
+ if (new->t_data == (time_t) -1)
+ errx(1, "Can't parse date/time: %s", fn_or_tspec);
+ } else {
+ if (stat(fn_or_tspec, &sb))
+ err(1, "%s", fn_or_tspec);
+ if (option->flags & F_TIME2_C)
+ new->t_data = sb.st_ctime;
+ else if (option->flags & F_TIME2_A)
+ new->t_data = sb.st_atime;
+ else if (option->flags & F_TIME2_B)
+ new->t_data = sb.st_birthtime;
+ else
+ new->t_data = sb.st_mtime;
+ }
+ return new;
+}
+
+/*
+ * -nogroup functions --
+ *
+ * True if file belongs to a user ID for which the equivalent
+ * of the getgrnam() 9.2.1 [POSIX.1] function returns NULL.
+ */
+int
+f_nogroup(PLAN *plan __unused, FTSENT *entry)
+{
+ return group_from_gid(entry->fts_statp->st_gid, 1) == NULL;
+}
+
+PLAN *
+c_nogroup(OPTION *option, char ***argvp __unused)
+{
+ ftsoptions &= ~FTS_NOSTAT;
+
+ return palloc(option);
+}
+
+/*
+ * -nouser functions --
+ *
+ * True if file belongs to a user ID for which the equivalent
+ * of the getpwuid() 9.2.2 [POSIX.1] function returns NULL.
+ */
+int
+f_nouser(PLAN *plan __unused, FTSENT *entry)
+{
+ return user_from_uid(entry->fts_statp->st_uid, 1) == NULL;
+}
+
+PLAN *
+c_nouser(OPTION *option, char ***argvp __unused)
+{
+ ftsoptions &= ~FTS_NOSTAT;
+
+ return palloc(option);
+}
+
+/*
+ * -path functions --
+ *
+ * True if the path of the filename being examined
+ * matches pattern using Pattern Matching Notation S3.14
+ */
+int
+f_path(PLAN *plan, FTSENT *entry)
+{
+ return !fnmatch(plan->c_data, entry->fts_path,
+ plan->flags & F_IGNCASE ? FNM_CASEFOLD : 0);
+}
+
+/* c_path is the same as c_name */
+
+/*
+ * -perm functions --
+ *
+ * The mode argument is used to represent file mode bits. If it starts
+ * with a leading digit, it's treated as an octal mode, otherwise as a
+ * symbolic mode.
+ */
+int
+f_perm(PLAN *plan, FTSENT *entry)
+{
+ mode_t mode;
+
+ mode = entry->fts_statp->st_mode &
+ (S_ISUID|S_ISGID|S_ISTXT|S_IRWXU|S_IRWXG|S_IRWXO);
+ if (plan->flags & F_ATLEAST)
+ return (plan->m_data | mode) == mode;
+ else if (plan->flags & F_ANY)
+ return (mode & plan->m_data);
+ else
+ return mode == plan->m_data;
+ /* NOTREACHED */
+}
+
+PLAN *
+c_perm(OPTION *option, char ***argvp)
+{
+ char *perm;
+ PLAN *new;
+ mode_t *set;
+
+ perm = nextarg(option, argvp);
+ ftsoptions &= ~FTS_NOSTAT;
+
+ new = palloc(option);
+
+ if (*perm == '-') {
+ new->flags |= F_ATLEAST;
+ ++perm;
+ } else if (*perm == '+') {
+ if ((set = setmode(perm + 1)) != NULL) {
+ new->flags |= F_ANY;
+ ++perm;
+ free(set);
+ }
+ }
+
+ if ((set = setmode(perm)) == NULL)
+ errx(1, "%s: %s: illegal mode string", option->name, perm);
+
+ new->m_data = getmode(set, 0);
+ free(set);
+ return new;
+}
+
+/*
+ * -print functions --
+ *
+ * Always true, causes the current pathname to be written to
+ * standard output.
+ */
+int
+f_print(PLAN *plan __unused, FTSENT *entry)
+{
+ (void)puts(entry->fts_path);
+ return 1;
+}
+
+PLAN *
+c_print(OPTION *option, char ***argvp __unused)
+{
+ isoutput = 1;
+
+ return palloc(option);
+}
+
+/*
+ * -print0 functions --
+ *
+ * Always true, causes the current pathname to be written to
+ * standard output followed by a NUL character
+ */
+int
+f_print0(PLAN *plan __unused, FTSENT *entry)
+{
+ fputs(entry->fts_path, stdout);
+ fputc('\0', stdout);
+ return 1;
+}
+
+/* c_print0 is the same as c_print */
+
+/*
+ * -prune functions --
+ *
+ * Prune a portion of the hierarchy.
+ */
+int
+f_prune(PLAN *plan __unused, FTSENT *entry)
+{
+ if (fts_set(tree, entry, FTS_SKIP))
+ err(1, "%s", entry->fts_path);
+ return 1;
+}
+
+/* c_prune == c_simple */
+
+/*
+ * -regex functions --
+ *
+ * True if the whole path of the file matches pattern using
+ * regular expression.
+ */
+int
+f_regex(PLAN *plan, FTSENT *entry)
+{
+ char *str;
+ int len;
+ regex_t *pre;
+ regmatch_t pmatch;
+ int errcode;
+ char errbuf[LINE_MAX];
+ int matched;
+
+ pre = plan->re_data;
+ str = entry->fts_path;
+ len = strlen(str);
+ matched = 0;
+
+ pmatch.rm_so = 0;
+ pmatch.rm_eo = len;
+
+ errcode = regexec(pre, str, 1, &pmatch, REG_STARTEND);
+
+ if (errcode != 0 && errcode != REG_NOMATCH) {
+ regerror(errcode, pre, errbuf, sizeof errbuf);
+ errx(1, "%s: %s",
+ plan->flags & F_IGNCASE ? "-iregex" : "-regex", errbuf);
+ }
+
+ if (errcode == 0 && pmatch.rm_so == 0 && pmatch.rm_eo == len)
+ matched = 1;
+
+ return matched;
+}
+
+PLAN *
+c_regex(OPTION *option, char ***argvp)
+{
+ PLAN *new;
+ char *pattern;
+ regex_t *pre;
+ int errcode;
+ char errbuf[LINE_MAX];
+
+ if ((pre = malloc(sizeof(regex_t))) == NULL)
+ err(1, NULL);
+
+ pattern = nextarg(option, argvp);
+
+ if ((errcode = regcomp(pre, pattern,
+ regexp_flags | (option->flags & F_IGNCASE ? REG_ICASE : 0))) != 0) {
+ regerror(errcode, pre, errbuf, sizeof errbuf);
+ errx(1, "%s: %s: %s",
+ option->flags & F_IGNCASE ? "-iregex" : "-regex",
+ pattern, errbuf);
+ }
+
+ new = palloc(option);
+ new->re_data = pre;
+
+ return new;
+}
+
+/* c_simple covers c_prune, c_openparen, c_closeparen, c_not, c_or, c_true, c_false */
+
+PLAN *
+c_simple(OPTION *option, char ***argvp __unused)
+{
+ return palloc(option);
+}
+
+/*
+ * -size n[c] functions --
+ *
+ * True if the file size in bytes, divided by an implementation defined
+ * value and rounded up to the next integer, is n. If n is followed by
+ * one of c k M G T P, the size is in bytes, kilobytes,
+ * megabytes, gigabytes, terabytes or petabytes respectively.
+ */
+#define FIND_SIZE 512
+static int divsize = 1;
+
+int
+f_size(PLAN *plan, FTSENT *entry)
+{
+ off_t size;
+
+ size = divsize ? (entry->fts_statp->st_size + FIND_SIZE - 1) /
+ FIND_SIZE : entry->fts_statp->st_size;
+ COMPARE(size, plan->o_data);
+}
+
+PLAN *
+c_size(OPTION *option, char ***argvp)
+{
+ char *size_str;
+ PLAN *new;
+ char endch;
+ off_t scale;
+
+ size_str = nextarg(option, argvp);
+ ftsoptions &= ~FTS_NOSTAT;
+
+ new = palloc(option);
+ endch = 'c';
+ new->o_data = find_parsenum(new, option->name, size_str, &endch);
+ if (endch != '\0') {
+ divsize = 0;
+
+ switch (endch) {
+ case 'c': /* characters */
+ scale = 0x1LL;
+ break;
+ case 'k': /* kilobytes 1<<10 */
+ scale = 0x400LL;
+ break;
+ case 'M': /* megabytes 1<<20 */
+ scale = 0x100000LL;
+ break;
+ case 'G': /* gigabytes 1<<30 */
+ scale = 0x40000000LL;
+ break;
+ case 'T': /* terabytes 1<<40 */
+ scale = 0x1000000000LL;
+ break;
+ case 'P': /* petabytes 1<<50 */
+ scale = 0x4000000000000LL;
+ break;
+ default:
+ errx(1, "%s: %s: illegal trailing character",
+ option->name, size_str);
+ break;
+ }
+ if (new->o_data > QUAD_MAX / scale)
+ errx(1, "%s: %s: value too large",
+ option->name, size_str);
+ new->o_data *= scale;
+ }
+ return new;
+}
+
+/*
+ * -type c functions --
+ *
+ * True if the type of the file is c, where c is b, c, d, p, f or w
+ * for block special file, character special file, directory, FIFO,
+ * regular file or whiteout respectively.
+ */
+int
+f_type(PLAN *plan, FTSENT *entry)
+{
+ return (entry->fts_statp->st_mode & S_IFMT) == plan->m_data;
+}
+
+PLAN *
+c_type(OPTION *option, char ***argvp)
+{
+ char *typestring;
+ PLAN *new;
+ mode_t mask;
+
+ typestring = nextarg(option, argvp);
+ ftsoptions &= ~FTS_NOSTAT;
+
+ switch (typestring[0]) {
+ case 'b':
+ mask = S_IFBLK;
+ break;
+ case 'c':
+ mask = S_IFCHR;
+ break;
+ case 'd':
+ mask = S_IFDIR;
+ break;
+ case 'f':
+ mask = S_IFREG;
+ break;
+ case 'l':
+ mask = S_IFLNK;
+ break;
+ case 'p':
+ mask = S_IFIFO;
+ break;
+ case 's':
+ mask = S_IFSOCK;
+ break;
+#ifdef FTS_WHITEOUT
+ case 'w':
+ mask = S_IFWHT;
+ ftsoptions |= FTS_WHITEOUT;
+ break;
+#endif /* FTS_WHITEOUT */
+ default:
+ errx(1, "%s: %s: unknown type", option->name, typestring);
+ }
+
+ new = palloc(option);
+ new->m_data = mask;
+ return new;
+}
+
+/*
+ * -user uname functions --
+ *
+ * True if the file belongs to the user uname. If uname is numeric and
+ * an equivalent of the getpwnam() S9.2.2 [POSIX.1] function does not
+ * return a valid user name, uname is taken as a user ID.
+ */
+int
+f_user(PLAN *plan, FTSENT *entry)
+{
+ COMPARE(entry->fts_statp->st_uid, plan->u_data);
+}
+
+PLAN *
+c_user(OPTION *option, char ***argvp)
+{
+ char *username;
+ PLAN *new;
+ struct passwd *p;
+ uid_t uid;
+
+ username = nextarg(option, argvp);
+ ftsoptions &= ~FTS_NOSTAT;
+
+ new = palloc(option);
+ p = getpwnam(username);
+ if (p == NULL) {
+ char* cp = username;
+ if( username[0] == '-' || username[0] == '+' )
+ username++;
+ uid = atoi(username);
+ if (uid == 0 && username[0] != '0')
+ errx(1, "%s: %s: no such user", option->name, username);
+ uid = find_parsenum(new, option->name, cp, NULL);
+ } else
+ uid = p->pw_uid;
+
+ new->u_data = uid;
+ return new;
+}
+
+/*
+ * -xdev functions --
+ *
+ * Always true, causes find not to descend past directories that have a
+ * different device ID (st_dev, see stat() S5.6.2 [POSIX.1])
+ */
+PLAN *
+c_xdev(OPTION *option, char ***argvp __unused)
+{
+ ftsoptions |= FTS_XDEV;
+
+ return palloc(option);
+}
+
+/*
+ * ( expression ) functions --
+ *
+ * True if expression is true.
+ */
+int
+f_expr(PLAN *plan, FTSENT *entry)
+{
+ PLAN *p;
+ int state = 0;
+
+ for (p = plan->p_data[0];
+ p && (state = (p->execute)(p, entry)); p = p->next);
+ return state;
+}
+
+/*
+ * f_openparen and f_closeparen nodes are temporary place markers. They are
+ * eliminated during phase 2 of find_formplan() --- the '(' node is converted
+ * to a f_expr node containing the expression and the ')' node is discarded.
+ * The functions themselves are only used as constants.
+ */
+
+int
+f_openparen(PLAN *plan __unused, FTSENT *entry __unused)
+{
+ abort();
+}
+
+int
+f_closeparen(PLAN *plan __unused, FTSENT *entry __unused)
+{
+ abort();
+}
+
+/* c_openparen == c_simple */
+/* c_closeparen == c_simple */
+
+/*
+ * AND operator. Since AND is implicit, no node is allocated.
+ */
+PLAN *
+c_and(OPTION *option __unused, char ***argvp __unused)
+{
+ return NULL;
+}
+
+/*
+ * ! expression functions --
+ *
+ * Negation of a primary; the unary NOT operator.
+ */
+int
+f_not(PLAN *plan, FTSENT *entry)
+{
+ PLAN *p;
+ int state = 0;
+
+ for (p = plan->p_data[0];
+ p && (state = (p->execute)(p, entry)); p = p->next);
+ return !state;
+}
+
+/* c_not == c_simple */
+
+/*
+ * expression -o expression functions --
+ *
+ * Alternation of primaries; the OR operator. The second expression is
+ * not evaluated if the first expression is true.
+ */
+int
+f_or(PLAN *plan, FTSENT *entry)
+{
+ PLAN *p;
+ int state = 0;
+
+ for (p = plan->p_data[0];
+ p && (state = (p->execute)(p, entry)); p = p->next);
+
+ if (state)
+ return 1;
+
+ for (p = plan->p_data[1];
+ p && (state = (p->execute)(p, entry)); p = p->next);
+ return state;
+}
+
+/* c_or == c_simple */
+
+/*
+ * -false
+ *
+ * Always false.
+ */
+int
+f_false(PLAN *plan __unused, FTSENT *entry __unused)
+{
+ return 0;
+}
+
+/* c_false == c_simple */
+
+/*
+ * -quit
+ *
+ * Exits the program
+ */
+int
+f_quit(PLAN *plan __unused, FTSENT *entry __unused)
+{
+ exit(0);
+}
+
+/* c_quit == c_simple */
diff --git a/shell_cmds/find/getdate.y b/shell_cmds/find/getdate.y
new file mode 100644
index 0000000..5a97c2c
--- /dev/null
+++ b/shell_cmds/find/getdate.y
@@ -0,0 +1,961 @@
+%{
+/*
+** Originally written by Steven M. Bellovin <smb@research.att.com> while
+** at the University of North Carolina at Chapel Hill. Later tweaked by
+** a couple of people on Usenet. Completely overhauled by Rich $alz
+** <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990;
+**
+** This grammar has 10 shift/reduce conflicts.
+**
+** This code is in the public domain and has no copyright.
+*/
+/* SUPPRESS 287 on yaccpar_sccsid *//* Unused static variable */
+/* SUPPRESS 288 on yyerrlab *//* Label unused */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/find/getdate.y,v 1.7 2010/02/09 21:24:41 ed Exp $");
+
+#include <stdio.h>
+#include <ctype.h>
+
+/* The code at the top of get_date which figures out the offset of the
+ current time zone checks various CPP symbols to see if special
+ tricks are need, but defaults to using the gettimeofday system call.
+ Include <sys/time.h> if that will be used. */
+
+#if defined(vms)
+# include <types.h>
+#else /* defined(vms) */
+# include <sys/types.h>
+# include <sys/time.h>
+#endif /* !defined(vms) */
+
+#if defined (__STDC__) || defined (USG)
+#include <string.h>
+#endif
+
+/* Some old versions of bison generate parsers that use bcopy.
+ That loses on systems that don't provide the function, so we have
+ to redefine it here. */
+#if !defined (HAVE_BCOPY) && defined (HAVE_MEMCPY) && !defined (bcopy)
+#define bcopy(from, to, len) memcpy ((to), (from), (len))
+#endif
+
+#if defined (__STDC__)
+#include <stdlib.h>
+#endif
+
+/* NOTES on rebuilding getdate.c (particularly for inclusion in CVS
+ releases):
+
+ We don't want to mess with all the portability hassles of alloca.
+ In particular, most (all?) versions of bison will use alloca in
+ their parser. If bison works on your system (e.g. it should work
+ with gcc), then go ahead and use it, but the more general solution
+ is to use byacc instead of bison, which should generate a portable
+ parser. I played with adding "#define alloca dont_use_alloca", to
+ give an error if the parser generator uses alloca (and thus detect
+ unportable getdate.c's), but that seems to cause as many problems
+ as it solves. */
+
+#include <time.h>
+
+#define yyparse getdate_yyparse
+#define yylex getdate_yylex
+#define yyerror getdate_yyerror
+
+static int yyparse(void);
+static int yylex(void);
+static int yyerror(const char *);
+
+time_t get_date(char *);
+
+#define EPOCH 1970
+#define HOUR(x) ((time_t)(x) * 60)
+#define SECSPERDAY (24L * 60L * 60L)
+
+
+/*
+** An entry in the lexical lookup table.
+*/
+typedef struct _TABLE {
+ const char *name;
+ int type;
+ time_t value;
+} TABLE;
+
+
+/*
+** Daylight-savings mode: on, off, or not yet known.
+*/
+typedef enum _DSTMODE {
+ DSTon, DSToff, DSTmaybe
+} DSTMODE;
+
+/*
+** Meridian: am, pm, or 24-hour style.
+*/
+typedef enum _MERIDIAN {
+ MERam, MERpm, MER24
+} MERIDIAN;
+
+
+/*
+** Global variables. We could get rid of most of these by using a good
+** union as the yacc stack. (This routine was originally written before
+** yacc had the %union construct.) Maybe someday; right now we only use
+** the %union very rarely.
+*/
+static char *yyInput;
+static DSTMODE yyDSTmode;
+static time_t yyDayOrdinal;
+static time_t yyDayNumber;
+static int yyHaveDate;
+static int yyHaveDay;
+static int yyHaveRel;
+static int yyHaveTime;
+static int yyHaveZone;
+static time_t yyTimezone;
+static time_t yyDay;
+static time_t yyHour;
+static time_t yyMinutes;
+static time_t yyMonth;
+static time_t yySeconds;
+static time_t yyYear;
+static MERIDIAN yyMeridian;
+static time_t yyRelMonth;
+static time_t yyRelSeconds;
+
+%}
+
+%union {
+ time_t Number;
+ enum _MERIDIAN Meridian;
+}
+
+%token tAGO tDAY tDAYZONE tID tMERIDIAN tMINUTE_UNIT tMONTH tMONTH_UNIT
+%token tSEC_UNIT tSNUMBER tUNUMBER tZONE tDST
+
+%type <Number> tDAY tDAYZONE tMINUTE_UNIT tMONTH tMONTH_UNIT
+%type <Number> tSEC_UNIT tSNUMBER tUNUMBER tZONE
+%type <Meridian> tMERIDIAN o_merid
+
+%%
+
+spec : /* NULL */
+ | spec item
+ ;
+
+item : time {
+ yyHaveTime++;
+ }
+ | zone {
+ yyHaveZone++;
+ }
+ | date {
+ yyHaveDate++;
+ }
+ | day {
+ yyHaveDay++;
+ }
+ | rel {
+ yyHaveRel++;
+ }
+ | number
+ ;
+
+time : tUNUMBER tMERIDIAN {
+ yyHour = $1;
+ yyMinutes = 0;
+ yySeconds = 0;
+ yyMeridian = $2;
+ }
+ | tUNUMBER ':' tUNUMBER o_merid {
+ yyHour = $1;
+ yyMinutes = $3;
+ yySeconds = 0;
+ yyMeridian = $4;
+ }
+ | tUNUMBER ':' tUNUMBER tSNUMBER {
+ yyHour = $1;
+ yyMinutes = $3;
+ yyMeridian = MER24;
+ yyDSTmode = DSToff;
+ yyTimezone = - ($4 % 100 + ($4 / 100) * 60);
+ }
+ | tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid {
+ yyHour = $1;
+ yyMinutes = $3;
+ yySeconds = $5;
+ yyMeridian = $6;
+ }
+ | tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER {
+ yyHour = $1;
+ yyMinutes = $3;
+ yySeconds = $5;
+ yyMeridian = MER24;
+ yyDSTmode = DSToff;
+ yyTimezone = - ($6 % 100 + ($6 / 100) * 60);
+ }
+ ;
+
+zone : tZONE {
+ yyTimezone = $1;
+ yyDSTmode = DSToff;
+ }
+ | tDAYZONE {
+ yyTimezone = $1;
+ yyDSTmode = DSTon;
+ }
+ |
+ tZONE tDST {
+ yyTimezone = $1;
+ yyDSTmode = DSTon;
+ }
+ ;
+
+day : tDAY {
+ yyDayOrdinal = 1;
+ yyDayNumber = $1;
+ }
+ | tDAY ',' {
+ yyDayOrdinal = 1;
+ yyDayNumber = $1;
+ }
+ | tUNUMBER tDAY {
+ yyDayOrdinal = $1;
+ yyDayNumber = $2;
+ }
+ ;
+
+date : tUNUMBER '/' tUNUMBER {
+ yyMonth = $1;
+ yyDay = $3;
+ }
+ | tUNUMBER '/' tUNUMBER '/' tUNUMBER {
+ if ($1 >= 100) {
+ yyYear = $1;
+ yyMonth = $3;
+ yyDay = $5;
+ } else {
+ yyMonth = $1;
+ yyDay = $3;
+ yyYear = $5;
+ }
+ }
+ | tUNUMBER tSNUMBER tSNUMBER {
+ /* ISO 8601 format. yyyy-mm-dd. */
+ yyYear = $1;
+ yyMonth = -$2;
+ yyDay = -$3;
+ }
+ | tUNUMBER tMONTH tSNUMBER {
+ /* e.g. 17-JUN-1992. */
+ yyDay = $1;
+ yyMonth = $2;
+ yyYear = -$3;
+ }
+ | tMONTH tUNUMBER {
+ yyMonth = $1;
+ yyDay = $2;
+ }
+ | tMONTH tUNUMBER ',' tUNUMBER {
+ yyMonth = $1;
+ yyDay = $2;
+ yyYear = $4;
+ }
+ | tUNUMBER tMONTH {
+ yyMonth = $2;
+ yyDay = $1;
+ }
+ | tUNUMBER tMONTH tUNUMBER {
+ yyMonth = $2;
+ yyDay = $1;
+ yyYear = $3;
+ }
+ ;
+
+rel : relunit tAGO {
+ yyRelSeconds = -yyRelSeconds;
+ yyRelMonth = -yyRelMonth;
+ }
+ | relunit
+ ;
+
+relunit : tUNUMBER tMINUTE_UNIT {
+ yyRelSeconds += $1 * $2 * 60L;
+ }
+ | tSNUMBER tMINUTE_UNIT {
+ yyRelSeconds += $1 * $2 * 60L;
+ }
+ | tMINUTE_UNIT {
+ yyRelSeconds += $1 * 60L;
+ }
+ | tSNUMBER tSEC_UNIT {
+ yyRelSeconds += $1;
+ }
+ | tUNUMBER tSEC_UNIT {
+ yyRelSeconds += $1;
+ }
+ | tSEC_UNIT {
+ yyRelSeconds++;
+ }
+ | tSNUMBER tMONTH_UNIT {
+ yyRelMonth += $1 * $2;
+ }
+ | tUNUMBER tMONTH_UNIT {
+ yyRelMonth += $1 * $2;
+ }
+ | tMONTH_UNIT {
+ yyRelMonth += $1;
+ }
+ ;
+
+number : tUNUMBER {
+ if (yyHaveTime && yyHaveDate && !yyHaveRel)
+ yyYear = $1;
+ else {
+ if($1>10000) {
+ yyHaveDate++;
+ yyDay= ($1)%100;
+ yyMonth= ($1/100)%100;
+ yyYear = $1/10000;
+ }
+ else {
+ yyHaveTime++;
+ if ($1 < 100) {
+ yyHour = $1;
+ yyMinutes = 0;
+ }
+ else {
+ yyHour = $1 / 100;
+ yyMinutes = $1 % 100;
+ }
+ yySeconds = 0;
+ yyMeridian = MER24;
+ }
+ }
+ }
+ ;
+
+o_merid : /* NULL */ {
+ $$ = MER24;
+ }
+ | tMERIDIAN {
+ $$ = $1;
+ }
+ ;
+
+%%
+
+/* Month and day table. */
+static TABLE const MonthDayTable[] = {
+ { "january", tMONTH, 1 },
+ { "february", tMONTH, 2 },
+ { "march", tMONTH, 3 },
+ { "april", tMONTH, 4 },
+ { "may", tMONTH, 5 },
+ { "june", tMONTH, 6 },
+ { "july", tMONTH, 7 },
+ { "august", tMONTH, 8 },
+ { "september", tMONTH, 9 },
+ { "sept", tMONTH, 9 },
+ { "october", tMONTH, 10 },
+ { "november", tMONTH, 11 },
+ { "december", tMONTH, 12 },
+ { "sunday", tDAY, 0 },
+ { "monday", tDAY, 1 },
+ { "tuesday", tDAY, 2 },
+ { "tues", tDAY, 2 },
+ { "wednesday", tDAY, 3 },
+ { "wednes", tDAY, 3 },
+ { "thursday", tDAY, 4 },
+ { "thur", tDAY, 4 },
+ { "thurs", tDAY, 4 },
+ { "friday", tDAY, 5 },
+ { "saturday", tDAY, 6 },
+ { NULL, 0, 0 }
+};
+
+/* Time units table. */
+static TABLE const UnitsTable[] = {
+ { "year", tMONTH_UNIT, 12 },
+ { "month", tMONTH_UNIT, 1 },
+ { "fortnight", tMINUTE_UNIT, 14 * 24 * 60 },
+ { "week", tMINUTE_UNIT, 7 * 24 * 60 },
+ { "day", tMINUTE_UNIT, 1 * 24 * 60 },
+ { "hour", tMINUTE_UNIT, 60 },
+ { "minute", tMINUTE_UNIT, 1 },
+ { "min", tMINUTE_UNIT, 1 },
+ { "second", tSEC_UNIT, 1 },
+ { "sec", tSEC_UNIT, 1 },
+ { NULL, 0, 0 }
+};
+
+/* Assorted relative-time words. */
+static TABLE const OtherTable[] = {
+ { "tomorrow", tMINUTE_UNIT, 1 * 24 * 60 },
+ { "yesterday", tMINUTE_UNIT, -1 * 24 * 60 },
+ { "today", tMINUTE_UNIT, 0 },
+ { "now", tMINUTE_UNIT, 0 },
+ { "last", tUNUMBER, -1 },
+ { "this", tMINUTE_UNIT, 0 },
+ { "next", tUNUMBER, 2 },
+ { "first", tUNUMBER, 1 },
+/* { "second", tUNUMBER, 2 }, */
+ { "third", tUNUMBER, 3 },
+ { "fourth", tUNUMBER, 4 },
+ { "fifth", tUNUMBER, 5 },
+ { "sixth", tUNUMBER, 6 },
+ { "seventh", tUNUMBER, 7 },
+ { "eighth", tUNUMBER, 8 },
+ { "ninth", tUNUMBER, 9 },
+ { "tenth", tUNUMBER, 10 },
+ { "eleventh", tUNUMBER, 11 },
+ { "twelfth", tUNUMBER, 12 },
+ { "ago", tAGO, 1 },
+ { NULL, 0, 0 }
+};
+
+/* The timezone table. */
+/* Some of these are commented out because a time_t can't store a float. */
+static TABLE const TimezoneTable[] = {
+ { "gmt", tZONE, HOUR( 0) }, /* Greenwich Mean */
+ { "ut", tZONE, HOUR( 0) }, /* Universal (Coordinated) */
+ { "utc", tZONE, HOUR( 0) },
+ { "wet", tZONE, HOUR( 0) }, /* Western European */
+ { "bst", tDAYZONE, HOUR( 0) }, /* British Summer */
+ { "wat", tZONE, HOUR( 1) }, /* West Africa */
+ { "at", tZONE, HOUR( 2) }, /* Azores */
+#if 0
+ /* For completeness. BST is also British Summer, and GST is
+ * also Guam Standard. */
+ { "bst", tZONE, HOUR( 3) }, /* Brazil Standard */
+ { "gst", tZONE, HOUR( 3) }, /* Greenland Standard */
+#endif
+#if 0
+ { "nft", tZONE, HOUR(3.5) }, /* Newfoundland */
+ { "nst", tZONE, HOUR(3.5) }, /* Newfoundland Standard */
+ { "ndt", tDAYZONE, HOUR(3.5) }, /* Newfoundland Daylight */
+#endif
+ { "ast", tZONE, HOUR( 4) }, /* Atlantic Standard */
+ { "adt", tDAYZONE, HOUR( 4) }, /* Atlantic Daylight */
+ { "est", tZONE, HOUR( 5) }, /* Eastern Standard */
+ { "edt", tDAYZONE, HOUR( 5) }, /* Eastern Daylight */
+ { "cst", tZONE, HOUR( 6) }, /* Central Standard */
+ { "cdt", tDAYZONE, HOUR( 6) }, /* Central Daylight */
+ { "mst", tZONE, HOUR( 7) }, /* Mountain Standard */
+ { "mdt", tDAYZONE, HOUR( 7) }, /* Mountain Daylight */
+ { "pst", tZONE, HOUR( 8) }, /* Pacific Standard */
+ { "pdt", tDAYZONE, HOUR( 8) }, /* Pacific Daylight */
+ { "yst", tZONE, HOUR( 9) }, /* Yukon Standard */
+ { "ydt", tDAYZONE, HOUR( 9) }, /* Yukon Daylight */
+ { "hst", tZONE, HOUR(10) }, /* Hawaii Standard */
+ { "hdt", tDAYZONE, HOUR(10) }, /* Hawaii Daylight */
+ { "cat", tZONE, HOUR(10) }, /* Central Alaska */
+ { "ahst", tZONE, HOUR(10) }, /* Alaska-Hawaii Standard */
+ { "nt", tZONE, HOUR(11) }, /* Nome */
+ { "idlw", tZONE, HOUR(12) }, /* International Date Line West */
+ { "cet", tZONE, -HOUR(1) }, /* Central European */
+ { "met", tZONE, -HOUR(1) }, /* Middle European */
+ { "mewt", tZONE, -HOUR(1) }, /* Middle European Winter */
+ { "mest", tDAYZONE, -HOUR(1) }, /* Middle European Summer */
+ { "swt", tZONE, -HOUR(1) }, /* Swedish Winter */
+ { "sst", tDAYZONE, -HOUR(1) }, /* Swedish Summer */
+ { "fwt", tZONE, -HOUR(1) }, /* French Winter */
+ { "fst", tDAYZONE, -HOUR(1) }, /* French Summer */
+ { "eet", tZONE, -HOUR(2) }, /* Eastern Europe, USSR Zone 1 */
+ { "bt", tZONE, -HOUR(3) }, /* Baghdad, USSR Zone 2 */
+#if 0
+ { "it", tZONE, -HOUR(3.5) },/* Iran */
+#endif
+ { "zp4", tZONE, -HOUR(4) }, /* USSR Zone 3 */
+ { "zp5", tZONE, -HOUR(5) }, /* USSR Zone 4 */
+#if 0
+ { "ist", tZONE, -HOUR(5.5) },/* Indian Standard */
+#endif
+ { "zp6", tZONE, -HOUR(6) }, /* USSR Zone 5 */
+#if 0
+ /* For completeness. NST is also Newfoundland Stanard, and SST is
+ * also Swedish Summer. */
+ { "nst", tZONE, -HOUR(6.5) },/* North Sumatra */
+ { "sst", tZONE, -HOUR(7) }, /* South Sumatra, USSR Zone 6 */
+#endif /* 0 */
+ { "wast", tZONE, -HOUR(7) }, /* West Australian Standard */
+ { "wadt", tDAYZONE, -HOUR(7) }, /* West Australian Daylight */
+#if 0
+ { "jt", tZONE, -HOUR(7.5) },/* Java (3pm in Cronusland!) */
+#endif
+ { "cct", tZONE, -HOUR(8) }, /* China Coast, USSR Zone 7 */
+ { "jst", tZONE, -HOUR(9) }, /* Japan Standard, USSR Zone 8 */
+#if 0
+ { "cast", tZONE, -HOUR(9.5) },/* Central Australian Standard */
+ { "cadt", tDAYZONE, -HOUR(9.5) },/* Central Australian Daylight */
+#endif
+ { "east", tZONE, -HOUR(10) }, /* Eastern Australian Standard */
+ { "eadt", tDAYZONE, -HOUR(10) }, /* Eastern Australian Daylight */
+ { "gst", tZONE, -HOUR(10) }, /* Guam Standard, USSR Zone 9 */
+ { "nzt", tZONE, -HOUR(12) }, /* New Zealand */
+ { "nzst", tZONE, -HOUR(12) }, /* New Zealand Standard */
+ { "nzdt", tDAYZONE, -HOUR(12) }, /* New Zealand Daylight */
+ { "idle", tZONE, -HOUR(12) }, /* International Date Line East */
+ { NULL, 0, 0 }
+};
+
+/* Military timezone table. */
+static TABLE const MilitaryTable[] = {
+ { "a", tZONE, HOUR( 1) },
+ { "b", tZONE, HOUR( 2) },
+ { "c", tZONE, HOUR( 3) },
+ { "d", tZONE, HOUR( 4) },
+ { "e", tZONE, HOUR( 5) },
+ { "f", tZONE, HOUR( 6) },
+ { "g", tZONE, HOUR( 7) },
+ { "h", tZONE, HOUR( 8) },
+ { "i", tZONE, HOUR( 9) },
+ { "k", tZONE, HOUR( 10) },
+ { "l", tZONE, HOUR( 11) },
+ { "m", tZONE, HOUR( 12) },
+ { "n", tZONE, HOUR(- 1) },
+ { "o", tZONE, HOUR(- 2) },
+ { "p", tZONE, HOUR(- 3) },
+ { "q", tZONE, HOUR(- 4) },
+ { "r", tZONE, HOUR(- 5) },
+ { "s", tZONE, HOUR(- 6) },
+ { "t", tZONE, HOUR(- 7) },
+ { "u", tZONE, HOUR(- 8) },
+ { "v", tZONE, HOUR(- 9) },
+ { "w", tZONE, HOUR(-10) },
+ { "x", tZONE, HOUR(-11) },
+ { "y", tZONE, HOUR(-12) },
+ { "z", tZONE, HOUR( 0) },
+ { NULL, 0, 0 }
+};
+
+
+
+
+/* ARGSUSED */
+static int
+yyerror(const char *s __unused)
+{
+ return 0;
+}
+
+
+static time_t
+ToSeconds(time_t Hours, time_t Minutes, time_t Seconds, MERIDIAN Meridian)
+{
+ if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59)
+ return -1;
+ switch (Meridian) {
+ case MER24:
+ if (Hours < 0 || Hours > 23)
+ return -1;
+ return (Hours * 60L + Minutes) * 60L + Seconds;
+ case MERam:
+ if (Hours < 1 || Hours > 12)
+ return -1;
+ if (Hours == 12)
+ Hours = 0;
+ return (Hours * 60L + Minutes) * 60L + Seconds;
+ case MERpm:
+ if (Hours < 1 || Hours > 12)
+ return -1;
+ if (Hours == 12)
+ Hours = 0;
+ return ((Hours + 12) * 60L + Minutes) * 60L + Seconds;
+ default:
+ abort ();
+ }
+ /* NOTREACHED */
+}
+
+
+/* Year is either
+ * A negative number, which means to use its absolute value (why?)
+ * A number from 0 to 99, which means a year from 1900 to 1999, or
+ * The actual year (>=100). */
+static time_t
+Convert(time_t Month, time_t Day, time_t Year,
+ time_t Hours, time_t Minutes, time_t Seconds,
+ MERIDIAN Meridian, DSTMODE DSTmode)
+{
+ static int DaysInMonth[12] = {
+ 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+ };
+ time_t tod;
+ time_t Julian;
+ int i;
+
+ if (Year < 0)
+ Year = -Year;
+ if (Year < 69)
+ Year += 2000;
+ else if (Year < 100)
+ Year += 1900;
+ DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0)
+ ? 29 : 28;
+ /* Checking for 2038 bogusly assumes that time_t is 32 bits. But
+ I'm too lazy to try to check for time_t overflow in another way. */
+ if (Year < EPOCH || Year > 2038
+ || Month < 1 || Month > 12
+ /* Lint fluff: "conversion from long may lose accuracy" */
+ || Day < 1 || Day > DaysInMonth[(int)--Month])
+ return -1;
+
+ for (Julian = Day - 1, i = 0; i < Month; i++)
+ Julian += DaysInMonth[i];
+ for (i = EPOCH; i < Year; i++)
+ Julian += 365 + (i % 4 == 0);
+ Julian *= SECSPERDAY;
+ Julian += yyTimezone * 60L;
+ if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0)
+ return -1;
+ Julian += tod;
+ if (DSTmode == DSTon
+ || (DSTmode == DSTmaybe && localtime(&Julian)->tm_isdst))
+ Julian -= 60 * 60;
+ return Julian;
+}
+
+
+static time_t
+DSTcorrect(time_t Start, time_t Future)
+{
+ time_t StartDay;
+ time_t FutureDay;
+
+ StartDay = (localtime(&Start)->tm_hour + 1) % 24;
+ FutureDay = (localtime(&Future)->tm_hour + 1) % 24;
+ return (Future - Start) + (StartDay - FutureDay) * 60L * 60L;
+}
+
+
+static time_t
+RelativeDate(time_t Start, time_t DayOrdinal, time_t DayNumber)
+{
+ struct tm *tm;
+ time_t now;
+
+ now = Start;
+ tm = localtime(&now);
+ now += SECSPERDAY * ((DayNumber - tm->tm_wday + 7) % 7);
+ now += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1);
+ return DSTcorrect(Start, now);
+}
+
+
+static time_t
+RelativeMonth(time_t Start, time_t RelMonth)
+{
+ struct tm *tm;
+ time_t Month;
+ time_t Year;
+
+ if (RelMonth == 0)
+ return 0;
+ tm = localtime(&Start);
+ Month = 12 * (tm->tm_year + 1900) + tm->tm_mon + RelMonth;
+ Year = Month / 12;
+ Month = Month % 12 + 1;
+ return DSTcorrect(Start,
+ Convert(Month, (time_t)tm->tm_mday, Year,
+ (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec,
+ MER24, DSTmaybe));
+}
+
+
+static int
+LookupWord(char *buff)
+{
+ char *p;
+ char *q;
+ const TABLE *tp;
+ int i;
+ int abbrev;
+
+ /* Make it lowercase. */
+ for (p = buff; *p; p++)
+ if (isupper(*p))
+ *p = tolower(*p);
+
+ if (strcmp(buff, "am") == 0 || strcmp(buff, "a.m.") == 0) {
+ yylval.Meridian = MERam;
+ return tMERIDIAN;
+ }
+ if (strcmp(buff, "pm") == 0 || strcmp(buff, "p.m.") == 0) {
+ yylval.Meridian = MERpm;
+ return tMERIDIAN;
+ }
+
+ /* See if we have an abbreviation for a month. */
+ if (strlen(buff) == 3)
+ abbrev = 1;
+ else if (strlen(buff) == 4 && buff[3] == '.') {
+ abbrev = 1;
+ buff[3] = '\0';
+ }
+ else
+ abbrev = 0;
+
+ for (tp = MonthDayTable; tp->name; tp++) {
+ if (abbrev) {
+ if (strncmp(buff, tp->name, 3) == 0) {
+ yylval.Number = tp->value;
+ return tp->type;
+ }
+ }
+ else if (strcmp(buff, tp->name) == 0) {
+ yylval.Number = tp->value;
+ return tp->type;
+ }
+ }
+
+ for (tp = TimezoneTable; tp->name; tp++)
+ if (strcmp(buff, tp->name) == 0) {
+ yylval.Number = tp->value;
+ return tp->type;
+ }
+
+ if (strcmp(buff, "dst") == 0)
+ return tDST;
+
+ for (tp = UnitsTable; tp->name; tp++)
+ if (strcmp(buff, tp->name) == 0) {
+ yylval.Number = tp->value;
+ return tp->type;
+ }
+
+ /* Strip off any plural and try the units table again. */
+ i = strlen(buff) - 1;
+ if (buff[i] == 's') {
+ buff[i] = '\0';
+ for (tp = UnitsTable; tp->name; tp++)
+ if (strcmp(buff, tp->name) == 0) {
+ yylval.Number = tp->value;
+ return tp->type;
+ }
+ buff[i] = 's'; /* Put back for "this" in OtherTable. */
+ }
+
+ for (tp = OtherTable; tp->name; tp++)
+ if (strcmp(buff, tp->name) == 0) {
+ yylval.Number = tp->value;
+ return tp->type;
+ }
+
+ /* Military timezones. */
+ if (buff[1] == '\0' && isalpha(*buff)) {
+ for (tp = MilitaryTable; tp->name; tp++)
+ if (strcmp(buff, tp->name) == 0) {
+ yylval.Number = tp->value;
+ return tp->type;
+ }
+ }
+
+ /* Drop out any periods and try the timezone table again. */
+ for (i = 0, p = q = buff; *q; q++)
+ if (*q != '.')
+ *p++ = *q;
+ else
+ i++;
+ *p = '\0';
+ if (i)
+ for (tp = TimezoneTable; tp->name; tp++)
+ if (strcmp(buff, tp->name) == 0) {
+ yylval.Number = tp->value;
+ return tp->type;
+ }
+
+ return tID;
+}
+
+
+static int
+yylex(void)
+{
+ char c;
+ char *p;
+ char buff[20];
+ int Count;
+ int sign;
+
+ for ( ; ; ) {
+ while (isspace(*yyInput))
+ yyInput++;
+
+ if (isdigit(c = *yyInput) || c == '-' || c == '+') {
+ if (c == '-' || c == '+') {
+ sign = c == '-' ? -1 : 1;
+ if (!isdigit(*++yyInput))
+ /* skip the '-' sign */
+ continue;
+ }
+ else
+ sign = 0;
+ for (yylval.Number = 0; isdigit(c = *yyInput++); )
+ yylval.Number = 10 * yylval.Number + c - '0';
+ yyInput--;
+ if (sign < 0)
+ yylval.Number = -yylval.Number;
+ return sign ? tSNUMBER : tUNUMBER;
+ }
+ if (isalpha(c)) {
+ for (p = buff; isalpha(c = *yyInput++) || c == '.'; )
+ if (p < &buff[sizeof buff - 1])
+ *p++ = c;
+ *p = '\0';
+ yyInput--;
+ return LookupWord(buff);
+ }
+ if (c != '(')
+ return *yyInput++;
+ Count = 0;
+ do {
+ c = *yyInput++;
+ if (c == '\0')
+ return c;
+ if (c == '(')
+ Count++;
+ else if (c == ')')
+ Count--;
+ } while (Count > 0);
+ }
+}
+
+#define TM_YEAR_ORIGIN 1900
+
+/* Yield A - B, measured in seconds. */
+static long
+difftm (struct tm *a, struct tm *b)
+{
+ int ay = a->tm_year + (TM_YEAR_ORIGIN - 1);
+ int by = b->tm_year + (TM_YEAR_ORIGIN - 1);
+ int days = (
+ /* difference in day of year */
+ a->tm_yday - b->tm_yday
+ /* + intervening leap days */
+ + ((ay >> 2) - (by >> 2))
+ - (ay/100 - by/100)
+ + ((ay/100 >> 2) - (by/100 >> 2))
+ /* + difference in years * 365 */
+ + (long)(ay-by) * 365
+ );
+ return (60*(60*(24*days + (a->tm_hour - b->tm_hour))
+ + (a->tm_min - b->tm_min))
+ + (a->tm_sec - b->tm_sec));
+}
+
+time_t
+get_date(char *p)
+{
+ struct tm *tm, *gmt_ptr, gmt;
+ int tzoff;
+ time_t Start;
+ time_t tod;
+ time_t nowtime;
+
+ bzero (&gmt, sizeof(struct tm));
+ yyInput = p;
+
+ (void)time (&nowtime);
+
+ gmt_ptr = gmtime (&nowtime);
+ if (gmt_ptr != NULL)
+ {
+ /* Make a copy, in case localtime modifies *tm (I think
+ that comment now applies to *gmt_ptr, but I am too
+ lazy to dig into how gmtime and locatime allocate the
+ structures they return pointers to). */
+ gmt = *gmt_ptr;
+ }
+
+ if (! (tm = localtime (&nowtime)))
+ return -1;
+
+ if (gmt_ptr != NULL)
+ tzoff = difftm (&gmt, tm) / 60;
+ else
+ /* We are on a system like VMS, where the system clock is
+ in local time and the system has no concept of timezones.
+ Hopefully we can fake this out (for the case in which the
+ user specifies no timezone) by just saying the timezone
+ is zero. */
+ tzoff = 0;
+
+ if(tm->tm_isdst)
+ tzoff += 60;
+
+ tm = localtime(&nowtime);
+ yyYear = tm->tm_year + 1900;
+ yyMonth = tm->tm_mon + 1;
+ yyDay = tm->tm_mday;
+ yyTimezone = tzoff;
+ yyDSTmode = DSTmaybe;
+ yyHour = 0;
+ yyMinutes = 0;
+ yySeconds = 0;
+ yyMeridian = MER24;
+ yyRelSeconds = 0;
+ yyRelMonth = 0;
+ yyHaveDate = 0;
+ yyHaveDay = 0;
+ yyHaveRel = 0;
+ yyHaveTime = 0;
+ yyHaveZone = 0;
+
+ if (yyparse()
+ || yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1)
+ return -1;
+
+ if (yyHaveDate || yyHaveTime || yyHaveDay) {
+ Start = Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds,
+ yyMeridian, yyDSTmode);
+ if (Start < 0)
+ return -1;
+ }
+ else {
+ Start = nowtime;
+ if (!yyHaveRel)
+ Start -= ((tm->tm_hour * 60L + tm->tm_min) * 60L) + tm->tm_sec;
+ }
+
+ Start += yyRelSeconds;
+ Start += RelativeMonth(Start, yyRelMonth);
+
+ if (yyHaveDay && !yyHaveDate) {
+ tod = RelativeDate(Start, yyDayOrdinal, yyDayNumber);
+ Start += tod;
+ }
+
+ /* Have to do *something* with a legitimate -1 so it's distinguishable
+ * from the error return value. (Alternately could set errno on error.) */
+ return Start == -1 ? 0 : Start;
+}
+
+
+#if defined(TEST)
+
+/* ARGSUSED */
+int
+main(int ac, char *av[])
+{
+ char buff[128];
+ time_t d;
+
+ (void)printf("Enter date, or blank line to exit.\n\t> ");
+ (void)fflush(stdout);
+ while (gets(buff) && buff[0]) {
+ d = get_date(buff);
+ if (d == -1)
+ (void)printf("Bad format - couldn't convert.\n");
+ else
+ (void)printf("%s", ctime(&d));
+ (void)printf("\t> ");
+ (void)fflush(stdout);
+ }
+ exit(0);
+ /* NOTREACHED */
+}
+#endif /* defined(TEST) */
diff --git a/shell_cmds/find/ls.c b/shell_cmds/find/ls.c
new file mode 100644
index 0000000..f58d969
--- /dev/null
+++ b/shell_cmds/find/ls.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)ls.c 8.1 (Berkeley) 6/6/93";
+#endif
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/find/ls.c,v 1.23 2011/09/28 18:53:36 ed Exp $");
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fts.h>
+#include <grp.h>
+#include <inttypes.h>
+#include <langinfo.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#ifdef __APPLE__
+#undef MAXLOGNAME
+#define MAXLOGNAME 17
+#endif /* __APPLE__ */
+
+#include "find.h"
+
+/* Derived from the print routines in the ls(1) source code. */
+
+static void printlink(char *);
+static void printtime(time_t);
+
+void
+printlong(char *name, char *accpath, struct stat *sb)
+{
+ char modep[15];
+
+ (void)printf("%6lu %8"PRId64" ", (u_long) sb->st_ino, sb->st_blocks);
+ (void)strmode(sb->st_mode, modep);
+ (void)printf("%s %3u %-*s %-*s ", modep, sb->st_nlink, MAXLOGNAME - 1,
+ user_from_uid(sb->st_uid, 0), MAXLOGNAME - 1,
+ group_from_gid(sb->st_gid, 0));
+
+ if (S_ISCHR(sb->st_mode) || S_ISBLK(sb->st_mode))
+ (void)printf("%#8jx ", (uintmax_t)sb->st_rdev);
+ else
+ (void)printf("%8"PRId64" ", sb->st_size);
+ printtime(sb->st_mtime);
+ (void)printf("%s", name);
+ if (S_ISLNK(sb->st_mode))
+ printlink(accpath);
+ (void)putchar('\n');
+}
+
+static void
+printtime(time_t ftime)
+{
+ char longstring[80];
+ static time_t lnow;
+ const char *format;
+ static int d_first = -1;
+
+ if (d_first < 0)
+ d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
+ if (lnow == 0)
+ lnow = time(NULL);
+
+#define SIXMONTHS ((365 / 2) * 86400)
+ if (ftime + SIXMONTHS > lnow && ftime < lnow + SIXMONTHS)
+ /* mmm dd hh:mm || dd mmm hh:mm */
+ format = d_first ? "%e %b %R " : "%b %e %R ";
+ else
+ /* mmm dd yyyy || dd mmm yyyy */
+ format = d_first ? "%e %b %Y " : "%b %e %Y ";
+ strftime(longstring, sizeof(longstring), format, localtime(&ftime));
+ fputs(longstring, stdout);
+}
+
+static void
+printlink(char *name)
+{
+ int lnklen;
+ char path[MAXPATHLEN];
+
+ if ((lnklen = readlink(name, path, MAXPATHLEN - 1)) == -1) {
+ warn("%s", name);
+ return;
+ }
+ path[lnklen] = '\0';
+ (void)printf(" -> %s", path);
+}
diff --git a/shell_cmds/find/main.c b/shell_cmds/find/main.c
new file mode 100644
index 0000000..e95e648
--- /dev/null
+++ b/shell_cmds/find/main.c
@@ -0,0 +1,166 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Cimarron D. Taylor of the University of California, Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1990, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)main.c 8.4 (Berkeley) 5/4/95";
+#endif
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/find/main.c,v 1.23 2011/12/10 18:11:06 ed Exp $");
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <fts.h>
+#include <locale.h>
+#include <regex.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "find.h"
+
+time_t now; /* time find was run */
+int dotfd; /* starting directory */
+int ftsoptions; /* options for the ftsopen(3) call */
+int isdeprecated; /* using deprecated syntax */
+int isdepth; /* do directories on post-order visit */
+int isoutput; /* user specified output operator */
+int issort; /* do hierarchies in lexicographical order */
+int isxargs; /* don't permit xargs delimiting chars */
+int mindepth = -1, maxdepth = -1; /* minimum and maximum depth */
+int regexp_flags = REG_BASIC; /* use the "basic" regexp by default*/
+
+static void usage(void);
+
+int
+main(int argc, char *argv[])
+{
+ char **p, **start;
+ int Hflag, Lflag, ch;
+
+ (void)setlocale(LC_ALL, "");
+
+ (void)time(&now); /* initialize the time-of-day */
+
+ p = start = argv;
+ Hflag = Lflag = 0;
+ ftsoptions = FTS_NOSTAT | FTS_PHYSICAL;
+ while ((ch = getopt(argc, argv, "EHLPXdf:sx")) != -1)
+ switch (ch) {
+ case 'E':
+ regexp_flags |= REG_EXTENDED;
+ break;
+ case 'H':
+ Hflag = 1;
+ Lflag = 0;
+ break;
+ case 'L':
+ Lflag = 1;
+ Hflag = 0;
+ break;
+ case 'P':
+ Hflag = Lflag = 0;
+ break;
+ case 'X':
+ isxargs = 1;
+ break;
+ case 'd':
+ isdepth = 1;
+ break;
+ case 'f':
+ *p++ = optarg;
+ break;
+ case 's':
+ issort = 1;
+ break;
+ case 'x':
+ ftsoptions |= FTS_XDEV;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (Hflag)
+ ftsoptions |= FTS_COMFOLLOW;
+ if (Lflag) {
+ ftsoptions &= ~FTS_PHYSICAL;
+ ftsoptions |= FTS_LOGICAL;
+ }
+
+ /*
+ * Find first option to delimit the file list. The first argument
+ * that starts with a -, or is a ! or a ( must be interpreted as a
+ * part of the find expression, according to POSIX .2.
+ */
+ for (; *argv != NULL; *p++ = *argv++) {
+ if (argv[0][0] == '-')
+ break;
+ if ((argv[0][0] == '!' || argv[0][0] == '(') &&
+ argv[0][1] == '\0')
+ break;
+ }
+
+ if (p == start)
+ usage();
+ *p = NULL;
+
+ if ((dotfd = open(".", O_RDONLY, 0)) < 0)
+ err(1, ".");
+
+ exit(find_execute(find_formplan(argv), start));
+}
+
+static void
+usage(void)
+{
+ (void)fprintf(stderr, "%s\n%s\n",
+"usage: find [-H | -L | -P] [-EXdsx] [-f path] path ... [expression]",
+" find [-H | -L | -P] [-EXdsx] -f path [path ...] [expression]");
+ exit(1);
+}
diff --git a/shell_cmds/find/misc.c b/shell_cmds/find/misc.c
new file mode 100644
index 0000000..a165c5e
--- /dev/null
+++ b/shell_cmds/find/misc.c
@@ -0,0 +1,106 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Cimarron D. Taylor of the University of California, Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)misc.c 8.2 (Berkeley) 4/1/94";
+#else
+#endif
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/find/misc.c,v 1.13 2010/12/11 08:32:16 joel Exp $");
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fts.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "find.h"
+
+/*
+ * brace_subst --
+ * Replace occurrences of {} in s1 with s2 and return the result string.
+ */
+void
+brace_subst(char *orig, char **store, char *path, int len)
+{
+ int plen;
+ char ch, *p;
+
+ plen = strlen(path);
+ for (p = *store; (ch = *orig) != '\0'; ++orig)
+ if (ch == '{' && orig[1] == '}') {
+ while ((p - *store) + plen > len)
+ if (!(*store = realloc(*store, len *= 2)))
+ err(1, NULL);
+ memmove(p, path, plen);
+ p += plen;
+ ++orig;
+ } else
+ *p++ = ch;
+ *p = '\0';
+}
+
+/*
+ * queryuser --
+ * print a message to standard error and then read input from standard
+ * input. If the input is an affirmative response (according to the
+ * current locale) then 1 is returned.
+ */
+int
+queryuser(char *argv[])
+{
+ char *p, resp[256];
+
+ (void)fprintf(stderr, "\"%s", *argv);
+ while (*++argv)
+ (void)fprintf(stderr, " %s", *argv);
+ (void)fprintf(stderr, "\"? ");
+ (void)fflush(stderr);
+
+ if (fgets(resp, sizeof(resp), stdin) == NULL)
+ *resp = '\0';
+ if ((p = strchr(resp, '\n')) != NULL)
+ *p = '\0';
+ else {
+ (void)fprintf(stderr, "\n");
+ (void)fflush(stderr);
+ }
+
+ return (rpmatch(resp) == 1);
+}
diff --git a/shell_cmds/find/operator.c b/shell_cmds/find/operator.c
new file mode 100644
index 0000000..1aa851e
--- /dev/null
+++ b/shell_cmds/find/operator.c
@@ -0,0 +1,273 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Cimarron D. Taylor of the University of California, Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)operator.c 8.1 (Berkeley) 6/6/93";
+#endif
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/find/operator.c,v 1.17 2010/12/11 08:32:16 joel Exp $");
+
+#include <sys/types.h>
+
+#include <err.h>
+#include <fts.h>
+#include <stdio.h>
+
+#include "find.h"
+
+static PLAN *yanknode(PLAN **);
+static PLAN *yankexpr(PLAN **);
+
+/*
+ * yanknode --
+ * destructively removes the top from the plan
+ */
+static PLAN *
+yanknode(PLAN **planp)
+{
+ PLAN *node; /* top node removed from the plan */
+
+ if ((node = (*planp)) == NULL)
+ return (NULL);
+ (*planp) = (*planp)->next;
+ node->next = NULL;
+ return (node);
+}
+
+/*
+ * yankexpr --
+ * Removes one expression from the plan. This is used mainly by
+ * paren_squish. In comments below, an expression is either a
+ * simple node or a f_expr node containing a list of simple nodes.
+ */
+static PLAN *
+yankexpr(PLAN **planp)
+{
+ PLAN *next; /* temp node holding subexpression results */
+ PLAN *node; /* pointer to returned node or expression */
+ PLAN *tail; /* pointer to tail of subplan */
+ PLAN *subplan; /* pointer to head of ( ) expression */
+
+ /* first pull the top node from the plan */
+ if ((node = yanknode(planp)) == NULL)
+ return (NULL);
+
+ /*
+ * If the node is an '(' then we recursively slurp up expressions
+ * until we find its associated ')'. If it's a closing paren we
+ * just return it and unwind our recursion; all other nodes are
+ * complete expressions, so just return them.
+ */
+ if (node->execute == f_openparen)
+ for (tail = subplan = NULL;;) {
+ if ((next = yankexpr(planp)) == NULL)
+ errx(1, "(: missing closing ')'");
+ /*
+ * If we find a closing ')' we store the collected
+ * subplan in our '(' node and convert the node to
+ * a f_expr. The ')' we found is ignored. Otherwise,
+ * we just continue to add whatever we get to our
+ * subplan.
+ */
+ if (next->execute == f_closeparen) {
+ if (subplan == NULL)
+ errx(1, "(): empty inner expression");
+ node->p_data[0] = subplan;
+ node->execute = f_expr;
+ break;
+ } else {
+ if (subplan == NULL)
+ tail = subplan = next;
+ else {
+ tail->next = next;
+ tail = next;
+ }
+ tail->next = NULL;
+ }
+ }
+ return (node);
+}
+
+/*
+ * paren_squish --
+ * replaces "parenthesized" plans in our search plan with "expr" nodes.
+ */
+PLAN *
+paren_squish(PLAN *plan)
+{
+ PLAN *expr; /* pointer to next expression */
+ PLAN *tail; /* pointer to tail of result plan */
+ PLAN *result; /* pointer to head of result plan */
+
+ result = tail = NULL;
+
+ /*
+ * the basic idea is to have yankexpr do all our work and just
+ * collect its results together.
+ */
+ while ((expr = yankexpr(&plan)) != NULL) {
+ /*
+ * if we find an unclaimed ')' it means there is a missing
+ * '(' someplace.
+ */
+ if (expr->execute == f_closeparen)
+ errx(1, "): no beginning '('");
+
+ /* add the expression to our result plan */
+ if (result == NULL)
+ tail = result = expr;
+ else {
+ tail->next = expr;
+ tail = expr;
+ }
+ tail->next = NULL;
+ }
+ return (result);
+}
+
+/*
+ * not_squish --
+ * compresses "!" expressions in our search plan.
+ */
+PLAN *
+not_squish(PLAN *plan)
+{
+ PLAN *next; /* next node being processed */
+ PLAN *node; /* temporary node used in f_not processing */
+ PLAN *tail; /* pointer to tail of result plan */
+ PLAN *result; /* pointer to head of result plan */
+
+ tail = result = NULL;
+
+ while ((next = yanknode(&plan))) {
+ /*
+ * if we encounter a ( expression ) then look for nots in
+ * the expr subplan.
+ */
+ if (next->execute == f_expr)
+ next->p_data[0] = not_squish(next->p_data[0]);
+
+ /*
+ * if we encounter a not, then snag the next node and place
+ * it in the not's subplan. As an optimization we compress
+ * several not's to zero or one not.
+ */
+ if (next->execute == f_not) {
+ int notlevel = 1;
+
+ node = yanknode(&plan);
+ while (node != NULL && node->execute == f_not) {
+ ++notlevel;
+ node = yanknode(&plan);
+ }
+ if (node == NULL)
+ errx(1, "!: no following expression");
+ if (node->execute == f_or)
+ errx(1, "!: nothing between ! and -o");
+ /*
+ * If we encounter ! ( expr ) then look for nots in
+ * the expr subplan.
+ */
+ if (node->execute == f_expr)
+ node->p_data[0] = not_squish(node->p_data[0]);
+ if (notlevel % 2 != 1)
+ next = node;
+ else
+ next->p_data[0] = node;
+ }
+
+ /* add the node to our result plan */
+ if (result == NULL)
+ tail = result = next;
+ else {
+ tail->next = next;
+ tail = next;
+ }
+ tail->next = NULL;
+ }
+ return (result);
+}
+
+/*
+ * or_squish --
+ * compresses -o expressions in our search plan.
+ */
+PLAN *
+or_squish(PLAN *plan)
+{
+ PLAN *next; /* next node being processed */
+ PLAN *tail; /* pointer to tail of result plan */
+ PLAN *result; /* pointer to head of result plan */
+
+ tail = result = next = NULL;
+
+ while ((next = yanknode(&plan)) != NULL) {
+ /*
+ * if we encounter a ( expression ) then look for or's in
+ * the expr subplan.
+ */
+ if (next->execute == f_expr)
+ next->p_data[0] = or_squish(next->p_data[0]);
+
+ /* if we encounter a not then look for or's in the subplan */
+ if (next->execute == f_not)
+ next->p_data[0] = or_squish(next->p_data[0]);
+
+ /*
+ * if we encounter an or, then place our collected plan in the
+ * or's first subplan and then recursively collect the
+ * remaining stuff into the second subplan and return the or.
+ */
+ if (next->execute == f_or) {
+ if (result == NULL)
+ errx(1, "-o: no expression before -o");
+ next->p_data[0] = result;
+ next->p_data[1] = or_squish(plan);
+ if (next->p_data[1] == NULL)
+ errx(1, "-o: no expression after -o");
+ return (next);
+ }
+
+ /* add the node to our result plan */
+ if (result == NULL)
+ tail = result = next;
+ else {
+ tail->next = next;
+ tail = next;
+ }
+ tail->next = NULL;
+ }
+ return (result);
+}
diff --git a/shell_cmds/find/option.c b/shell_cmds/find/option.c
new file mode 100644
index 0000000..5771da4
--- /dev/null
+++ b/shell_cmds/find/option.c
@@ -0,0 +1,201 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Cimarron D. Taylor of the University of California, Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+/*
+static char sccsid[] = "@(#)option.c 8.2 (Berkeley) 4/16/94";
+*/
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/find/option.c,v 1.32 2011/05/27 22:14:49 jilles Exp $");
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <fts.h>
+#include <regex.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "find.h"
+
+static int typecompare(const void *, const void *);
+
+/* NB: the following table must be sorted lexically. */
+/* Options listed with C++ comments are in gnu find, but not our find */
+static OPTION const options[] = {
+ { "!", c_simple, f_not, 0 },
+ { "(", c_simple, f_openparen, 0 },
+ { ")", c_simple, f_closeparen, 0 },
+ { "-Bmin", c_Xmin, f_Xmin, F_TIME_B },
+ { "-Bnewer", c_newer, f_newer, F_TIME_B },
+ { "-Btime", c_Xtime, f_Xtime, F_TIME_B },
+ { "-a", c_and, NULL, 0 },
+ { "-acl", c_acl, f_acl, 0 },
+ { "-amin", c_Xmin, f_Xmin, F_TIME_A },
+ { "-and", c_and, NULL, 0 },
+ { "-anewer", c_newer, f_newer, F_TIME_A },
+ { "-atime", c_Xtime, f_Xtime, F_TIME_A },
+ { "-cmin", c_Xmin, f_Xmin, F_TIME_C },
+ { "-cnewer", c_newer, f_newer, F_TIME_C },
+ { "-ctime", c_Xtime, f_Xtime, F_TIME_C },
+ { "-d", c_depth, f_depth, 0 },
+// -daystart
+ { "-delete", c_delete, f_delete, 0 },
+ { "-depth", c_depth, f_depth, 0 },
+ { "-empty", c_empty, f_empty, 0 },
+ { "-exec", c_exec, f_exec, 0 },
+ { "-execdir", c_exec, f_exec, F_EXECDIR },
+ { "-false", c_simple, f_false, 0 },
+ { "-flags", c_flags, f_flags, 0 },
+// -fls
+ { "-follow", c_follow, f_always_true, 0 },
+// -fprint
+// -fprint0
+// -fprintf
+ { "-fstype", c_fstype, f_fstype, 0 },
+ { "-gid", c_group, f_group, 0 },
+ { "-group", c_group, f_group, 0 },
+ { "-ignore_readdir_race",c_simple, f_always_true,0 },
+ { "-ilname", c_name, f_name, F_LINK | F_IGNCASE },
+ { "-iname", c_name, f_name, F_IGNCASE },
+ { "-inum", c_inum, f_inum, 0 },
+ { "-ipath", c_name, f_path, F_IGNCASE },
+ { "-iregex", c_regex, f_regex, F_IGNCASE },
+ { "-iwholename",c_name, f_path, F_IGNCASE },
+ { "-links", c_links, f_links, 0 },
+ { "-lname", c_name, f_name, F_LINK },
+ { "-ls", c_ls, f_ls, 0 },
+ { "-maxdepth", c_mXXdepth, f_always_true, F_MAXDEPTH },
+ { "-mindepth", c_mXXdepth, f_always_true, 0 },
+ { "-mmin", c_Xmin, f_Xmin, 0 },
+ { "-mnewer", c_newer, f_newer, 0 },
+ { "-mount", c_xdev, f_always_true, 0 },
+ { "-mtime", c_Xtime, f_Xtime, 0 },
+ { "-name", c_name, f_name, 0 },
+ { "-newer", c_newer, f_newer, 0 },
+ { "-newerBB", c_newer, f_newer, F_TIME_B | F_TIME2_B },
+ { "-newerBa", c_newer, f_newer, F_TIME_B | F_TIME2_A },
+ { "-newerBc", c_newer, f_newer, F_TIME_B | F_TIME2_C },
+ { "-newerBm", c_newer, f_newer, F_TIME_B },
+ { "-newerBt", c_newer, f_newer, F_TIME_B | F_TIME2_T },
+ { "-neweraB", c_newer, f_newer, F_TIME_A | F_TIME2_B },
+ { "-neweraa", c_newer, f_newer, F_TIME_A | F_TIME2_A },
+ { "-newerac", c_newer, f_newer, F_TIME_A | F_TIME2_C },
+ { "-neweram", c_newer, f_newer, F_TIME_A },
+ { "-newerat", c_newer, f_newer, F_TIME_A | F_TIME2_T },
+ { "-newercB", c_newer, f_newer, F_TIME_C | F_TIME2_B },
+ { "-newerca", c_newer, f_newer, F_TIME_C | F_TIME2_A },
+ { "-newercc", c_newer, f_newer, F_TIME_C | F_TIME2_C },
+ { "-newercm", c_newer, f_newer, F_TIME_C },
+ { "-newerct", c_newer, f_newer, F_TIME_C | F_TIME2_T },
+ { "-newermB", c_newer, f_newer, F_TIME2_B },
+ { "-newerma", c_newer, f_newer, F_TIME2_A },
+ { "-newermc", c_newer, f_newer, F_TIME2_C },
+ { "-newermm", c_newer, f_newer, 0 },
+ { "-newermt", c_newer, f_newer, F_TIME2_T },
+ { "-nogroup", c_nogroup, f_nogroup, 0 },
+ { "-noignore_readdir_race",c_simple, f_always_true,0 },
+ { "-noleaf", c_simple, f_always_true, 0 },
+ { "-not", c_simple, f_not, 0 },
+ { "-nouser", c_nouser, f_nouser, 0 },
+ { "-o", c_simple, f_or, 0 },
+ { "-ok", c_exec, f_exec, F_NEEDOK },
+ { "-okdir", c_exec, f_exec, F_NEEDOK | F_EXECDIR },
+ { "-or", c_simple, f_or, 0 },
+ { "-path", c_name, f_path, 0 },
+ { "-perm", c_perm, f_perm, 0 },
+ { "-print", c_print, f_print, 0 },
+ { "-print0", c_print, f_print0, 0 },
+// -printf
+ { "-prune", c_simple, f_prune, 0 },
+ { "-quit", c_simple, f_quit, 0 },
+ { "-regex", c_regex, f_regex, 0 },
+ { "-samefile", c_samefile, f_inum, 0 },
+ { "-size", c_size, f_size, 0 },
+ { "-true", c_simple, f_always_true, 0 },
+ { "-type", c_type, f_type, 0 },
+ { "-uid", c_user, f_user, 0 },
+ { "-user", c_user, f_user, 0 },
+ { "-wholename", c_name, f_path, 0 },
+#ifdef __APPLE__
+ { "-xattr", c_simple, f_xattr, 0 },
+ { "-xattrname", c_name, f_xattrname, 0 },
+#endif /* __APPLE__ */
+ { "-xdev", c_xdev, f_always_true, 0 },
+// -xtype
+};
+
+/*
+ * find_create --
+ * create a node corresponding to a command line argument.
+ *
+ * TODO:
+ * add create/process function pointers to node, so we can skip
+ * this switch stuff.
+ */
+PLAN *
+find_create(char ***argvp)
+{
+ OPTION *p;
+ PLAN *new;
+ char **argv;
+
+ argv = *argvp;
+
+ if ((p = lookup_option(*argv)) == NULL)
+ errx(1, "%s: unknown primary or operator", *argv);
+ ++argv;
+
+ new = (p->create)(p, &argv);
+ *argvp = argv;
+ return (new);
+}
+
+OPTION *
+lookup_option(const char *name)
+{
+ OPTION tmp;
+
+ tmp.name = name;
+ return ((OPTION *)bsearch(&tmp, options,
+ sizeof(options)/sizeof(OPTION), sizeof(OPTION), typecompare));
+}
+
+static int
+typecompare(const void *a, const void *b)
+{
+ return (strcmp(((const OPTION *)a)->name, ((const OPTION *)b)->name));
+}
diff --git a/shell_cmds/getopt/getopt.1 b/shell_cmds/getopt/getopt.1
new file mode 100644
index 0000000..793c87a
--- /dev/null
+++ b/shell_cmds/getopt/getopt.1
@@ -0,0 +1,134 @@
+.\" $FreeBSD: src/usr.bin/getopt/getopt.1,v 1.15 2002/04/19 23:43:02 charnier Exp $
+.\"
+.Dd April 3, 1999
+.Dt GETOPT 1
+.Os
+.Sh NAME
+.Nm getopt
+.Nd parse command options
+.Sh SYNOPSIS
+.Nm args=\`getopt Ar optstring $*\`
+; errcode=$?; set \-\- $args
+.Sh DESCRIPTION
+The
+.Nm
+utility is used to break up options in command lines for easy parsing by
+shell procedures, and to check for legal options.
+.Ar Optstring
+is a string of recognized option letters (see
+.Xr getopt 3 ) ;
+if a letter is followed by a colon, the option
+is expected to have an argument which may or may not be
+separated from it by white space.
+The special option
+.Ql \-\-
+is used to delimit the end of the options.
+The
+.Nm
+utility will place
+.Ql \-\-
+in the arguments at the end of the options,
+or recognize it if used explicitly.
+The shell arguments
+(\fB$1 $2\fR ...) are reset so that each option is
+preceded by a
+.Ql \-
+and in its own shell argument;
+each option argument is also in its own shell argument.
+.Sh EXAMPLES
+The following code fragment shows how one might process the arguments
+for a command that can take the options
+.Fl a
+and
+.Fl b ,
+and the option
+.Fl o ,
+which requires an argument.
+.Pp
+.Bd -literal -offset indent
+args=\`getopt abo: $*\`
+# you should not use \`getopt abo: "$@"\` since that would parse
+# the arguments differently from what the set command below does.
+if [ $? != 0 ]
+then
+ echo 'Usage: ...'
+ exit 2
+fi
+set \-\- $args
+# You cannot use the set command with a backquoted getopt directly,
+# since the exit code from getopt would be shadowed by those of set,
+# which is zero by definition.
+for i
+do
+ case "$i"
+ in
+ \-a|\-b)
+ echo flag $i set; sflags="${i#-}$sflags";
+ shift;;
+ \-o)
+ echo oarg is "'"$2"'"; oarg="$2"; shift;
+ shift;;
+ \-\-)
+ shift; break;;
+ esac
+done
+echo single-char flags: "'"$sflags"'"
+echo oarg is "'"$oarg"'"
+.Ed
+.Pp
+This code will accept any of the following as equivalent:
+.Pp
+.Bd -literal -offset indent
+cmd \-aoarg file file
+cmd \-a \-o arg file file
+cmd \-oarg -a file file
+cmd \-a \-oarg \-\- file file
+.Pp
+.Ed
+.Sh SEE ALSO
+.Xr sh 1 ,
+.Xr getopt 3
+.Sh DIAGNOSTICS
+The
+.Nm
+utility prints an error message on the standard error output and exits with
+status > 0 when it encounters an option letter not included in
+.Ar optstring .
+.Sh HISTORY
+Written by
+.An Henry Spencer ,
+working from a Bell Labs manual page.
+Behavior believed identical to the Bell version.
+Example changed in
+.Fx
+version 3.2 and 4.0.
+.Sh BUGS
+Whatever
+.Xr getopt 3
+has.
+.Pp
+Arguments containing white space or embedded shell metacharacters
+generally will not survive intact; this looks easy to fix but
+isn't. People trying to fix
+.Nm
+or the example in this manpage should check the history of this file
+in
+.Fx .
+.Pp
+The error message for an invalid option is identified as coming
+from
+.Nm
+rather than from the shell procedure containing the invocation
+of
+.Nm ;
+this again is hard to fix.
+.Pp
+The precise best way to use the
+.Nm set
+command to set the arguments without disrupting the value(s) of
+shell options varies from one shell version to another.
+.Pp
+Each shellscript has to carry complex code to parse arguments halfway
+correcty (like the example presented here). A better getopt-like tool
+would move much of the complexity into the tool and keep the client
+shell scripts simpler.
diff --git a/shell_cmds/getopt/getopt.c b/shell_cmds/getopt/getopt.c
new file mode 100644
index 0000000..5e8a743
--- /dev/null
+++ b/shell_cmds/getopt/getopt.c
@@ -0,0 +1,32 @@
+#include <sys/cdefs.h>
+__RCSID("$FreeBSD: src/usr.bin/getopt/getopt.c,v 1.10 2002/09/04 23:29:01 dwmalone Exp $");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+int
+main(int argc, char *argv[])
+{
+ int c;
+ int status = 0;
+
+ optind = 2; /* Past the program name and the option letters. */
+ while ((c = getopt(argc, argv, argv[1])) != -1)
+ switch (c) {
+ case '?':
+ status = 1; /* getopt routine gave message */
+ break;
+ default:
+ if (optarg != NULL)
+ printf(" -%c %s", c, optarg);
+ else
+ printf(" -%c", c);
+ break;
+ }
+ printf(" --");
+ for (; optind < argc; optind++)
+ printf(" %s", argv[optind]);
+ printf("\n");
+ return status;
+}
diff --git a/shell_cmds/hexdump/conv.c b/shell_cmds/hexdump/conv.c
new file mode 100644
index 0000000..9eebc51
--- /dev/null
+++ b/shell_cmds/hexdump/conv.c
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char sccsid[] = "@(#)conv.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+
+#include <assert.h>
+#include <ctype.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <wctype.h>
+#include "hexdump.h"
+
+void
+conv_c(PR *pr, u_char *p, size_t bufsize)
+{
+ char buf[10];
+ char const *str;
+ wchar_t wc;
+ size_t clen, oclen;
+ int converr, pad, width;
+ u_char peekbuf[MB_LEN_MAX];
+
+ if (pr->mbleft > 0) {
+ str = "**";
+ pr->mbleft--;
+ goto strpr;
+ }
+
+ switch(*p) {
+ case '\0':
+ str = "\\0";
+ goto strpr;
+ /* case '\a': */
+ case '\007':
+ str = "\\a";
+ goto strpr;
+ case '\b':
+ str = "\\b";
+ goto strpr;
+ case '\f':
+ str = "\\f";
+ goto strpr;
+ case '\n':
+ str = "\\n";
+ goto strpr;
+ case '\r':
+ str = "\\r";
+ goto strpr;
+ case '\t':
+ str = "\\t";
+ goto strpr;
+ case '\v':
+ str = "\\v";
+ goto strpr;
+ default:
+ break;
+ }
+ /*
+ * Multibyte characters are disabled for hexdump(1) for backwards
+ * compatibility and consistency (none of its other output formats
+ * recognize them correctly).
+ */
+ converr = 0;
+ if (odmode && MB_CUR_MAX > 1) {
+ oclen = 0;
+retry:
+ clen = mbrtowc(&wc, (const char *)p, bufsize, &pr->mbstate);
+ if (clen == 0)
+ clen = 1;
+ else if (clen == (size_t)-1 || (clen == (size_t)-2 &&
+ p == peekbuf)) {
+ memset(&pr->mbstate, 0, sizeof(pr->mbstate));
+ wc = *p;
+ clen = 1;
+ converr = 1;
+ } else if (clen == (size_t)-2) {
+ /*
+ * Incomplete character; peek ahead and see if we
+ * can complete it.
+ */
+ oclen = bufsize;
+ bufsize = peek(p = peekbuf, MB_CUR_MAX);
+ goto retry;
+ }
+ clen += oclen;
+ } else {
+ wc = *p;
+ clen = 1;
+ }
+ if (!converr && iswprint(wc)) {
+ if (!odmode) {
+ *pr->cchar = 'c';
+ (void)printf(pr->fmt, (int)wc);
+ } else {
+ *pr->cchar = 'C';
+ assert(strcmp(pr->fmt, "%3C") == 0);
+ width = wcwidth(wc);
+ assert(width >= 0);
+ pad = 3 - width;
+ if (pad < 0)
+ pad = 0;
+ (void)printf("%*s%C", pad, "", wc);
+ pr->mbleft = clen - 1;
+ }
+ } else {
+ (void)sprintf(buf, "%03o", (int)*p);
+ str = buf;
+strpr: *pr->cchar = 's';
+ (void)printf(pr->fmt, str);
+ }
+}
+
+void
+conv_u(PR *pr, u_char *p)
+{
+ static char const * list[] = {
+ "nul", "soh", "stx", "etx", "eot", "enq", "ack", "bel",
+ "bs", "ht", "lf", "vt", "ff", "cr", "so", "si",
+ "dle", "dc1", "dc2", "dc3", "dc4", "nak", "syn", "etb",
+ "can", "em", "sub", "esc", "fs", "gs", "rs", "us",
+ };
+
+ /* od used nl, not lf */
+ if (*p <= 0x1f) {
+ *pr->cchar = 's';
+ if (odmode && *p == 0x0a)
+ (void)printf(pr->fmt, "nl");
+ else
+ (void)printf(pr->fmt, list[*p]);
+ } else if (*p == 0x7f) {
+ *pr->cchar = 's';
+ (void)printf(pr->fmt, "del");
+ } else if (odmode && *p == 0x20) { /* od replaced space with sp */
+ *pr->cchar = 's';
+ (void)printf(pr->fmt, " sp");
+ } else if (isprint(*p)) {
+ *pr->cchar = 'c';
+ (void)printf(pr->fmt, *p);
+ } else {
+ *pr->cchar = 'x';
+ (void)printf(pr->fmt, (int)*p);
+ }
+}
diff --git a/shell_cmds/hexdump/display.c b/shell_cmds/hexdump/display.c
new file mode 100644
index 0000000..978a50c
--- /dev/null
+++ b/shell_cmds/hexdump/display.c
@@ -0,0 +1,417 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)display.c 8.1 (Berkeley) 6/6/93";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/hexdump/display.c,v 1.19 2004/07/11 01:11:12 tjr Exp $");
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "hexdump.h"
+
+enum _vflag vflag = FIRST;
+
+static off_t address; /* address/offset in stream */
+static off_t eaddress; /* end address */
+
+static __inline void print(PR *, u_char *);
+
+void
+display(void)
+{
+ FS *fs;
+ FU *fu;
+ PR *pr;
+ int cnt;
+ u_char *bp;
+ off_t saveaddress;
+ u_char savech=0, *savebp;
+
+ while ((bp = get()))
+ for (fs = fshead, savebp = bp, saveaddress = address; fs;
+ fs = fs->nextfs, bp = savebp, address = saveaddress)
+ for (fu = fs->nextfu; fu; fu = fu->nextfu) {
+ if (fu->flags&F_IGNORE)
+ break;
+ for (cnt = fu->reps; cnt; --cnt)
+ for (pr = fu->nextpr; pr; address += pr->bcnt,
+ bp += pr->bcnt, pr = pr->nextpr) {
+ if (eaddress && address >= eaddress &&
+ !(pr->flags & (F_TEXT|F_BPAD)))
+ bpad(pr);
+ if (cnt == 1 && pr->nospace) {
+ savech = *pr->nospace;
+ *pr->nospace = '\0';
+ }
+ print(pr, bp);
+ if (cnt == 1 && pr->nospace)
+ *pr->nospace = savech;
+ }
+ }
+ if (endfu) {
+ /*
+ * If eaddress not set, error or file size was multiple of
+ * blocksize, and no partial block ever found.
+ */
+ if (!eaddress) {
+ if (!address) {
+ return;
+ }
+ eaddress = address;
+ }
+ for (pr = endfu->nextpr; pr; pr = pr->nextpr)
+ switch(pr->flags) {
+ case F_ADDRESS:
+ (void)printf(pr->fmt, (quad_t)eaddress);
+ break;
+ case F_TEXT:
+ (void)printf("%s", pr->fmt);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+static __inline void
+print(PR *pr, u_char *bp)
+{
+ long double ldbl;
+ double f8;
+ float f4;
+ int16_t s2;
+ int8_t s8;
+ int32_t s4;
+ u_int16_t u2;
+ u_int32_t u4;
+ u_int64_t u8;
+
+ switch(pr->flags) {
+ case F_ADDRESS:
+ (void)printf(pr->fmt, (quad_t)address);
+ break;
+ case F_BPAD:
+ (void)printf(pr->fmt, "");
+ break;
+ case F_C:
+ conv_c(pr, bp, eaddress ? eaddress - address :
+ blocksize - address % blocksize);
+ break;
+ case F_CHAR:
+ (void)printf(pr->fmt, *bp);
+ break;
+ case F_DBL:
+ switch(pr->bcnt) {
+ case 4:
+ bcopy(bp, &f4, sizeof(f4));
+ (void)printf(pr->fmt, f4);
+ break;
+ case 8:
+ bcopy(bp, &f8, sizeof(f8));
+ (void)printf(pr->fmt, f8);
+ break;
+ default:
+ if (pr->bcnt == sizeof(long double)) {
+ bcopy(bp, &ldbl, sizeof(ldbl));
+ (void)printf(pr->fmt, ldbl);
+ }
+ break;
+ }
+ break;
+ case F_INT:
+ switch(pr->bcnt) {
+ case 1:
+ (void)printf(pr->fmt, (quad_t)(signed char)*bp);
+ break;
+ case 2:
+ bcopy(bp, &s2, sizeof(s2));
+ (void)printf(pr->fmt, (quad_t)s2);
+ break;
+ case 4:
+ bcopy(bp, &s4, sizeof(s4));
+ (void)printf(pr->fmt, (quad_t)s4);
+ break;
+ case 8:
+ bcopy(bp, &s8, sizeof(s8));
+ (void)printf(pr->fmt, s8);
+ break;
+ }
+ break;
+ case F_P:
+ (void)printf(pr->fmt, isprint(*bp) && isascii(*bp) ? *bp : '.');
+ break;
+ case F_STR:
+ (void)printf(pr->fmt, (char *)bp);
+ break;
+ case F_TEXT:
+ (void)printf("%s", pr->fmt);
+ break;
+ case F_U:
+ conv_u(pr, bp);
+ break;
+ case F_UINT:
+ switch(pr->bcnt) {
+ case 1:
+ (void)printf(pr->fmt, (u_quad_t)*bp);
+ break;
+ case 2:
+ bcopy(bp, &u2, sizeof(u2));
+ (void)printf(pr->fmt, (u_quad_t)u2);
+ break;
+ case 4:
+ bcopy(bp, &u4, sizeof(u4));
+ (void)printf(pr->fmt, (u_quad_t)u4);
+ break;
+ case 8:
+ bcopy(bp, &u8, sizeof(u8));
+ (void)printf(pr->fmt, u8);
+ break;
+ }
+ break;
+ }
+}
+
+void
+bpad(PR *pr)
+{
+ static char const *spec = " -0+#";
+ char *p1, *p2;
+
+ /*
+ * Remove all conversion flags; '-' is the only one valid
+ * with %s, and it's not useful here.
+ */
+ pr->flags = F_BPAD;
+ pr->cchar[0] = 's';
+ pr->cchar[1] = '\0';
+ for (p1 = pr->fmt; *p1 != '%'; ++p1);
+ for (p2 = ++p1; *p1 && index(spec, *p1); ++p1);
+ while ((*p2++ = *p1++));
+}
+
+static char **_argv;
+
+u_char *
+get(void)
+{
+ static int ateof = 1;
+ static u_char *curp, *savp;
+ int n;
+ int need, nread;
+ int valid_save = 0;
+ u_char *tmpp;
+
+ if (!curp) {
+ if ((curp = calloc(1, blocksize)) == NULL)
+ err(1, NULL);
+ if ((savp = calloc(1, blocksize)) == NULL)
+ err(1, NULL);
+ } else {
+ tmpp = curp;
+ curp = savp;
+ savp = tmpp;
+ address += blocksize;
+ valid_save = 1;
+ }
+ for (need = blocksize, nread = 0;;) {
+ /*
+ * if read the right number of bytes, or at EOF for one file,
+ * and no other files are available, zero-pad the rest of the
+ * block and set the end flag.
+ */
+ if (!length || (ateof && !next((char **)NULL))) {
+ if (odmode && address < skip)
+ errx(1, "cannot skip past end of input");
+ if (need == blocksize)
+ return((u_char *)NULL);
+ /*
+ * XXX bcmp() is not quite right in the presence
+ * of multibyte characters.
+ */
+#ifdef __APPLE__
+ /* 5650060 */
+ if (!need && vflag != ALL &&
+#else
+ if (vflag != ALL &&
+#endif
+ valid_save &&
+ bcmp(curp, savp, nread) == 0) {
+ if (vflag != DUP)
+ (void)printf("*\n");
+ return((u_char *)NULL);
+ }
+ bzero((char *)curp + nread, need);
+ eaddress = address + nread;
+ if (length == 0)
+ lseek(STDIN_FILENO, ftell(stdin), SEEK_SET); /* rewind stdin for next process */
+ return(curp);
+ }
+ n = fread((char *)curp + nread, sizeof(u_char),
+ length == -1 ? need : MIN(length, need), stdin);
+ if (!n) {
+ if (ferror(stdin))
+ warn("%s", _argv[-1]);
+ ateof = 1;
+ continue;
+ }
+ ateof = 0;
+ if (length != -1)
+ length -= n;
+ if (!(need -= n)) {
+ /*
+ * XXX bcmp() is not quite right in the presence
+ * of multibyte characters.
+ */
+ if (vflag == ALL || vflag == FIRST ||
+ valid_save == 0 ||
+ bcmp(curp, savp, blocksize) != 0) {
+ if (vflag == DUP || vflag == FIRST)
+ vflag = WAIT;
+ return(curp);
+ }
+ if (vflag == WAIT)
+ (void)printf("*\n");
+ vflag = DUP;
+ address += blocksize;
+ need = blocksize;
+ nread = 0;
+ }
+ else
+ nread += n;
+ }
+}
+
+size_t
+peek(u_char *buf, size_t nbytes)
+{
+ size_t n, nread;
+ int c;
+
+ if (length != -1 && nbytes > length)
+ nbytes = length;
+ nread = 0;
+ while (nread < nbytes && (c = getchar()) != EOF) {
+ *buf++ = c;
+ nread++;
+ }
+ n = nread;
+ while (n-- > 0) {
+ c = *--buf;
+ ungetc(c, stdin);
+ }
+ return (nread);
+}
+
+int
+next(char **argv)
+{
+ static int done;
+ int statok;
+
+ if (argv) {
+ _argv = argv;
+ return(1);
+ }
+ for (;;) {
+ if (*_argv) {
+ if (!(freopen(*_argv, "r", stdin))) {
+ warn("%s", *_argv);
+ exitval = 1;
+ ++_argv;
+ continue;
+ }
+ statok = done = 1;
+ } else {
+ if (done++)
+ return(0);
+ statok = 0;
+ }
+ if (skip)
+ doskip(statok ? *_argv : "stdin", statok);
+ if (*_argv)
+ ++_argv;
+ if (!skip)
+ return(1);
+ }
+ /* NOTREACHED */
+}
+
+void
+doskip(const char *fname, int statok)
+{
+ int cnt;
+ struct stat sb;
+
+ if (statok) {
+ if (fstat(fileno(stdin), &sb))
+ err(1, "%s", fname);
+ if (S_ISREG(sb.st_mode) && skip >= sb.st_size) {
+ address += sb.st_size;
+ skip -= sb.st_size;
+ return;
+ }
+ }
+#ifdef __APPLE__
+ /* try to seek first; fall back on ESPIPE */
+ if (fseeko(stdin, skip, SEEK_SET) == 0) {
+#else /* !__APPLE__ */
+ if (S_ISREG(sb.st_mode)) {
+ if (fseeko(stdin, skip, SEEK_SET))
+ err(1, "%s", fname);
+#endif /* __APPLE__ */
+ address += skip;
+ skip = 0;
+ } else {
+#ifdef __APPLE__
+ if (errno != ESPIPE)
+ err(1, "%s", fname);
+#endif /* __APPLE__ */
+ for (cnt = 0; cnt < skip; ++cnt)
+ if (getchar() == EOF)
+ break;
+ address += cnt;
+ skip -= cnt;
+ }
+}
diff --git a/shell_cmds/hexdump/hexdump.1 b/shell_cmds/hexdump/hexdump.1
new file mode 100644
index 0000000..5e49a64
--- /dev/null
+++ b/shell_cmds/hexdump/hexdump.1
@@ -0,0 +1,342 @@
+.\" Copyright (c) 1989, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)hexdump.1 8.2 (Berkeley) 4/18/94
+.\" $FreeBSD: src/usr.bin/hexdump/hexdump.1,v 1.21 2004/07/10 13:11:00 tjr Exp $
+.\"
+.Dd July 10, 2004
+.Dt HEXDUMP 1
+.Os
+.Sh NAME
+.Nm hexdump
+.Nd ASCII, decimal, hexadecimal, octal dump
+.Sh SYNOPSIS
+.Nm
+.Op Fl bcCdovx
+.Op Fl e Ar format_string
+.Op Fl f Ar format_file
+.Op Fl n Ar length
+.Bk -words
+.Op Fl s Ar skip
+.Ek
+.Ar
+.Sh DESCRIPTION
+The
+.Nm
+utility is a filter which displays the specified files, or
+the standard input, if no files are specified, in a user specified
+format.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl b
+.Em One-byte octal display .
+Display the input offset in hexadecimal, followed by sixteen
+space-separated, three column, zero-filled, bytes of input data,
+in octal, per line.
+.It Fl C
+.Em Canonical hex+ASCII display .
+Display the input offset in hexadecimal, followed by sixteen
+space-separated, two column, hexadecimal bytes, followed by the
+same sixteen bytes in %_p format enclosed in ``|'' characters.
+.It Fl c
+.Em One-byte character display .
+Display the input offset in hexadecimal, followed by sixteen
+space-separated, three column, space-filled, characters of input
+data per line.
+.It Fl d
+.Em Two-byte decimal display .
+Display the input offset in hexadecimal, followed by eight
+space-separated, five column, zero-filled, two-byte units
+of input data, in unsigned decimal, per line.
+.It Fl e Ar format_string
+Specify a format string to be used for displaying data.
+.It Fl f Ar format_file
+Specify a file that contains one or more newline separated format strings.
+Empty lines and lines whose first non-blank character is a hash mark
+.Pf ( Cm \&# )
+are ignored.
+.It Fl n Ar length
+Interpret only
+.Ar length
+bytes of input.
+.It Fl o
+.Em Two-byte octal display .
+Display the input offset in hexadecimal, followed by eight
+space-separated, six column, zero-filled, two byte quantities of
+input data, in octal, per line.
+.It Fl s Ar offset
+Skip
+.Ar offset
+bytes from the beginning of the input.
+By default,
+.Ar offset
+is interpreted as a decimal number.
+With a leading
+.Cm 0x
+or
+.Cm 0X ,
+.Ar offset
+is interpreted as a hexadecimal number,
+otherwise, with a leading
+.Cm 0 ,
+.Ar offset
+is interpreted as an octal number.
+Appending the character
+.Cm b ,
+.Cm k ,
+.Cm m ,
+or
+.Cm g
+to
+.Ar offset
+causes it to be interpreted as a multiple of
+.Li 512 ,
+.Li 1024 ,
+.Li 1048576 ,
+or
+.Li 1073741824 ,
+respectively.
+.It Fl v
+Cause
+.Nm
+to display all input data.
+Without the
+.Fl v
+option, any number of groups of output lines, which would be
+identical to the immediately preceding group of output lines (except
+for the input offsets), are replaced with a line comprised of a
+single asterisk.
+.It Fl x
+.Em Two-byte hexadecimal display .
+Display the input offset in hexadecimal, followed by eight, space
+separated, four column, zero-filled, two-byte quantities of input
+data, in hexadecimal, per line.
+.El
+.Pp
+For each input file,
+.Nm
+sequentially copies the input to standard output, transforming the
+data according to the format strings specified by the
+.Fl e
+and
+.Fl f
+options, in the order that they were specified.
+.Ss Formats
+A format string contains any number of format units, separated by
+whitespace.
+A format unit contains up to three items: an iteration count, a byte
+count, and a format.
+.Pp
+The iteration count is an optional positive integer, which defaults to
+one.
+Each format is applied iteration count times.
+.Pp
+The byte count is an optional positive integer.
+If specified it defines the number of bytes to be interpreted by
+each iteration of the format.
+.Pp
+If an iteration count and/or a byte count is specified, a single slash
+must be placed after the iteration count and/or before the byte count
+to disambiguate them.
+Any whitespace before or after the slash is ignored.
+.Pp
+The format is required and must be surrounded by double quote
+(" ") marks.
+It is interpreted as a fprintf-style format string (see
+.Xr fprintf 3 ) ,
+with the
+following exceptions:
+.Bl -bullet -offset indent
+.It
+An asterisk (*) may not be used as a field width or precision.
+.It
+A byte count or field precision
+.Em is
+required for each ``s'' conversion
+character (unlike the
+.Xr fprintf 3
+default which prints the entire string if the precision is unspecified).
+.It
+The conversion characters ``h'', ``l'', ``n'', ``p'' and ``q'' are
+not supported.
+.It
+The single character escape sequences
+described in the C standard are supported:
+.Bd -ragged -offset indent -compact
+.Bl -column <alert_character>
+.It "NUL \e0
+.It "<alert character> \ea
+.It "<backspace> \eb
+.It "<form-feed> \ef
+.It "<newline> \en
+.It "<carriage return> \er
+.It "<tab> \et
+.It "<vertical tab> \ev
+.El
+.Ed
+.El
+.Pp
+The
+.Nm
+utility also supports the following additional conversion strings:
+.Bl -tag -width Fl
+.It Cm \&_a Ns Op Cm dox
+Display the input offset, cumulative across input files, of the
+next byte to be displayed.
+The appended characters
+.Cm d ,
+.Cm o ,
+and
+.Cm x
+specify the display base
+as decimal, octal or hexadecimal respectively.
+.It Cm \&_A Ns Op Cm dox
+Identical to the
+.Cm \&_a
+conversion string except that it is only performed
+once, when all of the input data has been processed.
+.It Cm \&_c
+Output characters in the default character set.
+Nonprinting characters are displayed in three character, zero-padded
+octal, except for those representable by standard escape notation
+(see above),
+which are displayed as two character strings.
+.It Cm _p
+Output characters in the ASCII character set.
+Non-ASCII characters are displayed as a single
+.Dq Cm \&. .
+.It Cm _u
+Output US
+.Tn ASCII
+characters, with the exception that control characters are
+displayed using the following, lower-case, names.
+Characters greater than 0xff, hexadecimal, are displayed as hexadecimal
+strings.
+.Bl -column \&000_nu \&001_so \&002_st \&003_et \&004_eo
+.It "\&000\ NUL\t001\ SOH\t002\ STX\t003\ ETX\t004\ EOT\t005\ ENQ
+.It "\&006\ ACK\t007\ BEL\t008\ BS\t009\ HT\t00A\ LF\t00B\ VT
+.It "\&00C\ FF\t00D\ CR\t00E\ SO\t00F\ SI\t010\ DLE\t011\ DC1
+.It "\&012\ DC2\t013\ DC3\t014\ DC4\t015\ NAK\t016\ SYN\t017\ ETB
+.It "\&018\ CAN\t019\ EM\t01A\ SUB\t01B\ ESC\t01C\ FS\t01D\ GS
+.It "\&01E\ RS\t01F\ US\t0FF\ DEL
+.El
+.El
+.Pp
+The default and supported byte counts for the conversion characters
+are as follows:
+.Bl -tag -width "Xc,_Xc,_Xc,_Xc,_Xc,_Xc" -offset indent
+.It Li \&%_c , \&%_p , \&%_u , \&%c
+One byte counts only.
+.It Xo
+.Li \&%d , \&%i , \&%o ,
+.Li \&%u , \&%X , \&%x
+.Xc
+Four byte default, one, two and four byte counts supported.
+.It Xo
+.Li \&%E , \&%e , \&%f ,
+.Li \&%G , \&%g
+.Xc
+Eight byte default, four and twelve byte counts supported.
+.El
+.Pp
+The amount of data interpreted by each format string is the sum of the
+data required by each format unit, which is the iteration count times the
+byte count, or the iteration count times the number of bytes required by
+the format if the byte count is not specified.
+.Pp
+The input is manipulated in ``blocks'', where a block is defined as the
+largest amount of data specified by any format string.
+Format strings interpreting less than an input block's worth of data,
+whose last format unit both interprets some number of bytes and does
+not have a specified iteration count, have the iteration count
+incremented until the entire input block has been processed or there
+is not enough data remaining in the block to satisfy the format string.
+.Pp
+If, either as a result of user specification or
+.Nm
+modifying
+the iteration count as described above, an iteration count is
+greater than one, no trailing whitespace characters are output
+during the last iteration.
+.Pp
+It is an error to specify a byte count as well as multiple conversion
+characters or strings unless all but one of the conversion characters
+or strings is
+.Cm \&_a
+or
+.Cm \&_A .
+.Pp
+If, as a result of the specification of the
+.Fl n
+option or end-of-file being reached, input data only partially
+satisfies a format string, the input block is zero-padded sufficiently
+to display all available data (i.e., any format units overlapping the
+end of data will display some number of the zero bytes).
+.Pp
+Further output by such format strings is replaced by an equivalent
+number of spaces.
+An equivalent number of spaces is defined as the number of spaces
+output by an
+.Cm s
+conversion character with the same field width
+and precision as the original conversion character or conversion
+string but with any
+.Dq Li \&+ ,
+.Dq \&\ \& ,
+.Dq Li \&#
+conversion flag characters
+removed, and referencing a NULL string.
+.Pp
+If no format strings are specified, the default display is a
+one-byte hexadecimal display.
+.Sh DIAGNOSTICS
+.Ex -std
+.Sh EXAMPLES
+Note that the following format strings, used with
+.Fl e ,
+must be enclosed in single quotes.
+.Pp
+Display the input in perusal format:
+.Bd -literal -offset indent
+"%06.6_ao " 12/1 "%3_u "
+"\et\et" "%_p "
+"\en"
+.Ed
+.Pp
+Implement the \-x option:
+.Bd -literal -offset indent
+"%07.7_Ax\en"
+"%07.7_ax " 8/2 "%04x " "\en"
+.Ed
+.Sh SEE ALSO
+.Xr gdb 1 ,
+.Xr od 1
diff --git a/shell_cmds/hexdump/hexdump.c b/shell_cmds/hexdump/hexdump.c
new file mode 100644
index 0000000..78df723
--- /dev/null
+++ b/shell_cmds/hexdump/hexdump.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1989, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)hexdump.c 8.1 (Berkeley) 6/6/93";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/hexdump/hexdump.c,v 1.7 2002/09/04 23:29:01 dwmalone Exp $");
+
+#include <sys/types.h>
+#include <locale.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "hexdump.h"
+
+FS *fshead; /* head of format strings */
+int blocksize; /* data block size */
+int exitval; /* final exit value */
+int length = -1; /* max bytes to read */
+
+int
+main(int argc, char *argv[])
+{
+ FS *tfs;
+ char *p;
+
+ (void)setlocale(LC_ALL, "");
+
+ if (!(p = rindex(argv[0], 'o')) || strcmp(p, "od"))
+ newsyntax(argc, &argv);
+ else
+ oldsyntax(argc, &argv);
+
+ /* figure out the data block size */
+ for (blocksize = 0, tfs = fshead; tfs; tfs = tfs->nextfs) {
+ tfs->bcnt = size(tfs);
+ if (blocksize < tfs->bcnt)
+ blocksize = tfs->bcnt;
+ }
+ /* rewrite the rules, do syntax checking */
+ for (tfs = fshead; tfs; tfs = tfs->nextfs)
+ rewrite(tfs);
+
+ (void)next(argv);
+ display();
+ exit(exitval);
+}
diff --git a/shell_cmds/hexdump/hexdump.h b/shell_cmds/hexdump/hexdump.h
new file mode 100644
index 0000000..a984287
--- /dev/null
+++ b/shell_cmds/hexdump/hexdump.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)hexdump.h 8.1 (Berkeley) 6/6/93
+ * $FreeBSD: src/usr.bin/hexdump/hexdump.h,v 1.9 2004/07/11 01:11:12 tjr Exp $
+ */
+
+#include <wchar.h>
+
+typedef struct _pr {
+ struct _pr *nextpr; /* next print unit */
+#define F_ADDRESS 0x001 /* print offset */
+#define F_BPAD 0x002 /* blank pad */
+#define F_C 0x004 /* %_c */
+#define F_CHAR 0x008 /* %c */
+#define F_DBL 0x010 /* %[EefGf] */
+#define F_INT 0x020 /* %[di] */
+#define F_P 0x040 /* %_p */
+#define F_STR 0x080 /* %s */
+#define F_U 0x100 /* %_u */
+#define F_UINT 0x200 /* %[ouXx] */
+#define F_TEXT 0x400 /* no conversions */
+ u_int flags; /* flag values */
+ int bcnt; /* byte count */
+ char *cchar; /* conversion character */
+ char *fmt; /* printf format */
+ char *nospace; /* no whitespace version */
+ int mbleft; /* bytes left of multibyte char. */
+ mbstate_t mbstate; /* conversion state */
+} PR;
+
+typedef struct _fu {
+ struct _fu *nextfu; /* next format unit */
+ struct _pr *nextpr; /* next print unit */
+#define F_IGNORE 0x01 /* %_A */
+#define F_SETREP 0x02 /* rep count set, not default */
+ u_int flags; /* flag values */
+ int reps; /* repetition count */
+ int bcnt; /* byte count */
+ char *fmt; /* format string */
+} FU;
+
+typedef struct _fs { /* format strings */
+ struct _fs *nextfs; /* linked list of format strings */
+ struct _fu *nextfu; /* linked list of format units */
+ int bcnt;
+} FS;
+
+extern FS *fshead; /* head of format strings list */
+extern FU *endfu; /* format at end-of-data */
+extern int blocksize; /* data block size */
+extern int exitval; /* final exit value */
+extern int odmode; /* are we acting as od(1)? */
+extern int length; /* amount of data to read */
+extern off_t skip; /* amount of data to skip at start */
+enum _vflag { ALL, DUP, FIRST, WAIT }; /* -v values */
+extern enum _vflag vflag;
+
+void add(const char *);
+void addfile(char *);
+void badcnt(char *);
+void badconv(char *);
+void badfmt(const char *);
+void badsfmt(void);
+void bpad(PR *);
+void conv_c(PR *, u_char *, size_t);
+void conv_u(PR *, u_char *);
+void display(void);
+void doskip(const char *, int);
+void escape(char *);
+u_char *get(void);
+void newsyntax(int, char ***);
+int next(char **);
+void nomem(void);
+void oldsyntax(int, char ***);
+size_t peek(u_char *, size_t);
+void rewrite(FS *);
+int size(FS *);
+void usage(void);
diff --git a/shell_cmds/hexdump/hexsyntax.c b/shell_cmds/hexdump/hexsyntax.c
new file mode 100644
index 0000000..9961f2f
--- /dev/null
+++ b/shell_cmds/hexdump/hexsyntax.c
@@ -0,0 +1,147 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)hexsyntax.c 8.2 (Berkeley) 5/4/95";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/hexdump/hexsyntax.c,v 1.12 2002/09/04 23:29:01 dwmalone Exp $");
+
+#include <sys/types.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "hexdump.h"
+
+off_t skip; /* bytes to skip */
+
+void
+newsyntax(int argc, char ***argvp)
+{
+ int ch;
+ char *p, **argv;
+
+ argv = *argvp;
+ if ((p = rindex(argv[0], 'h')) != NULL &&
+ strcmp(p, "hd") == 0) {
+ /* "Canonical" format, implies -C. */
+ add("\"%08.8_Ax\n\"");
+ add("\"%08.8_ax \" 8/1 \"%02x \" \" \" 8/1 \"%02x \" ");
+ add("\" |\" 16/1 \"%_p\" \"|\\n\"");
+ }
+ while ((ch = getopt(argc, argv, "bcCde:f:n:os:vx")) != -1)
+ switch (ch) {
+ case 'b':
+ add("\"%07.7_Ax\n\"");
+ add("\"%07.7_ax \" 16/1 \"%03o \" \"\\n\"");
+ break;
+ case 'c':
+ add("\"%07.7_Ax\n\"");
+ add("\"%07.7_ax \" 16/1 \"%3_c \" \"\\n\"");
+ break;
+ case 'C':
+ add("\"%08.8_Ax\n\"");
+ add("\"%08.8_ax \" 8/1 \"%02x \" \" \" 8/1 \"%02x \" ");
+ add("\" |\" 16/1 \"%_p\" \"|\\n\"");
+ break;
+ case 'd':
+ add("\"%07.7_Ax\n\"");
+ add("\"%07.7_ax \" 8/2 \" %05u \" \"\\n\"");
+ break;
+ case 'e':
+ add(optarg);
+ break;
+ case 'f':
+ addfile(optarg);
+ break;
+ case 'n':
+ if ((length = atoi(optarg)) < 0)
+ errx(1, "%s: bad length value", optarg);
+ break;
+ case 'o':
+ add("\"%07.7_Ax\n\"");
+ add("\"%07.7_ax \" 8/2 \" %06o \" \"\\n\"");
+ break;
+ case 's':
+ if ((skip = strtoll(optarg, &p, 0)) < 0)
+ errx(1, "%s: bad skip value", optarg);
+ switch(*p) {
+ case 'b':
+ skip *= 512;
+ break;
+ case 'k':
+ skip *= 1024;
+ break;
+ case 'm':
+ skip *= 1048576;
+ break;
+ case 'g':
+ skip *= 1073741824;
+ break;
+ }
+ break;
+ case 'v':
+ vflag = ALL;
+ break;
+ case 'x':
+ add("\"%07.7_Ax\n\"");
+ add("\"%07.7_ax \" 8/2 \" %04x \" \"\\n\"");
+ break;
+ case '?':
+ usage();
+ }
+
+ if (!fshead) {
+ add("\"%07.7_Ax\n\"");
+ add("\"%07.7_ax \" 16/1 \"%02x \" \"\\n\"");
+ }
+
+ *argvp += optind;
+}
+
+void
+usage(void)
+{
+ (void)fprintf(stderr, "%s\n%s\n%s\n%s\n",
+"usage: hexdump [-bcCdovx] [-e fmt] [-f fmt_file] [-n length]",
+" [-s skip] [file ...]",
+" hd [-bcdovx] [-e fmt] [-f fmt_file] [-n length]",
+" [-s skip] [file ...]");
+ exit(1);
+}
diff --git a/shell_cmds/hexdump/od.1 b/shell_cmds/hexdump/od.1
new file mode 100644
index 0000000..f827f6c
--- /dev/null
+++ b/shell_cmds/hexdump/od.1
@@ -0,0 +1,267 @@
+.\" Copyright (c) 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)od.1 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD: src/usr.bin/hexdump/od.1,v 1.17 2004/07/11 01:11:12 tjr Exp $
+.\"
+.Dd July 11, 2004
+.Os
+.Dt OD 1
+.Sh NAME
+.Nm od
+.Nd octal, decimal, hex, ASCII dump
+.Sh SYNOPSIS
+.Nm
+.Op Fl aBbcDdeFfHhIiLlOosvXx
+.Op Fl A Ar base
+.Op Fl j Ar skip
+.Op Fl N Ar length
+.Op Fl t Ar type
+.Sm off
+.Oo
+.Op Cm \&+
+.Li offset
+.Op Cm \&.
+.Op Cm Bb
+.Oc
+.Sm on
+.Op Ar
+.Sh DESCRIPTION
+The
+.Nm
+utility is a filter which displays the specified files, or standard
+input if no files are specified, in a user specified format.
+.Pp
+The options are as follows:
+.Bl -tag -width ".Fl I , L , l"
+.It Fl A Ar base
+Specify the input address base.
+.Ar base
+may be one of
+.Cm d ,
+.Cm o ,
+.Cm x
+or
+.Cm n ,
+which specify decimal, octal, hexadecimal
+addresses or no address, respectively.
+.It Fl a
+Output named characters.
+Equivalent to
+.Fl t Ar a .
+.It Fl B , o
+Output octal shorts.
+Equivalent to
+.Fl t Ar o2 .
+.It Fl b
+Output octal bytes.
+Equivalent to
+.Fl t Ar o1 .
+.It Fl c
+Output C-style escaped characters.
+Equivalent to
+.Fl t Ar c .
+.It Fl D
+Output unsigned decimal ints.
+Equivalent to
+.Fl t Ar u4 .
+.It Fl e , F
+Output double-precision floating point numbers.
+Equivalent to
+.Fl t Ar fD .
+.It Fl f
+Output single-precision floating point numbers.
+Equivalent to
+.Fl t Ar fF .
+.It Fl H , X
+Output hexadecimal ints.
+Equivalent to
+.Fl t Ar x4 .
+.It Fl h , x
+Output hexadecimal shorts.
+Equivalent to
+.Fl t Ar x2 .
+.It Fl I , L , l
+Output signed decimal longs.
+Equivalent to
+.Fl t Ar dL .
+.It Fl i
+Output signed decimal ints.
+Equivalent to
+.Fl t Ar dI .
+.It Fl j Ar skip
+Skip
+.Ar skip
+bytes of the combined input before dumping.
+The number may be followed by one
+of
+.Cm b , k
+or
+.Cm m
+which specify the units of the number as blocks (512 bytes), kilobytes and
+megabytes, respectively.
+.It Fl N Ar length
+Dump at most
+.Ar length
+bytes of input.
+.It Fl O
+Output octal ints.
+Equivalent to
+.Fl t Ar o4 .
+.It Fl s
+Output signed decimal shorts.
+Equivalent to
+.Fl t Ar d2 .
+.It Fl t Ar type
+Specify the output format.
+.Ar type
+is a string containing one or more of the following kinds of type specifiers:
+.Bl -tag -width indent
+.It Cm a
+Named characters
+.Pq Tn ASCII .
+Control characters are displayed using the following names:
+.Bl -column "000 NUL" "001 SOH" "002 STX" "003 ETX" "004 EOT" "005 ENQ"
+.It "000 NUL 001 SOH 002 STX 003 ETX 004 EOT 005 ENQ"
+.It "006 ACK 007 BEL 008 BS 009 HT 00a NL 00b VT"
+.It "00c FF 00d CR 00e SO 00f SI 010 DLE 011 DC1"
+.It "012 DC2 013 DC3 014 DC4 015 NAK 016 SYN 017 ETB"
+.It "018 CAN 019 EM 01a SUB 01b ESC 01c FS 01d GS"
+.It "01e RS 01f US 020 SP 0ff DEL"
+.El
+.It Cm c
+Characters in the default character set.
+Non-printing characters are
+represented as 3-digit octal character codes, except the following
+characters, which are represented as C escapes:
+.Pp
+.Bl -tag -width carriage-return -compact
+.It NUL
+\e0
+.It alert
+\ea
+.It backspace
+\eb
+.It newline
+\en
+.It carriage-return
+\er
+.It tab
+\et
+.It vertical tab
+\ev
+.El
+.Pp
+Multi-byte characters are displayed in the area corresponding to the first
+byte of the character. The remaining bytes are shown as
+.Ql ** .
+.It Xo
+.Sm off
+.Op Cm d | o | u | x
+.Op Cm C | S | I | L | Ar n
+.Sm on
+.Xc
+Signed decimal
+.Pq Cm d ,
+octal
+.Pq Cm o ,
+unsigned decimal
+.Pq Cm u
+or
+hexadecimal
+.Pq Cm x .
+Followed by an optional size specifier, which may be either
+.Cm C
+.Pq Vt char ,
+.Cm S
+.Pq Vt short ,
+.Cm I
+.Pq Vt int ,
+.Cm L
+.Pq Vt long ,
+or a byte count as a decimal integer.
+.It Xo
+.Sm off
+.Cm f
+.Op Cm F | D | L | Ar n
+.Sm on
+.Xc
+Floating-point number.
+Followed by an optional size specifier, which may be either
+.Cm F
+.Pq Vt float ,
+.Cm D
+.Pq Vt double
+or
+.Cm L
+.Pq Vt "long double" .
+.El
+.It Fl v
+Write all input data, instead of replacing lines of duplicate values with a
+.Ql * .
+.El
+.Pp
+Multiple options that specify output format may be used; the output will
+contain one line for each format.
+.Pp
+If no output format is specified,
+.Fl t Ar oS
+is assumed.
+.Sh ENVIRONMENT
+The
+.Ev LANG , LC_ALL
+and
+.Ev LC_CTYPE
+environment variables affect the execution of
+.Nm
+as described in
+.Xr environ 7 .
+.Sh DIAGNOSTICS
+.Ex -std
+.Sh COMPATIBILITY
+The traditional
+.Fl s
+option to extract string constants is not supported; consider using
+.Xr strings 1
+instead.
+.Sh SEE ALSO
+.Xr hexdump 1 ,
+.Xr strings 1
+.Sh STANDARDS
+The
+.Nm
+utility conforms to
+.St -p1003.1-2001 .
+.Sh HISTORY
+An
+.Nm
+command appeared in
+.At v1 .
diff --git a/shell_cmds/hexdump/odsyntax.c b/shell_cmds/hexdump/odsyntax.c
new file mode 100644
index 0000000..6b9202e
--- /dev/null
+++ b/shell_cmds/hexdump/odsyntax.c
@@ -0,0 +1,447 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)odsyntax.c 8.2 (Berkeley) 5/4/95";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/hexdump/odsyntax.c,v 1.16 2002/09/04 23:29:01 dwmalone Exp $");
+
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <float.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "hexdump.h"
+
+#define PADDING " "
+
+int odmode;
+
+static void odadd(const char *);
+static void odformat(const char *);
+static const char *odformatfp(char, const char *);
+static const char *odformatint(char, const char *);
+static void odoffset(int, char ***);
+static void odusage(void);
+
+void
+oldsyntax(int argc, char ***argvp)
+{
+ static char _n[] = "%_n", padding[] = PADDING;
+ int ch;
+ char **argv, *end;
+
+ /* Add initial (default) address format. -A may change it later. */
+#define TYPE_OFFSET 7
+ add("\"%07.7_Ao\n\"");
+ add("\"%07.7_ao \"");
+
+ odmode = 1;
+ argv = *argvp;
+ while ((ch = getopt(argc, argv, "A:aBbcDdeFfHhIij:LlN:Oost:vXx")) != -1)
+ switch (ch) {
+ case 'A':
+ switch (*optarg) {
+ case 'd': case 'o': case 'x':
+ fshead->nextfu->fmt[TYPE_OFFSET] = *optarg;
+ fshead->nextfs->nextfu->fmt[TYPE_OFFSET] =
+ *optarg;
+ break;
+ case 'n':
+ fshead->nextfu->fmt = _n; /* mimic regular output */
+ fshead->nextfs->nextfu->fmt = padding;
+ break;
+ default:
+ errx(1, "%s: invalid address base", optarg);
+ }
+ break;
+ case 'a':
+ odformat("a");
+ break;
+ case 'B':
+ case 'o':
+ odformat("o2");
+ break;
+ case 'b':
+ odformat("o1");
+ break;
+ case 'c':
+ odformat("c");
+ break;
+ case 'd':
+ odformat("u2");
+ break;
+ case 'D':
+ odformat("u4");
+ break;
+ case 'e': /* undocumented in od */
+ case 'F':
+ odformat("fD");
+ break;
+ case 'f':
+ odformat("fF");
+ break;
+ case 'H':
+ case 'X':
+ odformat("x4");
+ break;
+ case 'h':
+ case 'x':
+ odformat("x2");
+ break;
+ case 'I':
+ case 'L':
+ case 'l':
+ odformat("dL");
+ break;
+ case 'i':
+ odformat("dI");
+ break;
+ case 'j':
+ errno = 0;
+ skip = strtoll(optarg, &end, 0);
+ if (*end == 'b')
+ skip *= 512;
+ else if (*end == 'k')
+ skip *= 1024;
+ else if (*end == 'm')
+ skip *= 1048576L;
+ else if (*end == 'g')
+ skip *= 1073741824;
+ else if (*end != '\0')
+ skip = -1;
+ if (errno != 0 || skip < 0 || strlen(end) > 1)
+ errx(1, "%s: invalid skip amount", optarg);
+ break;
+ case 'N':
+ if ((length = atoi(optarg)) <= 0)
+ errx(1, "%s: invalid length", optarg);
+ break;
+ case 'O':
+ odformat("o4");
+ break;
+ case 's':
+ odformat("d2");
+ break;
+ case 't':
+ odformat(optarg);
+ break;
+ case 'v':
+ vflag = ALL;
+ break;
+ case '?':
+ default:
+ odusage();
+ }
+
+ if (fshead->nextfs->nextfs == NULL)
+ odformat("oS");
+
+ argc -= optind;
+ *argvp += optind;
+
+ if (argc)
+ odoffset(argc, argvp);
+}
+
+static void
+odusage(void)
+{
+
+ fprintf(stderr,
+"usage: od [-aBbcDdeFfHhIiLlOosvXx] [-A base] [-j skip] [-N length] [-t type]\n");
+ fprintf(stderr,
+" [[+]offset[.][Bb]] [file ...]\n");
+ exit(1);
+}
+
+static void
+odoffset(int argc, char ***argvp)
+{
+ unsigned char *p, *q, *num, *end;
+ int base;
+
+ /*
+ * The offset syntax of od(1) was genuinely bizarre. First, if
+ * it started with a plus it had to be an offset. Otherwise, if
+ * there were at least two arguments, a number or lower-case 'x'
+ * followed by a number makes it an offset. By default it was
+ * octal; if it started with 'x' or '0x' it was hex. If it ended
+ * in a '.', it was decimal. If a 'b' or 'B' was appended, it
+ * multiplied the number by 512 or 1024 byte units. There was
+ * no way to assign a block count to a hex offset.
+ *
+ * We assume it's a file if the offset is bad.
+ */
+ p = (unsigned char *)(argc == 1 ? (*argvp)[0] : (*argvp)[1]);
+
+ if (*p != '+' && (argc < 2 ||
+ (!isdigit(p[0]) && (p[0] != 'x' || !isxdigit(p[1])))))
+ return;
+
+ base = 0;
+ /*
+ * skip over leading '+', 'x[0-9a-fA-f]' or '0x', and
+ * set base.
+ */
+ if (p[0] == '+')
+ ++p;
+ if (p[0] == 'x' && isxdigit(p[1])) {
+ ++p;
+ base = 16;
+ } else if (p[0] == '0' && p[1] == 'x') {
+ p += 2;
+ base = 16;
+ }
+
+ /* skip over the number */
+ if (base == 16)
+ for (num = p; isxdigit(*p); ++p);
+ else
+ for (num = p; isdigit(*p); ++p);
+
+ /* check for no number */
+ if (num == p)
+ return;
+ q = p;
+ /* if terminates with a '.', base is decimal */
+ if (*q == '.') {
+ if (base)
+ return;
+ base = 10;
+ q++;
+ }
+
+ skip = strtoll((const char *)num, (char **)&end, base ? base : 8);
+
+ /* if end isn't the same as p, we got a non-octal digit */
+ if (end != p) {
+ skip = 0;
+ return;
+ }
+
+ if (*q) {
+ if (*q == 'B') {
+ skip *= 1024;
+ ++p;
+ } else if (*q == 'b') {
+ skip *= 512;
+ ++q;
+ }
+ }
+
+ if (*q) {
+ skip = 0;
+ return;
+ }
+
+ /*
+ * If the offset uses a non-octal base, the base of the offset
+ * is changed as well. This isn't pretty, but it's easy.
+ */
+ if (base == 16) {
+ fshead->nextfu->fmt[TYPE_OFFSET] = 'x';
+ fshead->nextfs->nextfu->fmt[TYPE_OFFSET] = 'x';
+ } else if (base == 10) {
+ fshead->nextfu->fmt[TYPE_OFFSET] = 'd';
+ fshead->nextfs->nextfu->fmt[TYPE_OFFSET] = 'd';
+ }
+
+ /* Terminate file list. */
+ (*argvp)[1] = NULL;
+}
+
+static void
+odformat(const char *fmt)
+{
+ char fchar;
+
+ while (*fmt != '\0') {
+ switch ((fchar = *fmt++)) {
+ case 'a':
+ odadd("16/1 \"%3_u \" \"\\n\"");
+ break;
+ case 'c':
+ odadd("16/1 \"%3_c \" \"\\n\"");
+ break;
+ case 'o': case 'u': case 'd': case 'x':
+ fmt = odformatint(fchar, fmt);
+ break;
+ case 'f':
+ fmt = odformatfp(fchar, fmt);
+ break;
+ default:
+ errx(1, "%c: unrecognised format character", fchar);
+ }
+ }
+}
+
+static const char *
+odformatfp(char fchar __unused, const char *fmt)
+{
+ size_t isize;
+ int digits;
+ char *end, *hdfmt;
+
+ isize = sizeof(double);
+ switch (*fmt) {
+ case 'F':
+ isize = sizeof(float);
+ fmt++;
+ break;
+ case 'D':
+ isize = sizeof(double);
+ fmt++;
+ break;
+ case 'L':
+ isize = sizeof(long double);
+ fmt++;
+ break;
+ default:
+ if (isdigit((unsigned char)*fmt)) {
+ errno = 0;
+ isize = (size_t)strtoul(fmt, &end, 10);
+ if (errno != 0 || isize == 0)
+ errx(1, "%s: invalid size", fmt);
+ fmt = (const char *)end;
+ }
+ }
+ switch (isize) {
+ case sizeof(float):
+ digits = FLT_DIG;
+ break;
+ case sizeof(double):
+ digits = DBL_DIG;
+ break;
+ default:
+ if (isize == sizeof(long double))
+ digits = LDBL_DIG;
+ else
+ errx(1, "unsupported floating point size %lu",
+ (u_long)isize);
+ }
+
+ asprintf(&hdfmt, "%lu/%lu \" %%%d.%de \" \"\\n\"",
+ 16UL / (u_long)isize, (u_long)isize, digits + 8, digits);
+ if (hdfmt == NULL)
+ err(1, NULL);
+ odadd(hdfmt);
+ free(hdfmt);
+
+ return (fmt);
+}
+
+static const char *
+odformatint(char fchar, const char *fmt)
+{
+ unsigned long long n;
+ size_t isize;
+ int digits;
+ char *end, *hdfmt;
+
+ isize = sizeof(int);
+ switch (*fmt) {
+ case 'C':
+ isize = sizeof(char);
+ fmt++;
+ break;
+ case 'I':
+ isize = sizeof(int);
+ fmt++;
+ break;
+ case 'L':
+ isize = sizeof(long);
+ fmt++;
+ break;
+ case 'S':
+ isize = sizeof(short);
+ fmt++;
+ break;
+ default:
+ if (isdigit((unsigned char)*fmt)) {
+ errno = 0;
+ isize = (size_t)strtoul(fmt, &end, 10);
+ if (errno != 0 || isize == 0)
+ errx(1, "%s: invalid size", fmt);
+ if (isize != sizeof(char) && isize != sizeof(short) &&
+ isize != sizeof(int) && isize != sizeof(long))
+ errx(1, "unsupported int size %lu",
+ (u_long)isize);
+ fmt = (const char *)end;
+ }
+ }
+
+ /*
+ * Calculate the maximum number of digits we need to
+ * fit the number. Overestimate for decimal with log
+ * base 8. We need one extra space for signed numbers
+ * to store the sign.
+ */
+ n = (1ULL << (8 * isize)) - 1;
+ digits = 0;
+ while (n != 0) {
+ digits++;
+ n >>= (fchar == 'x') ? 4 : 3;
+ }
+ if (fchar == 'd')
+ digits++;
+ asprintf(&hdfmt, "%lu/%lu \"%*s%%%s%d%c\" \"\\n\"",
+ 16UL / (u_long)isize, (u_long)isize, (int)(4 * isize - digits),
+ "", (fchar == 'd' || fchar == 'u') ? "" : "0", digits, fchar);
+ if (hdfmt == NULL)
+ err(1, NULL);
+ odadd(hdfmt);
+ free(hdfmt);
+
+ return (fmt);
+}
+
+static void
+odadd(const char *fmt)
+{
+ static int needpad;
+
+ if (needpad)
+ add("\""PADDING"\"");
+ add(fmt);
+ needpad = 1;
+}
diff --git a/shell_cmds/hexdump/parse.c b/shell_cmds/hexdump/parse.c
new file mode 100644
index 0000000..5445f18
--- /dev/null
+++ b/shell_cmds/hexdump/parse.c
@@ -0,0 +1,523 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)parse.c 8.1 (Berkeley) 6/6/93";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/hexdump/parse.c,v 1.12 2002/09/04 23:29:01 dwmalone Exp $");
+
+#include <sys/types.h>
+
+#include <err.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include "hexdump.h"
+
+FU *endfu; /* format at end-of-data */
+
+void
+addfile(char *name)
+{
+ unsigned char *p;
+ FILE *fp;
+ int ch;
+ char buf[2048 + 1];
+
+ if ((fp = fopen(name, "r")) == NULL)
+ err(1, "%s", name);
+ while (fgets(buf, sizeof(buf), fp)) {
+ if (!(p = (unsigned char *)index(buf, '\n'))) {
+ warnx("line too long");
+ while ((ch = getchar()) != '\n' && ch != EOF);
+ continue;
+ }
+ *p = '\0';
+ for (p = (unsigned char *)buf; *p && isspace(*p); ++p);
+ if (!*p || *p == '#')
+ continue;
+ add((const char *)p);
+ }
+ (void)fclose(fp);
+}
+
+void
+add(const char *fmt)
+{
+ unsigned const char *p, *savep;
+ static FS **nextfs;
+ FS *tfs;
+ FU *tfu, **nextfu;
+
+ /* start new linked list of format units */
+ if ((tfs = calloc(1, sizeof(FS))) == NULL)
+ err(1, NULL);
+ if (!fshead)
+ fshead = tfs;
+ else
+ *nextfs = tfs;
+ nextfs = &tfs->nextfs;
+ nextfu = &tfs->nextfu;
+
+ /* take the format string and break it up into format units */
+ for (p = (unsigned const char *)fmt;;) {
+ /* skip leading white space */
+ for (; isspace(*p); ++p);
+ if (!*p)
+ break;
+
+ /* allocate a new format unit and link it in */
+ if ((tfu = calloc(1, sizeof(FU))) == NULL)
+ err(1, NULL);
+ *nextfu = tfu;
+ nextfu = &tfu->nextfu;
+ tfu->reps = 1;
+
+ /* if leading digit, repetition count */
+ if (isdigit(*p)) {
+ for (savep = p; isdigit(*p); ++p);
+ if (!isspace(*p) && *p != '/')
+ badfmt(fmt);
+ /* may overwrite either white space or slash */
+ tfu->reps = atoi((const char *)savep);
+ tfu->flags = F_SETREP;
+ /* skip trailing white space */
+ for (++p; isspace(*p); ++p);
+ }
+
+ /* skip slash and trailing white space */
+ if (*p == '/')
+ while (isspace(*++p));
+
+ /* byte count */
+ if (isdigit(*p)) {
+ for (savep = p; isdigit(*p); ++p);
+ if (!isspace(*p))
+ badfmt(fmt);
+ tfu->bcnt = atoi((const char *)savep);
+ /* skip trailing white space */
+ for (++p; isspace(*p); ++p);
+ }
+
+ /* format */
+ if (*p != '"')
+ badfmt(fmt);
+ for (savep = ++p; *p != '"';)
+ if (*p++ == 0)
+ badfmt(fmt);
+ if (!(tfu->fmt = malloc(p - savep + 1)))
+ err(1, NULL);
+ (void) strncpy(tfu->fmt, (const char *)savep, p - savep);
+ tfu->fmt[p - savep] = '\0';
+ escape(tfu->fmt);
+ p++;
+ }
+}
+
+static const char *spec = ".#-+ 0123456789";
+
+int
+size(FS *fs)
+{
+ FU *fu;
+ int bcnt, cursize;
+ unsigned char *fmt;
+ int prec;
+
+ /* figure out the data block size needed for each format unit */
+ for (cursize = 0, fu = fs->nextfu; fu; fu = fu->nextfu) {
+ if (fu->bcnt) {
+ cursize += fu->bcnt * fu->reps;
+ continue;
+ }
+ for (bcnt = prec = 0, fmt = (unsigned char *)fu->fmt; *fmt; ++fmt) {
+ if (*fmt != '%')
+ continue;
+ /*
+ * skip any special chars -- save precision in
+ * case it's a %s format.
+ */
+ while (index(spec + 1, *++fmt));
+ if (*fmt == '.' && isdigit(*++fmt)) {
+ prec = atoi((const char *)fmt);
+ while (isdigit(*++fmt));
+ }
+ switch(*fmt) {
+ case 'c':
+ bcnt += 1;
+ break;
+ case 'd': case 'i': case 'o': case 'u':
+ case 'x': case 'X':
+ bcnt += 4;
+ break;
+ case 'e': case 'E': case 'f': case 'g': case 'G':
+ bcnt += 8;
+ break;
+ case 's':
+ bcnt += prec;
+ break;
+ case '_':
+ switch(*++fmt) {
+ case 'c': case 'p': case 'u':
+ bcnt += 1;
+ break;
+ }
+ }
+ }
+ cursize += bcnt * fu->reps;
+ }
+ return (cursize);
+}
+
+void
+rewrite(FS *fs)
+{
+ enum { NOTOKAY, USEBCNT, USEPREC } sokay;
+ PR *pr, **nextpr = NULL;
+ FU *fu;
+ unsigned char *p1, *p2, *fmtp;
+ char savech, cs[3];
+ int nconv, prec = 0;
+
+ for (fu = fs->nextfu; fu; fu = fu->nextfu) {
+ /*
+ * Break each format unit into print units; each conversion
+ * character gets its own.
+ */
+ for (nconv = 0, fmtp = (unsigned char *)fu->fmt; *fmtp; nextpr = &pr->nextpr) {
+ if ((pr = calloc(1, sizeof(PR))) == NULL)
+ err(1, NULL);
+ if (!fu->nextpr)
+ fu->nextpr = pr;
+ else
+ *nextpr = pr;
+
+ /* Skip preceding text and up to the next % sign. */
+ for (p1 = fmtp; *p1 && *p1 != '%'; ++p1);
+
+ /* Only text in the string. */
+ if (!*p1) {
+ pr->fmt = (char *)fmtp;
+ pr->flags = F_TEXT;
+ break;
+ }
+
+ /*
+ * Get precision for %s -- if have a byte count, don't
+ * need it.
+ */
+ if (fu->bcnt) {
+ sokay = USEBCNT;
+ /* Skip to conversion character. */
+ for (++p1; index(spec, *p1); ++p1);
+ } else {
+ /* Skip any special chars, field width. */
+ while (index(spec + 1, *++p1));
+ if (*p1 == '.' && isdigit(*++p1)) {
+ sokay = USEPREC;
+ prec = atoi((const char *)p1);
+ while (isdigit(*++p1));
+ } else
+ sokay = NOTOKAY;
+ }
+
+ p2 = p1 + 1; /* Set end pointer. */
+ cs[0] = *p1; /* Set conversion string. */
+ cs[1] = '\0';
+
+ /*
+ * Figure out the byte count for each conversion;
+ * rewrite the format as necessary, set up blank-
+ * padding for end of data.
+ */
+ switch(cs[0]) {
+ case 'c':
+ pr->flags = F_CHAR;
+ switch(fu->bcnt) {
+ case 0: case 1:
+ pr->bcnt = 1;
+ break;
+ default:
+ p1[1] = '\0';
+ badcnt((char *)p1);
+ }
+ break;
+ case 'd': case 'i':
+ pr->flags = F_INT;
+ goto isint;
+ case 'o': case 'u': case 'x': case 'X':
+ pr->flags = F_UINT;
+isint: cs[2] = '\0';
+ cs[1] = cs[0];
+ cs[0] = 'q';
+ switch(fu->bcnt) {
+ case 0: case 4:
+ pr->bcnt = 4;
+ break;
+ case 1:
+ pr->bcnt = 1;
+ break;
+ case 2:
+ pr->bcnt = 2;
+ break;
+#ifdef __APPLE__
+ case 8:
+ pr->bcnt = 8;
+ break;
+#endif /* __APPLE__ */
+ default:
+ p1[1] = '\0';
+ badcnt((char *)p1);
+ }
+ break;
+ case 'e': case 'E': case 'f': case 'g': case 'G':
+ pr->flags = F_DBL;
+ switch(fu->bcnt) {
+ case 0: case 8:
+ pr->bcnt = 8;
+ break;
+ case 4:
+ pr->bcnt = 4;
+ break;
+ default:
+ if (fu->bcnt == sizeof(long double)) {
+ cs[2] = '\0';
+ cs[1] = cs[0];
+ cs[0] = 'L';
+ pr->bcnt = sizeof(long double);
+ } else {
+ p1[1] = '\0';
+ badcnt((char *)p1);
+ }
+ }
+ break;
+ case 's':
+ pr->flags = F_STR;
+ switch(sokay) {
+ case NOTOKAY:
+ badsfmt();
+ case USEBCNT:
+ pr->bcnt = fu->bcnt;
+ break;
+ case USEPREC:
+ pr->bcnt = prec;
+ break;
+ }
+ break;
+ case '_':
+ ++p2;
+ switch(p1[1]) {
+ case 'A':
+ endfu = fu;
+ fu->flags |= F_IGNORE;
+ /* FALLTHROUGH */
+ case 'a':
+ pr->flags = F_ADDRESS;
+ ++p2;
+ switch(p1[2]) {
+ case 'd': case 'o': case'x':
+ cs[0] = 'q';
+ cs[1] = p1[2];
+ cs[2] = '\0';
+ break;
+ default:
+ p1[3] = '\0';
+ badconv((char *)p1);
+ }
+ break;
+ case 'c':
+ pr->flags = F_C;
+ /* cs[0] = 'c'; set in conv_c */
+ goto isint2;
+ case 'p':
+ pr->flags = F_P;
+ cs[0] = 'c';
+ goto isint2;
+ case 'u':
+ pr->flags = F_U;
+ /* cs[0] = 'c'; set in conv_u */
+isint2: switch(fu->bcnt) {
+ case 0: case 1:
+ pr->bcnt = 1;
+ break;
+ default:
+ p1[2] = '\0';
+ badcnt((char *)p1);
+ }
+ break;
+ case 'n': /* Force -A n to dump extra blank line like default od behavior */
+ endfu = fu;
+ fu->flags = F_IGNORE;
+ pr->flags = F_TEXT;
+ fmtp = (unsigned char *)"\n";
+ cs[0] = '\0';
+ break;
+ default:
+ p1[2] = '\0';
+ badconv((char *)p1);
+ }
+ break;
+ default:
+ p1[1] = '\0';
+ badconv((char *)p1);
+ }
+
+ /*
+ * Copy to PR format string, set conversion character
+ * pointer, update original.
+ */
+ savech = *p2;
+ p1[0] = '\0';
+ if ((pr->fmt = calloc(1, strlen((const char *)fmtp) + 2)) == NULL)
+ err(1, NULL);
+ (void)strcpy(pr->fmt, (const char *)fmtp);
+ (void)strcat(pr->fmt, cs);
+ *p2 = savech;
+ pr->cchar = pr->fmt + (p1 - fmtp);
+ fmtp = p2;
+
+ /* Only one conversion character if byte count. */
+ if (!(pr->flags&F_ADDRESS) && fu->bcnt && nconv++)
+ errx(1, "byte count with multiple conversion characters");
+ }
+ /*
+ * If format unit byte count not specified, figure it out
+ * so can adjust rep count later.
+ */
+ if (!fu->bcnt)
+ for (pr = fu->nextpr; pr; pr = pr->nextpr)
+ fu->bcnt += pr->bcnt;
+ }
+ /*
+ * If the format string interprets any data at all, and it's
+ * not the same as the blocksize, and its last format unit
+ * interprets any data at all, and has no iteration count,
+ * repeat it as necessary.
+ *
+ * If, rep count is greater than 1, no trailing whitespace
+ * gets output from the last iteration of the format unit.
+ */
+ for (fu = fs->nextfu; fu; fu = fu->nextfu) {
+ if (!fu->nextfu && fs->bcnt < blocksize &&
+ !(fu->flags&F_SETREP) && fu->bcnt)
+ fu->reps += (blocksize - fs->bcnt) / fu->bcnt;
+ if (fu->reps > 1) {
+ for (pr = fu->nextpr;; pr = pr->nextpr)
+ if (!pr->nextpr)
+ break;
+ for (p1 = (unsigned char *)pr->fmt, p2 = NULL; *p1; ++p1)
+ p2 = isspace(*p1) ? p1 : NULL;
+ if (p2)
+ pr->nospace = (char *)p2;
+ }
+ }
+#ifdef DEBUG
+ for (fu = fs->nextfu; fu; fu = fu->nextfu) {
+ (void)printf("fmt:");
+ for (pr = fu->nextpr; pr; pr = pr->nextpr)
+ (void)printf(" {%s}", pr->fmt);
+ (void)printf("\n");
+ }
+#endif
+}
+
+void
+escape(char *p1)
+{
+ char *p2;
+
+ /* alphabetic escape sequences have to be done in place */
+ for (p2 = p1;; ++p1, ++p2) {
+ if (!*p1) {
+ *p2 = *p1;
+ break;
+ }
+ if (*p1 == '\\')
+ switch(*++p1) {
+ case 'a':
+ /* *p2 = '\a'; */
+ *p2 = '\007';
+ break;
+ case 'b':
+ *p2 = '\b';
+ break;
+ case 'f':
+ *p2 = '\f';
+ break;
+ case 'n':
+ *p2 = '\n';
+ break;
+ case 'r':
+ *p2 = '\r';
+ break;
+ case 't':
+ *p2 = '\t';
+ break;
+ case 'v':
+ *p2 = '\v';
+ break;
+ default:
+ *p2 = *p1;
+ break;
+ }
+ }
+}
+
+void
+badcnt(char *s)
+{
+ errx(1, "%s: bad byte count", s);
+}
+
+void
+badsfmt(void)
+{
+ errx(1, "%%s: requires a precision or a byte count");
+}
+
+void
+badfmt(const char *fmt)
+{
+ errx(1, "\"%s\": bad format", fmt);
+}
+
+void
+badconv(char *ch)
+{
+ errx(1, "%%%s: bad conversion character", ch);
+}
diff --git a/shell_cmds/hostname/hostname.1 b/shell_cmds/hostname/hostname.1
new file mode 100644
index 0000000..291b319
--- /dev/null
+++ b/shell_cmds/hostname/hostname.1
@@ -0,0 +1,67 @@
+.\"-
+.\" Copyright (c) 1983, 1988, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)hostname.1 8.2 (Berkeley) 4/28/95
+.\" $FreeBSD: src/bin/hostname/hostname.1,v 1.21 2006/12/08 07:47:08 kientzle Exp $
+.\"
+.Dd December 7, 2006
+.Dt HOSTNAME 1
+.Os
+.Sh NAME
+.Nm hostname
+.Nd set or print name of current host system
+.Sh SYNOPSIS
+.Nm
+.Op Fl fs
+.Op Ar name-of-host
+.Sh DESCRIPTION
+The
+.Nm
+utility prints the name of the current host.
+The super-user can
+set the hostname by supplying an argument.
+To keep the hostname between reboots, run
+.Sq scutil --set HostName Ar name-of-host .
+.Pp
+Options:
+.Bl -tag -width flag
+.It Fl f
+Include domain information in the printed name.
+This is the default behavior.
+.It Fl s
+Trim off any domain information from the printed
+name.
+.El
+.Sh SEE ALSO
+.Xr gethostname 3 ,
+.Xr scutil 8
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.2 .
diff --git a/shell_cmds/hostname/hostname.c b/shell_cmds/hostname/hostname.c
new file mode 100644
index 0000000..3df6542
--- /dev/null
+++ b/shell_cmds/hostname/hostname.c
@@ -0,0 +1,105 @@
+/*-
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static char const copyright[] =
+"@(#) Copyright (c) 1988, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)hostname.c 8.1 (Berkeley) 5/31/93";
+#endif /* not lint */
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/bin/hostname/hostname.c,v 1.19 2006/12/08 07:47:08 kientzle Exp $");
+
+#include <sys/param.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+void usage(void);
+
+int
+main(int argc, char *argv[])
+{
+ int ch, sflag;
+ char *p, hostname[MAXHOSTNAMELEN];
+
+ sflag = 0;
+ while ((ch = getopt(argc, argv, "fs")) != -1)
+ switch (ch) {
+ case 'f':
+ /*
+ * On Linux, "hostname -f" prints FQDN.
+ * BSD "hostname" always prints FQDN by
+ * default, so we accept but ignore -f.
+ */
+ break;
+ case 's':
+ sflag = 1;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc > 1)
+ usage();
+
+ if (*argv) {
+ if (sethostname(*argv, (int)strlen(*argv)))
+ err(1, "sethostname");
+ } else {
+ if (gethostname(hostname, (int)sizeof(hostname)))
+ err(1, "gethostname");
+ if (sflag) {
+ p = strchr(hostname, '.');
+ if (p != NULL)
+ *p = '\0';
+ }
+ (void)printf("%s\n", hostname);
+ }
+ exit(0);
+}
+
+void
+usage(void)
+{
+
+ (void)fprintf(stderr, "usage: hostname [-fs] [name-of-host]\n");
+ exit(1);
+}
diff --git a/shell_cmds/id/groups.1 b/shell_cmds/id/groups.1
new file mode 100644
index 0000000..00c030b
--- /dev/null
+++ b/shell_cmds/id/groups.1
@@ -0,0 +1,63 @@
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)groups.1 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD: src/usr.bin/id/groups.1,v 1.10 2006/12/23 17:14:01 ru Exp $
+.\"
+.Dd June 6, 1993
+.Dt GROUPS 1
+.Os
+.Sh NAME
+.Nm groups
+.Nd show group memberships
+.Sh SYNOPSIS
+.Nm
+.Op Ar user
+.Sh DESCRIPTION
+The
+.Nm
+utility has been obsoleted by the
+.Xr id 1
+utility, and is equivalent to
+.Dq Nm id Fl Gn Op Ar user .
+The command
+.Dq Nm id Fl p
+is suggested for normal interactive use.
+.Pp
+The
+.Nm
+utility displays the groups to which you (or the optionally specified
+.Ar user )
+belong.
+.Sh EXIT STATUS
+.Ex -std
+.Sh SEE ALSO
+.Xr id 1
diff --git a/shell_cmds/id/id.1 b/shell_cmds/id/id.1
new file mode 100644
index 0000000..1090c9a
--- /dev/null
+++ b/shell_cmds/id/id.1
@@ -0,0 +1,167 @@
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)id.1 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD: src/usr.bin/id/id.1,v 1.18 2006/09/26 22:28:12 ceri Exp $
+.\"
+.Dd September 26, 2006
+.Dt ID 1
+.Os
+.Sh NAME
+.Nm id
+.Nd return user identity
+.Sh SYNOPSIS
+.Nm
+.Op Ar user
+.Nm
+.Fl A
+.Nm
+.Fl F
+.Op Ar user
+.Nm
+.Fl G Op Fl n
+.Op Ar user
+.Nm
+.Fl M
+.Nm
+.Fl P
+.Op Ar user
+.Nm
+.Fl g Op Fl nr
+.Op Ar user
+.Nm
+.Fl p
+.Op Ar user
+.Nm
+.Fl u Op Fl nr
+.Op Ar user
+.Sh DESCRIPTION
+The
+.Nm
+utility displays the user and group names and numeric IDs, of the
+calling process, to the standard output.
+If the real and effective IDs are different, both are displayed,
+otherwise only the real ID is displayed.
+.Pp
+If a
+.Ar user
+(login name or user ID)
+is specified, the user and group IDs of that user are displayed.
+In this case, the real and effective IDs are assumed to be the same.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl A
+Display the process audit user ID and other process audit properties, which
+requires privilege.
+.It Fl F
+Display the full name of the user.
+.It Fl G
+Display the different group IDs (effective, real and supplementary)
+as white-space separated numbers, in no particular order.
+.It Fl M
+Display the MAC label of the current process.
+.It Fl P
+Display the id as a password file entry.
+.It Fl a
+Ignored for compatibility with other
+.Nm
+implementations.
+.It Fl g
+Display the effective group ID as a number.
+.It Fl n
+Display the name of the user or group ID for the
+.Fl G ,
+.Fl g
+and
+.Fl u
+options instead of the number.
+If any of the ID numbers cannot be mapped into names, the number will be
+displayed as usual.
+.It Fl p
+Make the output human-readable.
+If the user name returned by
+.Xr getlogin 2
+is different from the login name referenced by the user ID, the name
+returned by
+.Xr getlogin 2
+is displayed, preceded by the keyword
+.Dq login .
+The user ID as a name is displayed, preceded by the keyword
+.Dq uid .
+If the effective user ID is different from the real user ID, the real user
+ID is displayed as a name, preceded by the keyword
+.Dq euid .
+If the effective group ID is different from the real group ID, the real group
+ID is displayed as a name, preceded by the keyword
+.Dq rgid .
+The list of groups to which the user belongs is then displayed as names,
+preceded by the keyword
+.Dq groups .
+Each display is on a separate line.
+.It Fl r
+Display the real ID for the
+.Fl g
+and
+.Fl u
+options instead of the effective ID.
+.It Fl u
+Display the effective user ID as a number.
+.El
+.Sh EXIT STATUS
+.Ex -std
+.Sh SEE ALSO
+.Xr who 1
+.Sh STANDARDS
+The
+.Nm
+function is expected to conform to
+.St -p1003.2 .
+.Sh HISTORY
+The
+historic
+.Xr groups 1
+command is equivalent to
+.Dq Nm id Fl Gn Op Ar user .
+.Pp
+The
+historic
+.Xr whoami 1
+command is equivalent to
+.Dq Nm id Fl un .
+.Pp
+The
+.Nm
+command appeared in
+.Bx 4.4 .
diff --git a/shell_cmds/id/id.c b/shell_cmds/id/id.c
new file mode 100644
index 0000000..2567770
--- /dev/null
+++ b/shell_cmds/id/id.c
@@ -0,0 +1,529 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1991, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)id.c 8.2 (Berkeley) 2/16/94";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/id/id.c,v 1.33 2006/12/29 12:28:34 stefanf Exp $");
+
+#include <sys/param.h>
+#ifndef __APPLE__
+#include <sys/mac.h>
+#endif /* !__APPLE__ */
+
+#ifdef USE_BSM_AUDIT
+#include <bsm/audit.h>
+#endif
+
+#include <err.h>
+#include <errno.h>
+#include <grp.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+void id_print(struct passwd *, int, int, int);
+void pline(struct passwd *);
+void pretty(struct passwd *);
+void auditid(void);
+void fullname(struct passwd *);
+void group(struct passwd *, int);
+void maclabel(void);
+void usage(void);
+struct passwd *who(char *);
+
+int isgroups, iswhoami;
+
+#ifdef __APPLE__
+// SPI for 5235093
+int32_t getgrouplist_2(const char *, gid_t, gid_t **);
+#endif
+
+int
+main(int argc, char *argv[])
+{
+ struct group *gr;
+ struct passwd *pw;
+ int Gflag, Mflag, Pflag, ch, gflag, id, nflag, pflag, rflag, uflag;
+ int Aflag;
+ int Fflag;
+ const char *myname;
+
+ Gflag = Mflag = Pflag = gflag = nflag = pflag = rflag = uflag = 0;
+ Aflag = 0;
+ Fflag = 0;
+
+ myname = strrchr(argv[0], '/');
+ myname = (myname != NULL) ? myname + 1 : argv[0];
+ if (strcmp(myname, "groups") == 0) {
+ isgroups = 1;
+ Gflag = nflag = 1;
+ }
+ else if (strcmp(myname, "whoami") == 0) {
+ iswhoami = 1;
+ uflag = nflag = 1;
+ }
+
+ while ((ch = getopt(argc, argv,
+ (isgroups || iswhoami) ? "" : "AFPGMagnpru")) != -1)
+ switch(ch) {
+#ifdef USE_BSM_AUDIT
+ case 'A':
+ Aflag = 1;
+ break;
+#endif
+ case 'F':
+ Fflag = 1;
+ break;
+ case 'G':
+ Gflag = 1;
+ break;
+ case 'M':
+ Mflag = 1;
+ break;
+ case 'P':
+ Pflag = 1;
+ break;
+ case 'a':
+ break;
+ case 'g':
+ gflag = 1;
+ break;
+ case 'n':
+ nflag = 1;
+ break;
+ case 'p':
+ pflag = 1;
+ break;
+ case 'r':
+ rflag = 1;
+ break;
+ case 'u':
+ uflag = 1;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (iswhoami && argc > 0)
+ usage();
+
+ switch(Aflag + Fflag + Gflag + Mflag + Pflag + gflag + pflag + uflag) {
+ case 1:
+ break;
+ case 0:
+ if (!nflag && !rflag)
+ break;
+ /* FALLTHROUGH */
+ default:
+ usage();
+ }
+
+ pw = *argv ? who(*argv) : NULL;
+
+ if (Mflag && pw != NULL)
+ usage();
+
+#ifdef USE_BSM_AUDIT
+ if (Aflag) {
+ auditid();
+ exit(0);
+ }
+#endif
+
+ if (Fflag) {
+ fullname(pw);
+ exit(0);
+ }
+
+ if (gflag) {
+ id = pw ? pw->pw_gid : rflag ? getgid() : getegid();
+ if (nflag && (gr = getgrgid(id)))
+ (void)printf("%s\n", gr->gr_name);
+ else
+ (void)printf("%u\n", id);
+ exit(0);
+ }
+
+ if (uflag) {
+ id = pw ? pw->pw_uid : rflag ? getuid() : geteuid();
+ if (nflag && (pw = getpwuid(id)))
+ (void)printf("%s\n", pw->pw_name);
+ else
+ (void)printf("%u\n", id);
+ exit(0);
+ }
+
+ if (Gflag) {
+ group(pw, nflag);
+ exit(0);
+ }
+
+ if (Mflag) {
+ maclabel();
+ exit(0);
+ }
+
+ if (Pflag) {
+ pline(pw);
+ exit(0);
+ }
+
+ if (pflag) {
+ pretty(pw);
+ exit(0);
+ }
+
+ if (pw) {
+ id_print(pw, 1, 0, 0);
+ }
+ else {
+ id = getuid();
+ pw = getpwuid(id);
+ id_print(pw, 0, 1, 1);
+ }
+ exit(0);
+}
+
+void
+pretty(struct passwd *pw)
+{
+ struct group *gr;
+ u_int eid, rid;
+ char *login;
+
+ if (pw) {
+ (void)printf("uid\t%s\n", pw->pw_name);
+ (void)printf("groups\t");
+ group(pw, 1);
+ } else {
+ if ((login = getlogin()) == NULL)
+ err(1, "getlogin");
+
+ pw = getpwuid(rid = getuid());
+ if (pw == NULL || strcmp(login, pw->pw_name))
+ (void)printf("login\t%s\n", login);
+ if (pw)
+ (void)printf("uid\t%s\n", pw->pw_name);
+ else
+ (void)printf("uid\t%u\n", rid);
+
+ if ((eid = geteuid()) != rid) {
+ if ((pw = getpwuid(eid)))
+ (void)printf("euid\t%s\n", pw->pw_name);
+ else
+ (void)printf("euid\t%u\n", eid);
+ }
+ if ((rid = getgid()) != (eid = getegid())) {
+ if ((gr = getgrgid(rid)))
+ (void)printf("rgid\t%s\n", gr->gr_name);
+ else
+ (void)printf("rgid\t%u\n", rid);
+ }
+ (void)printf("groups\t");
+ group(NULL, 1);
+ }
+}
+
+void
+id_print(struct passwd *pw, int use_ggl, int p_euid, int p_egid)
+{
+ struct group *gr;
+ gid_t gid, egid, lastgid;
+ uid_t uid, euid;
+ int cnt, ngroups;
+#ifdef __APPLE__
+ gid_t *groups = NULL;
+#else
+ gid_t groups[NGROUPS + 1];
+#endif
+ const char *fmt;
+
+#ifdef __APPLE__
+ if (pw == NULL) {
+ pw = getpwuid(getuid());
+ }
+
+ use_ggl = 1;
+#endif
+
+ if (pw != NULL) {
+ uid = pw->pw_uid;
+ gid = pw->pw_gid;
+ }
+ else {
+ uid = getuid();
+ gid = getgid();
+ }
+
+ if (use_ggl && pw != NULL) {
+#ifdef __APPLE__
+ // 5235093
+ ngroups = getgrouplist_2(pw->pw_name, gid, &groups);
+#else
+ ngroups = NGROUPS + 1;
+ getgrouplist(pw->pw_name, gid, groups, &ngroups);
+#endif
+ }
+ else {
+#ifdef __APPLE__
+ groups = malloc((NGROUPS + 1) * sizeof(gid_t));
+#endif
+ ngroups = getgroups(NGROUPS + 1, groups);
+ }
+
+#ifdef __APPLE__
+ if (ngroups < 0)
+ warn("failed to retrieve group list");
+#endif
+
+ if (pw != NULL)
+ printf("uid=%u(%s)", uid, pw->pw_name);
+ else
+ printf("uid=%u", getuid());
+ printf(" gid=%u", gid);
+ if ((gr = getgrgid(gid)))
+ (void)printf("(%s)", gr->gr_name);
+ if (p_euid && (euid = geteuid()) != uid) {
+ (void)printf(" euid=%u", euid);
+ if ((pw = getpwuid(euid)))
+ (void)printf("(%s)", pw->pw_name);
+ }
+ if (p_egid && (egid = getegid()) != gid) {
+ (void)printf(" egid=%u", egid);
+ if ((gr = getgrgid(egid)))
+ (void)printf("(%s)", gr->gr_name);
+ }
+ fmt = " groups=%u";
+ for (lastgid = -1, cnt = 0; cnt < ngroups; ++cnt) {
+ if (lastgid == (gid = groups[cnt]))
+ continue;
+ printf(fmt, gid);
+ fmt = ",%u";
+ if ((gr = getgrgid(gid)))
+ printf("(%s)", gr->gr_name);
+ lastgid = gid;
+ }
+ printf("\n");
+#ifdef __APPLE__
+ free(groups);
+#endif
+}
+
+#ifdef USE_BSM_AUDIT
+void
+auditid(void)
+{
+ auditinfo_addr_t auditinfo;
+
+ if (getaudit_addr(&auditinfo, sizeof(auditinfo)) < 0)
+ err(1, "getaudit");
+ printf("auid=%d\n", auditinfo.ai_auid);
+ printf("mask.success=0x%08x\n", auditinfo.ai_mask.am_success);
+ printf("mask.failure=0x%08x\n", auditinfo.ai_mask.am_failure);
+ printf("termid.port=0x%08x\n", auditinfo.ai_termid.at_port);
+ printf("asid=%d\n", auditinfo.ai_asid);
+}
+#endif
+
+void
+fullname(struct passwd *pw)
+{
+
+ if (!pw) {
+ if ((pw = getpwuid(getuid())) == NULL)
+ err(1, "getpwuid");
+ }
+
+ (void)printf("%s\n", pw->pw_gecos);
+}
+
+void
+group(struct passwd *pw, int nflag)
+{
+ struct group *gr;
+ int cnt, id, lastid, ngroups;
+#ifdef __APPLE__
+ gid_t *groups = NULL;
+#else
+ gid_t groups[NGROUPS + 1];
+#endif
+ const char *fmt;
+
+#ifdef __APPLE__
+ if (pw == NULL) {
+ pw = getpwuid(getuid());
+ }
+#endif
+
+ if (pw) {
+#ifdef __APPLE__
+ // 5235093
+ ngroups = getgrouplist_2(pw->pw_name, pw->pw_gid, &groups);
+#else
+ ngroups = NGROUPS + 1;
+ (void) getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups);
+#endif
+ } else {
+#ifdef __APPLE__
+ groups = malloc((NGROUPS + 1) * sizeof(gid_t));
+#endif
+ groups[0] = getgid();
+ ngroups = getgroups(NGROUPS, groups + 1) + 1;
+ }
+ fmt = nflag ? "%s" : "%u";
+ for (lastid = -1, cnt = 0; cnt < ngroups; ++cnt) {
+ if (lastid == (id = groups[cnt]))
+ continue;
+ if (nflag) {
+ if ((gr = getgrgid(id)))
+ (void)printf(fmt, gr->gr_name);
+ else
+ (void)printf(*fmt == ' ' ? " %u" : "%u",
+ id);
+ fmt = " %s";
+ } else {
+ (void)printf(fmt, id);
+ fmt = " %u";
+ }
+ lastid = id;
+ }
+ (void)printf("\n");
+#ifdef __APPLE__
+ free(groups);
+#endif
+}
+
+void
+maclabel(void)
+{
+#ifdef __APPLE__
+ errx(1, "-M unsupported");
+#else /* !__APPLE__ */
+ char *string;
+ mac_t label;
+ int error;
+
+ error = mac_prepare_process_label(&label);
+ if (error == -1)
+ errx(1, "mac_prepare_type: %s", strerror(errno));
+
+ error = mac_get_proc(label);
+ if (error == -1)
+ errx(1, "mac_get_proc: %s", strerror(errno));
+
+ error = mac_to_text(label, &string);
+ if (error == -1)
+ errx(1, "mac_to_text: %s", strerror(errno));
+
+ (void)printf("%s\n", string);
+ mac_free(label);
+ free(string);
+#endif /* __APPLE__ */
+}
+
+struct passwd *
+who(char *u)
+{
+ struct passwd *pw;
+ long id;
+ char *ep;
+
+ /*
+ * Translate user argument into a pw pointer. First, try to
+ * get it as specified. If that fails, try it as a number.
+ */
+ if ((pw = getpwnam(u)))
+ return(pw);
+ id = strtol(u, &ep, 10);
+ if (*u && !*ep && (pw = getpwuid(id)))
+ return(pw);
+ errx(1, "%s: no such user", u);
+ /* NOTREACHED */
+}
+
+void
+pline(struct passwd *pw)
+{
+
+ if (!pw) {
+ if ((pw = getpwuid(getuid())) == NULL)
+ err(1, "getpwuid");
+ }
+
+ (void)printf("%s:%s:%d:%d:%s:%ld:%ld:%s:%s:%s\n", pw->pw_name,
+ pw->pw_passwd, pw->pw_uid, pw->pw_gid, pw->pw_class,
+ (long)pw->pw_change, (long)pw->pw_expire, pw->pw_gecos,
+ pw->pw_dir, pw->pw_shell);
+}
+
+
+void
+usage(void)
+{
+
+ if (isgroups)
+ (void)fprintf(stderr, "usage: groups [user]\n");
+ else if (iswhoami)
+ (void)fprintf(stderr, "usage: whoami\n");
+ else
+ (void)fprintf(stderr, "%s\n%s%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
+ "usage: id [user]",
+#ifdef USE_BSM_AUDIT
+ " id -A\n",
+#else
+ "",
+#endif
+ " id -F [user]",
+ " id -G [-n] [user]",
+ " id -M",
+ " id -P [user]",
+ " id -g [-nr] [user]",
+ " id -p [user]",
+ " id -u [-nr] [user]");
+ exit(1);
+}
diff --git a/shell_cmds/id/open_directory.c b/shell_cmds/id/open_directory.c
new file mode 100644
index 0000000..fb34de9
--- /dev/null
+++ b/shell_cmds/id/open_directory.c
@@ -0,0 +1,229 @@
+#include <membership.h>
+
+#include "open_directory.h"
+
+ODNodeRef
+CreateNode(void)
+{
+ CFErrorRef error = NULL;
+ ODNodeRef node = NULL;
+
+ node = ODNodeCreateWithNodeType(NULL, kODSessionDefault, kODTypeAuthenticationSearchNode, &error);
+
+ if (node == NULL) {
+ CFShow(error);
+ exit(1);
+ }
+
+ return node;
+}
+
+static ODRecordRef
+CopyRecordWithUUID(ODNodeRef node, CFStringRef type, uuid_t uuid)
+{
+ CFErrorRef error = NULL;
+ char uuidstr[37];
+ CFStringRef uuidref;
+ ODQueryRef query = NULL;
+ CFTypeRef vals[] = { CFSTR(kDSAttributesStandardAll) };
+ CFArrayRef attributes = CFArrayCreate(NULL, vals, 1, &kCFTypeArrayCallBacks);
+ CFArrayRef results = NULL;
+ ODRecordRef record = NULL;
+
+ uuid_unparse(uuid, uuidstr);
+ uuidref = CFStringCreateWithCString(NULL, uuidstr, kCFStringEncodingUTF8);
+
+ if (uuidref) {
+ query = ODQueryCreateWithNode(NULL, node, type, CFSTR(kDS1AttrGeneratedUID), kODMatchEqualTo, uuidref, attributes, 100, &error);
+
+ if (query) {
+ results = ODQueryCopyResults(query, false, &error);
+
+ if (results) {
+ if (CFArrayGetCount(results) == 1) {
+ record = (ODRecordRef)CFArrayGetValueAtIndex(results, 0);
+ CFRetain(record);
+ }
+
+ CFRelease(results);
+ }
+
+ CFRelease(query);
+ }
+
+ CFRelease(uuidref);
+ }
+
+ return record;
+}
+
+ODRecordRef
+CopyGroupRecordWithGID(ODNodeRef node, gid_t gid)
+{
+ uuid_t uuid;
+
+ mbr_gid_to_uuid(gid, uuid);
+
+ return CopyRecordWithUUID(node, CFSTR(kDSStdRecordTypeGroups), uuid);
+}
+
+ODRecordRef
+CopyUserRecordWithUID(ODNodeRef node, uid_t uid)
+{
+ uuid_t uuid;
+
+ mbr_uid_to_uuid(uid, uuid);
+
+ return CopyRecordWithUUID(node, CFSTR(kDSStdRecordTypeUsers), uuid);
+}
+
+ODRecordRef
+CopyUserRecordWithUsername(ODNodeRef node, char *name)
+{
+ CFStringRef nameref;
+ CFTypeRef vals[] = { CFSTR(kDSAttributesStandardAll) };
+ CFArrayRef attributes = CFArrayCreate(NULL, vals, 1, &kCFTypeArrayCallBacks);
+ CFErrorRef error;
+
+ nameref = CFStringCreateWithCString(NULL, name, kCFStringEncodingUTF8);
+
+ if (nameref == NULL)
+ return NULL;
+
+ return ODNodeCopyRecord(node, CFSTR(kDSStdRecordTypeUsers), nameref, attributes, &error);
+}
+
+CFStringRef
+CopyAttrFromRecord(ODRecordRef record, CFStringRef attribute)
+{
+ CFErrorRef error = NULL;
+ CFArrayRef values = ODRecordCopyValues(record, attribute, &error);
+ CFStringRef result = NULL;
+
+ if (values) {
+ if (CFArrayGetCount(values) == 1) {
+ result = CFArrayGetValueAtIndex(values, 0);
+ CFRetain(result);
+ }
+ CFRelease(values);
+ }
+
+ return result;
+}
+
+int
+GetIntAttrFromRecord(ODRecordRef record, CFStringRef attribute, int *output)
+{
+ int status = 1;
+ CFStringRef str = CopyAttrFromRecord(record, attribute);
+
+ if (str) {
+ *output = CFStringGetIntValue(str);
+ status = 0;
+ CFRelease(str);
+ }
+
+ return status;
+}
+
+uid_t
+GetUIDFromRecord(ODRecordRef record)
+{
+ int uid = -1;
+
+ GetIntAttrFromRecord(record, CFSTR(kDS1AttrUniqueID), &uid);
+
+ return uid;
+}
+
+gid_t
+GetGIDFromRecord(ODRecordRef record)
+{
+ int gid = -1;
+
+ GetIntAttrFromRecord(record, CFSTR(kDS1AttrPrimaryGroupID), &gid);
+
+ return gid;
+}
+
+CFArrayRef
+CopyGroupRecordsForUser(ODNodeRef node, ODRecordRef user, CFIndex limit)
+{
+ CFMutableArrayRef groups;
+ gid_t primary_gid;
+ ODRecordRef primary_group;
+ CFErrorRef error = NULL;
+ ODQueryRef query;
+ CFArrayRef results;
+ int i;
+ ODRecordRef gr;
+
+ query = ODQueryCreateWithNode(NULL, node, CFSTR(kDSStdRecordTypeGroups),
+ CFSTR(kDSNAttrMember), kODMatchContains, ODRecordGetRecordName(user), NULL, limit, &error);
+ results = ODQueryCopyResults(query, false, &error);
+ CFRelease(query);
+
+ groups = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+
+ primary_gid = GetGIDFromRecord(user);
+ primary_group = CopyGroupRecordWithGID(node, primary_gid);
+ CFArrayAppendValue(groups, primary_group);
+ CFRelease(primary_group);
+
+ for (i = 0; i < CFArrayGetCount(results); i++) {
+ gr = (ODRecordRef)CFArrayGetValueAtIndex(results, i);
+ if (GetGIDFromRecord(gr) != primary_gid) {
+ CFArrayAppendValue(groups, gr);
+ }
+ }
+
+ CFRelease(results);
+
+ return groups;
+}
+
+static int
+cvfprintf(FILE *file, const char *format, va_list args)
+{
+ char* cstr;
+ int result = 0;
+ CFStringRef formatStr = CFStringCreateWithCStringNoCopy(NULL, format, kCFStringEncodingUTF8, kCFAllocatorNull);
+ if (formatStr) {
+ CFStringRef str = CFStringCreateWithFormatAndArguments(NULL, NULL, formatStr, args);
+ if (str) {
+ size_t size = CFStringGetMaximumSizeForEncoding(CFStringGetLength(str), kCFStringEncodingUTF8) + 1;
+ cstr = malloc(size);
+ if (cstr && CFStringGetCString(str, cstr, size, kCFStringEncodingUTF8)) {
+ result = fprintf(file, "%s", cstr);
+ free(cstr);
+ }
+ CFRelease(str);
+ }
+ CFRelease(formatStr);
+ }
+ return result;
+}
+
+int
+cfprintf(FILE *file, const char *format, ...)
+{
+ int result;
+ va_list args;
+
+ va_start(args, format);
+ result = cvfprintf(file, format, args);
+ va_end(args);
+ return result;
+}
+
+int
+cprintf(const char *format, ...)
+{
+ int result;
+ va_list args;
+
+ va_start(args, format);
+ result = cvfprintf(stdout, format, args);
+ va_end(args);
+ return result;
+}
diff --git a/shell_cmds/id/open_directory.h b/shell_cmds/id/open_directory.h
new file mode 100644
index 0000000..2c79775
--- /dev/null
+++ b/shell_cmds/id/open_directory.h
@@ -0,0 +1,18 @@
+#include <OpenDirectory/OpenDirectory.h>
+
+ODNodeRef CreateNode(void);
+
+ODRecordRef CopyGroupRecordWithGID(ODNodeRef, gid_t);
+
+ODRecordRef CopyUserRecordWithUID(ODNodeRef, uid_t);
+ODRecordRef CopyUserRecordWithUsername(ODNodeRef, char *);
+
+CFArrayRef CopyGroupRecordsForUser(ODNodeRef, ODRecordRef, CFIndex);
+
+CFStringRef CopyAttrFromRecord(ODRecordRef record, CFStringRef attribute);
+int GetIntAttrFromRecord(ODRecordRef record, CFStringRef attribute, int *output);
+uid_t GetUIDFromRecord(ODRecordRef);
+gid_t GetGIDFromRecord(ODRecordRef);
+
+int cfprintf(FILE *file, const char *format, ...);
+int cprintf(const char *format, ...);
diff --git a/shell_cmds/id/whoami.1 b/shell_cmds/id/whoami.1
new file mode 100644
index 0000000..568fbaf
--- /dev/null
+++ b/shell_cmds/id/whoami.1
@@ -0,0 +1,60 @@
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)whoami.1 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD: src/usr.bin/id/whoami.1,v 1.9 2005/01/17 07:44:19 ru Exp $
+.\"
+.Dd June 6, 1993
+.Dt WHOAMI 1
+.Os
+.Sh NAME
+.Nm whoami
+.Nd display effective user id
+.Sh SYNOPSIS
+.Nm
+.Sh DESCRIPTION
+The
+.Nm
+utility has been obsoleted by the
+.Xr id 1
+utility, and is equivalent to
+.Dq Nm id Fl un .
+The command
+.Dq Nm id Fl p
+is suggested for normal interactive use.
+.Pp
+The
+.Nm
+utility displays your effective user ID as a name.
+.Sh EXIT STATUS
+.Ex -std
+.Sh SEE ALSO
+.Xr id 1
diff --git a/shell_cmds/jot/jot.1 b/shell_cmds/jot/jot.1
new file mode 100644
index 0000000..b94fab4
--- /dev/null
+++ b/shell_cmds/jot/jot.1
@@ -0,0 +1,251 @@
+.\" Copyright (c) 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)jot.1 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD: src/usr.bin/jot/jot.1,v 1.24 2010/02/20 00:16:44 delphij Exp $
+.\"
+.Dd February 19, 2010
+.Dt JOT 1
+.Os
+.Sh NAME
+.Nm jot
+.Nd print sequential or random data
+.Sh SYNOPSIS
+.Nm
+.Op Fl cnr
+.Op Fl b Ar word
+.Op Fl w Ar word
+.Op Fl s Ar string
+.Op Fl p Ar precision
+.Op Ar reps Op Ar begin Op Ar end Op Ar s
+.Sh DESCRIPTION
+The
+.Nm
+utility is used to print out increasing, decreasing, random,
+or redundant data, usually numbers, one per line.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl r
+Generate random data instead of the default sequential data.
+.It Fl b Ar word
+Just print
+.Ar word
+repetitively.
+.It Fl w Ar word
+Print
+.Ar word
+with the generated data appended to it.
+Octal, hexadecimal, exponential,
+.Tn ASCII ,
+zero padded,
+and right-adjusted representations
+are possible by using the appropriate
+.Xr printf 3
+conversion specification inside
+.Ar word ,
+in which case the data are inserted rather than appended.
+.It Fl c
+This is an abbreviation for
+.Fl w Ar %c .
+.It Fl s Ar string
+Print data separated by
+.Ar string .
+Normally, newlines separate data.
+.It Fl n
+Do not print the final newline normally appended to the output.
+.It Fl p Ar precision
+Print only as many digits or characters of the data
+as indicated by the integer
+.Ar precision .
+In the absence of
+.Fl p ,
+the precision is the greater of the precisions of
+.Ar begin
+and
+.Ar end .
+The
+.Fl p
+option is overridden by whatever appears in a
+.Xr printf 3
+conversion following
+.Fl w .
+.El
+.Pp
+The last four arguments indicate, respectively,
+the number of data, the lower bound, the upper bound,
+and the step size or, for random data, the seed.
+While at least one of them must appear,
+any of the other three may be omitted, and
+will be considered as such if given as
+.Fl ""
+or as an empty string.
+Any three of these arguments determines the fourth.
+If four are specified and the given and computed values of
+.Ar reps
+conflict, the lower value is used.
+If fewer than three are specified, defaults are assigned
+left to right, except for
+.Ar s ,
+which assumes a default of 1 or -1 if both
+.Ar begin
+and
+.Ar end
+are given.
+.Pp
+Defaults for the four arguments are, respectively,
+100, 1, 100, and 1, except that when random data are requested,
+the seed,
+.Ar s ,
+is picked randomly.
+The
+.Ar reps
+argument is expected to be an unsigned integer,
+and if given as zero is taken to be infinite.
+The
+.Ar begin
+and
+.Ar end
+arguments may be given as real numbers or as characters
+representing the corresponding value in
+.Tn ASCII .
+The last argument must be a real number.
+.Pp
+Random numbers are obtained through
+.Xr arc4random 3
+when no seed is specified,
+and through
+.Xr random 3
+when a seed is given.
+When
+.Nm
+is asked to generate random integers or characters with begin
+and end values in the range of the random number generator function
+and no format is specified with one of the
+.Fl w ,
+.Fl b ,
+or
+.Fl p
+options,
+.Nm
+will arrange for all the values in the range to appear in the output
+with an equal probability.
+In all other cases be careful to ensure that the output format's
+rounding or truncation will not skew the distribution of output
+values in an unintended way.
+.Pp
+The name
+.Nm
+derives in part from
+.Nm iota ,
+a function in APL.
+.Sh EXIT STATUS
+.Ex -std
+.Sh EXAMPLES
+The command
+.Dl jot - 1 10
+.Pp
+prints the integers from 1 to 10,
+while the command
+.Dl jot 21 -1 1.00
+.Pp
+prints 21 evenly spaced numbers increasing from -1 to 1.
+The
+.Tn ASCII
+character set is generated with
+.Dl jot -c 128 0
+.Pp
+and the strings xaa through xaz with
+.Dl jot -w xa%c 26 a
+.Pp
+while 20 random 8-letter strings are produced with
+.Dl "jot -r -c 160 a z | rs -g 0 8"
+.Pp
+Infinitely many
+.Em yes Ns 's
+may be obtained through
+.Dl jot -b yes 0
+.Pp
+and thirty
+.Xr ed 1
+substitution commands applying to lines 2, 7, 12, etc.\& is
+the result of
+.Dl jot -w %ds/old/new/ 30 2 - 5
+.Pp
+The stuttering sequence 9, 9, 8, 8, 7, etc.\& can be
+produced by suitable choice of step size,
+as in
+.Dl jot - 9 0 -.5
+.Pp
+and a file containing exactly 1024 bytes is created with
+.Dl jot -b x 512 > block
+.Pp
+Finally, to set tabs four spaces apart starting
+from column 10 and ending in column 132, use
+.Dl expand -`jot -s, - 10 132 4`
+.Pp
+and to print all lines 80 characters or longer,
+.Dl grep `jot -s \&"\&" -b \&. 80`
+.Sh DIAGNOSTICS
+The following diagnostic messages deserve special explanation:
+.Bl -diag
+.It "illegal or unsupported format '%s'"
+The requested conversion format specifier for
+.Xr printf 3
+was not of the form
+.Dl %[#][ ][{+,-}][0-9]*[.[0-9]*]?
+where
+.Dq ?\&
+must be one of
+.Dl [l]{d,i,o,u,x}
+or
+.Dl {c,e,f,g,D,E,G,O,U,X}
+.It "range error in conversion"
+A value to be printed fell outside the range of the data type
+associated with the requested output format.
+.It "too many conversions"
+More than one conversion format specifier has been supplied,
+but only one is allowed.
+.El
+.Sh SEE ALSO
+.Xr ed 1 ,
+.Xr expand 1 ,
+.Xr rs 1 ,
+.Xr seq 1 ,
+.Xr yes 1 ,
+.Xr arc4random 3 ,
+.Xr printf 3 ,
+.Xr random 3
+.Sh HISTORY
+The
+.Nm
+utility first appeared in
+.Bx 4.2 .
diff --git a/shell_cmds/jot/jot.c b/shell_cmds/jot/jot.c
new file mode 100644
index 0000000..1438755
--- /dev/null
+++ b/shell_cmds/jot/jot.c
@@ -0,0 +1,490 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)jot.c 8.1 (Berkeley) 6/6/93";
+#endif
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/jot/jot.c,v 1.40 2009/12/13 03:14:06 delphij Exp $");
+
+/*
+ * jot - print sequential or random data
+ *
+ * Author: John Kunze, Office of Comp. Affairs, UCB
+ */
+
+#include <ctype.h>
+#include <err.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+/* Defaults */
+#define REPS_DEF 100
+#define BEGIN_DEF 1
+#define ENDER_DEF 100
+#define STEP_DEF 1
+
+/* Flags of options that have been set */
+#define HAVE_STEP 1
+#define HAVE_ENDER 2
+#define HAVE_BEGIN 4
+#define HAVE_REPS 8
+
+#define is_default(s) (*(s) == 0 || strcmp((s), "-") == 0)
+
+static bool boring;
+static int prec;
+static bool longdata;
+static bool intdata;
+static bool chardata;
+static bool nosign;
+static const char *sepstring = "\n";
+static char format[BUFSIZ];
+
+static void getformat(void);
+static int getprec(const char *);
+static int putdata(double, bool);
+static void usage(void);
+
+int
+main(int argc, char **argv)
+{
+ bool have_format = false;
+ bool infinity = false;
+ bool nofinalnl = false;
+ bool randomize = false;
+ bool use_random = false;
+ int ch;
+ int mask = 0;
+ int n = 0;
+ double begin = BEGIN_DEF;
+ double divisor;
+ double ender = ENDER_DEF;
+ double s = STEP_DEF;
+ double x, y;
+ long i;
+ long reps = REPS_DEF;
+
+ while ((ch = getopt(argc, argv, "b:cnp:rs:w:")) != -1)
+ switch (ch) {
+ case 'b':
+ boring = true;
+ /* FALLTHROUGH */
+ case 'w':
+ if (strlcpy(format, optarg, sizeof(format)) >=
+ sizeof(format))
+ errx(1, "-%c word too long", ch);
+ have_format = true;
+ break;
+ case 'c':
+ chardata = true;
+ break;
+ case 'n':
+ nofinalnl = true;
+ break;
+ case 'p':
+ prec = atoi(optarg);
+ if (prec <= 0)
+ errx(1, "bad precision value");
+ have_format = true;
+ break;
+ case 'r':
+ randomize = true;
+ break;
+ case 's':
+ sepstring = optarg;
+ break;
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ switch (argc) { /* examine args right to left, falling thru cases */
+ case 4:
+ if (!is_default(argv[3])) {
+ if (!sscanf(argv[3], "%lf", &s))
+ errx(1, "bad s value: %s", argv[3]);
+ mask |= HAVE_STEP;
+ if (randomize)
+ use_random = true;
+ }
+ /* FALLTHROUGH */
+ case 3:
+ if (!is_default(argv[2])) {
+ if (!sscanf(argv[2], "%lf", &ender))
+ ender = argv[2][strlen(argv[2])-1];
+ mask |= HAVE_ENDER;
+ if (!prec)
+ n = getprec(argv[2]);
+ }
+ /* FALLTHROUGH */
+ case 2:
+ if (!is_default(argv[1])) {
+ if (!sscanf(argv[1], "%lf", &begin))
+ begin = argv[1][strlen(argv[1])-1];
+ mask |= HAVE_BEGIN;
+ if (!prec)
+ prec = getprec(argv[1]);
+ if (n > prec) /* maximum precision */
+ prec = n;
+ }
+ /* FALLTHROUGH */
+ case 1:
+ if (!is_default(argv[0])) {
+ if (!sscanf(argv[0], "%ld", &reps))
+ errx(1, "bad reps value: %s", argv[0]);
+ mask |= HAVE_REPS;
+ }
+ break;
+ case 0:
+ usage();
+ default:
+ errx(1, "too many arguments. What do you mean by %s?",
+ argv[4]);
+ }
+ getformat();
+ while (mask) /* 4 bit mask has 1's where last 4 args were given */
+ switch (mask) { /* fill in the 0's by default or computation */
+ case HAVE_STEP:
+ case HAVE_ENDER:
+ case HAVE_ENDER | HAVE_STEP:
+ case HAVE_BEGIN:
+ case HAVE_BEGIN | HAVE_STEP:
+ reps = REPS_DEF;
+ mask |= HAVE_REPS;
+ break;
+ case HAVE_BEGIN | HAVE_ENDER:
+ s = ender > begin ? 1 : -1;
+ mask |= HAVE_STEP;
+ break;
+ case HAVE_BEGIN | HAVE_ENDER | HAVE_STEP:
+ if (randomize)
+ reps = REPS_DEF;
+ else if (s == 0.0)
+ reps = 0;
+ else
+ reps = (ender - begin + s) / s;
+ if (reps <= 0)
+ errx(1, "impossible stepsize");
+ mask = 0;
+ break;
+ case HAVE_REPS:
+ case HAVE_REPS | HAVE_STEP:
+ begin = BEGIN_DEF;
+ mask |= HAVE_BEGIN;
+ break;
+ case HAVE_REPS | HAVE_ENDER:
+ s = STEP_DEF;
+ mask = HAVE_REPS | HAVE_ENDER | HAVE_STEP;
+ break;
+ case HAVE_REPS | HAVE_ENDER | HAVE_STEP:
+ if (randomize)
+ begin = BEGIN_DEF;
+ else if (reps == 0)
+ errx(1, "must specify begin if reps == 0");
+ begin = ender - reps * s + s;
+ mask = 0;
+ break;
+ case HAVE_REPS | HAVE_BEGIN:
+ s = STEP_DEF;
+ mask = HAVE_REPS | HAVE_BEGIN | HAVE_STEP;
+ break;
+ case HAVE_REPS | HAVE_BEGIN | HAVE_STEP:
+ if (randomize)
+ ender = ENDER_DEF;
+ else
+ ender = begin + reps * s - s;
+ mask = 0;
+ break;
+ case HAVE_REPS | HAVE_BEGIN | HAVE_ENDER:
+ if (reps == 0)
+ errx(1, "infinite sequences cannot be bounded");
+ else if (reps == 1)
+ s = 0.0;
+ else
+ s = (ender - begin) / (reps - 1);
+ mask = 0;
+ break;
+ case HAVE_REPS | HAVE_BEGIN | HAVE_ENDER | HAVE_STEP:
+ /* if reps given and implied, */
+ if (!randomize && s != 0.0) {
+ long t = (ender - begin + s) / s;
+ if (t <= 0)
+ errx(1, "impossible stepsize");
+ if (t < reps) /* take lesser */
+ reps = t;
+ }
+ mask = 0;
+ break;
+ default:
+ errx(1, "bad mask");
+ }
+ if (reps == 0)
+ infinity = true;
+ if (randomize) {
+ if (use_random) {
+ srandom((unsigned long)s);
+ divisor = (double)INT32_MAX + 1;
+ } else
+ divisor = (double)UINT32_MAX + 1;
+
+ /*
+ * Attempt to DWIM when the user has specified an
+ * integer range within that of the random number
+ * generator: distribute the numbers equally in
+ * the range [begin .. ender]. Jot's default %.0f
+ * format would make the appearance of the first and
+ * last specified value half as likely as the rest.
+ */
+ if (!have_format && prec == 0 &&
+ begin >= 0 && begin < divisor &&
+ ender >= 0 && ender < divisor) {
+ ender += 1;
+ nosign = true;
+ intdata = true;
+ (void)strlcpy(format,
+ chardata ? "%c" : "%u", sizeof(format));
+ }
+ x = (ender - begin) * (ender > begin ? 1 : -1);
+ for (i = 1; i <= reps || infinity; i++) {
+ if (use_random)
+ y = random() / divisor;
+ else
+ y = arc4random() / divisor;
+ if (putdata(y * x + begin, !(reps - i)))
+ errx(1, "range error in conversion");
+ }
+ } else
+ for (i = 1, x = begin; i <= reps || infinity; i++, x += s)
+ if (putdata(x, !(reps - i)))
+ errx(1, "range error in conversion");
+ if (!nofinalnl)
+ putchar('\n');
+ exit(0);
+}
+
+/*
+ * Send x to stdout using the specified format.
+ * Last is true if this is the set's last value.
+ * Return 0 if OK, or a positive number if the number passed was
+ * outside the range specified by the various flags.
+ */
+static int
+putdata(double x, bool last)
+{
+
+ if (boring)
+ printf("%s", format);
+ else if (longdata && nosign) {
+ if (x <= (double)ULONG_MAX && x >= (double)0)
+ printf(format, (unsigned long)x);
+ else
+ return (1);
+ } else if (longdata) {
+ if (x <= (double)LONG_MAX && x >= (double)LONG_MIN)
+ printf(format, (long)x);
+ else
+ return (1);
+ } else if (chardata || (intdata && !nosign)) {
+ if (x <= (double)INT_MAX && x >= (double)INT_MIN)
+ printf(format, (int)x);
+ else
+ return (1);
+ } else if (intdata) {
+ if (x <= (double)UINT_MAX && x >= (double)0)
+ printf(format, (unsigned int)x);
+ else
+ return (1);
+
+ } else
+ printf(format, x);
+ if (!last)
+ fputs(sepstring, stdout);
+
+ return (0);
+}
+
+static void
+usage(void)
+{
+ fprintf(stderr, "%s\n%s\n",
+ "usage: jot [-cnr] [-b word] [-w word] [-s string] [-p precision]",
+ " [reps [begin [end [s]]]]");
+ exit(1);
+}
+
+/*
+ * Return the number of digits following the number's decimal point.
+ * Return 0 if no decimal point is found.
+ */
+static int
+getprec(const char *str)
+{
+ const char *p;
+ const char *q;
+
+ for (p = str; *p; p++)
+ if (*p == '.')
+ break;
+ if (!*p)
+ return (0);
+ for (q = ++p; *p; p++)
+ if (!isdigit((unsigned char)*p))
+ break;
+ return (p - q);
+}
+
+/*
+ * Set format, intdata, chardata, longdata, and nosign
+ * based on the command line arguments.
+ */
+static void
+getformat(void)
+{
+ char *p, *p2;
+ int dot, hash, space, sign, numbers = 0;
+ size_t sz;
+
+ if (boring) /* no need to bother */
+ return;
+ for (p = format; *p; p++) /* look for '%' */
+ if (*p == '%') {
+ if (p[1] == '%')
+ p++; /* leave %% alone */
+ else
+ break;
+ }
+ sz = sizeof(format) - strlen(format) - 1;
+ if (!*p && !chardata) {
+ if (snprintf(p, sz, "%%.%df", prec) >= (int)sz)
+ errx(1, "-w word too long");
+ } else if (!*p && chardata) {
+ if (strlcpy(p, "%c", sz) >= sz)
+ errx(1, "-w word too long");
+ intdata = true;
+ } else if (!*(p+1)) {
+ if (sz <= 0)
+ errx(1, "-w word too long");
+ strcat(format, "%"); /* cannot end in single '%' */
+ } else {
+ /*
+ * Allow conversion format specifiers of the form
+ * %[#][ ][{+,-}][0-9]*[.[0-9]*]? where ? must be one of
+ * [l]{d,i,o,u,x} or {f,e,g,E,G,d,o,x,D,O,U,X,c,u}
+ */
+ p2 = p++;
+ dot = hash = space = sign = numbers = 0;
+ while (!isalpha((unsigned char)*p)) {
+ if (isdigit((unsigned char)*p)) {
+ numbers++;
+ p++;
+ } else if ((*p == '#' && !(numbers|dot|sign|space|
+ hash++)) ||
+ (*p == ' ' && !(numbers|dot|space++)) ||
+ ((*p == '+' || *p == '-') && !(numbers|dot|sign++))
+ || (*p == '.' && !(dot++)))
+ p++;
+ else
+ goto fmt_broken;
+ }
+ if (*p == 'l') {
+ longdata = true;
+ if (*++p == 'l') {
+ if (p[1] != '\0')
+ p++;
+ goto fmt_broken;
+ }
+ }
+ switch (*p) {
+ case 'o': case 'u': case 'x': case 'X':
+ intdata = nosign = true;
+ break;
+ case 'd': case 'i':
+ intdata = true;
+ break;
+ case 'D':
+ if (!longdata) {
+ intdata = true;
+ break;
+ }
+ case 'O': case 'U':
+ if (!longdata) {
+ intdata = nosign = true;
+ break;
+ }
+ case 'c':
+ if (!(intdata | longdata)) {
+ chardata = true;
+ break;
+ }
+ case 'h': case 'n': case 'p': case 'q': case 's': case 'L':
+ case '$': case '*':
+ goto fmt_broken;
+ case 'f': case 'e': case 'g': case 'E': case 'G':
+ if (!longdata)
+ break;
+ /* FALLTHROUGH */
+ default:
+fmt_broken:
+ *++p = '\0';
+ errx(1, "illegal or unsupported format '%s'", p2);
+ /* NOTREACHED */
+ }
+ while (*++p)
+ if (*p == '%' && *(p+1) && *(p+1) != '%')
+ errx(1, "too many conversions");
+ else if (*p == '%' && *(p+1) == '%')
+ p++;
+ else if (*p == '%' && !*(p+1)) {
+ if (strlcat(format, "%", sizeof(format)) >=
+ sizeof(format))
+ errx(1, "-w word too long");
+ break;
+ }
+ }
+}
diff --git a/shell_cmds/kill/kill.1 b/shell_cmds/kill/kill.1
new file mode 100644
index 0000000..07699e6
--- /dev/null
+++ b/shell_cmds/kill/kill.1
@@ -0,0 +1,152 @@
+.\"-
+.\" Copyright (c) 1980, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)kill.1 8.2 (Berkeley) 4/28/95
+.\" $FreeBSD$
+.\"
+.Dd April 28, 1995
+.Dt KILL 1
+.Os
+.Sh NAME
+.Nm kill
+.Nd terminate or signal a process
+.Sh SYNOPSIS
+.Nm
+.Op Fl s Ar signal_name
+.Ar pid ...
+.Nm
+.Fl l
+.Op Ar exit_status
+.Nm
+.Fl Ar signal_name
+.Ar pid ...
+.Nm
+.Fl Ar signal_number
+.Ar pid ...
+.Sh DESCRIPTION
+The
+.Nm
+utility sends a signal to the processes specified by the
+.Ar pid
+operands.
+.Pp
+Only the super-user may send signals to other users' processes.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl s Ar signal_name
+A symbolic signal name specifying the signal to be sent instead of the
+default
+.Dv TERM .
+.It Fl l Op Ar exit_status
+If no operand is given, list the signal names; otherwise, write
+the signal name corresponding to
+.Ar exit_status .
+.It Fl Ar signal_name
+A symbolic signal name specifying the signal to be sent instead of the
+default
+.Dv TERM .
+.It Fl Ar signal_number
+A non-negative decimal integer, specifying the signal to be sent instead
+of the default
+.Dv TERM .
+.El
+.Pp
+The following PIDs have special meanings:
+.Bl -tag -width indent
+.It -1
+If superuser, broadcast the signal to all processes; otherwise broadcast
+to all processes belonging to the user.
+.El
+.Pp
+Some of the more commonly used signals:
+.Pp
+.Bl -tag -width indent -compact
+.It 1
+HUP (hang up)
+.It 2
+INT (interrupt)
+.It 3
+QUIT (quit)
+.It 6
+ABRT (abort)
+.It 9
+KILL (non-catchable, non-ignorable kill)
+.It 14
+ALRM (alarm clock)
+.It 15
+TERM (software termination signal)
+.El
+.Pp
+Some shells may provide a builtin
+.Nm
+command which is similar or identical to this utility.
+Consult the
+.Xr builtin 1
+manual page.
+.Sh EXIT STATUS
+.Ex -std
+.Sh EXAMPLES
+Terminate
+the processes with PIDs 142 and 157:
+.Pp
+.Dl "kill 142 157"
+.Pp
+Send the hangup signal
+.Pq Dv SIGHUP
+to the process with PID 507:
+.Pp
+.Dl "kill -s HUP 507"
+.Sh SEE ALSO
+.Xr builtin 1 ,
+.Xr csh 1 ,
+.Xr killall 1 ,
+.Xr ps 1 ,
+.Xr sh 1 ,
+.Xr kill 2 ,
+.Xr sigaction 2
+.Sh STANDARDS
+The
+.Nm
+utility is expected to be
+.St -p1003.2
+compatible.
+.Sh HISTORY
+A
+.Nm
+command appeared in
+.At v3 .
+.Sh BUGS
+A replacement for the command
+.Dq Li kill 0
+for
+.Xr csh 1
+users should be provided.
diff --git a/shell_cmds/kill/kill.c b/shell_cmds/kill/kill.c
new file mode 100644
index 0000000..bd4d908
--- /dev/null
+++ b/shell_cmds/kill/kill.c
@@ -0,0 +1,230 @@
+/*-
+ * Copyright (c) 1988, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * Important: This file is used both as a standalone program /bin/kill and
+ * as a builtin for /bin/sh (#define SHELL).
+ */
+
+#if 0
+#ifndef lint
+static char const copyright[] =
+"@(#) Copyright (c) 1988, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)kill.c 8.4 (Berkeley) 4/28/95";
+#endif /* not lint */
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef SHELL
+#define main killcmd
+#include "bltin/bltin.h"
+#endif
+
+static void nosig(const char *);
+static void printsignals(FILE *);
+static int signame_to_signum(const char *);
+static void usage(void);
+static void print_signum(int, FILE *, char);
+
+#ifdef __APPLE__
+#define sys_nsig NSIG
+#endif /* __APPLE__ */
+
+int
+main(int argc, char *argv[])
+{
+ int errors, numsig, pid, ret;
+ char *ep;
+
+ if (argc < 2)
+ usage();
+
+ numsig = SIGTERM;
+
+ argc--, argv++;
+ if (!strcmp(*argv, "-l")) {
+ argc--, argv++;
+ if (argc > 1)
+ usage();
+ if (argc == 1) {
+ if (!isdigit(**argv))
+ usage();
+ numsig = strtol(*argv, &ep, 10);
+ if (!**argv || *ep)
+ errx(2, "illegal signal number: %s", *argv);
+ if (numsig >= 128)
+ numsig -= 128;
+ if (numsig <= 0 || numsig >= sys_nsig)
+ nosig(*argv);
+ print_signum(numsig, stdout, '\n');
+ return (0);
+ }
+ printsignals(stdout);
+ return (0);
+ }
+
+ if (!strcmp(*argv, "-s")) {
+ argc--, argv++;
+ if (argc < 1) {
+ warnx("option requires an argument -- s");
+ usage();
+ }
+ if (strcmp(*argv, "0")) {
+ if ((numsig = signame_to_signum(*argv)) < 0)
+ nosig(*argv);
+ } else
+ numsig = 0;
+ argc--, argv++;
+ } else if (**argv == '-' && *(*argv + 1) != '-') {
+ ++*argv;
+ if (isalpha(**argv)) {
+ if ((numsig = signame_to_signum(*argv)) < 0)
+ nosig(*argv);
+ } else if (isdigit(**argv)) {
+ numsig = strtol(*argv, &ep, 10);
+ if (!**argv || *ep)
+ errx(2, "illegal signal number: %s", *argv);
+ if (numsig < 0)
+ nosig(*argv);
+ } else
+ nosig(*argv);
+ argc--, argv++;
+ }
+
+ if (argc > 0 && strncmp(*argv, "--", 2) == 0)
+ argc--, argv++;
+
+ if (argc == 0)
+ usage();
+
+ for (errors = 0; argc; argc--, argv++) {
+#ifdef SHELL
+ if (**argv == '%')
+ ret = killjob(*argv, numsig);
+ else
+#endif
+ {
+ pid = strtol(*argv, &ep, 10);
+ if (!**argv || *ep)
+ errx(2, "illegal process id: %s", *argv);
+ ret = kill(pid, numsig);
+ }
+ if (ret == -1) {
+ warn("%s", *argv);
+ errors = 1;
+ }
+ }
+
+ return (errors);
+}
+
+static void
+print_signum(int numsig, FILE *fp, char separator)
+{
+ char *signame;
+ int i;
+
+ signame = strdup(sys_signame[numsig]);
+
+ for(i = 0; signame[i] != '\0'; i++) {
+ char upper = toupper(signame[i]);
+ signame[i] = upper;
+ }
+ fprintf(fp, "%s%c", signame, separator);
+
+ free(signame);
+}
+
+static int
+signame_to_signum(const char *sig)
+{
+ int n;
+
+ if (strncasecmp(sig, "SIG", 3) == 0)
+ sig += 3;
+ for (n = 1; n < sys_nsig; n++) {
+ if (!strcasecmp(sys_signame[n], sig))
+ return (n);
+ }
+ return (-1);
+}
+
+static void
+nosig(const char *name)
+{
+
+ warnx("unknown signal %s; valid signals:", name);
+ printsignals(stderr);
+#ifdef SHELL
+ error(NULL);
+#else
+ exit(2);
+#endif
+}
+
+static void
+printsignals(FILE *fp)
+{
+ int n;
+
+ for (n = 1; n < sys_nsig; n++) {
+ char sep = ' ';
+ if (n == (sys_nsig / 2) || n == (sys_nsig - 1))
+ sep = '\n';
+ print_signum(n, fp, sep);
+ }
+}
+
+static void
+usage(void)
+{
+
+ (void)fprintf(stderr, "%s\n%s\n%s\n%s\n",
+ "usage: kill [-s signal_name] pid ...",
+ " kill -l [exit_status]",
+ " kill -signal_name pid ...",
+ " kill -signal_number pid ...");
+#ifdef SHELL
+ error(NULL);
+#else
+ exit(2);
+#endif
+}
diff --git a/shell_cmds/kill/kill.plist.part b/shell_cmds/kill/kill.plist.part
new file mode 100644
index 0000000..f7fcb9e
--- /dev/null
+++ b/shell_cmds/kill/kill.plist.part
@@ -0,0 +1,18 @@
+ <dict>
+ <key>OpenSourceProject</key>
+ <string>kill</string>
+ <key>OpenSourceVersion</key>
+ <string>2015-03-01</string>
+ <key>OpenSourceWebsiteURL</key>
+ <string>http://svnweb.freebsd.org/base/head/bin/kill/</string>
+ <key>OpenSourceSCM</key>
+ <string>svn co http://svn.freebsd.org/base/head/bin/kill/</string>
+ <key>OpenSourceImportDate</key>
+ <string>2015-07-24</string>
+ <key>OpenSourceModifications</key>
+ <array>
+ <string>kill.c: sys_nsig</string>
+ </array>
+ <key>OpenSourceLicense</key>
+ <string>bsd</string>
+ </dict>
diff --git a/shell_cmds/killall/killall.1 b/shell_cmds/killall/killall.1
new file mode 100644
index 0000000..7c7b59d
--- /dev/null
+++ b/shell_cmds/killall/killall.1
@@ -0,0 +1,159 @@
+.\" Copyright (C) 1995 by Joerg Wunsch, Dresden
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS
+.\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+.\" DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT,
+.\" INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+.\" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+.\" SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+.\" STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+.\" IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/usr.bin/killall/killall.1,v 1.34 2005/01/17 07:44:20 ru Exp $
+.\"
+.Dd January 26, 2004
+.Os
+.Dt KILLALL 1
+.Sh NAME
+.Nm killall
+.Nd kill processes by name
+.Sh SYNOPSIS
+.Nm
+.Op Fl delmsvz
+.Op Fl help
+.Op Fl u Ar user
+.Op Fl t Ar tty
+.Op Fl c Ar procname
+.Op Fl SIGNAL
+.Op Ar procname ...
+.Sh DESCRIPTION
+The
+.Nm
+utility kills processes selected by name, as opposed to the selection by pid
+as done by
+.Xr kill 1 .
+By default, it will send a
+.Dv TERM
+signal to all processes with a real UID identical to the
+caller of
+.Nm
+that match the name
+.Ar procname .
+The super-user is allowed to kill any process.
+.Pp
+The options are as follows:
+.Bl -tag -width 10n -offset indent
+.It Fl v
+Be more verbose about what will be done.
+.It Fl e
+Use the effective user ID instead of the (default) real user ID for matching
+processes specified with the
+.Fl u
+option.
+.It Fl help
+Give a help on the command usage and exit.
+.It Fl l
+List the names of the available signals and exit, like in
+.Xr kill 1 .
+.It Fl m
+Match the argument
+.Ar procname
+as a (case sensitive) regular expression against the names
+of processes found.
+CAUTION!
+This is dangerous, a single dot will match any process
+running under the real UID of the caller.
+.It Fl s
+Show only what would be done, but do not send any signal.
+.It Fl d
+Print detailed information about the processes matched,
+but do not send any signal.
+.It Fl SIGNAL
+Send a different signal instead of the default
+.Dv TERM .
+The signal may be specified either as a name
+(with or without a leading
+.Dv SIG ) ,
+or numerically.
+.It Fl u Ar user
+Limit potentially matching processes to those belonging to
+the specified
+.Ar user .
+.It Fl t Ar tty
+Limit potentially matching processes to those running on
+the specified
+.Ar tty .
+.It Fl c Ar procname
+When used with the
+.Fl u
+or
+.Fl t
+flags, limit potentially matching processes to those matching
+the specified
+.Ar procname .
+.It Fl z
+Do not skip zombies.
+This should not have any effect except to print a few error messages
+if there are zombie processes that match the specified pattern.
+.El
+.Sh ALL PROCESSES
+Sending a signal to all processes with uid
+.Em XYZ
+is already supported by
+.Xr kill 1 .
+So use
+.Xr kill 1
+for this job (e.g.\& $ kill -TERM -1 or
+as root $ echo kill -TERM -1 | su -m <user>)
+.Sh EXIT STATUS
+The
+.Nm
+command will respond with a short usage message and exit with a status
+of 2 in case of a command error.
+A status of 1 will be returned if
+either no matching process has been found or not all processes have
+been signalled successfully.
+Otherwise, a status of 0 will be
+returned.
+.Sh DIAGNOSTICS
+Diagnostic messages will only be printed if requested by
+.Fl d
+options.
+.Sh SEE ALSO
+.Xr kill 1 ,
+.Xr sysctl 3
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Fx 2.1 .
+It has been modeled after the
+.Nm
+command as available on other platforms.
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm
+program was originally written in Perl and was contributed by
+.An Wolfram Schneider ,
+this manual page has been written by
+.An J\(:org Wunsch .
+The current version of
+.Nm
+was rewritten in C by
+.An Peter Wemm
+using
+.Xr sysctl 3 .
diff --git a/shell_cmds/killall/killall.c b/shell_cmds/killall/killall.c
new file mode 100644
index 0000000..4ef96a9
--- /dev/null
+++ b/shell_cmds/killall/killall.c
@@ -0,0 +1,549 @@
+/*-
+ * Copyright (c) 2000 Peter Wemm <peter@FreeBSD.org>
+ * Copyright (c) 2000 Paul Saab <ps@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/killall/killall.c,v 1.31 2004/07/29 18:36:35 maxim Exp $");
+
+#include <sys/param.h>
+#ifndef __APPLE__
+#include <sys/jail.h>
+#endif /* !__APPLE__ */
+#include <sys/stat.h>
+#include <sys/user.h>
+#include <sys/sysctl.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pwd.h>
+#include <signal.h>
+#include <regex.h>
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <unistd.h>
+#include <locale.h>
+
+#include <getopt.h>
+#define OPTIONS ("c:dej:lmst:u:vz")
+
+#ifdef __APPLE__
+#include <TargetConditionals.h>
+#endif
+
+static void __dead2
+usage(void)
+{
+
+#ifdef __APPLE__
+ fprintf(stderr, "usage: killall [-delmsvz] [-help]\n");
+#else /* !__APPLE__ */
+ fprintf(stderr, "usage: killall [-delmsvz] [-help] [-j jid]\n");
+#endif /* __APPLE__ */
+ fprintf(stderr,
+ " [-u user] [-t tty] [-c cmd] [-SIGNAL] [cmd]...\n");
+ fprintf(stderr, "At least one option or argument to specify processes must be given.\n");
+ exit(1);
+}
+
+static char *
+upper(const char *str)
+{
+ static char buf[80];
+ char *s;
+
+ strncpy(buf, str, sizeof(buf));
+ buf[sizeof(buf) - 1] = '\0';
+ for (s = buf; *s; s++)
+ *s = toupper((unsigned char)*s);
+ return buf;
+}
+
+
+static void
+printsig(FILE *fp)
+{
+ const char *const * p;
+ int cnt;
+ int offset = 0;
+
+ for (cnt = NSIG, p = sys_signame + 1; --cnt; ++p) {
+ offset += fprintf(fp, "%s ", upper(*p));
+ if (offset >= 75 && cnt > 1) {
+ offset = 0;
+ fprintf(fp, "\n");
+ }
+ }
+ fprintf(fp, "\n");
+}
+
+static void
+nosig(char *name)
+{
+
+ warnx("unknown signal %s; valid signals:", name);
+ printsig(stderr);
+ exit(1);
+}
+
+/*
+ * kludge_signal_args - remove any signal option (-SIGXXX, -##) from the argv array.
+ */
+void
+kludge_signal_args(int *argc, char **argv, int *sig)
+{
+ int i;
+ int shift = 0;
+ int kludge = 1;
+ char *ptr;
+ const char *const *p;
+ char *ep;
+
+ /* i = 1, skip program name */
+ for (i = 1; i < *argc; i++) {
+ /* Stop kludging if we encounter -- */
+ if (strcmp(argv[i], "--") == 0)
+ kludge = 0;
+ ptr = argv[i] + 1;
+ /* Only process arguments that start with - and do not look like an existing option. */
+ if (kludge && *argv[i] == '-' && *ptr && strchr(OPTIONS, *ptr) == NULL) {
+ if (isalpha(*ptr)) {
+ if (strcmp(ptr, "help") == 0)
+ usage();
+ if (strncasecmp(ptr, "sig", 3) == 0)
+ ptr += 3;
+ for (*sig = NSIG, p = sys_signame + 1; --*sig; ++p)
+ if (strcasecmp(*p, ptr) == 0) {
+ *sig = p - sys_signame;
+ break;
+ }
+ if (!*sig)
+ nosig(ptr);
+ } else if (isdigit(*ptr)) {
+ *sig = strtol(ptr, &ep, 10);
+ if (*ep)
+ errx(1, "illegal signal number: %s", ptr);
+ if (*sig < 0 || *sig >= NSIG)
+ nosig(ptr);
+ } else
+ nosig(ptr);
+
+ shift++;
+ continue;
+ }
+
+ argv[i - shift] = argv[i];
+ }
+
+ for (i = *argc - shift; i < *argc; i++) {
+ argv[i] = NULL;
+ }
+
+ *argc -= shift;
+}
+
+int
+main(int ac, char **av)
+{
+ struct kinfo_proc *procs = NULL, *newprocs;
+ struct stat sb;
+ struct passwd *pw;
+ regex_t rgx;
+ regmatch_t pmatch;
+ int i, j;
+ char buf[256];
+ char *user = NULL;
+ char *tty = NULL;
+ char *cmd = NULL;
+ int vflag = 0;
+ int sflag = 0;
+ int dflag = 0;
+ int eflag = 0;
+#ifndef __APPLE__
+ int jflag = 0;
+#endif /* !__APPLE__*/
+ int mflag = 0;
+ int zflag = 0;
+ uid_t uid = 0;
+ dev_t tdev = 0;
+ pid_t mypid;
+#ifdef __APPLE__
+ char *thiscmd;
+#else /* !__APPLE__ */
+ char thiscmd[MAXCOMLEN + 1];
+#endif /* __APPLE__ */
+ pid_t thispid;
+#ifndef __APPLE__
+ uid_t thisuid;
+#endif /* !__APPLE__ */
+ dev_t thistdev;
+ int sig = SIGTERM;
+ char *ep;
+ int errors = 0;
+#ifndef __APPLE__
+ int jid;
+#endif /* !__APPLE__ */
+ int mib[4];
+ size_t miblen;
+ int st, nprocs;
+ size_t size;
+ int matched;
+ int killed = 0;
+ int ch;
+
+ setlocale(LC_ALL, "");
+
+ kludge_signal_args(&ac, av, &sig);
+
+ while ((ch = getopt(ac, av, OPTIONS)) != -1) {
+ switch (ch) {
+ case 'c':
+ cmd = optarg;
+ break;
+ case 'd':
+ dflag++;
+ break;
+ case 'e':
+ eflag++;
+ break;
+#ifndef __APPLE__
+ case 'j':
+ jflag++;
+ jid = strtol(optarg, &ep, 10);
+ if (*ep)
+ errx(1, "illegal jid: %s", optarg);
+ if (jail_attach(jid) == -1)
+ err(1, "jail_attach(): %d", jid);
+ break;
+#endif /* __APPLE__ */
+ case 'l':
+ printsig(stdout);
+ exit(0);
+ case 'm':
+ mflag++;
+ break;
+ case 's':
+ sflag++;
+ break;
+ case 't':
+ tty = optarg;
+ break;
+ case 'u':
+ user = optarg;
+ break;
+ case 'v':
+ vflag++;
+ break;
+ case 'z':
+ zflag++;
+ break;
+ default:
+ usage();
+ }
+ }
+
+ ac -= optind;
+ av += optind;
+
+#ifdef __APPLE__
+ if (user == NULL && tty == NULL && cmd == NULL && ac == 0)
+#else /* !__APPLE__*/
+ if (user == NULL && tty == NULL && cmd == NULL && !jflag && ac == 0)
+#endif /* __APPLE__ */
+ usage();
+
+ if (tty) {
+ if (strncmp(tty, "/dev/", 5) == 0)
+ snprintf(buf, sizeof(buf), "%s", tty);
+ else if (strncmp(tty, "tty", 3) == 0)
+ snprintf(buf, sizeof(buf), "/dev/%s", tty);
+ else
+ snprintf(buf, sizeof(buf), "/dev/tty%s", tty);
+ if (stat(buf, &sb) < 0)
+ err(1, "stat(%s)", buf);
+ if (!S_ISCHR(sb.st_mode))
+ errx(1, "%s: not a character device", buf);
+ tdev = sb.st_rdev;
+ if (dflag)
+ printf("ttydev:0x%x\n", tdev);
+ }
+ if (user) {
+ uid = strtol(user, &ep, 10);
+ if (*user == '\0' || *ep != '\0') { /* was it a number? */
+ pw = getpwnam(user);
+ if (pw == NULL)
+ errx(1, "user %s does not exist", user);
+ uid = pw->pw_uid;
+ if (dflag)
+ printf("uid:%d\n", uid);
+ }
+ } else {
+ uid = getuid();
+ if (uid != 0) {
+ pw = getpwuid(uid);
+ if (pw)
+ user = pw->pw_name;
+ if (dflag)
+ printf("uid:%d\n", uid);
+ }
+ }
+ size = 0;
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+#ifdef __APPLE__
+ mib[2] = KERN_PROC_ALL;
+#else /* !__APPLE__ */
+ mib[2] = KERN_PROC_PROC;
+#endif /* __APPLE__ */
+ mib[3] = 0;
+ miblen = 3;
+
+ if (user) {
+ mib[2] = eflag ? KERN_PROC_UID : KERN_PROC_RUID;
+ mib[3] = uid;
+ miblen = 4;
+ } else if (tty) {
+ mib[2] = KERN_PROC_TTY;
+ mib[3] = tdev;
+ miblen = 4;
+ }
+
+ do {
+ st = sysctl(mib, miblen, NULL, &size, NULL, 0);
+ if (st == -1)
+ err(1, "could not sysctl(KERN_PROC)");
+ if (!size)
+ errx(1, "could not get size from sysctl(KERN_PROC)");
+ size += size / 10;
+ newprocs = realloc(procs, size);
+ if (newprocs == 0) {
+ if (procs)
+ free(procs);
+ errx(1, "could not reallocate memory");
+ }
+ procs = newprocs;
+ st = sysctl(mib, miblen, procs, &size, NULL, 0);
+ } while (st == -1 && errno == ENOMEM);
+ if (st == -1)
+ err(1, "could not sysctl(KERN_PROC)");
+ if (size % sizeof(struct kinfo_proc) != 0) {
+ fprintf(stderr, "proc size mismatch (%zu total, %zu chunks)\n",
+ size, sizeof(struct kinfo_proc));
+ fprintf(stderr, "userland out of sync with kernel, recompile libkvm etc\n");
+ exit(1);
+ }
+ nprocs = size / sizeof(struct kinfo_proc);
+ if (dflag)
+ printf("nprocs %d\n", nprocs);
+ mypid = getpid();
+
+ for (i = 0; i < nprocs; i++) {
+#ifdef __APPLE__
+ if (procs[i].kp_proc.p_stat == SZOMB && !zflag)
+ continue;
+ thispid = procs[i].kp_proc.p_pid;
+
+ int mib[3], argmax;
+ size_t syssize;
+ char *procargs, *cp;
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_ARGMAX;
+
+ syssize = sizeof(argmax);
+ if (sysctl(mib, 2, &argmax, &syssize, NULL, 0) == -1)
+ continue;
+
+ procargs = malloc(argmax);
+ if (procargs == NULL)
+ continue;
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROCARGS2;
+ mib[2] = thispid;
+
+ syssize = (size_t)argmax;
+ if (sysctl(mib, 3, procargs, &syssize, NULL, 0) == -1) {
+ free(procargs);
+ continue;
+ }
+
+ for (cp = procargs; cp < &procargs[syssize]; cp++) {
+ if (*cp == '\0') {
+ break;
+ }
+ }
+
+ if (cp == &procargs[syssize]) {
+ free(procargs);
+ continue;
+ }
+
+ for (; cp < &procargs[syssize]; cp++) {
+ if (*cp != '\0') {
+ break;
+ }
+ }
+
+ if (cp == &procargs[syssize]) {
+ free(procargs);
+ continue;
+ }
+
+ /* Strip off any path that was specified */
+ for (thiscmd = cp; (cp < &procargs[syssize]) && (*cp != '\0'); cp++) {
+ if (*cp == '/') {
+ thiscmd = cp + 1;
+ }
+ }
+
+ thistdev = procs[i].kp_eproc.e_tdev;
+#else /* !__APPLE__ */
+ if (procs[i].ki_stat == SZOMB && !zflag)
+ continue;
+ thispid = procs[i].ki_pid;
+ strncpy(thiscmd, procs[i].ki_comm, MAXCOMLEN);
+ thiscmd[MAXCOMLEN] = '\0';
+ thistdev = procs[i].ki_tdev;
+#endif /* __APPLE__ */
+#ifndef __APPLE__
+ if (eflag)
+ thisuid = procs[i].ki_uid; /* effective uid */
+ else
+ thisuid = procs[i].ki_ruid; /* real uid */
+#endif /* !__APPLE__ */
+
+ if (thispid == mypid) {
+#ifdef __APPLE__
+ free(procargs);
+#endif /* __APPLE__ */
+ continue;
+ }
+ matched = 1;
+#ifndef __APPLE__
+ if (user) {
+ if (thisuid != uid)
+ matched = 0;
+ }
+#endif /* !__APPLE__ */
+ if (tty) {
+ if (thistdev != tdev)
+ matched = 0;
+ }
+ if (cmd) {
+ if (mflag) {
+ if (regcomp(&rgx, cmd,
+ REG_EXTENDED|REG_NOSUB) != 0) {
+ mflag = 0;
+ warnx("%s: illegal regexp", cmd);
+ }
+ }
+ if (mflag) {
+ pmatch.rm_so = 0;
+ pmatch.rm_eo = strlen(thiscmd);
+ if (regexec(&rgx, thiscmd, 0, &pmatch,
+ REG_STARTEND) != 0)
+ matched = 0;
+ regfree(&rgx);
+ } else {
+ if (strncmp(thiscmd, cmd, MAXCOMLEN) != 0)
+ matched = 0;
+ }
+ }
+#ifndef __APPLE__
+ if (jflag && thispid == getpid())
+ matched = 0;
+#endif /* !__APPLE__ */
+ if (matched == 0) {
+#ifdef __APPLE__
+ free(procargs);
+#endif /* !__APPLE__ */
+ continue;
+ }
+ if (ac > 0)
+ matched = 0;
+ for (j = 0; j < ac; j++) {
+ if (mflag) {
+ if (regcomp(&rgx, av[j],
+ REG_EXTENDED|REG_NOSUB) != 0) {
+ mflag = 0;
+ warnx("%s: illegal regexp", av[j]);
+ }
+ }
+ if (mflag) {
+ pmatch.rm_so = 0;
+ pmatch.rm_eo = strlen(thiscmd);
+ if (regexec(&rgx, thiscmd, 0, &pmatch,
+ REG_STARTEND) == 0)
+ matched = 1;
+ regfree(&rgx);
+ } else {
+ if (strcmp(thiscmd, av[j]) == 0)
+ matched = 1;
+ }
+ if (matched)
+ break;
+ }
+ if (matched == 0) {
+#ifdef __APPLE__
+ free(procargs);
+#endif /* __APPLE__ */
+ continue;
+ }
+ if (dflag)
+#ifdef __APPLE__
+ printf("sig:%d, cmd:%s, pid:%d, dev:0x%x\n", sig,
+ thiscmd, thispid, thistdev);
+#else /* !__APPLE__ */
+ printf("sig:%d, cmd:%s, pid:%d, dev:0x%x uid:%d\n", sig,
+ thiscmd, thispid, thistdev, thisuid);
+#endif /* __APPLE__ */
+
+ if (vflag || sflag)
+ printf("kill -%s %d\n", upper(sys_signame[sig]),
+ thispid);
+
+ killed++;
+ if (!dflag && !sflag) {
+ if (kill(thispid, sig) < 0 /* && errno != ESRCH */ ) {
+ warn("warning: kill -%s %d",
+ upper(sys_signame[sig]), thispid);
+ errors = 1;
+ }
+ }
+#ifdef __APPLE__
+ free(procargs);
+#endif /* __APPLE__ */
+ }
+ if (killed == 0) {
+ fprintf(stderr, "No matching processes %swere found\n",
+ getuid() != 0 ? "belonging to you " : "");
+ errors = 1;
+ }
+ exit(errors);
+}
diff --git a/shell_cmds/lastcomm/lastcomm.1 b/shell_cmds/lastcomm/lastcomm.1
new file mode 100644
index 0000000..96f7638
--- /dev/null
+++ b/shell_cmds/lastcomm/lastcomm.1
@@ -0,0 +1,132 @@
+.\" $NetBSD: lastcomm.1,v 1.11 2006/12/22 08:00:20 ad Exp $
+.\"
+.\" Copyright (c) 1980, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)lastcomm.1 8.1 (Berkeley) 6/6/93
+.\"
+.Dd December 22, 2006
+.Dt LASTCOMM 1
+.Os
+.Sh NAME
+.Nm lastcomm
+.Nd show last commands executed in reverse order
+.Sh SYNOPSIS
+.Nm
+.Op Fl f Ar file
+.Op Ar command ...
+.Op Ar user ...
+.Op Ar terminal ...
+.Sh DESCRIPTION
+.Nm
+gives information on previously executed commands.
+With no arguments,
+.Nm
+prints information about all the commands recorded
+during the current accounting file's lifetime.
+.Pp
+Option:
+.Pp
+.Bl -tag -width Fl
+.It Fl f Ar file
+Read from
+.Ar file
+rather than the default
+accounting file.
+.El
+.Pp
+If called with arguments, only accounting entries with a
+matching
+.Ar command
+name,
+.Ar user
+name,
+or
+.Ar terminal
+name
+are printed.
+So, for example:
+.Pp
+.Dl lastcomm a.out root ttyd0
+.Pp
+would produce a listing of all the
+executions of commands named
+.Pa a.out
+by user
+.Ar root
+on the terminal
+.Ar ttyd0 .
+.Pp
+For each process entry, the following are printed.
+.Pp
+.Bl -bullet -offset indent -compact
+.It
+The name of the user who ran the process.
+.It
+Flags, as accumulated by the accounting facilities in the system.
+.It
+The command name under which the process was called.
+.It
+The amount of cpu time used by the process (in seconds).
+.It
+The time the process started.
+.It
+The elapsed time of the process.
+.El
+.Pp
+The flags are encoded as follows:
+.Dq S
+indicates the command was
+executed by the super-user,
+.Dq F
+indicates the command ran after
+a fork, but without a following
+.Xr exec 3 ,
+.Dq C
+indicates the command was run in PDP-11 compatibility mode
+(VAX only),
+.Dq D
+indicates the command terminated with the generation of a
+.Pa core
+file, and
+.Dq X
+indicates the command was terminated with a signal.
+.Sh FILES
+.Bl -tag -width /var/account/acct -compact
+.It Pa /var/account/acct
+Default accounting file.
+.El
+.Sh SEE ALSO
+.Xr last 1 ,
+.Xr sigaction 2 ,
+.Xr acct 5 ,
+.Xr core 5
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 3.0 .
diff --git a/shell_cmds/lastcomm/lastcomm.c b/shell_cmds/lastcomm/lastcomm.c
new file mode 100644
index 0000000..e1d9b66
--- /dev/null
+++ b/shell_cmds/lastcomm/lastcomm.c
@@ -0,0 +1,235 @@
+/* $NetBSD: lastcomm.c,v 1.21 2009/04/12 13:08:31 lukem Exp $ */
+
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1980, 1993\
+ The Regents of the University of California. All rights reserved.");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)lastcomm.c 8.2 (Berkeley) 4/29/95";
+#endif
+__RCSID("$NetBSD: lastcomm.c,v 1.21 2009/04/12 13:08:31 lukem Exp $");
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/acct.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <fcntl.h>
+#include <math.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <struct.h>
+#include <time.h>
+#include <tzfile.h>
+#include <unistd.h>
+/* definitions from utmp.h */
+#define UT_NAMESIZE 8
+#define UT_LINESIZE 8
+#include "pathnames.h"
+
+static time_t expand(u_int);
+static char *flagbits(int);
+static const char *getdev(dev_t);
+static int requested(char *[], struct acct *);
+static void usage(void) __dead;
+
+int main(int, char **);
+
+int
+main(int argc, char *argv[])
+{
+ char *p;
+ struct acct ab;
+ struct stat sb;
+ FILE *fp;
+ off_t size;
+ time_t t;
+ double delta;
+ int ch;
+ const char *acctfile = _PATH_ACCT;
+
+ setprogname(argv[0]);
+
+ while ((ch = getopt(argc, argv, "f:")) != -1)
+ switch((char)ch) {
+ case 'f':
+ acctfile = optarg;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ /* Open the file. */
+ if ((fp = fopen(acctfile, "r")) == NULL || fstat(fileno(fp), &sb))
+ err(1, "%s", acctfile);
+
+ /*
+ * Round off to integral number of accounting records, probably
+ * not necessary, but it doesn't hurt.
+ */
+ size = sb.st_size - sb.st_size % sizeof(struct acct);
+
+ /* Check if any records to display. */
+ if (size < (off_t)sizeof(struct acct))
+ exit(0);
+
+ /*
+ * Seek to before the last entry in the file; use lseek(2) in case
+ * the file is bigger than a "long".
+ */
+ size -= sizeof(struct acct);
+ if (lseek(fileno(fp), size, SEEK_SET) == -1)
+ err(1, "%s", acctfile);
+
+ for (;;) {
+ if (fread(&ab, sizeof(struct acct), 1, fp) != 1)
+ err(1, "%s", acctfile);
+
+ if (ab.ac_comm[0] == '\0') {
+ ab.ac_comm[0] = '?';
+ ab.ac_comm[1] = '\0';
+ } else
+ for (p = &ab.ac_comm[0];
+ p < &ab.ac_comm[fldsiz(acct, ac_comm)] && *p; ++p)
+ if (!isprint((unsigned char)*p))
+ *p = '?';
+ if (!*argv || requested(argv, &ab)) {
+
+ time_t timelong = ab.ac_btime;
+ t = expand(ab.ac_utime) + expand(ab.ac_stime);
+ (void)printf(
+ "%-*.*s %-7s %-*.*s %-*.*s %6.2f secs %.16s",
+ (int)fldsiz(acct, ac_comm),
+ (int)fldsiz(acct, ac_comm),
+ ab.ac_comm, flagbits(ab.ac_flag),
+ UT_NAMESIZE, UT_NAMESIZE,
+ user_from_uid(ab.ac_uid, 0), UT_LINESIZE,
+ UT_LINESIZE, getdev(ab.ac_tty),
+ t / (double)AHZ, ctime(&timelong));
+ delta = expand(ab.ac_etime) / (double)AHZ;
+ printf(" (%1.0f:%02.0f:%05.2f)\n",
+ floor(delta / SECSPERHOUR),
+ floor(fmod(delta, SECSPERHOUR) / SECSPERMIN),
+ fmod(delta, SECSPERMIN));
+ }
+ /* are we at the beginning of the file yet? */
+ if (size == 0)
+ break;
+ /* seek backward over the one we read and the next to read */
+ if (fseek(fp, 2 * -(long)sizeof(struct acct), SEEK_CUR) == -1)
+ err(1, "%s", acctfile);
+ /* and account for its size */
+ size -= sizeof(struct acct);
+ }
+ exit(0);
+}
+
+static time_t
+expand(u_int t)
+{
+ time_t nt;
+
+ nt = t & 017777;
+ t >>= 13;
+ while (t) {
+ t--;
+ nt <<= 3;
+ }
+ return (nt);
+}
+
+static char *
+flagbits(int f)
+{
+ static char flags[20] = "-";
+ char *p;
+
+#define BIT(flag, ch) if (f & flag) *p++ = ch
+
+ p = flags + 1;
+ BIT(ASU, 'S');
+ BIT(AFORK, 'F');
+ BIT(ACOMPAT, 'C');
+ BIT(ACORE, 'D');
+ BIT(AXSIG, 'X');
+ *p = '\0';
+ return (flags);
+}
+
+static int
+requested(char *argv[], struct acct *acp)
+{
+ do {
+ if (!strcmp(user_from_uid(acp->ac_uid, 0), *argv))
+ return (1);
+ if (!strcmp(getdev(acp->ac_tty), *argv))
+ return (1);
+ if (!strncmp(acp->ac_comm, *argv, fldsiz(acct, ac_comm)))
+ return (1);
+ } while (*++argv);
+ return (0);
+}
+
+static const char *
+getdev(dev_t dev)
+{
+ static dev_t lastdev = (dev_t)-1;
+ static const char *lastname;
+
+ if (dev == NODEV) /* Special case. */
+ return ("__");
+ if (dev == lastdev) /* One-element cache. */
+ return (lastname);
+ lastdev = dev;
+ if ((lastname = devname(dev, S_IFCHR)) == NULL)
+ lastname = "??";
+ return (lastname);
+}
+
+static void
+usage(void)
+{
+ (void)fprintf(stderr,
+ "Usage: %s [ -f file ] [command ...] [user ...] [tty ...]\n",
+ getprogname());
+ exit(1);
+}
diff --git a/shell_cmds/lastcomm/pathnames.h b/shell_cmds/lastcomm/pathnames.h
new file mode 100644
index 0000000..6ca75d8
--- /dev/null
+++ b/shell_cmds/lastcomm/pathnames.h
@@ -0,0 +1,36 @@
+/* $NetBSD: pathnames.h,v 1.4 2003/08/07 11:14:18 agc Exp $ */
+
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)pathnames.h 8.1 (Berkeley) 6/6/93
+ */
+
+#include <paths.h>
+
+#define _PATH_ACCT "/var/account/acct"
diff --git a/shell_cmds/locate/bigram/locate.bigram.8 b/shell_cmds/locate/bigram/locate.bigram.8
new file mode 100644
index 0000000..129334c
--- /dev/null
+++ b/shell_cmds/locate/bigram/locate.bigram.8
@@ -0,0 +1 @@
+.so man8/locate.code.8
diff --git a/shell_cmds/locate/bigram/locate.bigram.c b/shell_cmds/locate/bigram/locate.bigram.c
new file mode 100644
index 0000000..a4ad2b1
--- /dev/null
+++ b/shell_cmds/locate/bigram/locate.bigram.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 1995 Wolfram Schneider <wosch@FreeBSD.org>. Berlin.
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * James A. Woods.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/usr.bin/locate/bigram/locate.bigram.c,v 1.12 2005/02/09 09:13:36 stefanf Exp $
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1989, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)locate.bigram.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*
+ * bigram < sorted_file_names | sort -nr |
+ * awk 'NR <= 128 { printf $2 }' > bigrams
+ *
+ * List bigrams for 'updatedb' script.
+ * Use 'code' to encode a file using this output.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/param.h> /* for MAXPATHLEN */
+#include "locate.h"
+
+u_char buf1[MAXPATHLEN] = " ";
+u_char buf2[MAXPATHLEN];
+u_int bigram[UCHAR_MAX + 1][UCHAR_MAX + 1];
+
+int
+main(void)
+{
+ register u_char *cp;
+ register u_char *oldpath = buf1, *path = buf2;
+ register u_int i, j;
+
+ while (fgets(path, sizeof(buf2), stdin) != NULL) {
+
+ /*
+ * We don't need remove newline character '\n'.
+ * '\n' is less than ASCII_MIN and will be later
+ * ignored at output.
+ */
+
+
+ /* skip longest common prefix */
+ for (cp = path; *cp == *oldpath; cp++, oldpath++)
+ if (*cp == '\0')
+ break;
+
+ while (*cp != '\0' && *(cp + 1) != '\0') {
+ bigram[(u_char)*cp][(u_char)*(cp + 1)]++;
+ cp += 2;
+ }
+
+ /* swap pointers */
+ if (path == buf1) {
+ path = buf2;
+ oldpath = buf1;
+ } else {
+ path = buf1;
+ oldpath = buf2;
+ }
+ }
+
+ /* output, boundary check */
+ for (i = ASCII_MIN; i <= ASCII_MAX; i++)
+ for (j = ASCII_MIN; j <= ASCII_MAX; j++)
+ if (bigram[i][j] != 0)
+ (void)printf("%4u %c%c\n", bigram[i][j], i, j);
+
+ exit(0);
+}
diff --git a/shell_cmds/locate/code/locate.code.8 b/shell_cmds/locate/code/locate.code.8
new file mode 100644
index 0000000..64dcfea
--- /dev/null
+++ b/shell_cmds/locate/code/locate.code.8
@@ -0,0 +1,23 @@
+.Dd October 15, 2004
+.Dt LOCATE.CODE 8
+.Os Darwin
+.Sh NAME
+.Nm locate.code, locate.bigram
+.Nd sorted list compressor
+.Sh SYNOPSIS
+.Nm locate.code
+.Nm locate.bigram
+.Sh DESCRIPTION
+.Nm locate.code
+and
+.Nm locate.bigram
+are programs used by
+.Xr locate 1
+during the indexing process.
+.Nm locate.code
+and
+.Nm locate.bigram
+should not be run manually.
+.Sh SEE ALSO
+.Xr locate 1 ,
+.Xr locate.updatedb 8
diff --git a/shell_cmds/locate/code/locate.code.c b/shell_cmds/locate/code/locate.code.c
new file mode 100644
index 0000000..9f7850e
--- /dev/null
+++ b/shell_cmds/locate/code/locate.code.c
@@ -0,0 +1,279 @@
+/*
+ * Copyright (c) 1995 Wolfram Schneider <wosch@FreeBSD.org>. Berlin.
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * James A. Woods.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/usr.bin/locate/code/locate.code.c,v 1.13 2002/03/22 01:22:47 imp Exp $
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1989, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)locate.code.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*
+ * PURPOSE: sorted list compressor (works with a modified 'find'
+ * to encode/decode a filename database)
+ *
+ * USAGE: bigram < list > bigrams
+ * process bigrams (see updatedb) > common_bigrams
+ * code common_bigrams < list > squozen_list
+ *
+ * METHOD: Uses 'front compression' (see ";login:", Volume 8, Number 1
+ * February/March 1983, p. 8). Output format is, per line, an
+ * offset differential count byte followed by a partially bigram-
+ * encoded ascii residue. A bigram is a two-character sequence,
+ * the first 128 most common of which are encoded in one byte.
+ *
+ * EXAMPLE: For simple front compression with no bigram encoding,
+ * if the input is... then the output is...
+ *
+ * /usr/src 0 /usr/src
+ * /usr/src/cmd/aardvark.c 8 /cmd/aardvark.c
+ * /usr/src/cmd/armadillo.c 14 armadillo.c
+ * /usr/tmp/zoo 5 tmp/zoo
+ *
+ * The codes are:
+ *
+ * 0-28 likeliest differential counts + offset to make nonnegative
+ * 30 switch code for out-of-range count to follow in next word
+ * 31 an 8 bit char followed
+ * 128-255 bigram codes (128 most common, as determined by 'updatedb')
+ * 32-127 single character (printable) ascii residue (ie, literal)
+ *
+ * The locate database store any character except newline ('\n')
+ * and NUL ('\0'). The 8-bit character support don't wast extra
+ * space until you have characters in file names less than 32
+ * or greather than 127.
+ *
+ *
+ * SEE ALSO: updatedb.sh, ../bigram/locate.bigram.c
+ *
+ * AUTHOR: James A. Woods, Informatics General Corp.,
+ * NASA Ames Research Center, 10/82
+ * 8-bit file names characters:
+ * Wolfram Schneider, Berlin September 1996
+ */
+
+#include <sys/param.h>
+#include <err.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include "locate.h"
+
+#define BGBUFSIZE (NBG * 2) /* size of bigram buffer */
+
+u_char buf1[MAXPATHLEN] = " ";
+u_char buf2[MAXPATHLEN];
+u_char bigrams[BGBUFSIZE + 1] = { 0 };
+
+#define LOOKUP 1 /* use a lookup array instead a function, 3x faster */
+
+#ifdef LOOKUP
+#define BGINDEX(x) (big[(u_char)*x][(u_char)*(x + 1)])
+typedef short bg_t;
+bg_t big[UCHAR_MAX + 1][UCHAR_MAX + 1];
+#else
+#define BGINDEX(x) bgindex(x)
+typedef int bg_t;
+int bgindex(char *);
+#endif /* LOOKUP */
+
+
+void usage(void);
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register u_char *cp, *oldpath, *path;
+ int ch, code, count, diffcount, oldcount;
+ FILE *fp;
+ register int i, j;
+
+ while ((ch = getopt(argc, argv, "")) != -1)
+ switch(ch) {
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc != 1)
+ usage();
+
+ if ((fp = fopen(argv[0], "r")) == NULL)
+ err(1, "%s", argv[0]);
+
+ /* First copy bigram array to stdout. */
+ (void)fgets(bigrams, BGBUFSIZE + 1, fp);
+
+ if (fwrite(bigrams, 1, BGBUFSIZE, stdout) != BGBUFSIZE)
+ err(1, "stdout");
+ (void)fclose(fp);
+
+#ifdef LOOKUP
+ /* init lookup table */
+ for (i = 0; i < UCHAR_MAX + 1; i++)
+ for (j = 0; j < UCHAR_MAX + 1; j++)
+ big[i][j] = (bg_t)-1;
+
+ for (cp = bigrams, i = 0; *cp != '\0'; i += 2, cp += 2)
+ big[(u_char)*cp][(u_char)*(cp + 1)] = (bg_t)i;
+
+#endif /* LOOKUP */
+
+ oldpath = buf1;
+ path = buf2;
+ oldcount = 0;
+
+ while (fgets(path, sizeof(buf2), stdin) != NULL) {
+
+ /* skip empty lines */
+ if (*path == '\n')
+ continue;
+
+ /* remove newline */
+ for (cp = path; *cp != '\0'; cp++) {
+#ifndef LOCATE_CHAR30
+ /* old locate implementations core'd for char 30 */
+ if (*cp == SWITCH)
+ *cp = '?';
+ else
+#endif /* !LOCATE_CHAR30 */
+
+ /* chop newline */
+ if (*cp == '\n')
+ *cp = '\0';
+ }
+
+ /* Skip longest common prefix. */
+ for (cp = path; *cp == *oldpath; cp++, oldpath++)
+ if (*cp == '\0')
+ break;
+
+ count = cp - path;
+ diffcount = count - oldcount + OFFSET;
+ oldcount = count;
+ if (diffcount < 0 || diffcount > 2 * OFFSET) {
+ if (putchar(SWITCH) == EOF ||
+ putw(diffcount, stdout) == EOF)
+ err(1, "stdout");
+ } else
+ if (putchar(diffcount) == EOF)
+ err(1, "stdout");
+
+ while (*cp != '\0') {
+ /* print *two* characters */
+
+ if ((code = BGINDEX(cp)) != (bg_t)-1) {
+ /*
+ * print *one* as bigram
+ * Found, so mark byte with
+ * parity bit.
+ */
+ if (putchar((code / 2) | PARITY) == EOF)
+ err(1, "stdout");
+ cp += 2;
+ }
+
+ else {
+ for (i = 0; i < 2; i++) {
+ if (*cp == '\0')
+ break;
+
+ /* print umlauts in file names */
+ if (*cp < ASCII_MIN ||
+ *cp > ASCII_MAX) {
+ if (putchar(UMLAUT) == EOF ||
+ putchar(*cp++) == EOF)
+ err(1, "stdout");
+ }
+
+ else {
+ /* normal character */
+ if(putchar(*cp++) == EOF)
+ err(1, "stdout");
+ }
+ }
+
+ }
+ }
+
+ if (path == buf1) { /* swap pointers */
+ path = buf2;
+ oldpath = buf1;
+ } else {
+ path = buf1;
+ oldpath = buf2;
+ }
+ }
+ /* Non-zero status if there were errors */
+ if (fflush(stdout) != 0 || ferror(stdout))
+ exit(1);
+ exit(0);
+}
+
+#ifndef LOOKUP
+int
+bgindex(bg) /* Return location of bg in bigrams or -1. */
+ char *bg;
+{
+ register char bg0, bg1, *p;
+
+ bg0 = bg[0];
+ bg1 = bg[1];
+ for (p = bigrams; *p != NULL; p++)
+ if (*p++ == bg0 && *p == bg1)
+ break;
+ return (*p == NULL ? -1 : (--p - bigrams));
+}
+#endif /* !LOOKUP */
+
+void
+usage()
+{
+ (void)fprintf(stderr,
+ "usage: locate.code common_bigrams < list > squozen_list\n");
+ exit(1);
+}
diff --git a/shell_cmds/locate/locate/com.apple.locate.plist b/shell_cmds/locate/locate/com.apple.locate.plist
new file mode 100644
index 0000000..ceb9078
--- /dev/null
+++ b/shell_cmds/locate/locate/com.apple.locate.plist
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>Label</key>
+ <string>com.apple.locate</string>
+ <key>Disabled</key>
+ <true/>
+ <key>ProgramArguments</key>
+ <array>
+ <string>/usr/libexec/locate.updatedb</string>
+ </array>
+ <key>ProcessType</key>
+ <string>Background</string>
+ <key>KeepAlive</key>
+ <dict>
+ <key>PathState</key>
+ <dict>
+ <key>/var/db/locate.database</key>
+ <false/>
+ </dict>
+ </dict>
+ <key>StartCalendarInterval</key>
+ <dict>
+ <key>Hour</key>
+ <integer>3</integer>
+ <key>Minute</key>
+ <integer>15</integer>
+ <key>Weekday</key>
+ <integer>6</integer>
+ </dict>
+ <key>AbandonProcessGroup</key>
+ <true/>
+</dict>
+</plist>
diff --git a/shell_cmds/locate/locate/concatdb.sh b/shell_cmds/locate/locate/concatdb.sh
new file mode 100644
index 0000000..a236332
--- /dev/null
+++ b/shell_cmds/locate/locate/concatdb.sh
@@ -0,0 +1,70 @@
+#!/bin/sh
+#
+# Copyright (c) September 1995 Wolfram Schneider <wosch@FreeBSD.org>. Berlin.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# concatdb - concatenate locate databases
+#
+# usage: concatdb database1 ... databaseN > newdb
+#
+# Sequence of databases is important.
+#
+# $FreeBSD: src/usr.bin/locate/locate/concatdb.sh,v 1.10 2000/01/12 08:01:00 kris Exp $
+
+# The directory containing locate subprograms
+: ${LIBEXECDIR:=/usr/libexec}; export LIBEXECDIR
+
+PATH=$LIBEXECDIR:/bin:/usr/bin:$PATH; export PATH
+
+umask 077 # protect temp files
+
+: ${TMPDIR:=/var/tmp}; export TMPDIR;
+test -d "$TMPDIR" || TMPDIR=/var/tmp
+
+# utilities to built locate database
+: ${bigram:=locate.bigram}
+: ${code:=locate.code}
+: ${sort:=sort}
+: ${locate:=locate}
+
+
+case $# in
+ [01]) echo 'usage: concatdb databases1 ... databaseN > newdb'
+ exit 1
+ ;;
+esac
+
+
+bigrams=`mktemp ${TMPDIR=/tmp}/_bigrams.XXXXXXXXXX` || exit 1
+trap 'rm -f $bigrams' 0 1 2 3 5 10 15
+
+for db
+do
+ $locate -d $db /
+done | $bigram | $sort -nr | awk 'NR <= 128 { printf $2 }' > $bigrams
+
+for db
+do
+ $locate -d $db /
+done | $code $bigrams
diff --git a/shell_cmds/locate/locate/fastfind.c b/shell_cmds/locate/locate/fastfind.c
new file mode 100644
index 0000000..e683de7
--- /dev/null
+++ b/shell_cmds/locate/locate/fastfind.c
@@ -0,0 +1,338 @@
+/*
+ * Copyright (c) 1995 Wolfram Schneider <wosch@FreeBSD.org>. Berlin.
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * James A. Woods.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/usr.bin/locate/locate/fastfind.c,v 1.14 2005/12/07 12:22:46 des Exp $
+ */
+
+
+#ifndef _LOCATE_STATISTIC_
+#define _LOCATE_STATISTIC_
+
+void
+statistic (fp, path_fcodes)
+ FILE *fp; /* open database */
+ char *path_fcodes; /* for error message */
+{
+ register int lines, chars, size, big, zwerg;
+ register u_char *p, *s;
+ register int c;
+ int count, umlaut;
+ u_char bigram1[NBG], bigram2[NBG], path[MAXPATHLEN];
+
+ for (c = 0, p = bigram1, s = bigram2; c < NBG; c++) {
+ p[c] = check_bigram_char(getc(fp));
+ s[c] = check_bigram_char(getc(fp));
+ }
+
+ lines = chars = big = zwerg = umlaut = 0;
+ size = NBG + NBG;
+
+ for (c = getc(fp), count = 0; c != EOF; size++) {
+ if (c == SWITCH) {
+ count += getwf(fp) - OFFSET;
+ size += sizeof(int);
+ zwerg++;
+ } else
+ count += c - OFFSET;
+
+ for (p = path + count; (c = getc(fp)) > SWITCH; size++)
+ if (c < PARITY) {
+ if (c == UMLAUT) {
+ c = getc(fp);
+ size++;
+ umlaut++;
+ }
+ p++;
+ } else {
+ /* bigram char */
+ big++;
+ p += 2;
+ }
+
+ p++;
+ lines++;
+ chars += (p - path);
+ }
+
+ (void)printf("\nDatabase: %s\n", path_fcodes);
+ (void)printf("Compression: Front: %2.2f%%, ",
+ (size + big - (2 * NBG)) / (chars / (float)100));
+ (void)printf("Bigram: %2.2f%%, ", (size - big) / (size / (float)100));
+ (void)printf("Total: %2.2f%%\n",
+ (size - (2 * NBG)) / (chars / (float)100));
+ (void)printf("Filenames: %d, ", lines);
+ (void)printf("Characters: %d, ", chars);
+ (void)printf("Database size: %d\n", size);
+ (void)printf("Bigram characters: %d, ", big);
+ (void)printf("Integers: %d, ", zwerg);
+ (void)printf("8-Bit characters: %d\n", umlaut);
+
+}
+#endif /* _LOCATE_STATISTIC_ */
+
+extern char separator;
+
+void
+#ifdef FF_MMAP
+
+
+#ifdef FF_ICASE
+fastfind_mmap_icase
+#else
+fastfind_mmap
+#endif /* FF_ICASE */
+(pathpart, paddr, len, database)
+ char *pathpart; /* search string */
+ caddr_t paddr; /* mmap pointer */
+ int len; /* length of database */
+ char *database; /* for error message */
+
+
+#else /* MMAP */
+
+
+#ifdef FF_ICASE
+fastfind_icase
+#else
+fastfind
+#endif /* FF_ICASE */
+
+(fp, pathpart, database)
+ FILE *fp; /* open database */
+ char *pathpart; /* search string */
+ char *database; /* for error message */
+
+
+#endif /* MMAP */
+
+{
+ register u_char *p, *s, *patend, *q, *foundchar;
+ register int c, cc;
+ int count, found, globflag;
+ u_char *cutoff;
+ u_char bigram1[NBG], bigram2[NBG], path[MAXPATHLEN];
+
+#ifdef FF_ICASE
+ /* use a lookup table for case insensitive search */
+ u_char table[UCHAR_MAX + 1];
+
+ tolower_word(pathpart);
+#endif /* FF_ICASE*/
+
+ /* init bigram table */
+#ifdef FF_MMAP
+ if (len < (2*NBG))
+ errx(1, "database too small: %s", database);
+
+ for (c = 0, p = bigram1, s = bigram2; c < NBG; c++, len-= 2) {
+ p[c] = check_bigram_char(*paddr++);
+ s[c] = check_bigram_char(*paddr++);
+ }
+#else
+ for (c = 0, p = bigram1, s = bigram2; c < NBG; c++) {
+ p[c] = check_bigram_char(getc(fp));
+ s[c] = check_bigram_char(getc(fp));
+ }
+#endif /* FF_MMAP */
+
+ /* find optimal (last) char for searching */
+ for (p = pathpart; *p != '\0'; p++)
+ if (index(LOCATE_REG, *p) != NULL)
+ break;
+
+ if (*p == '\0')
+ globflag = 0;
+ else
+ globflag = 1;
+
+ p = pathpart;
+ patend = patprep(p);
+ cc = *patend;
+
+#ifdef FF_ICASE
+ /* set patend char to true */
+ for (c = 0; c < UCHAR_MAX + 1; c++)
+ table[c] = 0;
+
+ table[TOLOWER(*patend)] = 1;
+ table[toupper(*patend)] = 1;
+#endif /* FF_ICASE */
+
+
+ /* main loop */
+ found = count = 0;
+ foundchar = 0;
+
+#ifdef FF_MMAP
+ c = (u_char)*paddr++; len--;
+ for (; len > 0; ) {
+#else
+ c = getc(fp);
+ for (; c != EOF; ) {
+#endif /* FF_MMAP */
+
+ /* go forward or backward */
+ if (c == SWITCH) { /* big step, an integer */
+#ifdef FF_MMAP
+ count += getwm(paddr) - OFFSET;
+ len -= INTSIZE; paddr += INTSIZE;
+#else
+ count += getwf(fp) - OFFSET;
+#endif /* FF_MMAP */
+ } else { /* slow step, =< 14 chars */
+ count += c - OFFSET;
+ }
+
+#ifdef __APPLE__
+ if (count < 0) {
+ errx(1, "Your locate database appears to be corrupt. "
+ "Run 'sudo /usr/libexec/locate.updatedb' to "
+ "regenerate the database.");
+ }
+#endif /* __APPLE__ */
+
+ /* overlay old path */
+ p = path + count;
+ foundchar = p - 1;
+
+#ifdef FF_MMAP
+ for (; len > 0;) {
+ c = (u_char)*paddr++;
+ len--;
+#else
+ for (;;) {
+ c = getc(fp);
+#endif /* FF_MMAP */
+ /*
+ * == UMLAUT: 8 bit char followed
+ * <= SWITCH: offset
+ * >= PARITY: bigram
+ * rest: single ascii char
+ *
+ * offset < SWITCH < UMLAUT < ascii < PARITY < bigram
+ */
+ if (c < PARITY) {
+ if (c <= UMLAUT) {
+ if (c == UMLAUT) {
+#ifdef FF_MMAP
+ c = (u_char)*paddr++;
+ len--;
+#else
+ c = getc(fp);
+#endif /* FF_MMAP */
+
+ } else
+ break; /* SWITCH */
+ }
+#ifdef FF_ICASE
+ if (table[c])
+#else
+ if (c == cc)
+#endif /* FF_ICASE */
+ foundchar = p;
+ *p++ = c;
+ }
+ else {
+ /* bigrams are parity-marked */
+ TO7BIT(c);
+
+#ifndef FF_ICASE
+ if (bigram1[c] == cc ||
+ bigram2[c] == cc)
+#else
+
+ if (table[bigram1[c]] ||
+ table[bigram2[c]])
+#endif /* FF_ICASE */
+ foundchar = p + 1;
+
+ *p++ = bigram1[c];
+ *p++ = bigram2[c];
+ }
+ }
+
+ if (found) { /* previous line matched */
+ cutoff = path;
+ *p-- = '\0';
+ foundchar = p;
+ } else if (foundchar >= path + count) { /* a char matched */
+ *p-- = '\0';
+ cutoff = path + count;
+ } else /* nothing to do */
+ continue;
+
+ found = 0;
+ for (s = foundchar; s >= cutoff; s--) {
+ if (*s == cc
+#ifdef FF_ICASE
+ || TOLOWER(*s) == cc
+#endif /* FF_ICASE */
+ ) { /* fast first char check */
+ for (p = patend - 1, q = s - 1; *p != '\0';
+ p--, q--)
+ if (*q != *p
+#ifdef FF_ICASE
+ && TOLOWER(*q) != *p
+#endif /* FF_ICASE */
+ )
+ break;
+ if (*p == '\0') { /* fast match success */
+ found = 1;
+ if (!globflag ||
+#ifndef FF_ICASE
+ !fnmatch(pathpart, path, 0))
+#else
+ !fnmatch(pathpart, path,
+ FNM_CASEFOLD))
+#endif /* !FF_ICASE */
+ {
+ if (f_silent)
+ counter++;
+ else if (f_limit) {
+ counter++;
+ if (f_limit >= counter)
+ (void)printf("%s%c",path,separator);
+ else
+ errx(0, "[show only %d lines]", counter - 1);
+ } else
+ (void)printf("%s%c",path,separator);
+ }
+ break;
+ }
+ }
+ }
+ }
+}
diff --git a/shell_cmds/locate/locate/locate.1 b/shell_cmds/locate/locate/locate.1
new file mode 100644
index 0000000..cdde718
--- /dev/null
+++ b/shell_cmds/locate/locate/locate.1
@@ -0,0 +1,276 @@
+.\" Copyright (c) 1995 Wolfram Schneider <wosch@FreeBSD.org>. Berlin.
+.\" Copyright (c) 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)locate.1 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD: src/usr.bin/locate/locate/locate.1,v 1.34 2006/09/29 15:20:45 ru Exp $
+.\"
+.Dd August 17, 2006
+.Dt LOCATE 1
+.Os
+.Sh NAME
+.Nm locate
+.Nd find filenames quickly
+.Sh SYNOPSIS
+.Nm
+.Op Fl 0Scims
+.Op Fl l Ar limit
+.Op Fl d Ar database
+.Ar pattern ...
+.Sh DESCRIPTION
+The
+.Nm
+program searches a database for all pathnames which match the specified
+.Ar pattern .
+The database is recomputed periodically (usually weekly or daily),
+and contains the pathnames
+of all files which are publicly accessible.
+.Pp
+Shell globbing and quoting characters
+.Dq ( * ,
+.Dq \&? ,
+.Dq \e ,
+.Dq \&[
+and
+.Dq \&] )
+may be used in
+.Ar pattern ,
+although they will have to be escaped from the shell.
+Preceding any character with a backslash
+.Pq Dq \e
+eliminates any special
+meaning which it may have.
+The matching differs in that no characters must be matched explicitly,
+including slashes
+.Pq Dq / .
+.Pp
+As a special case, a pattern containing no globbing characters
+.Pq Dq foo
+is matched as though it were
+.Dq *foo* .
+.Pp
+Historically, locate only stored characters between 32 and 127.
+The
+current implementation store any character except newline
+.Pq Sq \en
+and
+.Dv NUL
+.Pq Sq \e0 .
+The 8-bit character support does not waste extra space for
+plain ASCII file names.
+Characters less than 32 or greater than 127
+are stored in 2 bytes.
+.Pp
+The following options are available:
+.Bl -tag -width 10n
+.It Fl 0
+Print pathnames separated by an
+.Tn ASCII
+.Dv NUL
+character (character code 0) instead of default NL
+(newline, character code 10).
+.It Fl S
+Print some statistics about the database and exit.
+.It Fl c
+Suppress normal output; instead print a count of matching file names.
+.It Fl d Ar database
+Search in
+.Ar database
+instead of the default file name database.
+Multiple
+.Fl d
+options are allowed.
+Each additional
+.Fl d
+option adds the specified database to the list
+of databases to be searched.
+.Pp
+The option
+.Ar database
+may be a colon-separated list of databases.
+A single colon is a reference
+to the default database.
+.Bd -literal
+$ locate -d $HOME/lib/mydb: foo
+.Ed
+.Pp
+will first search string
+.Dq foo
+in
+.Pa $HOME/lib/mydb
+and then in
+.Pa /var/db/locate.database .
+.Bd -literal
+$ locate -d $HOME/lib/mydb::/cdrom/locate.database foo
+.Ed
+.Pp
+will first search string
+.Dq foo
+in
+.Pa $HOME/lib/mydb
+and then in
+.Pa /var/db/locate.database
+and then in
+.Pa /cdrom/locate.database .
+.Pp
+.Dl "$ locate -d db1 -d db2 -d db3 pattern"
+.Pp
+is the same as
+.Pp
+.Dl "$ locate -d db1:db2:db3 pattern"
+.Pp
+or
+.Pp
+.Dl "$ locate -d db1:db2 -d db3 pattern"
+.Pp
+If
+.Fl
+is given as the database name, standard input will be read instead.
+For example, you can compress your database
+and use:
+.Bd -literal
+$ zcat database.gz | locate -d - pattern
+.Ed
+.Pp
+This might be useful on machines with a fast CPU and little RAM and slow
+I/O.
+Note: you can only use
+.Em one
+pattern for stdin.
+.It Fl i
+Ignore case distinctions in both the pattern and the database.
+.It Fl l Ar number
+Limit output to
+.Ar number
+of file names and exit.
+.It Fl m
+Use
+.Xr mmap 2
+instead of the
+.Xr stdio 3
+library.
+This is the default behavior
+and is faster in most cases.
+.It Fl s
+Use the
+.Xr stdio 3
+library instead of
+.Xr mmap 2 .
+.El
+.Sh ENVIRONMENT
+.Bl -tag -width LOCATE_PATH -compact
+.It Pa LOCATE_PATH
+path to the locate database if set and not empty, ignored if the
+.Fl d
+option was specified.
+.El
+.Sh FILES
+.Bl -tag -width /System/Library/LaunchDaemons/com.apple.locate.plist -compact
+.It Pa /var/db/locate.database
+locate database
+.It Pa /usr/libexec/locate.updatedb
+Script to update the locate database
+.It Pa /System/Library/LaunchDaemons/com.apple.locate.plist
+Job that starts the database rebuild
+.El
+.Sh SEE ALSO
+.Xr find 1 ,
+.Xr whereis 1 ,
+.Xr which 1 ,
+.Xr fnmatch 3 ,
+.Xr locate.updatedb 8
+.Rs
+.%A Woods, James A.
+.%D 1983
+.%T "Finding Files Fast"
+.%J ";login"
+.%V 8:1
+.%P pp. 8-10
+.Re
+.Sh HISTORY
+The
+.Nm
+command first appeared in
+.Bx 4.4 .
+Many new features were
+added in
+.Fx 2.2 .
+.Sh BUGS
+The
+.Nm
+program may fail to list some files that are present, or may
+list files that have been removed from the system.
+This is because
+locate only reports files that are present in the database, which is
+typically only regenerated once a week by the
+.Pa /System/Library/LaunchDaemons/com.apple.locate.plist
+job.
+Use
+.Xr find 1
+to locate files that are of a more transitory nature.
+.Pp
+The
+.Nm
+database is typically built by user
+.Dq nobody
+and the
+.Xr locate.updatedb 8
+utility skips directories
+which are not readable for user
+.Dq nobody ,
+group
+.Dq nobody ,
+or
+world.
+For example, if your HOME directory is not world-readable,
+.Em none
+of your files are
+in the database.
+.Pp
+The
+.Nm
+database is not byte order independent.
+It is not possible
+to share the databases between machines with different byte order.
+The current
+.Nm
+implementation understands databases in host byte order or
+network byte order if both architectures use the same integer size.
+So on a
+.Fx Ns /i386
+machine
+(little endian), you can read
+a locate database which was built on SunOS/sparc machine
+(big endian, net).
+.Pp
+The
+.Nm
+utility does not recognize multibyte characters.
diff --git a/shell_cmds/locate/locate/locate.c b/shell_cmds/locate/locate/locate.c
new file mode 100644
index 0000000..315bfd3
--- /dev/null
+++ b/shell_cmds/locate/locate/locate.c
@@ -0,0 +1,389 @@
+/*
+ * Copyright (c) 1995 Wolfram Schneider <wosch@FreeBSD.org>. Berlin.
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * James A. Woods.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1995-1996 Wolfram Schneider, Berlin.\n\
+@(#) Copyright (c) 1989, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)locate.c 8.1 (Berkeley) 6/6/93";
+#endif
+static const char rcsid[] =
+ "$FreeBSD: src/usr.bin/locate/locate/locate.c,v 1.17 2006/06/11 17:40:25 maxim Exp $";
+#endif /* not lint */
+
+/*
+ * Ref: Usenix ;login:, Vol 8, No 1, February/March, 1983, p. 8.
+ *
+ * Locate scans a file list for the full pathname of a file given only part
+ * of the name. The list has been processed with with "front-compression"
+ * and bigram coding. Front compression reduces space by a factor of 4-5,
+ * bigram coding by a further 20-25%.
+ *
+ * The codes are:
+ *
+ * 0-28 likeliest differential counts + offset to make nonnegative
+ * 30 switch code for out-of-range count to follow in next word
+ * 31 an 8 bit char followed
+ * 128-255 bigram codes (128 most common, as determined by 'updatedb')
+ * 32-127 single character (printable) ascii residue (ie, literal)
+ *
+ * A novel two-tiered string search technique is employed:
+ *
+ * First, a metacharacter-free subpattern and partial pathname is matched
+ * BACKWARDS to avoid full expansion of the pathname list. The time savings
+ * is 40-50% over forward matching, which cannot efficiently handle
+ * overlapped search patterns and compressed path residue.
+ *
+ * Then, the actual shell glob-style regular expression (if in this form) is
+ * matched against the candidate pathnames using the slower routines provided
+ * in the standard 'find'.
+ */
+
+#include <sys/param.h>
+#include <ctype.h>
+#include <err.h>
+#ifdef __APPLE__
+#include <errno.h>
+#endif /* __APPLE__ */
+#include <fnmatch.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifdef MMAP
+# include <sys/types.h>
+# include <sys/stat.h>
+# include <sys/mman.h>
+# include <fcntl.h>
+#endif
+
+
+#include "locate.h"
+#include "pathnames.h"
+
+#ifdef DEBUG
+# include <sys/time.h>
+# include <sys/types.h>
+# include <sys/resource.h>
+#endif
+
+int f_mmap; /* use mmap */
+int f_icase; /* ignore case */
+int f_stdin; /* read database from stdin */
+int f_statistic; /* print statistic */
+int f_silent; /* suppress output, show only count of matches */
+int f_limit; /* limit number of output lines, 0 == infinite */
+u_int counter; /* counter for matches [-c] */
+char separator='\n'; /* line separator */
+#ifdef __APPLE__
+u_char myctype[UCHAR_MAX + 1];
+#endif /* __APPLE__ */
+
+
+void usage(void);
+void statistic(FILE *, char *);
+void fastfind(FILE *, char *, char *);
+void fastfind_icase(FILE *, char *, char *);
+void fastfind_mmap(char *, caddr_t, int, char *);
+void fastfind_mmap_icase(char *, caddr_t, int, char *);
+void search_mmap(char *, char **);
+void search_fopen(char *, char **);
+unsigned long cputime(void);
+
+extern char **colon(char **, char*, char*);
+extern void print_matches(u_int);
+extern int getwm(caddr_t);
+extern int getwf(FILE *);
+extern u_char *tolower_word(u_char *);
+extern int check_bigram_char(int);
+extern char *patprep(char *);
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ register int ch;
+ char **dbv = NULL;
+ char *path_fcodes; /* locate database */
+#ifdef MMAP
+ f_mmap = 1; /* mmap is default */
+#endif
+ (void) setlocale(LC_ALL, "");
+
+ while ((ch = getopt(argc, argv, "0Scd:il:ms")) != -1)
+ switch(ch) {
+ case '0': /* 'find -print0' style */
+ separator = '\0';
+ break;
+ case 'S': /* statistic lines */
+ f_statistic = 1;
+ break;
+ case 'l': /* limit number of output lines, 0 == infinite */
+ f_limit = atoi(optarg);
+ break;
+ case 'd': /* database */
+ dbv = colon(dbv, optarg, _PATH_FCODES);
+ break;
+ case 'i': /* ignore case */
+ f_icase = 1;
+ break;
+ case 'm': /* mmap */
+#ifdef MMAP
+ f_mmap = 1;
+#else
+ warnx("mmap(2) not implemented");
+#endif
+ break;
+ case 's': /* stdio lib */
+ f_mmap = 0;
+ break;
+ case 'c': /* suppress output, show only count of matches */
+ f_silent = 1;
+ break;
+ default:
+ usage();
+ }
+ argv += optind;
+ argc -= optind;
+
+ /* to few arguments */
+ if (argc < 1 && !(f_statistic))
+ usage();
+
+ /* no (valid) database as argument */
+ if (dbv == NULL || *dbv == NULL) {
+ /* try to read database from enviroment */
+ if ((path_fcodes = getenv("LOCATE_PATH")) == NULL ||
+ *path_fcodes == '\0')
+ /* use default database */
+ dbv = colon(dbv, _PATH_FCODES, _PATH_FCODES);
+ else /* $LOCATE_PATH */
+ dbv = colon(dbv, path_fcodes, _PATH_FCODES);
+ }
+
+ if (f_icase && UCHAR_MAX < 4096) /* init tolower lookup table */
+ for (ch = 0; ch < UCHAR_MAX + 1; ch++)
+ myctype[ch] = tolower(ch);
+
+ /* foreach database ... */
+ while((path_fcodes = *dbv) != NULL) {
+ dbv++;
+
+ if (!strcmp(path_fcodes, "-"))
+ f_stdin = 1;
+ else
+ f_stdin = 0;
+
+#ifndef MMAP
+ f_mmap = 0; /* be paranoid */
+#endif
+ if (!f_mmap || f_stdin || f_statistic)
+ search_fopen(path_fcodes, argv);
+ else
+ search_mmap(path_fcodes, argv);
+ }
+
+ if (f_silent)
+ print_matches(counter);
+ exit(0);
+}
+
+
+void
+search_fopen(db, s)
+ char *db; /* database */
+ char **s; /* search strings */
+{
+ FILE *fp;
+#ifdef DEBUG
+ long t0;
+#endif
+
+ /* can only read stdin once */
+ if (f_stdin) {
+ fp = stdin;
+ if (*(s+1) != NULL) {
+ warnx("read database from stdin, use only `%s' as pattern", *s);
+ *(s+1) = NULL;
+ }
+ }
+#ifdef __APPLE__
+ else if ((fp = fopen(db, "r")) == NULL) {
+ if (errno == ENOENT && !strcmp(db, _PATH_FCODES)) {
+ fprintf(stderr, "\n"
+ "WARNING: The locate database (%s) does not exist.\n"
+ "To create the database, run the following command:\n"
+ "\n"
+ " sudo launchctl load -w /System/Library/LaunchDaemons/com.apple.locate.plist\n"
+ "\n"
+ "Please be aware that the database can take some time to generate; once\n"
+ "the database has been created, this message will no longer appear.\n"
+ "\n",
+ db);
+ exit(1);
+ }
+ err(1, "`%s'", db);
+ }
+#else /* !__APPLE__ */
+ else if ((fp = fopen(db, "r")) == NULL)
+ err(1, "`%s'", db);
+#endif /* __APPLE__ */
+
+ /* count only chars or lines */
+ if (f_statistic) {
+ statistic(fp, db);
+ (void)fclose(fp);
+ return;
+ }
+
+ /* foreach search string ... */
+ while(*s != NULL) {
+#ifdef DEBUG
+ t0 = cputime();
+#endif
+ if (!f_stdin &&
+ fseek(fp, (long)0, SEEK_SET) == -1)
+ err(1, "fseek to begin of ``%s''\n", db);
+
+ if (f_icase)
+ fastfind_icase(fp, *s, db);
+ else
+ fastfind(fp, *s, db);
+#ifdef DEBUG
+ warnx("fastfind %ld ms", cputime () - t0);
+#endif
+ s++;
+ }
+ (void)fclose(fp);
+}
+
+#ifdef MMAP
+void
+search_mmap(db, s)
+ char *db; /* database */
+ char **s; /* search strings */
+{
+ struct stat sb;
+ int fd;
+ caddr_t p;
+ off_t len;
+#ifdef DEBUG
+ long t0;
+#endif
+ if ((fd = open(db, O_RDONLY)) == -1 ||
+ fstat(fd, &sb) == -1)
+ err(1, "`%s'", db);
+ len = sb.st_size;
+
+ if ((p = mmap((caddr_t)0, (size_t)len,
+ PROT_READ, MAP_SHARED,
+ fd, (off_t)0)) == MAP_FAILED)
+ err(1, "mmap ``%s''", db);
+
+ /* foreach search string ... */
+ while (*s != NULL) {
+#ifdef DEBUG
+ t0 = cputime();
+#endif
+ if (f_icase)
+ fastfind_mmap_icase(*s, p, (int)len, db);
+ else
+ fastfind_mmap(*s, p, (int)len, db);
+#ifdef DEBUG
+ warnx("fastfind %ld ms", cputime () - t0);
+#endif
+ s++;
+ }
+
+ if (munmap(p, (size_t)len) == -1)
+ warn("munmap %s\n", db);
+
+ (void)close(fd);
+}
+#endif /* MMAP */
+
+#ifdef DEBUG
+unsigned long
+cputime ()
+{
+ struct rusage rus;
+
+ getrusage(0, &rus);
+ return(rus.ru_utime.tv_sec * 1000 + rus.ru_utime.tv_usec / 1000);
+}
+#endif /* DEBUG */
+
+void
+usage ()
+{
+ (void)fprintf(stderr,
+ "usage: locate [-0Scims] [-l limit] [-d database] pattern ...\n\n");
+ (void)fprintf(stderr,
+ "default database: `%s' or $LOCATE_PATH\n", _PATH_FCODES);
+ exit(1);
+}
+
+
+/* load fastfind functions */
+
+/* statistic */
+/* fastfind_mmap, fastfind_mmap_icase */
+#ifdef MMAP
+#undef FF_MMAP
+#undef FF_ICASE
+
+#define FF_MMAP
+#include "fastfind.c"
+#define FF_ICASE
+#include "fastfind.c"
+#endif /* MMAP */
+
+/* fopen */
+/* fastfind, fastfind_icase */
+#undef FF_MMAP
+#undef FF_ICASE
+#include "fastfind.c"
+#define FF_ICASE
+#include "fastfind.c"
diff --git a/shell_cmds/locate/locate/locate.h b/shell_cmds/locate/locate/locate.h
new file mode 100644
index 0000000..d4aef46
--- /dev/null
+++ b/shell_cmds/locate/locate/locate.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 1995 Wolfram Schneider <wosch@FreeBSD.org>. Berlin.
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)locate.h 8.1 (Berkeley) 6/6/93
+ * $FreeBSD: src/usr.bin/locate/locate/locate.h,v 1.7 1999/08/28 01:02:59 peter Exp $
+ */
+
+/* Symbolic constants shared by locate.c and code.c */
+
+#define NBG 128 /* number of bigrams considered */
+#define OFFSET 14 /* abs value of max likely diff */
+#define PARITY 0200 /* parity bit */
+#define SWITCH 30 /* switch code */
+#define UMLAUT 31 /* an 8 bit char followed */
+
+/* 0-28 likeliest differential counts + offset to make nonnegative */
+#define LDC_MIN 0
+#define LDC_MAX 28
+
+/* 128-255 bigram codes (128 most common, as determined by 'updatedb') */
+#define BIGRAM_MIN (UCHAR_MAX - CHAR_MAX)
+#define BIGRAM_MAX UCHAR_MAX
+
+/* 32-127 single character (printable) ascii residue (ie, literal) */
+#define ASCII_MIN 32
+#define ASCII_MAX CHAR_MAX
+
+/* #define TO7BIT(x) (x = ( ((u_char)x) & CHAR_MAX )) */
+#define TO7BIT(x) (x = x & CHAR_MAX )
+
+
+#if UCHAR_MAX >= 4096
+ define TOLOWER(ch) tolower(ch)
+#else
+
+#ifdef __APPLE__
+extern u_char myctype[UCHAR_MAX + 1];
+#else
+u_char myctype[UCHAR_MAX + 1];
+#endif
+#define TOLOWER(ch) (myctype[ch])
+#endif
+
+#define INTSIZE (sizeof(int))
+
+#define LOCATE_REG "*?[]\\" /* fnmatch(3) meta characters */
diff --git a/shell_cmds/locate/locate/locate.rc b/shell_cmds/locate/locate/locate.rc
new file mode 100644
index 0000000..09fbf0e
--- /dev/null
+++ b/shell_cmds/locate/locate/locate.rc
@@ -0,0 +1,26 @@
+#
+# /etc/locate.rc - command script for updatedb(8)
+#
+# $FreeBSD: src/usr.bin/locate/locate/locate.rc,v 1.9 2005/08/22 08:22:48 cperciva Exp $
+
+#
+# All commented values are the defaults
+#
+# temp directory
+#TMPDIR="/tmp"
+
+# the actual database
+#FCODES="/var/db/locate.database"
+
+# directories to be put in the database
+#SEARCHPATHS="/"
+
+# directories unwanted in output
+#PRUNEPATHS="/tmp /var/tmp"
+
+# filesystems allowed. Beware: a non-listed filesystem will be pruned
+# and if the SEARCHPATHS starts in such a filesystem locate will build
+# an empty database.
+#
+# be careful if you add 'nfs'
+#FILESYSTEMS="hfs ufs apfs"
diff --git a/shell_cmds/locate/locate/locate.updatedb.8 b/shell_cmds/locate/locate/locate.updatedb.8
new file mode 100755
index 0000000..880668a
--- /dev/null
+++ b/shell_cmds/locate/locate/locate.updatedb.8
@@ -0,0 +1,75 @@
+.\" Copyright (c) 1996
+.\" Mike Pritchard <mpp@FreeBSD.org>. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by Mike Pritchard.
+.\" 4. Neither the name of the author nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/usr.bin/locate/locate/locate.updatedb.8,v 1.12 2005/01/18 13:43:50 ru Exp $
+.\"
+.Dd February 11, 1996
+.Dt LOCATE.UPDATEDB 8
+.Os
+.Sh NAME
+.Nm locate.updatedb
+.Nd update locate database
+.Sh SYNOPSIS
+.Nm /usr/libexec/locate.updatedb
+.Sh DESCRIPTION
+The
+.Nm
+utility updates the database used by
+.Xr locate 1 .
+It is typically run once a week by the
+.Pa /System/Library/LaunchDaemons/com.apple.locate.plist
+job.
+.Pp
+The contents of the newly built database can be controlled by the
+.Pa /etc/locate.rc
+file.
+.Sh ENVIRONMENT
+.Bl -tag -width /var/db/locate.database -compact
+.It Pa LOCATE_CONFIG
+path to the configuration file
+.El
+.Sh FILES
+.Bl -tag -width /var/db/locate.database -compact
+.It Pa /var/db/locate.database
+the default database
+.It Pa /etc/locate.rc
+the configuration file
+.El
+.Sh SEE ALSO
+.Xr locate 1 ,
+.Xr launchd 8
+.Rs
+.%A Woods, James A.
+.%D 1983
+.%T "Finding Files Fast"
+.%J ";login"
+.%V 8:1
+.%P pp. 8-10
+.Re
diff --git a/shell_cmds/locate/locate/mklocatedb.sh b/shell_cmds/locate/locate/mklocatedb.sh
new file mode 100644
index 0000000..7231eba
--- /dev/null
+++ b/shell_cmds/locate/locate/mklocatedb.sh
@@ -0,0 +1,92 @@
+#!/bin/sh
+#
+# Copyright (c) September 1995 Wolfram Schneider <wosch@FreeBSD.org>. Berlin.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# mklocatedb - build locate database
+#
+# usage: mklocatedb [-presort] < filelist > database
+#
+# $FreeBSD: src/usr.bin/locate/locate/mklocatedb.sh,v 1.13 2002/07/22 05:35:59 tjr Exp $
+
+# The directory containing locate subprograms
+: ${LIBEXECDIR:=/usr/libexec}; export LIBEXECDIR
+
+PATH=$LIBEXECDIR:/bin:/usr/bin:$PATH; export PATH
+
+umask 077 # protect temp files
+
+: ${TMPDIR:=/tmp}; export TMPDIR
+test -d "$TMPDIR" || TMPDIR=/tmp
+if ! TMPDIR=`mktemp -d $TMPDIR/mklocateXXXXXXXXXX`; then
+ exit 1
+fi
+
+
+# utilities to built locate database
+: ${bigram:=locate.bigram}
+: ${code:=locate.code}
+: ${sort:=sort}
+
+
+sortopt="-u -T $TMPDIR"
+sortcmd=$sort
+
+
+bigrams=$TMPDIR/_mklocatedb$$.bigrams
+filelist=$TMPDIR/_mklocatedb$$.list
+
+trap 'rm -f $bigrams $filelist; rmdir $TMPDIR' 0 1 2 3 5 10 15
+
+
+# Input already sorted
+if [ X"$1" = "X-presort" ]; then
+ shift;
+
+ # create an empty file
+ true > $bigrams
+
+ # Locate database bootstrapping
+ # 1. first build a temp database without bigram compression
+ # 2. create the bigram from the temp database
+ # 3. create the real locate database with bigram compression.
+ #
+ # This scheme avoid large temporary files in /tmp
+
+ $code $bigrams > $filelist || exit 1
+ locate -d $filelist / | $bigram | $sort -nr | head -128 |
+ awk '{if (/^[ ]*[0-9]+[ ]+..$/) {printf("%s",$2)} else {exit 1}}' > $bigrams || exit 1
+ locate -d $filelist / | $code $bigrams || exit 1
+ exit
+
+else
+ if $sortcmd $sortopt > $filelist; then
+ $bigram < $filelist | $sort -nr |
+ awk '{if (/^[ ]*[0-9]+[ ]+..$/) {printf("%s",$2)} else {exit 1}}' > $bigrams || exit 1
+ $code $bigrams < $filelist || exit 1
+ else
+ echo "`basename $0`: cannot build locate database" >&2
+ exit 1
+ fi
+fi
diff --git a/shell_cmds/locate/locate/pathnames.h b/shell_cmds/locate/locate/pathnames.h
new file mode 100644
index 0000000..8fb0e8c
--- /dev/null
+++ b/shell_cmds/locate/locate/pathnames.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)pathnames.h 8.1 (Berkeley) 6/6/93
+ */
+
+#define _PATH_FCODES "/var/db/locate.database"
diff --git a/shell_cmds/locate/locate/updatedb.sh b/shell_cmds/locate/locate/updatedb.sh
new file mode 100644
index 0000000..2506f22
--- /dev/null
+++ b/shell_cmds/locate/locate/updatedb.sh
@@ -0,0 +1,106 @@
+#!/bin/sh
+#
+# Copyright (c) September 1995 Wolfram Schneider <wosch@FreeBSD.org>. Berlin.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# updatedb - update locate database for local mounted filesystems
+#
+# $FreeBSD: src/usr.bin/locate/locate/updatedb.sh,v 1.20 2005/11/12 12:45:08 grog Exp $
+
+if [ "$(id -u)" = "0" ]; then
+ rc=0
+ export FCODES=`sudo -u nobody mktemp -t updatedb`
+ chown nobody $FCODES
+ tmpdb=`su -fm nobody -c "$0"` || rc=1
+ if [ $rc = 0 ]; then
+ install -m 0444 -o nobody -g wheel $FCODES /var/db/locate.database
+ fi
+ rm $FCODES
+ exit $rc
+fi
+: ${LOCATE_CONFIG="/etc/locate.rc"}
+if [ -f "$LOCATE_CONFIG" -a -r "$LOCATE_CONFIG" ]; then
+ . $LOCATE_CONFIG
+fi
+
+# The directory containing locate subprograms
+: ${LIBEXECDIR:=/usr/libexec}; export LIBEXECDIR
+: ${TMPDIR:=/tmp}; export TMPDIR
+if ! TMPDIR=`mktemp -d $TMPDIR/locateXXXXXXXXXX`; then
+ exit 1
+fi
+
+PATH=$LIBEXECDIR:/bin:/usr/bin:$PATH; export PATH
+
+# 6497475
+set -o noglob
+
+: ${mklocatedb:=locate.mklocatedb} # make locate database program
+: ${FCODES:=/var/db/locate.database} # the database
+: ${SEARCHPATHS:="/"} # directories to be put in the database
+: ${PRUNEPATHS:="/private/tmp /private/var/folders /private/var/tmp */Backups.backupdb"} # unwanted directories
+: ${FILESYSTEMS:="hfs ufs apfs"} # allowed filesystems
+: ${find:=find}
+
+case X"$SEARCHPATHS" in
+ X) echo "$0: empty variable SEARCHPATHS"; exit 1;; esac
+case X"$FILESYSTEMS" in
+ X) echo "$0: empty variable FILESYSTEMS"; exit 1;; esac
+
+# Make a list a paths to exclude in the locate run
+excludes="! (" or=""
+for fstype in $FILESYSTEMS
+do
+ excludes="$excludes $or -fstype $fstype"
+ or="-or"
+done
+excludes="$excludes ) -prune"
+
+case X"$PRUNEPATHS" in
+ X) ;;
+ *) for path in $PRUNEPATHS
+ do
+ excludes="$excludes -or -path $path -prune"
+ done;;
+esac
+
+# Ignore the target of firmlinks
+while read firmlink; do
+ excludes="$excludes -or -path $firmlink -prune"
+done <<< "$(awk -F'\t' '{print "/System/Volumes/Data/" $2}' /usr/share/firmlinks)"
+
+tmp=$TMPDIR/_updatedb$$
+trap 'rm -f $tmp; rmdir $TMPDIR; exit' 0 1 2 3 5 10 15
+
+# search locally
+# echo $find $SEARCHPATHS $excludes -or -print && exit
+if $find -s $SEARCHPATHS $excludes -or -print 2>/dev/null |
+ $mklocatedb -presort > $tmp
+then
+ case X"`$find $tmp -size -257c -print`" in
+ X) cat $tmp > $FCODES;;
+ *) echo "updatedb: locate database $tmp is empty"
+ exit 1
+ esac
+fi
diff --git a/shell_cmds/locate/locate/util.c b/shell_cmds/locate/locate/util.c
new file mode 100644
index 0000000..0a94c9c
--- /dev/null
+++ b/shell_cmds/locate/locate/util.c
@@ -0,0 +1,278 @@
+/*
+ * Copyright (c) 1995 Wolfram Schneider <wosch@FreeBSD.org>. Berlin.
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * James A. Woods.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/usr.bin/locate/locate/util.c,v 1.10 2002/06/24 12:40:11 naddy Exp $
+ */
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <err.h>
+#include <sys/param.h>
+#include <arpa/inet.h>
+#include <stdio.h>
+
+#include "locate.h"
+
+char **colon(char **, char*, char*);
+char *patprep(char *);
+void print_matches(u_int);
+u_char *tolower_word(u_char *);
+int getwm(caddr_t);
+int getwf(FILE *);
+int check_bigram_char(int);
+
+/*
+ * Validate bigram chars. If the test failed the database is corrupt
+ * or the database is obviously not a locate database.
+ */
+int
+check_bigram_char(ch)
+ int ch;
+{
+ /* legal bigram: 0, ASCII_MIN ... ASCII_MAX */
+ if (ch == 0 ||
+ (ch >= ASCII_MIN && ch <= ASCII_MAX))
+ return(ch);
+
+ errx(1,
+ "locate database header corrupt, bigram char outside 0, %d-%d: %d",
+ ASCII_MIN, ASCII_MAX, ch);
+ exit(1);
+}
+
+/* split a colon separated string into a char vector
+ *
+ * "bla:foo" -> {"foo", "bla"}
+ * "bla:" -> {"foo", dot}
+ * "bla" -> {"bla"}
+ * "" -> do nothing
+ *
+ */
+char **
+colon(dbv, path, dot)
+ char **dbv;
+ char *path;
+ char *dot; /* default for single ':' */
+{
+ int vlen, slen;
+ char *c, *ch, *p;
+ char **pv;
+
+ if (dbv == NULL) {
+ if ((dbv = malloc(sizeof(char **))) == NULL)
+ err(1, "malloc");
+ *dbv = NULL;
+ }
+
+ /* empty string */
+ if (*path == '\0') {
+ warnx("empty database name, ignored");
+ return(dbv);
+ }
+
+ /* length of string vector */
+ for(vlen = 0, pv = dbv; *pv != NULL; pv++, vlen++);
+
+ for (ch = c = path; ; ch++) {
+ if (*ch == ':' ||
+ (!*ch && !(*(ch - 1) == ':' && ch == 1+ path))) {
+ /* single colon -> dot */
+ if (ch == c)
+ p = dot;
+ else {
+ /* a string */
+ slen = ch - c;
+ if ((p = malloc(sizeof(char) * (slen + 1)))
+ == NULL)
+ err(1, "malloc");
+ bcopy(c, p, slen);
+ *(p + slen) = '\0';
+ }
+ /* increase dbv with element p */
+ if ((dbv = realloc(dbv, sizeof(char **) * (vlen + 2)))
+ == NULL)
+ err(1, "realloc");
+ *(dbv + vlen) = p;
+ *(dbv + ++vlen) = NULL;
+ c = ch + 1;
+ }
+ if (*ch == '\0')
+ break;
+ }
+ return (dbv);
+}
+
+void
+print_matches(counter)
+ u_int counter;
+{
+ (void)printf("%d\n", counter);
+}
+
+
+/*
+ * extract last glob-free subpattern in name for fast pre-match; prepend
+ * '\0' for backwards match; return end of new pattern
+ */
+static char globfree[100];
+
+char *
+patprep(name)
+ char *name;
+{
+ register char *endmark, *p, *subp;
+
+ subp = globfree;
+ *subp++ = '\0'; /* set first element to '\0' */
+ p = name + strlen(name) - 1;
+
+ /* skip trailing metacharacters */
+ for (; p >= name; p--)
+ if (index(LOCATE_REG, *p) == NULL)
+ break;
+
+ /*
+ * check if maybe we are in a character class
+ *
+ * 'foo.[ch]'
+ * |----< p
+ */
+ if (p >= name &&
+ (index(p, '[') != NULL || index(p, ']') != NULL)) {
+ for (p = name; *p != '\0'; p++)
+ if (*p == ']' || *p == '[')
+ break;
+ p--;
+
+ /*
+ * cannot find a non-meta character, give up
+ * '*\*[a-z]'
+ * |-------< p
+ */
+ if (p >= name && index(LOCATE_REG, *p) != NULL)
+ p = name - 1;
+ }
+
+ if (p < name)
+ /* only meta chars: "???", force '/' search */
+ *subp++ = '/';
+
+ else {
+ for (endmark = p; p >= name; p--)
+ if (index(LOCATE_REG, *p) != NULL)
+ break;
+ for (++p;
+ (p <= endmark) && subp < (globfree + sizeof(globfree));)
+ *subp++ = *p++;
+ }
+ *subp = '\0';
+ return(--subp);
+}
+
+/* tolower word */
+u_char *
+tolower_word(word)
+ u_char *word;
+{
+ register u_char *p;
+
+ for(p = word; *p != '\0'; p++)
+ *p = TOLOWER(*p);
+
+ return(word);
+}
+
+
+/*
+ * Read integer from mmap pointer.
+ * Essential a simple ``return *(int *)p'' but avoid sigbus
+ * for integer alignment (SunOS 4.x, 5.x).
+ *
+ * Convert network byte order to host byte order if neccessary.
+ * So we can read on FreeBSD/i386 (little endian) a locate database
+ * which was built on SunOS/sparc (big endian).
+ */
+
+int
+getwm(p)
+ caddr_t p;
+{
+ union {
+ char buf[INTSIZE];
+ int i;
+ } u;
+ register int i;
+
+ for (i = 0; i < INTSIZE; i++)
+ u.buf[i] = *p++;
+
+ i = u.i;
+
+ if (i > MAXPATHLEN || i < -(MAXPATHLEN)) {
+ i = ntohl(i);
+ if (i > MAXPATHLEN || i < -(MAXPATHLEN))
+ errx(1, "integer out of +-MAXPATHLEN (%d): %d",
+ MAXPATHLEN, abs(i) < abs(htonl(i)) ? i : htonl(i));
+ }
+ return(i);
+}
+
+/*
+ * Read integer from stream.
+ *
+ * Convert network byte order to host byte order if neccessary.
+ * So we can read on FreeBSD/i386 (little endian) a locate database
+ * which was built on SunOS/sparc (big endian).
+ */
+
+int
+getwf(fp)
+ FILE *fp;
+{
+ register int word;
+
+ word = getw(fp);
+
+ if (word > MAXPATHLEN || word < -(MAXPATHLEN)) {
+ word = ntohl(word);
+ if (word > MAXPATHLEN || word < -(MAXPATHLEN))
+ errx(1, "integer out of +-MAXPATHLEN (%d): %d",
+ MAXPATHLEN, abs(word) < abs(htonl(word)) ? word :
+ htonl(word));
+ }
+ return(word);
+}
diff --git a/shell_cmds/logname/logname.1 b/shell_cmds/logname/logname.1
new file mode 100644
index 0000000..4d2a508
--- /dev/null
+++ b/shell_cmds/logname/logname.1
@@ -0,0 +1,78 @@
+.\" $NetBSD: logname.1,v 1.8 1997/10/19 04:20:06 lukem Exp $
+.\"
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)logname.1 8.1 (Berkeley) 6/9/93
+.\"
+.Dd June 9, 1993
+.Dt LOGNAME 1
+.Os BSD 4.4
+.Sh NAME
+.Nm logname
+.Nd display user's login name
+.Sh SYNOPSIS
+.Nm
+.Sh DESCRIPTION
+The
+.Nm
+utility writes the user's login name to standard output followed by
+a newline.
+.Pp
+The
+.Nm
+utility explicitly ignores the
+.Ev LOGNAME
+and
+.Ev USER
+environment variables
+because the environment cannot be trusted.
+.Pp
+The
+.Nm
+utility exits 0 on success, and >0 if an error occurs.
+.Sh SEE ALSO
+.Xr who 1 ,
+.Xr whoami 1 ,
+.Xr getlogin 2
+.Sh STANDARDS
+The
+.Nm
+utility conforms to
+.St -p1003.2-92 .
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.4 .
diff --git a/shell_cmds/logname/logname.c b/shell_cmds/logname/logname.c
new file mode 100644
index 0000000..ed63ffe
--- /dev/null
+++ b/shell_cmds/logname/logname.c
@@ -0,0 +1,92 @@
+/* $NetBSD: logname.c,v 1.7 1997/10/19 04:20:06 lukem Exp $ */
+
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1991, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)logname.c 8.2 (Berkeley) 4/3/94";
+#endif
+__RCSID("$NetBSD: logname.c,v 1.7 1997/10/19 04:20:06 lukem Exp $");
+#endif /* not lint */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <locale.h>
+#include <unistd.h>
+#include <err.h>
+
+int main __P((int, char **));
+void usage __P((void));
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int ch;
+ char *p;
+
+ setlocale(LC_ALL, "");
+
+ while ((ch = getopt(argc, argv, "")) != -1)
+ switch (ch) {
+ case '?':
+ default:
+ usage();
+ /* NOTREACHED */
+ }
+
+ if (argc != optind) {
+ usage();
+ /* NOTREACHED */
+ }
+
+ if ((p = getlogin()) == NULL)
+ err(1, "getlogin");
+ (void)printf("%s\n", p);
+ exit(0);
+}
+
+void
+usage()
+{
+ (void)fprintf(stderr, "usage: logname\n");
+ exit(1);
+}
diff --git a/shell_cmds/mktemp/mktemp.1 b/shell_cmds/mktemp/mktemp.1
new file mode 100644
index 0000000..921ffa3
--- /dev/null
+++ b/shell_cmds/mktemp/mktemp.1
@@ -0,0 +1,215 @@
+.\" Copyright (c) 1989, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" From: $OpenBSD: mktemp.1,v 1.8 1998/03/19 06:13:37 millert Exp $
+.\" $FreeBSD$
+.\"
+.Dd December 30, 2005
+.Dt MKTEMP 1
+.Os
+.Sh NAME
+.Nm mktemp
+.Nd make temporary file name (unique)
+.Sh SYNOPSIS
+.Nm
+.Op Fl d
+.Op Fl q
+.Op Fl t Ar prefix
+.Op Fl u
+.Ar template ...
+.Nm
+.Op Fl d
+.Op Fl q
+.Op Fl u
+.Fl t Ar prefix
+.Sh DESCRIPTION
+The
+.Nm
+utility takes each of the given file name templates and overwrites a
+portion of it to create a file name.
+This file name is unique
+and suitable for use by the application.
+The template may be
+any file name with some number of
+.Ql X Ns s
+appended
+to it, for example
+.Pa /tmp/temp.XXXX .
+The trailing
+.Ql X Ns s
+are replaced with the current process number and/or a
+unique letter combination.
+The number of unique file names
+.Nm
+can return depends on the number of
+.Ql X Ns s
+provided; six
+.Ql X Ns s
+will
+result in
+.Nm
+selecting 1 of 56800235584 (62 ** 6) possible file names.
+On case-insensitive file systems, the effective number of unique
+names is significantly less; given six
+.Ql X Ns s ,
+.Nm
+will instead select 1 of 2176782336 (36 ** 6) possible unique file names.
+.Pp
+If
+.Nm
+can successfully generate a unique file name, the file
+is created with mode 0600 (unless the
+.Fl u
+flag is given) and the filename is printed
+to standard output.
+.Pp
+If the
+.Fl t Ar prefix
+option is given,
+.Nm
+will generate a template string based on the
+.Ar prefix
+and the
+.Dv _CS_DARWIN_USER_TEMP_DIR
+configuration variable if available.
+Fallback locations if
+.Dv _CS_DARWIN_USER_TEMP_DIR
+is not available are
+.Ev TMPDIR
+and
+.Pa /tmp .
+Care should
+be taken to ensure that it is appropriate to use an environment variable
+potentially supplied by the user.
+.Pp
+If no arguments are passed or if only the
+.Fl d
+flag is passed
+.Nm
+behaves as if
+.Fl t Li tmp
+was supplied.
+.Pp
+Any number of temporary files may be created in a single invocation,
+including one based on the internal template resulting from the
+.Fl t
+flag.
+.Pp
+The
+.Nm
+utility is provided to allow shell scripts to safely use temporary files.
+Traditionally, many shell scripts take the name of the program with
+the pid as a suffix and use that as a temporary file name.
+This
+kind of naming scheme is predictable and the race condition it creates
+is easy for an attacker to win.
+A safer, though still inferior, approach
+is to make a temporary directory using the same naming scheme.
+While
+this does allow one to guarantee that a temporary file will not be
+subverted, it still allows a simple denial of service attack.
+For these
+reasons it is suggested that
+.Nm
+be used instead.
+.Sh OPTIONS
+The available options are as follows:
+.Bl -tag -width indent
+.It Fl d
+Make a directory instead of a file.
+.It Fl q
+Fail silently if an error occurs.
+This is useful if
+a script does not want error output to go to standard error.
+.It Fl t Ar prefix
+Generate a template (using the supplied
+.Ar prefix
+and
+.Ev TMPDIR
+if set) to create a filename template.
+.It Fl u
+Operate in
+.Dq unsafe
+mode.
+The temp file will be unlinked before
+.Nm
+exits.
+This is slightly better than
+.Xr mktemp 3
+but still introduces a race condition.
+Use of this
+option is not encouraged.
+.El
+.Sh EXIT STATUS
+.Ex -std
+.Sh EXAMPLES
+The following
+.Xr sh 1
+fragment illustrates a simple use of
+.Nm
+where the script should quit if it cannot get a safe
+temporary file.
+.Bd -literal -offset indent
+tempfoo=`basename $0`
+TMPFILE=`mktemp /tmp/${tempfoo}.XXXXXX` || exit 1
+echo "program output" >> $TMPFILE
+.Ed
+.Pp
+To allow the use of $TMPDIR:
+.Bd -literal -offset indent
+tempfoo=`basename $0`
+TMPFILE=`mktemp -t ${tempfoo}` || exit 1
+echo "program output" >> $TMPFILE
+.Ed
+.Pp
+In this case, we want the script to catch the error itself.
+.Bd -literal -offset indent
+tempfoo=`basename $0`
+TMPFILE=`mktemp -q /tmp/${tempfoo}.XXXXXX`
+if [ $? -ne 0 ]; then
+ echo "$0: Can't create temp file, exiting..."
+ exit 1
+fi
+.Ed
+.Sh SEE ALSO
+.Xr mkdtemp 3 ,
+.Xr mkstemp 3 ,
+.Xr mktemp 3 ,
+.Xr confstr 3 ,
+.Xr environ 7
+.Sh HISTORY
+A
+.Nm
+utility appeared in
+.Ox 2.1 .
+This implementation was written independently based on the
+.Ox
+man page, and
+first appeared in
+.Fx 2.2.7 .
+This man page is taken from
+.Ox .
diff --git a/shell_cmds/mktemp/mktemp.c b/shell_cmds/mktemp/mktemp.c
new file mode 100644
index 0000000..11db17e
--- /dev/null
+++ b/shell_cmds/mktemp/mktemp.c
@@ -0,0 +1,182 @@
+/*-
+ * Copyright (c) 1994, 1995, 1996, 1998 Peter Wemm <peter@netplex.com.au>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+/*
+ * This program was originally written long ago, originally for a non
+ * BSD-like OS without mkstemp(). It's been modified over the years
+ * to use mkstemp() rather than the original O_CREAT|O_EXCL/fstat/lstat
+ * etc style hacks.
+ * A cleanup, misc options and mkdtemp() calls were added to try and work
+ * more like the OpenBSD version - which was first to publish the interface.
+ */
+
+#include <err.h>
+#ifdef __APPLE__
+#include <limits.h>
+#endif
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifndef lint
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif /* not lint */
+
+static void usage(void);
+
+int
+main(int argc, char **argv)
+{
+ int c, fd, ret;
+ char *tmpdir;
+ const char *prefix;
+ char *name;
+ int dflag, qflag, tflag, uflag;
+#ifdef __APPLE__
+ char tmpbuf[PATH_MAX];
+ size_t len;
+#endif
+
+ ret = dflag = qflag = tflag = uflag = 0;
+ prefix = "mktemp";
+ name = NULL;
+
+ while ((c = getopt(argc, argv, "dqt:u")) != -1)
+ switch (c) {
+ case 'd':
+ dflag++;
+ break;
+
+ case 'q':
+ qflag++;
+ break;
+
+ case 't':
+ prefix = optarg;
+ tflag++;
+ break;
+
+ case 'u':
+ uflag++;
+ break;
+
+ default:
+ usage();
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (!tflag && argc < 1) {
+ tflag = 1;
+ prefix = "tmp";
+ }
+
+ if (tflag) {
+#ifdef __APPLE__
+ if (confstr(_CS_DARWIN_USER_TEMP_DIR, tmpbuf, sizeof(tmpbuf)) > 0) {
+ tmpdir = tmpbuf;
+ } else {
+ tmpdir = getenv("TMPDIR");
+ }
+
+ if (tmpdir == NULL) {
+ tmpdir = _PATH_TMP;
+ }
+
+ len = strlen(tmpdir);
+ if (len > 0 && tmpdir[len - 1] == '/') {
+ asprintf(&name, "%s%s.XXXXXXXX", tmpdir, prefix);
+ } else {
+ asprintf(&name, "%s/%s.XXXXXXXX", tmpdir, prefix);
+ }
+#else
+ tmpdir = getenv("TMPDIR");
+ if (tmpdir == NULL)
+ asprintf(&name, "%s%s.XXXXXXXX", _PATH_TMP, prefix);
+ else
+ asprintf(&name, "%s/%s.XXXXXXXX", tmpdir, prefix);
+#endif
+ /* if this fails, the program is in big trouble already */
+ if (name == NULL) {
+ if (qflag)
+ return (1);
+ else
+ errx(1, "cannot generate template");
+ }
+ }
+
+ /* generate all requested files */
+ while (name != NULL || argc > 0) {
+ if (name == NULL) {
+ name = strdup(argv[0]);
+ argv++;
+ argc--;
+ }
+
+ if (dflag) {
+ if (mkdtemp(name) == NULL) {
+ ret = 1;
+ if (!qflag)
+ warn("mkdtemp failed on %s", name);
+ } else {
+ printf("%s\n", name);
+ if (uflag)
+ rmdir(name);
+ }
+ } else {
+ fd = mkstemp(name);
+ if (fd < 0) {
+ ret = 1;
+ if (!qflag)
+ warn("mkstemp failed on %s", name);
+ } else {
+ close(fd);
+ if (uflag)
+ unlink(name);
+ printf("%s\n", name);
+ }
+ }
+ if (name)
+ free(name);
+ name = NULL;
+ }
+ return (ret);
+}
+
+static void
+usage(void)
+{
+ fprintf(stderr,
+ "usage: mktemp [-d] [-q] [-t prefix] [-u] template ...\n");
+ fprintf(stderr,
+ " mktemp [-d] [-q] [-u] -t prefix \n");
+ exit (1);
+}
diff --git a/shell_cmds/mktemp/mktemp.plist.part b/shell_cmds/mktemp/mktemp.plist.part
new file mode 100644
index 0000000..db10919
--- /dev/null
+++ b/shell_cmds/mktemp/mktemp.plist.part
@@ -0,0 +1,21 @@
+ <dict>
+ <key>OpenSourceProject</key>
+ <string>mktemp</string>
+ <key>OpenSourceVersion</key>
+ <string>2012-11-18</string>
+ <key>OpenSourceWebsiteURL</key>
+ <string>http://svnweb.freebsd.org/base/head/usr.bin/mktemp/</string>
+ <key>OpenSourceSCM</key>
+ <string>svn co http://svn.freebsd.org/base/head/usr.bin/mktemp/</string>
+ <key>OpenSourceImportDate</key>
+ <string>2014-08-11</string>
+ <key>OpenSourceModifications</key>
+ <array>
+ <string>Avoid double-slash in output. (5334050)</string>
+ <string>Document case-insensitive file system behavior. (14280248)</string>
+ <string>Prefer _CS_DARWIN_USER_TEMP_DIR over TMPDIR and _PATH_TMP. (14338140)</string>
+ <string>mktemp.1: Clarification of _CS_DARWIN_USER_TEMP_DIR/TMPDIR/_PATH_TMP behavior. (22954705)</string>
+ </array>
+ <key>OpenSourceLicense</key>
+ <string>bsd</string>
+ </dict>
diff --git a/shell_cmds/nice/nice.1 b/shell_cmds/nice/nice.1
new file mode 100644
index 0000000..4dba5c9
--- /dev/null
+++ b/shell_cmds/nice/nice.1
@@ -0,0 +1,120 @@
+.\" $NetBSD: nice.1,v 1.8 1997/10/19 06:28:02 lukem Exp $
+.\"
+.\" Copyright (c) 1980, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)nice.1 8.1 (Berkeley) 6/6/93
+.\"
+.Dd June 6, 1993
+.Dt NICE 1
+.Os
+.Sh NAME
+.Nm nice
+.Nd execute a utility with an altered scheduling priority
+.Sh SYNOPSIS
+.Nm
+.Op Fl n Ar increment
+.Ar utility
+.Op Ar argument ...
+.Sh DESCRIPTION
+.Nm
+runs
+.Ar utility
+at an altered scheduling priority.
+If an
+.Ar increment
+is given, it is used; otherwise
+an increment of 10 is assumed.
+The super-user can run utilities with priorities higher than normal by using
+a negative
+.Ar increment .
+The priority can be adjusted over a
+range of -20 (the highest) to 20 (the lowest).
+.Pp
+Available options:
+.Bl -tag -width indent
+.It Fl n Ar increment
+A positive or negative decimal integer used to modify the system scheduling
+priority of
+.Ar utility.
+.El
+.Sh DIAGNOSTICS
+The
+.Nm
+utility shall exit with one of the following values:
+.Bl -tag -width indent
+.It 1-125
+An error occurred in the
+.Nm
+utility.
+.It 126
+The
+.Ar utility
+was found but could not be invoked.
+.It 127
+The
+.Ar utility
+could not be found.
+.El
+.Pp
+Otherwise, the exit status of
+.Nm
+shall be that of
+.Ar utility .
+.Sh COMPATIBILITY
+The historic
+.Fl Ns Ar increment
+option has been deprecated but is still supported in this implementation.
+.Sh SEE ALSO
+.Xr csh 1 ,
+.Xr getpriority 2 ,
+.Xr setpriority 2 ,
+.Xr renice 8
+.Sh STANDARDS
+The
+.Nm
+utility conforms to
+.St -p1003.2-92 .
+.Sh HISTORY
+A
+.Nm
+utility appeared in
+.At v6 .
+.Sh BUGS
+.Nm
+is built into
+.Xr csh 1
+with a slightly different syntax than described here. The form
+.Ql nice +10
+nices to positive nice, and
+.Ql nice \-10
+can be used
+by the super-user to give a process more of the processor.
diff --git a/shell_cmds/nice/nice.c b/shell_cmds/nice/nice.c
new file mode 100644
index 0000000..62a197e
--- /dev/null
+++ b/shell_cmds/nice/nice.c
@@ -0,0 +1,122 @@
+/* $NetBSD: nice.c,v 1.10 1997/10/19 06:28:04 lukem Exp $ */
+
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT(
+ "@(#) Copyright (c) 1989 The Regents of the University of California.\n\
+ All rights reserved.\n");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)nice.c 5.4 (Berkeley) 6/1/90";
+#endif
+__RCSID("$NetBSD: nice.c,v 1.10 1997/10/19 06:28:04 lukem Exp $");
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <locale.h>
+#include <ctype.h>
+#include <errno.h>
+#include <err.h>
+#include <unistd.h>
+
+#define DEFNICE 10
+
+int main __P((int, char **));
+static void usage __P((void));
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ int niceness = DEFNICE;
+ int c;
+
+ setlocale(LC_ALL, "");
+
+ /* handle obsolete -number syntax */
+ if (argc > 1 && argv[1][0] == '-' && isdigit(argv[1][1])) {
+ niceness = atoi (argv[1] + 1);
+ argc--; argv++;
+ }
+
+ while ((c = getopt (argc, argv, "n:")) != -1) {
+ switch (c) {
+ case 'n':
+ niceness = atoi (optarg);
+ break;
+
+ case '?':
+ default:
+ usage();
+ break;
+ }
+ }
+ argc -= optind; argv += optind;
+
+ if (argc == 0)
+ usage();
+
+ errno = 0;
+ niceness += getpriority(PRIO_PROCESS, 0);
+ if (errno) {
+ err (1, "getpriority");
+ /* NOTREACHED */
+ }
+ if (setpriority(PRIO_PROCESS, 0, niceness)) {
+ warn ("setpriority");
+ }
+
+ execvp(argv[0], &argv[0]);
+ err ((errno == ENOENT) ? 127 : 126, "%s", argv[0]);
+ /* NOTREACHED */
+}
+
+static void
+usage()
+{
+ (void)fprintf(stderr,
+ "usage: nice [ -n increment ] utility [ argument ...]\n");
+
+ exit(1);
+}
diff --git a/shell_cmds/nohup/nohup.1 b/shell_cmds/nohup/nohup.1
new file mode 100644
index 0000000..34f19e6
--- /dev/null
+++ b/shell_cmds/nohup/nohup.1
@@ -0,0 +1,124 @@
+.\" Copyright (c) 1989, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)nohup.1 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD: src/usr.bin/nohup/nohup.1,v 1.13 2005/01/17 07:44:27 ru Exp $
+.\"
+.Dd July 19, 2001
+.Dt NOHUP 1
+.Os
+.Sh NAME
+.Nm nohup
+.Nd invoke a utility immune to hangups
+.Sh SYNOPSIS
+.Nm
+.Op Fl Fl
+.Ar utility
+.Op Ar arguments
+.Sh DESCRIPTION
+The
+.Nm
+utility invokes
+.Ar utility
+with its
+.Ar arguments
+and at this time sets the signal
+.Dv SIGHUP
+to be ignored.
+If the standard output is a terminal, the standard output is
+appended to the file
+.Pa nohup.out
+in the current directory.
+If standard error is a terminal, it is directed to the same place
+as the standard output.
+.Pp
+Some shells may provide a builtin
+.Nm
+command which is similar or identical to this utility.
+Consult the
+.Xr builtin 1
+manual page.
+.Sh ENVIRONMENT
+The following variables are utilized by
+.Nm :
+.Bl -tag -width flag
+.It Ev HOME
+If the output file
+.Pa nohup.out
+cannot be created in the current directory, the
+.Nm
+utility uses the directory named by
+.Ev HOME
+to create the file.
+.It Ev PATH
+Used to locate the requested
+.Ar utility
+if the name contains no
+.Ql /
+characters.
+.El
+.Sh EXIT STATUS
+The
+.Nm
+utility exits with one of the following values:
+.Bl -tag -width Ds
+.It 126
+The
+.Ar utility
+was found, but could not be invoked.
+.It 127
+The
+.Ar utility
+could not be found or an error occurred in
+.Nm .
+.El
+.Pp
+Otherwise, the exit status of
+.Nm
+will be that of
+.Ar utility .
+.Sh SEE ALSO
+.Xr builtin 1 ,
+.Xr csh 1 ,
+.Xr signal 3
+.Sh STANDARDS
+The
+.Nm
+utility is expected to be
+.St -p1003.2
+compatible.
+.Sh BUGS
+Two or more instances of
+.Nm
+can append to the same file, which makes for a confusing output.
diff --git a/shell_cmds/nohup/nohup.c b/shell_cmds/nohup/nohup.c
new file mode 100644
index 0000000..021361c
--- /dev/null
+++ b/shell_cmds/nohup/nohup.c
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Portions copyright (c) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1989, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)nohup.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+#endif
+#include <sys/cdefs.h>
+#ifndef __APPLE__
+__FBSDID("$FreeBSD: src/usr.bin/nohup/nohup.c,v 1.10 2003/05/03 19:44:46 obrien Exp $");
+#endif
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifdef __APPLE__
+#include <TargetConditionals.h>
+#include <vproc.h>
+#include <vproc_priv.h>
+#endif
+
+static void dofile(void);
+static void usage(void);
+
+#define FILENAME "nohup.out"
+/*
+ * POSIX mandates that we exit with:
+ * 126 - If the utility was found, but failed to execute.
+ * 127 - If any other error occurred.
+ */
+#define EXIT_NOEXEC 126
+#define EXIT_NOTFOUND 127
+#define EXIT_MISC 127
+
+int
+main(int argc, char *argv[])
+{
+ int exit_status;
+
+ while (getopt(argc, argv, "") != -1)
+ usage();
+ argc -= optind;
+ argv += optind;
+ if (argc < 1)
+ usage();
+
+ if (isatty(STDOUT_FILENO))
+ dofile();
+ if (isatty(STDERR_FILENO) && dup2(STDOUT_FILENO, STDERR_FILENO) == -1)
+ /* may have just closed stderr */
+ err(EXIT_MISC, "%s", argv[0]);
+
+ (void)signal(SIGHUP, SIG_IGN);
+
+#if defined(__APPLE__) && !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+ if (_vprocmgr_detach_from_console(0) != NULL)
+ err(EXIT_MISC, "can't detach from console");
+#endif
+ execvp(*argv, argv);
+ exit_status = (errno == ENOENT) ? EXIT_NOTFOUND : EXIT_NOEXEC;
+ err(exit_status, "%s", argv[0]);
+}
+
+static void
+dofile(void)
+{
+ int fd;
+ char path[MAXPATHLEN];
+ const char *p;
+
+ /*
+ * POSIX mandates if the standard output is a terminal, the standard
+ * output is appended to nohup.out in the working directory. Failing
+ * that, it will be appended to nohup.out in the directory obtained
+ * from the HOME environment variable. If file creation is required,
+ * the mode_t is set to S_IRUSR | S_IWUSR.
+ */
+ p = FILENAME;
+ fd = open(p, O_RDWR | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
+ if (fd != -1)
+ goto dupit;
+ if ((p = getenv("HOME")) != NULL && *p != '\0' &&
+ (size_t)snprintf(path, sizeof(path), "%s/%s", p, FILENAME) <
+ sizeof(path)) {
+ fd = open(p = path, O_RDWR | O_CREAT | O_APPEND,
+ S_IRUSR | S_IWUSR);
+ if (fd != -1)
+ goto dupit;
+ }
+ errx(EXIT_MISC, "can't open a nohup.out file");
+
+dupit:
+#ifdef __APPLE__
+ (void)lseek(fd, 0L, SEEK_END);
+#endif
+ if (dup2(fd, STDOUT_FILENO) == -1)
+ err(EXIT_MISC, NULL);
+ (void)fprintf(stderr, "appending output to %s\n", p);
+}
+
+static void
+usage(void)
+{
+ (void)fprintf(stderr, "usage: nohup [--] utility [arguments]\n");
+ exit(EXIT_MISC);
+}
diff --git a/shell_cmds/path_helper/path_helper.8 b/shell_cmds/path_helper/path_helper.8
new file mode 100644
index 0000000..c86f2d7
--- /dev/null
+++ b/shell_cmds/path_helper/path_helper.8
@@ -0,0 +1,76 @@
+.\"
+.\" Copyright (c) 2007 Apple Inc. All rights reserved.
+.\"
+.\" @APPLE_LICENSE_HEADER_START@
+.\"
+.\" This file contains Original Code and/or Modifications of Original Code
+.\" as defined in and that are subject to the Apple Public Source License
+.\" Version 2.0 (the 'License'). You may not use this file except in
+.\" compliance with the License. Please obtain a copy of the License at
+.\" http://www.opensource.apple.com/apsl/ and read it before using this
+.\" file.
+.\"
+.\" The Original Code and all software distributed under the License are
+.\" distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+.\" EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+.\" INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+.\" FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+.\" Please see the License for the specific language governing rights and
+.\" limitations under the License.
+.\"
+.\" @APPLE_LICENSE_HEADER_END@
+.\"
+.Dd March 15, 2007
+.Dt path_helper 8
+.Os "Mac OS X"
+.Sh NAME
+.Nm path_helper
+.Nd helper for constructing PATH environment variable
+.Sh SYNOPSIS
+.Nm
+.Op Fl c | Fl s
+.Sh DESCRIPTION
+The
+.Nm
+utility reads the contents of the files in the directories
+.Pa /etc/paths.d
+and
+.Pa /etc/manpaths.d
+and appends their contents to the
+.Ev PATH
+and
+.Ev MANPATH
+environment variables respectively.
+(The
+.Ev MANPATH
+environment variable will not be modified unless it is already set
+in the environment.)
+.Pp
+Files in these directories should contain one path element per line.
+.Pp
+Prior to reading these directories, default
+.Ev PATH
+and
+.Ev MANPATH
+values are obtained from the files
+.Pa /etc/paths
+and
+.Pa /etc/manpaths
+respectively.
+.Pp
+Options:
+.Bl -tag -width Ds
+.It Fl c
+Generate C-shell commands on stdout. This is the default if
+.Ev SHELL
+ends with "csh".
+.It Fl s
+Generate Bourne shell commands on stdout. This is the default if
+.Ev SHELL
+does not end with "csh".
+.El
+.Sh NOTE
+The
+.Nm
+utility should not be invoked directly.
+It is intended only for use by the shell profile.
diff --git a/shell_cmds/path_helper/path_helper.c b/shell_cmds/path_helper/path_helper.c
new file mode 100644
index 0000000..2313c99
--- /dev/null
+++ b/shell_cmds/path_helper/path_helper.c
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2008 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <fts.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <limits.h>
+
+static void usage() {
+ fprintf(stderr, "usage: path_helper [-c | -s]");
+ exit(1);
+}
+
+// Append path segment if it does not exist. Reallocate
+// the path buffer as necessary.
+
+int append_path_segment(char** path, const char* segment) {
+ if (*path == NULL || segment == NULL) return -1;
+
+ size_t pathlen = strlen(*path);
+ size_t seglen = strlen(segment);
+
+ if (seglen == 0) return 0;
+
+ // Does the segment already exist in the path?
+ // (^|:)segment(:|$)
+ char* match = strstr(*path, segment);
+ while (match) {
+ if ((match == *path || match[-1] == ':') &&
+ (match[seglen] == ':' || match[seglen] == 0)) {
+ return 0;
+ }
+ match = strstr(match+1, segment);
+ }
+
+ // size = pathlen + ':' + segment + '\0'
+ size_t size = pathlen + seglen + 2;
+ *path = reallocf(*path, size);
+ if (*path == NULL) return -1;
+
+ if (pathlen > 0) strlcat(*path, ":", size);
+ strlcat(*path, segment, size);
+ return 0;
+}
+
+// Convert fgetln output into a sanitized segment
+// escape quotes, dollars, etc.
+char* read_segment(const char* line, size_t len) {
+ int escapes = 0;
+ size_t i, j;
+
+ for (i = 0; i < len; ++i) {
+ char c = line[i];
+ if (c == '\"' || c == '\'' || c == '$') {
+ ++escapes;
+ }
+ }
+
+ size_t size = len + escapes + 1;
+
+ char* segment = calloc(1, size);
+ if (segment == NULL) return NULL;
+
+ for (i = 0, j = 0; i < len; ++i, ++j) {
+ char c = line[i];
+ if (c == '\"' || c == '\'' || c == '$') {
+ segment[j++] = '\\';
+ segment[j] = c;
+ } else if (c == '\n') {
+ segment[j] = 0;
+ break;
+ } else {
+ segment[j] = line[i];
+ }
+ }
+
+ return segment;
+}
+
+// Construct a path variable, starting with the contents
+// of the given environment variable, adding the contents
+// of the default file and files in the path directory.
+
+char* construct_path(char* env_var, char* defaults_path, char* dir_path) {
+ FTS* fts;
+ FTSENT* ent;
+
+ char* result = calloc(sizeof(char), 1);
+
+ char* dirpathv[] = { defaults_path, dir_path, NULL };
+ fts = fts_open(dirpathv, FTS_PHYSICAL | FTS_XDEV, NULL);
+ if (!fts) {
+ perror(dir_path);
+ return NULL;
+ }
+
+ while ((ent = fts_read(fts)) != NULL) {
+ // only interested in regular files, one level deep
+ if (ent->fts_info != FTS_F) {
+ if (ent->fts_level >= 1) fts_set(fts, ent, FTS_SKIP);
+ continue;
+ }
+
+ FILE* f = fopen(ent->fts_accpath, "r");
+ if (f == NULL) {
+ perror(ent->fts_accpath);
+ continue;
+ }
+
+ for (;;) {
+ size_t len;
+ char* line = fgetln(f, &len);
+ if (line == NULL) break;
+ char* segment = read_segment(line, len);
+
+ append_path_segment(&result, segment);
+ }
+
+ fclose(f);
+ }
+ fts_close(fts);
+
+ // merge in any existing custom PATH elemenets
+ char* str = getenv(env_var);
+ if (str) str = strdup(str);
+ while (str) {
+ char* sep = strchr(str, ':');
+ if (sep) *sep = 0;
+
+ append_path_segment(&result, str);
+ if (sep) {
+ str = sep + 1;
+ } else {
+ str = NULL;
+ }
+ }
+
+ return result;
+}
+
+enum {
+ STYLE_CSH,
+ STYLE_SH
+};
+
+int main(int argc, char* argv[]) {
+ int style = STYLE_SH;
+
+ if (argc > 2) usage();
+
+ // default to csh style, if $SHELL ends with "csh".
+ char* shell = getenv("SHELL");
+ if (shell) {
+ char* str = strstr(shell, "csh");
+ if (str) style = STYLE_CSH;
+ }
+
+ if (argc == 2 && strcmp(argv[1], "-c") == 0) style = STYLE_CSH;
+ if (argc == 2 && strcmp(argv[1], "-s") == 0) style = STYLE_SH;
+
+ char* path = construct_path("PATH", "/etc/paths", "/etc/paths.d");
+ char* manpath = NULL;
+
+ // only adjust manpath if already set
+ int do_manpath = (getenv("MANPATH") != NULL);
+ if (do_manpath) {
+ manpath = construct_path("MANPATH", "/etc/manpaths", "/etc/manpaths.d");
+ }
+
+ if (style == STYLE_CSH) {
+ printf("setenv PATH \"%s\";\n", path);
+ if (do_manpath) printf("setenv MANPATH \"%s\";\n", manpath);
+ } else {
+ printf("PATH=\"%s\"; export PATH;\n", path);
+ if (do_manpath) printf("MANPATH=\"%s\"; export MANPATH;\n", manpath);
+ }
+
+ return 0;
+}
diff --git a/shell_cmds/printenv/printenv.1 b/shell_cmds/printenv/printenv.1
new file mode 100644
index 0000000..4444375
--- /dev/null
+++ b/shell_cmds/printenv/printenv.1
@@ -0,0 +1,84 @@
+.\" Copyright (c) 1980, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)printenv.1 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD$
+.\"
+.Dd May 12, 2003
+.Dt PRINTENV 1
+.Os
+.Sh NAME
+.Nm printenv
+.Nd print out the environment
+.Sh SYNOPSIS
+.Nm
+.Op Ar name
+.Sh DESCRIPTION
+The
+.Nm
+utility prints out the names and values of the variables in the environment,
+with one name/value pair per line.
+If
+.Ar name
+is specified, only
+its value is printed.
+.Pp
+Some shells may provide a builtin
+.Nm
+command which is similar or identical to this utility.
+Consult the
+.Xr builtin 1
+manual page.
+.Sh EXIT STATUS
+.Ex -std
+.Sh SEE ALSO
+.Xr csh 1 ,
+.Xr env 1 ,
+.Xr sh 1 ,
+.Xr environ 7
+.Sh STANDARDS
+The
+.Nm
+utility is provided for compatibility with earlier
+.Bx
+and
+.Fx
+releases and is not specified by any standards.
+The functionality of
+.Nm
+can be duplicated with the
+.Xr echo 1
+and
+.Xr env 1
+utilities.
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 3.0 .
diff --git a/shell_cmds/printenv/printenv.c b/shell_cmds/printenv/printenv.c
new file mode 100644
index 0000000..315833e
--- /dev/null
+++ b/shell_cmds/printenv/printenv.c
@@ -0,0 +1,99 @@
+/*-
+ * Copyright (c) 1987, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1987, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)printenv.c 8.2 (Berkeley) 5/4/95";
+#endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+void usage(void);
+extern char **environ;
+
+/*
+ * printenv
+ *
+ * Bill Joy, UCB
+ * February, 1979
+ */
+int
+main(int argc, char *argv[])
+{
+ char *cp, **ep;
+ size_t len;
+ int ch;
+
+ while ((ch = getopt(argc, argv, "")) != -1)
+ switch(ch) {
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc == 0) {
+ for (ep = environ; *ep; ep++)
+ (void)printf("%s\n", *ep);
+ exit(0);
+ }
+ len = strlen(*argv);
+ for (ep = environ; *ep; ep++)
+ if (!memcmp(*ep, *argv, len)) {
+ cp = *ep + len;
+ if (!*cp || *cp == '=') {
+ (void)printf("%s\n", *cp ? cp + 1 : cp);
+ exit(0);
+ }
+ }
+ exit(1);
+}
+
+void
+usage(void)
+{
+ (void)fprintf(stderr, "usage: printenv [name]\n");
+ exit(1);
+}
diff --git a/shell_cmds/printf/printf.1 b/shell_cmds/printf/printf.1
new file mode 100644
index 0000000..226b87b
--- /dev/null
+++ b/shell_cmds/printf/printf.1
@@ -0,0 +1,418 @@
+.\" Copyright (c) 1989, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)printf.1 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD$
+.\"
+.Dd July 1, 2020
+.Dt PRINTF 1
+.Os
+.Sh NAME
+.Nm printf
+.Nd formatted output
+.Sh SYNOPSIS
+.Nm
+.Ar format Op Ar arguments ...
+.Sh DESCRIPTION
+The
+.Nm
+utility formats and prints its arguments, after the first, under control
+of the
+.Ar format .
+The
+.Ar format
+is a character string which contains three types of objects: plain characters,
+which are simply copied to standard output, character escape sequences which
+are converted and copied to the standard output, and format specifications,
+each of which causes printing of the next successive
+.Ar argument .
+.Pp
+The
+.Ar arguments
+after the first are treated as strings if the corresponding format is
+either
+.Cm c , b
+or
+.Cm s ;
+otherwise it is evaluated as a C constant, with the following extensions:
+.Pp
+.Bl -bullet -offset indent -compact
+.It
+A leading plus or minus sign is allowed.
+.It
+If the leading character is a single or double quote, the value is the
+character code of the next character.
+.El
+.Pp
+The format string is reused as often as necessary to satisfy the
+.Ar arguments .
+Any extra format specifications are evaluated with zero or the null
+string.
+.Pp
+Character escape sequences are in backslash notation as defined in the
+.St -ansiC ,
+with extensions.
+The characters and their meanings
+are as follows:
+.Pp
+.Bl -tag -width Ds -offset indent -compact
+.It Cm \ea
+Write a <bell> character.
+.It Cm \eb
+Write a <backspace> character.
+.It Cm \ef
+Write a <form-feed> character.
+.It Cm \en
+Write a <new-line> character.
+.It Cm \er
+Write a <carriage return> character.
+.It Cm \et
+Write a <tab> character.
+.It Cm \ev
+Write a <vertical tab> character.
+.It Cm \e\'
+Write a <single quote> character.
+.It Cm \e\e
+Write a backslash character.
+.It Cm \e Ns Ar num
+Write a byte whose
+value is the 1-, 2-, or 3-digit
+octal number
+.Ar num .
+Multibyte characters can be constructed using multiple
+.Cm \e Ns Ar num
+sequences.
+.El
+.Pp
+Each format specification is introduced by the percent character
+(``%'').
+The remainder of the format specification includes,
+in the following order:
+.Bl -tag -width Ds
+.It "Zero or more of the following flags:"
+.Bl -tag -width Ds
+.It Cm #
+A `#' character
+specifying that the value should be printed in an ``alternate form''.
+For
+.Cm b , c , d , s
+and
+.Cm u
+formats, this option has no effect.
+For the
+.Cm o
+formats the precision of the number is increased to force the first
+character of the output string to a zero.
+For the
+.Cm x
+.Pq Cm X
+format, a non-zero result has the string
+.Li 0x
+.Pq Li 0X
+prepended to it.
+For
+.Cm a , A , e , E , f , F , g
+and
+.Cm G
+formats, the result will always contain a decimal point, even if no
+digits follow the point (normally, a decimal point only appears in the
+results of those formats if a digit follows the decimal point).
+For
+.Cm g
+and
+.Cm G
+formats, trailing zeros are not removed from the result as they
+would otherwise be;
+.It Cm \&\-
+A minus sign `\-' which specifies
+.Em left adjustment
+of the output in the indicated field;
+.It Cm \&+
+A `+' character specifying that there should always be
+a sign placed before the number when using signed formats.
+.It Sq \&\ \&
+A space specifying that a blank should be left before a positive number
+for a signed format.
+A `+' overrides a space if both are used;
+.It Cm \&0
+A zero `0' character indicating that zero-padding should be used
+rather than blank-padding.
+A `\-' overrides a `0' if both are used;
+.El
+.It "Field Width:"
+An optional digit string specifying a
+.Em field width ;
+if the output string has fewer bytes than the field width it will
+be blank-padded on the left (or right, if the left-adjustment indicator
+has been given) to make up the field width (note that a leading zero
+is a flag, but an embedded zero is part of a field width);
+.It Precision:
+An optional period,
+.Sq Cm \&.\& ,
+followed by an optional digit string giving a
+.Em precision
+which specifies the number of digits to appear after the decimal point,
+for
+.Cm e
+and
+.Cm f
+formats, or the maximum number of bytes to be printed
+from a string; if the digit string is missing, the precision is treated
+as zero;
+.It Format:
+A character which indicates the type of format to use (one of
+.Cm diouxXfFeEgGaAcsb ) .
+The uppercase formats differ from their lowercase counterparts only in
+that the output of the former is entirely in uppercase.
+The floating-point format specifiers
+.Pq Cm fFeEgGaA
+may be prefixed by an
+.Cm L
+to request that additional precision be used, if available.
+.El
+.Pp
+A field width or precision may be
+.Sq Cm \&*
+instead of a digit string.
+In this case an
+.Ar argument
+supplies the field width or precision.
+.Pp
+The format characters and their meanings are:
+.Bl -tag -width Fl
+.It Cm diouXx
+The
+.Ar argument
+is printed as a signed decimal (d or i), unsigned octal, unsigned decimal,
+or unsigned hexadecimal (X or x), respectively.
+.It Cm fF
+The
+.Ar argument
+is printed in the style `[\-]ddd.ddd' where the number of d's
+after the decimal point is equal to the precision specification for
+the argument.
+If the precision is missing, 6 digits are given; if the precision
+is explicitly 0, no digits and no decimal point are printed.
+The values \*[If] and \*[Na] are printed as
+.Ql inf
+and
+.Ql nan ,
+respectively.
+.It Cm eE
+The
+.Ar argument
+is printed in the style
+.Cm e
+.Sm off
+.Sq Op - Ar d.ddd No \(+- Ar dd
+.Sm on
+where there
+is one digit before the decimal point and the number after is equal to
+the precision specification for the argument; when the precision is
+missing, 6 digits are produced.
+The values \*[If] and \*[Na] are printed as
+.Ql inf
+and
+.Ql nan ,
+respectively.
+.It Cm gG
+The
+.Ar argument
+is printed in style
+.Cm f
+.Pq Cm F
+or in style
+.Cm e
+.Pq Cm E
+whichever gives full precision in minimum space.
+.It Cm aA
+The
+.Ar argument
+is printed in style
+.Sm off
+.Sq Op - Ar h.hhh No \(+- Li p Ar d
+.Sm on
+where there is one digit before the hexadecimal point and the number
+after is equal to the precision specification for the argument;
+when the precision is missing, enough digits are produced to convey
+the argument's exact double-precision floating-point representation.
+The values \*[If] and \*[Na] are printed as
+.Ql inf
+and
+.Ql nan ,
+respectively.
+.It Cm c
+The first byte of
+.Ar argument
+is printed.
+.It Cm s
+Bytes from the string
+.Ar argument
+are printed until the end is reached or until the number of bytes
+indicated by the precision specification is reached; however if the
+precision is 0 or missing, the string is printed entirely.
+.It Cm b
+As for
+.Cm s ,
+but interpret character escapes in backslash notation in the string
+.Ar argument .
+The permitted escape sequences are slightly different in that
+octal escapes are
+.Cm \e0 Ns Ar num
+instead of
+.Cm \e Ns Ar num
+and that an additional escape sequence
+.Cm \ec
+stops further output from this
+.Nm
+invocation.
+.It Cm n$
+Allows reordering of the output according to
+.Ar argument .
+.It Cm \&%
+Print a `%'; no argument is used.
+.El
+.Pp
+The decimal point
+character is defined in the program's locale (category
+.Dv LC_NUMERIC ) .
+.Pp
+In no case does a non-existent or small field width cause truncation of
+a field; padding takes place only if the specified field width exceeds
+the actual width.
+.Pp
+Some shells may provide a builtin
+.Nm
+command which is similar or identical to this utility.
+Consult the
+.Xr builtin 1
+manual page.
+.Sh EXIT STATUS
+.Ex -std
+.Sh EXAMPLES
+Print the string
+.Qq hello :
+.Bd -literal -offset indent
+$ printf "%s\en" hello
+hello
+.Ed
+.Pp
+Same as above, but notice that the format string is not quoted and hence we
+do not get the expected behavior:
+.Bd -literal -offset indent
+$ printf %s\en hello
+hellon$
+.Ed
+.Pp
+Print arguments forcing sign only for the first argument:
+.Bd -literal -offset indent
+$ printf "%+d\en%d\en%d\en" 1 -2 13
++1
+-2
+13
+.Ed
+.Pp
+Same as above, but the single format string will be applied to the three
+arguments:
+.Bd -literal -offset indent
+$ printf "%+d\en" 1 -2 13
++1
+-2
++13
+.Ed
+.Pp
+Print number using only two digits after the decimal point:
+.Bd -literal -offset indent
+$ printf "%.2f\en" 31.7456
+31.75
+.Ed
+.Sh COMPATIBILITY
+The traditional
+.Bx
+behavior of converting arguments of numeric formats not beginning
+with a digit to the ASCII
+code of the first character is not supported.
+.Sh SEE ALSO
+.Xr builtin 1 ,
+.Xr echo 1 ,
+.Xr sh 1 ,
+.Xr printf 3
+.Sh STANDARDS
+The
+.Nm
+command is expected to be compatible with the
+.St -p1003.2
+specification.
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.3 Reno .
+It is modeled
+after the standard library function,
+.Xr printf 3 .
+.Sh CAVEATS
+ANSI hexadecimal character constants were deliberately not provided.
+.Pp
+Trying to print a dash ("-") as the first character causes
+.Nm
+to interpret the dash as a program argument.
+.Nm --
+must be used before
+.Ar format .
+.Pp
+If the locale contains multibyte characters
+(such as UTF-8),
+the
+.Cm c
+format and
+.Cm b
+and
+.Cm s
+formats with a precision
+may not operate as expected.
+.Sh BUGS
+Since the floating point numbers are translated from ASCII
+to floating-point and then back again, floating-point precision may be lost.
+(By default, the number is translated to an IEEE-754 double-precision
+value before being printed.
+The
+.Cm L
+modifier may produce additional precision, depending on the hardware platform.)
+.Pp
+The escape sequence \e000 is the string terminator.
+When present in the argument for the
+.Cm b
+format, the argument will be truncated at the \e000 character.
+.Pp
+Multibyte characters are not recognized in format strings (this is only
+a problem if
+.Ql %
+can appear inside a multibyte character).
diff --git a/shell_cmds/printf/printf.c b/shell_cmds/printf/printf.c
new file mode 100644
index 0000000..6cc09ae
--- /dev/null
+++ b/shell_cmds/printf/printf.c
@@ -0,0 +1,697 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
+ * Copyright 2014 Garrett D'Amore <garrett@damore.org>
+ * Copyright 2010 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * Important: This file is used both as a standalone program /usr/bin/printf
+ * and as a builtin for /bin/sh (#define SHELL).
+ */
+
+#ifndef SHELL
+#ifndef lint
+static char const copyright[] =
+"@(#) Copyright (c) 1989, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+#endif
+
+#ifndef lint
+#if 0
+static char const sccsid[] = "@(#)printf.c 8.1 (Berkeley) 7/20/93";
+#endif
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif /* not lint */
+
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <wchar.h>
+
+#ifdef SHELL
+#define main printfcmd
+#include "bltin/bltin.h"
+#include "options.h"
+#endif
+
+#define PF(f, func) do { \
+ if (havewidth) \
+ if (haveprec) \
+ (void)printf(f, fieldwidth, precision, func); \
+ else \
+ (void)printf(f, fieldwidth, func); \
+ else if (haveprec) \
+ (void)printf(f, precision, func); \
+ else \
+ (void)printf(f, func); \
+} while (0)
+
+static int asciicode(void);
+static char *printf_doformat(char *, int *);
+static int escape(char *, int, size_t *);
+static int getchr(void);
+static int getfloating(long double *, int);
+static int getint(int *);
+static int getnum(intmax_t *, uintmax_t *, int);
+static const char
+ *getstr(void);
+static char *mknum(char *, char);
+static void usage(void);
+
+static const char digits[] = "0123456789";
+
+static char end_fmt[1];
+
+static int myargc;
+static char **myargv;
+static char **gargv;
+static char **maxargv;
+
+int
+main(int argc, char *argv[])
+{
+ size_t len;
+ int end, rval;
+ char *format, *fmt, *start;
+#ifndef SHELL
+ int ch;
+
+ (void) setlocale(LC_ALL, "");
+#endif
+
+#ifdef SHELL
+ nextopt("");
+ argc -= argptr - argv;
+ argv = argptr;
+#else
+ while ((ch = getopt(argc, argv, "")) != -1)
+ switch (ch) {
+ case '?':
+ default:
+ usage();
+ return (1);
+ }
+ argc -= optind;
+ argv += optind;
+#endif
+
+ if (argc < 1) {
+ usage();
+ return (1);
+ }
+
+#ifdef SHELL
+ INTOFF;
+#endif
+ /*
+ * Basic algorithm is to scan the format string for conversion
+ * specifications -- once one is found, find out if the field
+ * width or precision is a '*'; if it is, gather up value. Note,
+ * format strings are reused as necessary to use up the provided
+ * arguments, arguments of zero/null string are provided to use
+ * up the format string.
+ */
+ fmt = format = *argv;
+ escape(fmt, 1, &len); /* backslash interpretation */
+ rval = end = 0;
+ gargv = ++argv;
+
+ for (;;) {
+ maxargv = gargv;
+
+ myargv = gargv;
+ for (myargc = 0; gargv[myargc]; myargc++)
+ /* nop */;
+ start = fmt;
+ while (fmt < format + len) {
+ if (fmt[0] == '%') {
+ fwrite(start, 1, fmt - start, stdout);
+ if (fmt[1] == '%') {
+ /* %% prints a % */
+ putchar('%');
+ fmt += 2;
+ } else {
+ fmt = printf_doformat(fmt, &rval);
+ if (fmt == NULL || fmt == end_fmt) {
+#ifdef SHELL
+ INTON;
+#endif
+ return (fmt == NULL ? 1 : rval);
+ }
+ end = 0;
+ }
+ start = fmt;
+ } else
+ fmt++;
+ if (gargv > maxargv)
+ maxargv = gargv;
+ }
+ gargv = maxargv;
+
+ if (end == 1) {
+ warnx("missing format character");
+#ifdef SHELL
+ INTON;
+#endif
+ return (1);
+ }
+ fwrite(start, 1, fmt - start, stdout);
+ if (!*gargv) {
+#ifdef SHELL
+ INTON;
+#endif
+ return (rval);
+ }
+ /* Restart at the beginning of the format string. */
+ fmt = format;
+ end = 1;
+ }
+ /* NOTREACHED */
+}
+
+
+static char *
+printf_doformat(char *fmt, int *rval)
+{
+ static const char skip1[] = "#'-+ 0";
+ int fieldwidth, haveprec, havewidth, mod_ldbl, precision;
+ char convch, nextch;
+ char start[strlen(fmt) + 1];
+ char **fargv;
+ char *dptr;
+ int l;
+
+ dptr = start;
+ *dptr++ = '%';
+ *dptr = 0;
+
+ fmt++;
+
+ /* look for "n$" field index specifier */
+ l = strspn(fmt, digits);
+ if ((l > 0) && (fmt[l] == '$')) {
+ int idx = atoi(fmt);
+ if (idx <= myargc) {
+ gargv = &myargv[idx - 1];
+ } else {
+ gargv = &myargv[myargc];
+ }
+ if (gargv > maxargv)
+ maxargv = gargv;
+ fmt += l + 1;
+
+ /* save format argument */
+ fargv = gargv;
+ } else {
+ fargv = NULL;
+ }
+
+ /* skip to field width */
+ while (*fmt && strchr(skip1, *fmt) != NULL) {
+ *dptr++ = *fmt++;
+ *dptr = 0;
+ }
+
+ if (*fmt == '*') {
+
+ fmt++;
+ l = strspn(fmt, digits);
+ if ((l > 0) && (fmt[l] == '$')) {
+ int idx = atoi(fmt);
+ if (fargv == NULL) {
+ warnx("incomplete use of n$");
+ return (NULL);
+ }
+ if (idx <= myargc) {
+ gargv = &myargv[idx - 1];
+ } else {
+ gargv = &myargv[myargc];
+ }
+ fmt += l + 1;
+ } else if (fargv != NULL) {
+ warnx("incomplete use of n$");
+ return (NULL);
+ }
+
+ if (getint(&fieldwidth))
+ return (NULL);
+ if (gargv > maxargv)
+ maxargv = gargv;
+ havewidth = 1;
+
+ *dptr++ = '*';
+ *dptr = 0;
+ } else {
+ havewidth = 0;
+
+ /* skip to possible '.', get following precision */
+ while (isdigit(*fmt)) {
+ *dptr++ = *fmt++;
+ *dptr = 0;
+ }
+ }
+
+ if (*fmt == '.') {
+ /* precision present? */
+ fmt++;
+ *dptr++ = '.';
+
+ if (*fmt == '*') {
+
+ fmt++;
+ l = strspn(fmt, digits);
+ if ((l > 0) && (fmt[l] == '$')) {
+ int idx = atoi(fmt);
+ if (fargv == NULL) {
+ warnx("incomplete use of n$");
+ return (NULL);
+ }
+ if (idx <= myargc) {
+ gargv = &myargv[idx - 1];
+ } else {
+ gargv = &myargv[myargc];
+ }
+ fmt += l + 1;
+ } else if (fargv != NULL) {
+ warnx("incomplete use of n$");
+ return (NULL);
+ }
+
+ if (getint(&precision))
+ return (NULL);
+ if (gargv > maxargv)
+ maxargv = gargv;
+ haveprec = 1;
+ *dptr++ = '*';
+ *dptr = 0;
+ } else {
+ haveprec = 0;
+
+ /* skip to conversion char */
+ while (isdigit(*fmt)) {
+ *dptr++ = *fmt++;
+ *dptr = 0;
+ }
+ }
+ } else
+ haveprec = 0;
+ if (!*fmt) {
+ warnx("missing format character");
+ return (NULL);
+ }
+ *dptr++ = *fmt;
+ *dptr = 0;
+
+ /*
+ * Look for a length modifier. POSIX doesn't have these, so
+ * we only support them for floating-point conversions, which
+ * are extensions. This is useful because the L modifier can
+ * be used to gain extra range and precision, while omitting
+ * it is more likely to produce consistent results on different
+ * architectures. This is not so important for integers
+ * because overflow is the only bad thing that can happen to
+ * them, but consider the command printf %a 1.1
+ */
+ if (*fmt == 'L') {
+ mod_ldbl = 1;
+ fmt++;
+ if (!strchr("aAeEfFgG", *fmt)) {
+ warnx("bad modifier L for %%%c", *fmt);
+ return (NULL);
+ }
+ } else {
+ mod_ldbl = 0;
+ }
+
+ /* save the current arg offset, and set to the format arg */
+ if (fargv != NULL) {
+ gargv = fargv;
+ }
+
+ convch = *fmt;
+ nextch = *++fmt;
+
+ *fmt = '\0';
+ switch (convch) {
+ case 'b': {
+ size_t len;
+ char *p;
+ int getout;
+
+ /* Convert "b" to "s" for output. */
+ start[strlen(start) - 1] = 's';
+ if ((p = strdup(getstr())) == NULL) {
+ warnx("%s", strerror(ENOMEM));
+ return (NULL);
+ }
+ getout = escape(p, 0, &len);
+ /*
+ * Special-case conversion of zero; print it instead of
+ * feeding an empty string to printf("%s") which would not
+ * print anything.
+ */
+ if (len == 1 && p[0] == '\0') {
+ putchar(p[0]);
+ } else {
+ PF(start, p);
+ }
+ /* Restore format for next loop. */
+
+ free(p);
+ if (getout)
+ return (end_fmt);
+ break;
+ }
+ case 'c': {
+ char p;
+
+ p = getchr();
+ if (p != '\0')
+ PF(start, p);
+ break;
+ }
+ case 's': {
+ const char *p;
+
+ p = getstr();
+ PF(start, p);
+ break;
+ }
+ case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': {
+ char *f;
+ intmax_t val;
+ uintmax_t uval;
+ int signedconv;
+
+ signedconv = (convch == 'd' || convch == 'i');
+ if ((f = mknum(start, convch)) == NULL)
+ return (NULL);
+ if (getnum(&val, &uval, signedconv))
+ *rval = 1;
+ if (signedconv)
+ PF(f, val);
+ else
+ PF(f, uval);
+ break;
+ }
+ case 'e': case 'E':
+ case 'f': case 'F':
+ case 'g': case 'G':
+ case 'a': case 'A': {
+ long double p;
+
+ if (getfloating(&p, mod_ldbl))
+ *rval = 1;
+ if (mod_ldbl)
+ PF(start, p);
+ else
+ PF(start, (double)p);
+ break;
+ }
+ default:
+ warnx("illegal format character %c", convch);
+ return (NULL);
+ }
+ *fmt = nextch;
+ /* return the gargv to the next element */
+ return (fmt);
+}
+
+static char *
+mknum(char *str, char ch)
+{
+ static char *copy;
+ static size_t copy_size;
+ char *newcopy;
+ size_t len, newlen;
+
+ len = strlen(str) + 2;
+ if (len > copy_size) {
+ newlen = ((len + 1023) >> 10) << 10;
+ if ((newcopy = realloc(copy, newlen)) == NULL) {
+ warnx("%s", strerror(ENOMEM));
+ return (NULL);
+ }
+ copy = newcopy;
+ copy_size = newlen;
+ }
+
+ memmove(copy, str, len - 3);
+ copy[len - 3] = 'j';
+ copy[len - 2] = ch;
+ copy[len - 1] = '\0';
+ return (copy);
+}
+
+static int
+escape(char *fmt, int percent, size_t *len)
+{
+ char *save, *store, c;
+ int value;
+
+ for (save = store = fmt; ((c = *fmt) != 0); ++fmt, ++store) {
+ if (c != '\\') {
+ *store = c;
+ continue;
+ }
+ switch (*++fmt) {
+ case '\0': /* EOS, user error */
+ *store = '\\';
+ *++store = '\0';
+ *len = store - save;
+ return (0);
+ case '\\': /* backslash */
+ case '\'': /* single quote */
+ *store = *fmt;
+ break;
+ case 'a': /* bell/alert */
+ *store = '\a';
+ break;
+ case 'b': /* backspace */
+ *store = '\b';
+ break;
+ case 'c':
+ if (!percent) {
+ *store = '\0';
+ *len = store - save;
+ return (1);
+ }
+ *store = 'c';
+ break;
+ case 'f': /* form-feed */
+ *store = '\f';
+ break;
+ case 'n': /* newline */
+ *store = '\n';
+ break;
+ case 'r': /* carriage-return */
+ *store = '\r';
+ break;
+ case 't': /* horizontal tab */
+ *store = '\t';
+ break;
+ case 'v': /* vertical tab */
+ *store = '\v';
+ break;
+ /* octal constant */
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ c = (!percent && *fmt == '0') ? 4 : 3;
+ for (value = 0;
+ c-- && *fmt >= '0' && *fmt <= '7'; ++fmt) {
+ value <<= 3;
+ value += *fmt - '0';
+ }
+ --fmt;
+ if (percent && value == '%') {
+ *store++ = '%';
+ *store = '%';
+ } else
+ *store = (char)value;
+ break;
+ default:
+ *store = *fmt;
+ break;
+ }
+ }
+ *store = '\0';
+ *len = store - save;
+ return (0);
+}
+
+static int
+getchr(void)
+{
+ if (!*gargv)
+ return ('\0');
+ return ((int)**gargv++);
+}
+
+static const char *
+getstr(void)
+{
+ if (!*gargv)
+ return ("");
+ return (*gargv++);
+}
+
+static int
+getint(int *ip)
+{
+ intmax_t val;
+ uintmax_t uval;
+ int rval;
+
+ if (getnum(&val, &uval, 1))
+ return (1);
+ rval = 0;
+ if (val < INT_MIN || val > INT_MAX) {
+ warnx("%s: %s", *gargv, strerror(ERANGE));
+ rval = 1;
+ }
+ *ip = (int)val;
+ return (rval);
+}
+
+static int
+getnum(intmax_t *ip, uintmax_t *uip, int signedconv)
+{
+ char *ep;
+ int rval;
+
+ if (!*gargv) {
+ *ip = *uip = 0;
+ return (0);
+ }
+ if (**gargv == '"' || **gargv == '\'') {
+ if (signedconv)
+ *ip = asciicode();
+ else
+ *uip = asciicode();
+ return (0);
+ }
+ rval = 0;
+ errno = 0;
+ if (signedconv)
+ *ip = strtoimax(*gargv, &ep, 0);
+ else
+ *uip = strtoumax(*gargv, &ep, 0);
+ if (ep == *gargv) {
+ warnx("%s: expected numeric value", *gargv);
+ rval = 1;
+ }
+ else if (*ep != '\0') {
+ warnx("%s: not completely converted", *gargv);
+ rval = 1;
+ }
+ if (errno == ERANGE) {
+ warnx("%s: %s", *gargv, strerror(ERANGE));
+ rval = 1;
+ }
+ ++gargv;
+ return (rval);
+}
+
+static int
+getfloating(long double *dp, int mod_ldbl)
+{
+ char *ep;
+ int rval;
+
+ if (!*gargv) {
+ *dp = 0.0;
+ return (0);
+ }
+ if (**gargv == '"' || **gargv == '\'') {
+ *dp = asciicode();
+ return (0);
+ }
+ rval = 0;
+ errno = 0;
+ if (mod_ldbl)
+ *dp = strtold(*gargv, &ep);
+ else
+ *dp = strtod(*gargv, &ep);
+ if (ep == *gargv) {
+ warnx("%s: expected numeric value", *gargv);
+ rval = 1;
+ } else if (*ep != '\0') {
+ warnx("%s: not completely converted", *gargv);
+ rval = 1;
+ }
+ if (errno == ERANGE) {
+ warnx("%s: %s", *gargv, strerror(ERANGE));
+ rval = 1;
+ }
+ ++gargv;
+ return (rval);
+}
+
+static int
+asciicode(void)
+{
+ int ch;
+ wchar_t wch;
+ mbstate_t mbs;
+
+ ch = (unsigned char)**gargv;
+ if (ch == '\'' || ch == '"') {
+ memset(&mbs, 0, sizeof(mbs));
+ switch (mbrtowc(&wch, *gargv + 1, MB_LEN_MAX, &mbs)) {
+ case (size_t)-2:
+ case (size_t)-1:
+ wch = (unsigned char)gargv[0][1];
+ break;
+ case 0:
+ wch = 0;
+ break;
+ }
+ ch = wch;
+ }
+ ++gargv;
+ return (ch);
+}
+
+static void
+usage(void)
+{
+ (void)fprintf(stderr, "usage: printf format [arguments ...]\n");
+}
diff --git a/shell_cmds/printf/printf.plist.part b/shell_cmds/printf/printf.plist.part
new file mode 100644
index 0000000..a040cf7
--- /dev/null
+++ b/shell_cmds/printf/printf.plist.part
@@ -0,0 +1,18 @@
+ <dict>
+ <key>OpenSourceProject</key>
+ <string>printf</string>
+ <key>OpenSourceVersion</key>
+ <string>2020-07-01</string>
+ <key>OpenSourceWebsiteURL</key>
+ <string>https://github.com/freebsd/freebsd/tree/master/usr.bin/printf</string>
+ <key>OpenSourceSCM</key>
+ <string>https://github.com/freebsd/freebsd/tree/master/usr.bin/printf</string>
+ <key>OpenSourceImportDate</key>
+ <string>2020-07-23</string>
+ <key>OpenSourceModifications</key>
+ <array>
+ <string>65959587: UNIX Conformance | /usr/bin/printf, multiple format assertion failures in VSC</string>
+ </array>
+ <key>OpenSourceLicense</key>
+ <string>bsd</string>
+ </dict>
diff --git a/shell_cmds/printf/tests/Makefile b/shell_cmds/printf/tests/Makefile
new file mode 100644
index 0000000..b4ea79b
--- /dev/null
+++ b/shell_cmds/printf/tests/Makefile
@@ -0,0 +1,23 @@
+# $FreeBSD$
+
+PACKAGE= tests
+
+TAP_TESTS_SH= legacy_test
+
+${PACKAGE}FILES+= regress.b.out
+${PACKAGE}FILES+= regress.bwidth.out
+${PACKAGE}FILES+= regress.d.out
+${PACKAGE}FILES+= regress.f.out
+${PACKAGE}FILES+= regress.l1.out
+${PACKAGE}FILES+= regress.l2.out
+${PACKAGE}FILES+= regress.m1.out
+${PACKAGE}FILES+= regress.m2.out
+${PACKAGE}FILES+= regress.m3.out
+${PACKAGE}FILES+= regress.m4.out
+${PACKAGE}FILES+= regress.m5.out
+${PACKAGE}FILES+= regress.missingpos1.out
+${PACKAGE}FILES+= regress.s.out
+${PACKAGE}FILES+= regress.sh
+${PACKAGE}FILES+= regress.zero.out
+
+.include <bsd.test.mk>
diff --git a/shell_cmds/printf/tests/Makefile.depend b/shell_cmds/printf/tests/Makefile.depend
new file mode 100644
index 0000000..f80275d
--- /dev/null
+++ b/shell_cmds/printf/tests/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/shell_cmds/printf/tests/legacy_test.sh b/shell_cmds/printf/tests/legacy_test.sh
new file mode 100644
index 0000000..a919deb
--- /dev/null
+++ b/shell_cmds/printf/tests/legacy_test.sh
@@ -0,0 +1,6 @@
+#!/bin/sh
+# $FreeBSD$
+
+SRCDIR="$(dirname "${0}")"; export SRCDIR
+
+m4 /AppleInternal/Tests/shell_cmds/regress.m4 "${SRCDIR}/regress.sh" | sh
diff --git a/shell_cmds/printf/tests/regress.b.out b/shell_cmds/printf/tests/regress.b.out
new file mode 100644
index 0000000..0373d93
--- /dev/null
+++ b/shell_cmds/printf/tests/regress.b.out
@@ -0,0 +1 @@
+abcdef
diff --git a/shell_cmds/printf/tests/regress.bwidth.out b/shell_cmds/printf/tests/regress.bwidth.out
new file mode 100644
index 0000000..9e2ff61
--- /dev/null
+++ b/shell_cmds/printf/tests/regress.bwidth.out
@@ -0,0 +1 @@
+ a
diff --git a/shell_cmds/printf/tests/regress.d.out b/shell_cmds/printf/tests/regress.d.out
new file mode 100644
index 0000000..da83c08
--- /dev/null
+++ b/shell_cmds/printf/tests/regress.d.out
@@ -0,0 +1 @@
+123, 123,00123,00123,00123
diff --git a/shell_cmds/printf/tests/regress.f.out b/shell_cmds/printf/tests/regress.f.out
new file mode 100644
index 0000000..127cb8a
--- /dev/null
+++ b/shell_cmds/printf/tests/regress.f.out
@@ -0,0 +1 @@
+42.250000,-42.250 ,inf,nan
diff --git a/shell_cmds/printf/tests/regress.l1.out b/shell_cmds/printf/tests/regress.l1.out
new file mode 100644
index 0000000..9be0dc9
--- /dev/null
+++ b/shell_cmds/printf/tests/regress.l1.out
@@ -0,0 +1 @@
+228
diff --git a/shell_cmds/printf/tests/regress.l2.out b/shell_cmds/printf/tests/regress.l2.out
new file mode 100644
index 0000000..9be0dc9
--- /dev/null
+++ b/shell_cmds/printf/tests/regress.l2.out
@@ -0,0 +1 @@
+228
diff --git a/shell_cmds/printf/tests/regress.m1.out b/shell_cmds/printf/tests/regress.m1.out
new file mode 100644
index 0000000..a9e063e
--- /dev/null
+++ b/shell_cmds/printf/tests/regress.m1.out
Binary files differ
diff --git a/shell_cmds/printf/tests/regress.m2.out b/shell_cmds/printf/tests/regress.m2.out
new file mode 100644
index 0000000..cf14915
--- /dev/null
+++ b/shell_cmds/printf/tests/regress.m2.out
@@ -0,0 +1,2 @@
+abc
+cdef \ No newline at end of file
diff --git a/shell_cmds/printf/tests/regress.m3.out b/shell_cmds/printf/tests/regress.m3.out
new file mode 100644
index 0000000..bbe4e70
--- /dev/null
+++ b/shell_cmds/printf/tests/regress.m3.out
@@ -0,0 +1,4 @@
+%abc
+%def
+%ghi
+%jkl
diff --git a/shell_cmds/printf/tests/regress.m4.out b/shell_cmds/printf/tests/regress.m4.out
new file mode 100644
index 0000000..5e0b5d4
--- /dev/null
+++ b/shell_cmds/printf/tests/regress.m4.out
@@ -0,0 +1 @@
+0,0.000000,,
diff --git a/shell_cmds/printf/tests/regress.m5.out b/shell_cmds/printf/tests/regress.m5.out
new file mode 100644
index 0000000..2838468
--- /dev/null
+++ b/shell_cmds/printf/tests/regress.m5.out
@@ -0,0 +1 @@
+-d
diff --git a/shell_cmds/printf/tests/regress.missingpos1.out b/shell_cmds/printf/tests/regress.missingpos1.out
new file mode 100644
index 0000000..3b04f03
--- /dev/null
+++ b/shell_cmds/printf/tests/regress.missingpos1.out
@@ -0,0 +1 @@
+printf: incomplete use of n$
diff --git a/shell_cmds/printf/tests/regress.s.out b/shell_cmds/printf/tests/regress.s.out
new file mode 100644
index 0000000..3d572b9
--- /dev/null
+++ b/shell_cmds/printf/tests/regress.s.out
@@ -0,0 +1 @@
+abc,abc
diff --git a/shell_cmds/printf/tests/regress.sh b/shell_cmds/printf/tests/regress.sh
new file mode 100644
index 0000000..a2cf5fb
--- /dev/null
+++ b/shell_cmds/printf/tests/regress.sh
@@ -0,0 +1,32 @@
+# $FreeBSD$
+
+REGRESSION_START($1)
+
+echo '1..24'
+
+REGRESSION_TEST(`b', `printf "abc%b%b" "def\n" "\cghi"')
+REGRESSION_TEST(`d', `printf "%d,%5d,%.5d,%0*d,%.*d\n" 123 123 123 5 123 5 123')
+REGRESSION_TEST(`f', `printf "%f,%-8.3f,%f,%f\n" +42.25 -42.25 inf nan')
+REGRESSION_TEST(`l1', `LC_ALL=en_US.ISO8859-1 printf "%d\n" $(printf \"\\344)')
+REGRESSION_TEST(`l2', `LC_ALL=en_US.UTF-8 printf "%d\n" $(printf \"\\303\\244)')
+REGRESSION_TEST(`m1', `printf "%c%%%d\0\045\n" abc \"abc')
+REGRESSION_TEST(`m2', `printf "abc\n\cdef"')
+REGRESSION_TEST(`m3', `printf "%%%s\n" abc def ghi jkl')
+REGRESSION_TEST(`m4', `printf "%d,%f,%c,%s\n"')
+REGRESSION_TEST(`m5', `printf -- "-d\n"')
+REGRESSION_TEST(`s', `printf "%.3s,%-5s\n" abcd abc')
+REGRESSION_TEST('zero', `printf "%u%u\n" 15')
+REGRESSION_TEST('zero', `printf "%d%d\n" 15')
+REGRESSION_TEST('zero', `printf "%d%u\n" 15')
+REGRESSION_TEST('zero', `printf "%u%d\n" 15')
+REGRESSION_TEST(`missingpos1', `printf "%1\$*s" 1 1 2>&1')
+REGRESSION_TEST(`missingpos1', `printf "%*1\$s" 1 1 2>&1')
+REGRESSION_TEST(`missingpos1', `printf "%1\$*.*s" 1 1 1 2>&1')
+REGRESSION_TEST(`missingpos1', `printf "%*1\$.*s" 1 1 1 2>&1')
+REGRESSION_TEST(`missingpos1', `printf "%*.*1\$s" 1 1 1 2>&1')
+REGRESSION_TEST(`missingpos1', `printf "%1\$*2\$.*s" 1 1 1 2>&1')
+REGRESSION_TEST(`missingpos1', `printf "%*1\$.*2\$s" 1 1 1 2>&1')
+REGRESSION_TEST(`missingpos1', `printf "%1\$*.*2\$s" 1 1 1 2>&1')
+REGRESSION_TEST(`bwidth', `printf "%8.2b" "a\nb\n"')
+
+REGRESSION_END()
diff --git a/shell_cmds/printf/tests/regress.zero.out b/shell_cmds/printf/tests/regress.zero.out
new file mode 100644
index 0000000..fa8f08c
--- /dev/null
+++ b/shell_cmds/printf/tests/regress.zero.out
@@ -0,0 +1 @@
+150
diff --git a/shell_cmds/pwd/pwd.1 b/shell_cmds/pwd/pwd.1
new file mode 100644
index 0000000..929c4b3
--- /dev/null
+++ b/shell_cmds/pwd/pwd.1
@@ -0,0 +1,103 @@
+.\"-
+.\" Copyright (c) 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)pwd.1 8.2 (Berkeley) 4/28/95
+.\" $FreeBSD: src/bin/pwd/pwd.1,v 1.26 2005/01/16 16:41:58 ru Exp $
+.\"
+.Dd April 12, 2003
+.Dt PWD 1
+.Os
+.Sh NAME
+.Nm pwd
+.Nd return working directory name
+.Sh SYNOPSIS
+.Nm
+.Op Fl L | P
+.Sh DESCRIPTION
+The
+.Nm
+utility writes the absolute pathname of the current working directory to
+the standard output.
+.Pp
+Some shells may provide a builtin
+.Nm
+command which is similar or identical to this utility.
+Consult the
+.Xr builtin 1
+manual page.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl L
+Display the logical current working directory.
+.It Fl P
+Display the physical current working directory (all symbolic links resolved).
+.El
+.Pp
+If no options are specified, the
+.\" 4207130
+.Fl L
+option is assumed.
+.Sh ENVIRONMENT
+Environment variables used by
+.Nm :
+.Bl -tag -width ".Ev PWD"
+.It Ev PWD
+Logical current working directory.
+.El
+.Sh EXIT STATUS
+.Ex -std
+.Sh SEE ALSO
+.Xr builtin 1 ,
+.Xr cd 1 ,
+.Xr csh 1 ,
+.Xr sh 1 ,
+.Xr getcwd 3
+.Sh STANDARDS
+The
+.Nm
+utility conforms to
+.St -p1003.1-2001 .
+.Sh BUGS
+In
+.Xr csh 1
+the command
+.Ic dirs
+is always faster because it is built into that shell.
+However, it can give a different answer in the rare case
+that the current directory or a containing directory was moved after
+the shell descended into it.
+.Pp
+The
+.Fl L
+option does not work unless the
+.Ev PWD
+environment variable is exported by the shell.
diff --git a/shell_cmds/pwd/pwd.c b/shell_cmds/pwd/pwd.c
new file mode 100644
index 0000000..c5788b1
--- /dev/null
+++ b/shell_cmds/pwd/pwd.c
@@ -0,0 +1,127 @@
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static char const copyright[] =
+"@(#) Copyright (c) 1991, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)pwd.c 8.3 (Berkeley) 4/1/94";
+#endif /* not lint */
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/bin/pwd/pwd.c,v 1.25 2005/02/09 17:37:38 ru Exp $");
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+static char *getcwd_logical(void);
+void usage(void);
+
+int
+main(int argc, char *argv[])
+{
+ int physical;
+ int ch;
+ char *p;
+
+ // 4207130
+ physical = 0;
+ while ((ch = getopt(argc, argv, "LP")) != -1)
+ switch (ch) {
+ case 'L':
+ physical = 0;
+ break;
+ case 'P':
+ physical = 1;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc != 0)
+ usage();
+
+ /*
+ * If we're trying to find the logical current directory and that
+ * fails, behave as if -P was specified.
+ *
+ * 4701537: Only fall back if $PWD was actually wrong. We want to
+ * fail if the path is too long (errno == ENAMETOOLONG).
+ */
+ if ((!physical && (p = getcwd_logical()) != NULL) ||
+ ((physical || errno == ENOENT) && (p = getcwd(NULL, 0)) != NULL))
+ printf("%s\n", p);
+ else
+ err(1, ".");
+
+ exit(0);
+}
+
+void
+usage(void)
+{
+
+ (void)fprintf(stderr, "usage: pwd [-L | -P]\n");
+ exit(1);
+}
+
+static char *
+getcwd_logical(void)
+{
+ struct stat lg, phy;
+ char *pwd;
+
+ /*
+ * Check that $PWD is an absolute logical pathname referring to
+ * the current working directory.
+ */
+ if ((pwd = getenv("PWD")) != NULL && *pwd == '/') {
+ if (stat(pwd, &lg) == -1 || stat(".", &phy) == -1)
+ return (NULL);
+ if (lg.st_dev == phy.st_dev && lg.st_ino == phy.st_ino)
+ return (pwd);
+ }
+
+ errno = ENOENT;
+ return (NULL);
+}
diff --git a/shell_cmds/renice/renice.8 b/shell_cmds/renice/renice.8
new file mode 100644
index 0000000..5a03755
--- /dev/null
+++ b/shell_cmds/renice/renice.8
@@ -0,0 +1,138 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)renice.8 8.1 (Berkeley) 6/9/93
+.\" $FreeBSD: src/usr.bin/renice/renice.8,v 1.16 2003/02/26 20:27:24 charnier Exp $
+.\"
+.Dd June 9, 1993
+.Dt RENICE 8
+.Os
+.Sh NAME
+.Nm renice
+.Nd alter priority of running processes
+.Sh SYNOPSIS
+.Nm
+.Ar priority
+.Op Oo Fl p Oc Ar pid ...
+.Op Oo Fl g Oc Ar pgrp ...
+.Op Oo Fl u Oc Ar user ...
+.Nm
+.Fl n Ar increment
+.Op Oo Fl p Oc Ar pid ...
+.Op Oo Fl g Oc Ar pgrp ...
+.Op Oo Fl u Oc Ar user ...
+.Sh DESCRIPTION
+The
+.Nm
+utility alters the
+scheduling priority of one or more running processes.
+The following
+.Ar who
+parameters are interpreted as process ID's, process group
+ID's, user ID's or user names.
+The
+.Nm Ns 'ing
+of a process group causes all processes in the process group
+to have their scheduling priority altered.
+The
+.Nm Ns 'ing
+of a user causes all processes owned by the user to have
+their scheduling priority altered.
+By default, the processes to be affected are specified by
+their process ID's.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl g
+Force
+.Ar who
+parameters to be interpreted as process group ID's.
+.It Fl n
+Instead of changing the specified processes to the given priority,
+interpret the following argument as an increment to be applied to
+the current priority of each process.
+.It Fl u
+Force the
+.Ar who
+parameters to be interpreted as user names or user ID's.
+.It Fl p
+Reset the
+.Ar who
+interpretation to be (the default) process ID's.
+.El
+.Pp
+For example,
+.Pp
+.Dl "renice +1 987 -u daemon root -p 32"
+.Pp
+would change the priority of process ID's 987 and 32, and
+all processes owned by users daemon and root.
+.Pp
+Users other than the super-user may only alter the priority of
+processes they own,
+and can only monotonically increase their ``nice value''
+within the range 0 to
+.Dv PRIO_MAX
+(20).
+(This prevents overriding administrative fiats.)
+The super-user
+may alter the priority of any process
+and set the priority to any value in the range
+.Dv PRIO_MIN
+(\-20)
+to
+.Dv PRIO_MAX .
+Useful priorities are:
+20 (the affected processes will run at the lowest priority),
+0 (the ``base'' scheduling priority),
+anything negative (lower values cause more favorable scheduling).
+.Sh FILES
+.Bl -tag -width /etc/passwd -compact
+.It Pa /etc/passwd
+to map user names to user ID's
+.El
+.Sh SEE ALSO
+.Xr nice 1 ,
+.Xr getpriority 2 ,
+.Xr setpriority 2
+.Sh STANDARDS
+The
+.Nm
+utility conforms to
+.St -p1003.1-2001 .
+.Sh HISTORY
+The
+.Nm
+utility appeared in
+.Bx 4.0 .
+.Sh BUGS
+Non super-users cannot increase scheduling priorities of their own processes,
+even if they were the ones that decreased the priorities in the first place.
diff --git a/shell_cmds/renice/renice.c b/shell_cmds/renice/renice.c
new file mode 100644
index 0000000..d7253e0
--- /dev/null
+++ b/shell_cmds/renice/renice.c
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 1983, 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1983, 1989, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)renice.c 8.1 (Berkeley) 6/9/93";
+#endif /* not lint */
+#endif
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+#include <err.h>
+#include <errno.h>
+#include <limits.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static int donice(int, int, int, int);
+static int getnum(const char *, const char *, int *);
+static void usage(void);
+
+/*
+ * Change the priority (nice) of processes
+ * or groups of processes which are already
+ * running.
+ */
+int
+main(int argc, char *argv[])
+{
+ struct passwd *pwd;
+ int errs, incr, prio, which, who;
+ int delim;
+ int priflag;
+
+ errs = 0;
+ incr = 0;
+ which = PRIO_PROCESS;
+ who = 0;
+ argc--, argv++;
+ if (argc < 2)
+ usage();
+ delim = 0;
+ priflag = 0;
+
+ /* incrementing priflag here ensures we only process
+ the single priority arg if it is the very first arg */
+ for (; argc > 0; argc--, argv++, priflag++) {
+ /* once we've seen -- , don't process anymore switches */
+ if (0 == delim) {
+ /* -n must immediately be followed by the incremental
+ priority */
+ if (strcmp(*argv, "-n") == 0) {
+ incr = 1;
+ argc--, argv++;
+ if (getnum("priority", *argv, &prio))
+ return (1);
+ continue;
+ }
+ if (strcmp(*argv, "-g") == 0) {
+ which = PRIO_PGRP;
+ continue;
+ }
+ if (strcmp(*argv, "-u") == 0) {
+ which = PRIO_USER;
+ continue;
+ }
+ if (strcmp(*argv, "-p") == 0) {
+ which = PRIO_PROCESS;
+ continue;
+ }
+ if (strcmp(*argv, "--") == 0) {
+ delim = 1;
+ continue;
+ }
+ if (0 == priflag) {
+ /* if very first switch/arg and we've made it to
+ here, this must be the priority */
+ if (getnum("priority", *argv, &prio)) {
+ return(1);
+ }
+ continue;
+ }
+ }
+ if (which == PRIO_USER) {
+ if ((pwd = getpwnam(*argv)) != NULL)
+ who = pwd->pw_uid;
+ else if (getnum("uid", *argv, &who)) {
+ errs++;
+ continue;
+ } else if (who < 0) {
+ warnx("%s: bad value", *argv);
+ errs++;
+ continue;
+ }
+ } else {
+ if (getnum("pid", *argv, &who)) {
+ errs++;
+ continue;
+ }
+ if (who < 0) {
+ warnx("%s: bad value", *argv);
+ errs++;
+ continue;
+ }
+ }
+ errs += donice(which, who, prio, incr);
+ }
+ exit(errs != 0);
+}
+
+static int
+donice(int which, int who, int prio, int incr)
+{
+ int oldprio;
+
+ errno = 0;
+ oldprio = getpriority(which, who);
+ if (oldprio == -1 && errno) {
+ warn("%d: getpriority", who);
+ return (1);
+ }
+ if (incr)
+ prio = oldprio + prio;
+ if (prio > PRIO_MAX)
+ prio = PRIO_MAX;
+ if (prio < PRIO_MIN)
+ prio = PRIO_MIN;
+ if (setpriority(which, who, prio) < 0) {
+ warn("%d: setpriority", who);
+ return (1);
+ }
+ return (0);
+}
+
+static int
+getnum(const char *com, const char *str, int *val)
+{
+ long v;
+ char *ep;
+
+ errno = 0;
+ v = strtol(str, &ep, 10);
+ if (v < INT_MIN || v > INT_MAX || errno == ERANGE) {
+ warnx("%s argument %s is out of range.", com, str);
+ return (1);
+ }
+ if (ep == str || *ep != '\0' || errno != 0) {
+ warnx("Bad %s argument: %s.", com, str);
+ return (1);
+ }
+
+ *val = (int)v;
+ return (0);
+}
+
+static void
+usage()
+{
+ fprintf(stderr, "%s\n%s\n",
+"usage: renice priority [[-p] pid ...] [[-g] pgrp ...] [[-u] user ...]",
+" renice -n increment [[-p] pid ...] [[-g] pgrp ...] [[-u] user ...]");
+ exit(1);
+}
diff --git a/shell_cmds/script/script.1 b/shell_cmds/script/script.1
new file mode 100644
index 0000000..ad12c53
--- /dev/null
+++ b/shell_cmds/script/script.1
@@ -0,0 +1,217 @@
+.\" Copyright (c) 1980, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)script.1 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD$
+.\"
+.Dd December 4, 2013
+.Dt SCRIPT 1
+.Os
+.Sh NAME
+.Nm script
+.Nd make typescript of terminal session
+.Sh SYNOPSIS
+.Nm
+.Op Fl adkpqr
+.Op Fl F Ar pipe
+.Op Fl t Ar time
+.Op Ar file Op Ar command ...
+.Sh DESCRIPTION
+The
+.Nm
+utility makes a typescript of everything printed on your terminal.
+It is useful for students who need a hardcopy record of an interactive
+session as proof of an assignment, as the typescript file
+can be printed out later with
+.Xr lpr 1 .
+.Pp
+If the argument
+.Ar file
+is given,
+.Nm
+saves all dialogue in
+.Ar file .
+If no file name is given, the typescript is saved in the file
+.Pa typescript .
+.Pp
+If the argument
+.Ar command
+is given,
+.Nm
+will run the specified command with an optional argument vector
+instead of an interactive shell.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl a
+Append the output to
+.Ar file
+or
+.Pa typescript ,
+retaining the prior contents.
+.It Fl d
+When playing back a session with the
+.Fl p
+flag, do not sleep between records when playing back a timestamped session.
+.It Fl F Ar pipe
+Immediately flush output after each write.
+This will allow a user to create a named pipe using
+.Xr mkfifo 1
+and another user may watch the live session using a utility like
+.Xr cat 1 .
+.\".It Fl f
+.\"Create
+.\".Ar file.filemon
+.\"or
+.\".Pa typescript.filemon
+.\"using
+.\".Xr filemon 4 .
+.It Fl k
+Log keys sent to the program as well as output.
+.It Fl p
+Play back a session recorded with the
+.Fl r
+flag in real time.
+.It Fl q
+Run in quiet mode, omit the start, stop and command status messages.
+.It Fl r
+Record a session with input, output, and timestamping.
+.It Fl t Ar time
+Specify the interval at which the script output file will be flushed
+to disk, in seconds.
+A value of 0
+causes
+.Nm
+to flush after every character I/O event.
+The default interval is
+30 seconds.
+.El
+.Pp
+The script ends when the forked shell (or command) exits (a
+.Em control-D
+to exit
+the Bourne shell
+.Pf ( Xr sh 1 ) ,
+and
+.Em exit ,
+.Em logout
+or
+.Em control-D
+(if
+.Em ignoreeof
+is not set) for the
+C-shell,
+.Xr csh 1 ) .
+.Pp
+Certain interactive commands, such as
+.Xr vi 1 ,
+create garbage in the typescript file.
+The
+.Nm
+utility works best with commands that do not manipulate the screen.
+The results are meant to emulate a hardcopy terminal, not an addressable one.
+.Sh ENVIRONMENT
+The following environment variables are utilized by
+.Nm :
+.Bl -tag -width SHELL
+.It Ev SCRIPT
+The
+.Ev SCRIPT
+environment variable is added to the sub-shell.
+If
+.Ev SCRIPT
+already existed in the users environment,
+its value is overwritten within the sub-shell.
+The value of
+.Ev SCRIPT
+is the name of the
+.Ar typescript
+file.
+.It Ev SHELL
+If the variable
+.Ev SHELL
+exists, the shell forked by
+.Nm
+will be that shell.
+If
+.Ev SHELL
+is not set, the Bourne shell
+is assumed.
+.Pq Most shells set this variable automatically .
+.El
+.Sh SEE ALSO
+.Xr csh 1
+.\".Xr filemon 4
+.\".Po
+.\"for the
+.\".Em history
+.\"mechanism
+.\".Pc .
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 3.0 .
+.Pp
+The
+.Fl d ,
+.Fl p
+and
+.Fl r
+options first appeared in
+.Nx 2.0
+and were ported to
+.Fx 9.2 .
+.Sh BUGS
+The
+.Nm
+utility places
+.Sy everything
+in the log file, including linefeeds and backspaces.
+This is not what the naive user expects.
+.Pp
+It is not possible to specify a command without also naming the script file
+because of argument parsing compatibility issues.
+.Pp
+When running in
+.Fl k
+mode, echo cancelling is far from ideal.
+The slave terminal mode is checked
+for ECHO mode to check when to avoid manual echo logging.
+This does not
+work when the terminal is in a raw mode where
+the program being run is doing manual echo.
+.Pp
+If
+.Nm
+reads zero bytes from the terminal, it switches to a mode when it
+only attempts to read
+once a second until there is data to read.
+This prevents
+.Nm
+from spinning on zero-byte reads, but might cause a 1-second delay in
+processing of user input.
diff --git a/shell_cmds/script/script.c b/shell_cmds/script/script.c
new file mode 100644
index 0000000..90e895e
--- /dev/null
+++ b/shell_cmds/script/script.c
@@ -0,0 +1,546 @@
+/*
+ * Copyright (c) 2010, 2012 David E. O'Brien
+ * Copyright (c) 1980, 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+__FBSDID("$FreeBSD$");
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1980, 1992, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif
+#ifndef lint
+static const char sccsid[] = "@(#)script.c 8.1 (Berkeley) 6/6/93";
+#endif
+
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <sys/uio.h>
+#ifdef __APPLE__
+#include <libkern/OSByteOrder.h>
+#else
+#include <sys/endian.h>
+#endif
+#ifdef ENABLE_FILEMON
+#include <dev/filemon/filemon.h>
+#endif /* ENABLE_FILEMON */
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#ifdef __APPLE__
+#include <util.h>
+#else
+#include <libutil.h>
+#endif
+#include <paths.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+
+#define DEF_BUF 65536
+
+struct stamp {
+ uint64_t scr_len; /* amount of data */
+ uint64_t scr_sec; /* time it arrived in seconds... */
+ uint32_t scr_usec; /* ...and microseconds */
+ uint32_t scr_direction; /* 'i', 'o', etc (also indicates endianness) */
+};
+
+static FILE *fscript;
+static int master, slave;
+static int child;
+static const char *fname;
+static char *fmfname;
+#ifdef ENABLE_FILEMON
+static int fflg, qflg, ttyflg;
+#else /* !ENABLE_FILEMON */
+static int qflg, ttyflg;
+#endif /* ENABLE_FILEMON */
+static int usesleep, rawout;
+
+static struct termios tt;
+
+static void done(int) __dead2;
+static void doshell(char **);
+static void fail(void);
+static void finish(void);
+static void record(FILE *, char *, size_t, int);
+static void consume(FILE *, off_t, char *, int);
+static void playback(FILE *) __dead2;
+static void usage(void);
+
+int
+main(int argc, char *argv[])
+{
+ int cc;
+ struct termios rtt, stt;
+ struct winsize win;
+ struct timeval tv, *tvp;
+ time_t tvec, start;
+ char obuf[BUFSIZ];
+ char ibuf[BUFSIZ];
+ fd_set rfd;
+ int aflg, Fflg, kflg, pflg, ch, k, n;
+ int flushtime, readstdin;
+#ifdef ENABLE_FILEMON
+ int fm_fd, fm_log;
+#endif /* ENABLE_FILEMON */
+
+ aflg = Fflg = kflg = pflg = 0;
+ usesleep = 1;
+ rawout = 0;
+ flushtime = 30;
+#ifdef ENABLE_FILEMON
+ fm_fd = -1; /* Shut up stupid "may be used uninitialized" GCC
+ warning. (not needed w/clang) */
+#endif /* ENABLE_FILEMON */
+
+#ifdef ENABLE_FILEMON
+ while ((ch = getopt(argc, argv, "adFfkpqrt:")) != -1)
+#else /* !ENABLE_FILEMON */
+ while ((ch = getopt(argc, argv, "adFkpqrt:")) != -1)
+#endif /* ENABLE_FILEMON */
+ switch(ch) {
+ case 'a':
+ aflg = 1;
+ break;
+ case 'd':
+ usesleep = 0;
+ break;
+ case 'F':
+ Fflg = 1;
+ break;
+#ifdef ENABLE_FILEMON
+ case 'f':
+ fflg = 1;
+ break;
+#endif /* ENABLE_FILEMON */
+ case 'k':
+ kflg = 1;
+ break;
+ case 'p':
+ pflg = 1;
+ break;
+ case 'q':
+ qflg = 1;
+ break;
+ case 'r':
+ rawout = 1;
+ break;
+ case 't':
+ flushtime = atoi(optarg);
+ if (flushtime < 0)
+ err(1, "invalid flush time %d", flushtime);
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc > 0) {
+ fname = argv[0];
+ argv++;
+ argc--;
+ } else
+ fname = "typescript";
+
+ if ((fscript = fopen(fname, pflg ? "r" : aflg ? "a" : "w")) == NULL)
+ err(1, "%s", fname);
+
+#ifdef ENABLE_FILEMON
+ if (fflg) {
+ asprintf(&fmfname, "%s.filemon", fname);
+ if (!fmfname)
+ err(1, "%s.filemon", fname);
+ if ((fm_fd = open("/dev/filemon", O_RDWR)) == -1)
+ err(1, "open(\"/dev/filemon\", O_RDWR)");
+ if ((fm_log = open(fmfname, O_WRONLY | O_CREAT | O_TRUNC,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1)
+ err(1, "open(%s)", fmfname);
+ if (ioctl(fm_fd, FILEMON_SET_FD, &fm_log) < 0)
+ err(1, "Cannot set filemon log file descriptor");
+
+ /* Set up these two fd's to close on exec. */
+ (void)fcntl(fm_fd, F_SETFD, FD_CLOEXEC);
+ (void)fcntl(fm_log, F_SETFD, FD_CLOEXEC);
+ }
+#endif /* ENABLE_FILEMON */
+
+ if (pflg)
+ playback(fscript);
+
+ if ((ttyflg = isatty(STDIN_FILENO)) != 0) {
+ if (tcgetattr(STDIN_FILENO, &tt) == -1)
+ err(1, "tcgetattr");
+ if (ioctl(STDIN_FILENO, TIOCGWINSZ, &win) == -1)
+ err(1, "ioctl");
+ if (openpty(&master, &slave, NULL, &tt, &win) == -1)
+ err(1, "openpty");
+ } else {
+ if (openpty(&master, &slave, NULL, NULL, NULL) == -1)
+ err(1, "openpty");
+ }
+
+ if (rawout)
+ record(fscript, NULL, 0, 's');
+
+ if (!qflg) {
+ tvec = time(NULL);
+ (void)printf("Script started, output file is %s\n", fname);
+ if (!rawout) {
+ (void)fprintf(fscript, "Script started on %s",
+ ctime(&tvec));
+ if (argv[0]) {
+ fprintf(fscript, "command: ");
+ for (k = 0 ; argv[k] ; ++k)
+ fprintf(fscript, "%s%s", k ? " " : "",
+ argv[k]);
+ fprintf(fscript, "\n");
+ }
+ }
+ fflush(fscript);
+#ifdef ENABLE_FILEMON
+ if (fflg) {
+ (void)printf("Filemon started, output file is %s\n",
+ fmfname);
+ }
+#endif /* ENABLE_FILEMON */
+ }
+ if (ttyflg) {
+ rtt = tt;
+ cfmakeraw(&rtt);
+ rtt.c_lflag &= ~ECHO;
+ (void)tcsetattr(STDIN_FILENO, TCSAFLUSH, &rtt);
+ }
+
+ child = fork();
+ if (child < 0) {
+ warn("fork");
+ done(1);
+ }
+ if (child == 0)
+ doshell(argv);
+ close(slave);
+
+#ifdef ENABLE_FILEMON
+ if (fflg && ioctl(fm_fd, FILEMON_SET_PID, &child) < 0)
+ err(1, "Cannot set filemon PID");
+#endif /* ENABLE_FILEMON */
+
+ start = tvec = time(0);
+ readstdin = 1;
+ for (;;) {
+ FD_ZERO(&rfd);
+ FD_SET(master, &rfd);
+ if (readstdin)
+ FD_SET(STDIN_FILENO, &rfd);
+ if (!readstdin && ttyflg) {
+ tv.tv_sec = 1;
+ tv.tv_usec = 0;
+ tvp = &tv;
+ readstdin = 1;
+ } else if (flushtime > 0) {
+ tv.tv_sec = flushtime - (tvec - start);
+ tv.tv_usec = 0;
+ tvp = &tv;
+ } else {
+ tvp = NULL;
+ }
+ n = select(master + 1, &rfd, 0, 0, tvp);
+ if (n < 0 && errno != EINTR)
+ break;
+ if (n > 0 && FD_ISSET(STDIN_FILENO, &rfd)) {
+ cc = read(STDIN_FILENO, ibuf, BUFSIZ);
+ if (cc < 0)
+ break;
+ if (cc == 0) {
+ if (tcgetattr(master, &stt) == 0 &&
+ (stt.c_lflag & ICANON) != 0) {
+ (void)write(master, &stt.c_cc[VEOF], 1);
+ }
+ readstdin = 0;
+ }
+ if (cc > 0) {
+ if (rawout)
+ record(fscript, ibuf, cc, 'i');
+ (void)write(master, ibuf, cc);
+ if (kflg && tcgetattr(master, &stt) >= 0 &&
+ ((stt.c_lflag & ECHO) == 0)) {
+ (void)fwrite(ibuf, 1, cc, fscript);
+ }
+ }
+ }
+ if (n > 0 && FD_ISSET(master, &rfd)) {
+ cc = read(master, obuf, sizeof (obuf));
+ if (cc <= 0)
+ break;
+ (void)write(STDOUT_FILENO, obuf, cc);
+ if (rawout)
+ record(fscript, obuf, cc, 'o');
+ else
+ (void)fwrite(obuf, 1, cc, fscript);
+ }
+ tvec = time(0);
+ if (tvec - start >= flushtime) {
+ fflush(fscript);
+ start = tvec;
+ }
+ if (Fflg)
+ fflush(fscript);
+ }
+ finish();
+ done(0);
+}
+
+static void
+usage(void)
+{
+ (void)fprintf(stderr,
+#ifdef ENABLE_FILEMON
+ "usage: script [-adfkpqr] [-t time] [file [command ...]]\n");
+#else /* !ENABLE_FILEMON */
+ "usage: script [-adkpqr] [-t time] [file [command ...]]\n");
+#endif /* ENABLE_FILEMON */
+ exit(1);
+}
+
+static void
+finish(void)
+{
+ int e, status;
+
+ if (waitpid(child, &status, 0) == child) {
+ if (WIFEXITED(status))
+ e = WEXITSTATUS(status);
+ else if (WIFSIGNALED(status))
+ e = WTERMSIG(status);
+ else /* can't happen */
+ e = 1;
+ done(e);
+ }
+}
+
+static void
+doshell(char **av)
+{
+ const char *shell;
+
+ shell = getenv("SHELL");
+ if (shell == NULL)
+ shell = _PATH_BSHELL;
+
+ (void)close(master);
+ (void)fclose(fscript);
+ free(fmfname);
+ login_tty(slave);
+ setenv("SCRIPT", fname, 1);
+ if (av[0]) {
+ execvp(av[0], av);
+ warn("%s", av[0]);
+ } else {
+ execl(shell, shell, "-i", (char *)NULL);
+ warn("%s", shell);
+ }
+ fail();
+}
+
+static void
+fail(void)
+{
+ (void)kill(0, SIGTERM);
+ done(1);
+}
+
+static void
+done(int eno)
+{
+ time_t tvec;
+
+ if (ttyflg)
+ (void)tcsetattr(STDIN_FILENO, TCSAFLUSH, &tt);
+ tvec = time(NULL);
+ if (rawout)
+ record(fscript, NULL, 0, 'e');
+ if (!qflg) {
+ if (!rawout)
+ (void)fprintf(fscript,"\nScript done on %s",
+ ctime(&tvec));
+ (void)printf("\nScript done, output file is %s\n", fname);
+#ifdef ENABLE_FILEMON
+ if (fflg) {
+ (void)printf("Filemon done, output file is %s\n",
+ fmfname);
+ }
+#endif /* ENABLE_FILEMON */
+ }
+ (void)fclose(fscript);
+ (void)close(master);
+ exit(eno);
+}
+
+static void
+record(FILE *fp, char *buf, size_t cc, int direction)
+{
+ struct iovec iov[2];
+ struct stamp stamp;
+ struct timeval tv;
+
+ (void)gettimeofday(&tv, NULL);
+ stamp.scr_len = cc;
+ stamp.scr_sec = tv.tv_sec;
+ stamp.scr_usec = tv.tv_usec;
+ stamp.scr_direction = direction;
+ iov[0].iov_len = sizeof(stamp);
+ iov[0].iov_base = &stamp;
+ iov[1].iov_len = cc;
+ iov[1].iov_base = buf;
+ if (writev(fileno(fp), &iov[0], 2) == -1)
+ err(1, "writev");
+}
+
+static void
+consume(FILE *fp, off_t len, char *buf, int reg)
+{
+ size_t l;
+
+ if (reg) {
+ if (fseeko(fp, len, SEEK_CUR) == -1)
+ err(1, NULL);
+ }
+ else {
+ while (len > 0) {
+ l = MIN(DEF_BUF, len);
+ if (fread(buf, sizeof(char), l, fp) != l)
+ err(1, "cannot read buffer");
+ len -= l;
+ }
+ }
+}
+
+#ifdef __APPLE__
+#define bswap32 OSSwapInt32
+#define bswap64 OSSwapInt64
+#endif /* __APPLE__ */
+#define swapstamp(stamp) do { \
+ if (stamp.scr_direction > 0xff) { \
+ stamp.scr_len = bswap64(stamp.scr_len); \
+ stamp.scr_sec = bswap64(stamp.scr_sec); \
+ stamp.scr_usec = bswap32(stamp.scr_usec); \
+ stamp.scr_direction = bswap32(stamp.scr_direction); \
+ } \
+} while (0/*CONSTCOND*/)
+
+static void
+playback(FILE *fp)
+{
+ struct timespec tsi, tso;
+ struct stamp stamp;
+ struct stat pst;
+ char buf[DEF_BUF];
+ off_t nread, save_len;
+ size_t l;
+ time_t tclock;
+ int reg;
+
+ if (fstat(fileno(fp), &pst) == -1)
+ err(1, "fstat failed");
+
+ reg = S_ISREG(pst.st_mode);
+
+ for (nread = 0; !reg || nread < pst.st_size; nread += save_len) {
+ if (fread(&stamp, sizeof(stamp), 1, fp) != 1) {
+ if (reg)
+ err(1, "reading playback header");
+ else
+ break;
+ }
+ swapstamp(stamp);
+ save_len = sizeof(stamp);
+
+ if (reg && stamp.scr_len >
+ (uint64_t)(pst.st_size - save_len) - nread)
+ errx(1, "invalid stamp");
+
+ save_len += stamp.scr_len;
+ tclock = stamp.scr_sec;
+ tso.tv_sec = stamp.scr_sec;
+ tso.tv_nsec = stamp.scr_usec * 1000;
+
+ switch (stamp.scr_direction) {
+ case 's':
+ if (!qflg)
+ (void)printf("Script started on %s",
+ ctime(&tclock));
+ tsi = tso;
+ (void)consume(fp, stamp.scr_len, buf, reg);
+ break;
+ case 'e':
+ if (!qflg)
+ (void)printf("\nScript done on %s",
+ ctime(&tclock));
+ (void)consume(fp, stamp.scr_len, buf, reg);
+ break;
+ case 'i':
+ /* throw input away */
+ (void)consume(fp, stamp.scr_len, buf, reg);
+ break;
+ case 'o':
+ tsi.tv_sec = tso.tv_sec - tsi.tv_sec;
+ tsi.tv_nsec = tso.tv_nsec - tsi.tv_nsec;
+ if (tsi.tv_nsec < 0) {
+ tsi.tv_sec -= 1;
+ tsi.tv_nsec += 1000000000;
+ }
+ if (usesleep)
+ (void)nanosleep(&tsi, NULL);
+ tsi = tso;
+ while (stamp.scr_len > 0) {
+ l = MIN(DEF_BUF, stamp.scr_len);
+ if (fread(buf, sizeof(char), l, fp) != l)
+ err(1, "cannot read buffer");
+
+ (void)write(STDOUT_FILENO, buf, l);
+ stamp.scr_len -= l;
+ }
+ break;
+ default:
+ errx(1, "invalid direction");
+ }
+ }
+ (void)fclose(fp);
+ exit(0);
+}
diff --git a/shell_cmds/script/script.plist.part b/shell_cmds/script/script.plist.part
new file mode 100644
index 0000000..b112d31
--- /dev/null
+++ b/shell_cmds/script/script.plist.part
@@ -0,0 +1,20 @@
+ <dict>
+ <key>OpenSourceProject</key>
+ <string>script</string>
+ <key>OpenSourceVersion</key>
+ <string>2014-01-17</string>
+ <key>OpenSourceWebsiteURL</key>
+ <string>http://svnweb.freebsd.org/base/head/usr.bin/script/</string>
+ <key>OpenSourceSCM</key>
+ <string>svn co http://svn.freebsd.org/base/head/usr.bin/script/</string>
+ <key>OpenSourceImportDate</key>
+ <string>2014-09-22</string>
+ <key>OpenSourceModifications</key>
+ <array>
+ <string>Use OSByteOrder swap functions.</string>
+ <string>Include util.h instead of libutil.h.</string>
+ <string>Disable -f (filemon) feature, guarded with ENABLE_FILEMON.</string>
+ </array>
+ <key>OpenSourceLicense</key>
+ <string>bsd</string>
+ </dict>
diff --git a/shell_cmds/seq/seq.1 b/shell_cmds/seq/seq.1
new file mode 100644
index 0000000..4af7b99
--- /dev/null
+++ b/shell_cmds/seq/seq.1
@@ -0,0 +1,187 @@
+.\" $NetBSD: seq.1,v 1.6 2008/11/26 15:03:47 ginsbach Exp $
+.\"
+.\" Copyright (c) 2005 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Brian Ginsbach.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/usr.bin/seq/seq.1,v 1.1 2010/02/19 23:54:12 delphij Exp $
+.\"
+.Dd February 19, 2010
+.Dt SEQ 1
+.Os
+.Sh NAME
+.Nm seq
+.Nd print sequences of numbers
+.Sh SYNOPSIS
+.Nm
+.Op Fl w
+.Op Fl f Ar format
+.Op Fl s Ar string
+.Op Fl t Ar string
+.Op Ar first Op Ar incr
+.Ar last
+.Sh DESCRIPTION
+The
+.Nm
+utility prints a sequence of numbers, one per line
+.Pq default ,
+from
+.Ar first
+.Pq default 1 ,
+to near
+.Ar last
+as possible, in increments of
+.Ar incr
+.Pq default 1 .
+When
+.Ar first
+is larger than
+.Ar last
+the default
+.Ar incr
+is -1.
+.Pp
+All numbers are interpreted as floating point.
+.Pp
+Normally integer values are printed as decimal integers.
+.Pp
+The
+.Nm
+utility accepts the following options:
+.Bl -tag -width Ar
+.It Fl f Ar format
+Use a
+.Xr printf 3
+style
+.Ar format
+to print each number.
+Only the
+.Cm E ,
+.Cm e ,
+.Cm f ,
+.Cm G ,
+.Cm g ,
+and
+.Cm %
+conversion characters are valid, along with any optional
+flags and an optional numeric minimum field width or precision.
+The
+.Ar format
+can contain character escape sequences in backslash notation as
+defined in
+.St -ansiC .
+The default is
+.Cm %g .
+.It Fl s Ar string
+Use
+.Ar string
+to separate numbers.
+The
+.Ar string
+can contain character escape sequences in backslash notation as
+defined in
+.St -ansiC .
+The default is
+.Cm \en .
+.It Fl t Ar string
+Use
+.Ar string
+to terminate sequence of numbers.
+The
+.Ar string
+can contain character escape sequences in backslash notation as
+defined in
+.St -ansiC .
+This option is useful when the default separator
+does not contain a
+.Cm \en .
+.It Fl w
+Equalize the widths of all numbers by padding with zeros as necessary.
+This option has no effect with the
+.Fl f
+option.
+If any sequence numbers will be printed in exponential notation,
+the default conversion is changed to
+.Cm %e .
+.El
+.Pp
+The
+.Nm
+utility exits 0 on success and non-zero if an error occurs.
+.Sh EXAMPLES
+.Bd -literal -offset indent
+# seq 1 3
+1
+2
+3
+
+# seq 3 1
+3
+2
+1
+
+# seq -w 0 .05 .1
+0.00
+0.05
+0.10
+.Ed
+.Sh SEE ALSO
+.Xr jot 1 ,
+.Xr printf 1 ,
+.Xr printf 3
+.Sh HISTORY
+The
+.Nm
+command first appeared in
+.Tn "Plan 9 from Bell Labs" .
+A
+.Nm
+command appeared in
+.Nx 3.0 ,
+and ported to
+.Fx 9.0 .
+This command was based on the command of the same name in
+.Tn "Plan 9 from Bell Labs"
+and the
+.Tn GNU
+core utilities.
+The
+.Tn GNU
+.Nm
+command first appeared in the 1.13 shell utilities release.
+.Sh BUGS
+The
+.Fl w
+option does not handle the transition from pure floating point
+to exponent representation very well.
+The
+.Nm
+command is not bug for bug compatible with the
+.Tn "Plan 9 from Bell Labs"
+or
+.Tn GNU
+versions of
+.Nm .
diff --git a/shell_cmds/seq/seq.c b/shell_cmds/seq/seq.c
new file mode 100644
index 0000000..9c3623d
--- /dev/null
+++ b/shell_cmds/seq/seq.c
@@ -0,0 +1,453 @@
+/* $NetBSD: seq.c,v 1.5 2008/07/21 14:19:26 lukem Exp $ */
+/*
+ * Copyright (c) 2005 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Brian Ginsbach.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/seq/seq.c,v 1.2 2010/02/20 01:23:15 delphij Exp $");
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <math.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define ZERO '0'
+#define SPACE ' '
+
+#define MAX(a, b) (((a) < (b))? (b) : (a))
+#define ISSIGN(c) ((int)(c) == '-' || (int)(c) == '+')
+#define ISEXP(c) ((int)(c) == 'e' || (int)(c) == 'E')
+#define ISODIGIT(c) ((int)(c) >= '0' && (int)(c) <= '7')
+
+/* Globals */
+
+const char *decimal_point = "."; /* default */
+char default_format[] = { "%g" }; /* default */
+
+/* Prototypes */
+
+double e_atof(const char *);
+
+int decimal_places(const char *);
+int main(int, char *[]);
+int numeric(const char *);
+int valid_format(const char *);
+
+char *generate_format(double, double, double, int, char);
+char *unescape(char *);
+
+/*
+ * The seq command will print out a numeric sequence from 1, the default,
+ * to a user specified upper limit by 1. The lower bound and increment
+ * maybe indicated by the user on the command line. The sequence can
+ * be either whole, the default, or decimal numbers.
+ */
+int
+main(int argc, char *argv[])
+{
+ int c = 0, errflg = 0;
+ int equalize = 0;
+ double first = 1.0;
+ double last = 0.0;
+ double incr = 0.0;
+ struct lconv *locale;
+ char *fmt = NULL;
+ const char *sep = "\n";
+ const char *term = NULL;
+ char pad = ZERO;
+
+ /* Determine the locale's decimal point. */
+ locale = localeconv();
+ if (locale && locale->decimal_point && locale->decimal_point[0] != '\0')
+ decimal_point = locale->decimal_point;
+
+ /*
+ * Process options, but handle negative numbers separately
+ * least they trip up getopt(3).
+ */
+ while ((optind < argc) && !numeric(argv[optind]) &&
+ (c = getopt(argc, argv, "f:hs:t:w")) != -1) {
+
+ switch (c) {
+ case 'f': /* format (plan9) */
+ fmt = optarg;
+ equalize = 0;
+ break;
+ case 's': /* separator (GNU) */
+ sep = unescape(optarg);
+ break;
+ case 't': /* terminator (new) */
+ term = unescape(optarg);
+ break;
+ case 'w': /* equal width (plan9) */
+ if (!fmt)
+ if (equalize++)
+ pad = SPACE;
+ break;
+ case 'h': /* help (GNU) */
+ default:
+ errflg++;
+ break;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+ if (argc < 1 || argc > 3)
+ errflg++;
+
+ if (errflg) {
+ fprintf(stderr,
+ "usage: %s [-w] [-f format] [-s string] [-t string] [first [incr]] last\n",
+ getprogname());
+ exit(1);
+ }
+
+ last = e_atof(argv[argc - 1]);
+
+ if (argc > 1)
+ first = e_atof(argv[0]);
+
+ if (argc > 2) {
+ incr = e_atof(argv[1]);
+ /* Plan 9/GNU don't do zero */
+ if (incr == 0.0)
+ errx(1, "zero %screment", (first < last)? "in" : "de");
+ }
+
+ /* default is one for Plan 9/GNU work alike */
+ if (incr == 0.0)
+ incr = (first < last) ? 1.0 : -1.0;
+
+ if (incr <= 0.0 && first < last)
+ errx(1, "needs positive increment");
+
+ if (incr >= 0.0 && first > last)
+ errx(1, "needs negative decrement");
+
+ if (fmt != NULL) {
+ if (!valid_format(fmt))
+ errx(1, "invalid format string: `%s'", fmt);
+ fmt = unescape(fmt);
+ /*
+ * XXX to be bug for bug compatible with Plan 9 add a
+ * newline if none found at the end of the format string.
+ */
+ } else
+ fmt = generate_format(first, incr, last, equalize, pad);
+
+ if (incr > 0) {
+ for (; first <= last; first += incr) {
+ printf(fmt, first);
+ fputs(sep, stdout);
+ }
+ } else {
+ for (; first >= last; first += incr) {
+ printf(fmt, first);
+ fputs(sep, stdout);
+ }
+ }
+ if (term != NULL)
+ fputs(term, stdout);
+
+ return (0);
+}
+
+/*
+ * numeric - verify that string is numeric
+ */
+int
+numeric(const char *s)
+{
+ int seen_decimal_pt, decimal_pt_len;
+
+ /* skip any sign */
+ if (ISSIGN((unsigned char)*s))
+ s++;
+
+ seen_decimal_pt = 0;
+ decimal_pt_len = strlen(decimal_point);
+ while (*s) {
+ if (!isdigit((unsigned char)*s)) {
+ if (!seen_decimal_pt &&
+ strncmp(s, decimal_point, decimal_pt_len) == 0) {
+ s += decimal_pt_len;
+ seen_decimal_pt = 1;
+ continue;
+ }
+ if (ISEXP((unsigned char)*s)) {
+ s++;
+ if (ISSIGN((unsigned char)*s) ||
+ isdigit((unsigned char)*s)) {
+ s++;
+ continue;
+ }
+ }
+ break;
+ }
+ s++;
+ }
+ return (*s == '\0');
+}
+
+/*
+ * valid_format - validate user specified format string
+ */
+int
+valid_format(const char *fmt)
+{
+ int conversions = 0;
+
+ while (*fmt != '\0') {
+ /* scan for conversions */
+ if (*fmt != '\0' && *fmt != '%') {
+ do {
+ fmt++;
+ } while (*fmt != '\0' && *fmt != '%');
+ }
+ /* scan a conversion */
+ if (*fmt != '\0') {
+ do {
+ fmt++;
+
+ /* ok %% */
+ if (*fmt == '%') {
+ fmt++;
+ break;
+ }
+ /* valid conversions */
+ if (strchr("eEfgG", *fmt) &&
+ conversions++ < 1) {
+ fmt++;
+ break;
+ }
+ /* flags, width and precsision */
+ if (isdigit((unsigned char)*fmt) ||
+ strchr("+- 0#.", *fmt))
+ continue;
+
+ /* oops! bad conversion format! */
+ return (0);
+ } while (*fmt != '\0');
+ }
+ }
+
+ return (conversions <= 1);
+}
+
+/*
+ * unescape - handle C escapes in a string
+ */
+char *
+unescape(char *orig)
+{
+ char c, *cp, *new = orig;
+ int i;
+
+ for (cp = orig; (*orig = *cp); cp++, orig++) {
+ if (*cp != '\\')
+ continue;
+
+ switch (*++cp) {
+ case 'a': /* alert (bell) */
+ *orig = '\a';
+ continue;
+ case 'b': /* backspace */
+ *orig = '\b';
+ continue;
+ case 'e': /* escape */
+ *orig = '\e';
+ continue;
+ case 'f': /* formfeed */
+ *orig = '\f';
+ continue;
+ case 'n': /* newline */
+ *orig = '\n';
+ continue;
+ case 'r': /* carriage return */
+ *orig = '\r';
+ continue;
+ case 't': /* horizontal tab */
+ *orig = '\t';
+ continue;
+ case 'v': /* vertical tab */
+ *orig = '\v';
+ continue;
+ case '\\': /* backslash */
+ *orig = '\\';
+ continue;
+ case '\'': /* single quote */
+ *orig = '\'';
+ continue;
+ case '\"': /* double quote */
+ *orig = '"';
+ continue;
+ case '0':
+ case '1':
+ case '2':
+ case '3': /* octal */
+ case '4':
+ case '5':
+ case '6':
+ case '7': /* number */
+ for (i = 0, c = 0;
+ ISODIGIT((unsigned char)*cp) && i < 3;
+ i++, cp++) {
+ c <<= 3;
+ c |= (*cp - '0');
+ }
+ *orig = c;
+ --cp;
+ continue;
+ case 'x': /* hexidecimal number */
+ cp++; /* skip 'x' */
+ for (i = 0, c = 0;
+ isxdigit((unsigned char)*cp) && i < 2;
+ i++, cp++) {
+ c <<= 4;
+ if (isdigit((unsigned char)*cp))
+ c |= (*cp - '0');
+ else
+ c |= ((toupper((unsigned char)*cp) -
+ 'A') + 10);
+ }
+ *orig = c;
+ --cp;
+ continue;
+ default:
+ --cp;
+ break;
+ }
+ }
+
+ return (new);
+}
+
+/*
+ * e_atof - convert an ASCII string to a double
+ * exit if string is not a valid double, or if converted value would
+ * cause overflow or underflow
+ */
+double
+e_atof(const char *num)
+{
+ char *endp;
+ double dbl;
+
+ errno = 0;
+ dbl = strtod(num, &endp);
+
+ if (errno == ERANGE)
+ /* under or overflow */
+ err(2, "%s", num);
+ else if (*endp != '\0')
+ /* "junk" left in number */
+ errx(2, "invalid floating point argument: %s", num);
+
+ /* zero shall have no sign */
+ if (dbl == -0.0)
+ dbl = 0;
+ return (dbl);
+}
+
+/*
+ * decimal_places - count decimal places in a number (string)
+ */
+int
+decimal_places(const char *number)
+{
+ int places = 0;
+ char *dp;
+
+ /* look for a decimal point */
+ if ((dp = strstr(number, decimal_point))) {
+ dp += strlen(decimal_point);
+
+ while (isdigit((unsigned char)*dp++))
+ places++;
+ }
+ return (places);
+}
+
+/*
+ * generate_format - create a format string
+ *
+ * XXX to be bug for bug compatable with Plan9 and GNU return "%g"
+ * when "%g" prints as "%e" (this way no width adjustments are made)
+ */
+char *
+generate_format(double first, double incr, double last, int equalize, char pad)
+{
+ static char buf[256];
+ char cc = '\0';
+ int precision, width1, width2, places;
+
+ if (equalize == 0)
+ return (default_format);
+
+ /* figure out "last" value printed */
+ if (first > last)
+ last = first - incr * floor((first - last) / incr);
+ else
+ last = first + incr * floor((last - first) / incr);
+
+ sprintf(buf, "%g", incr);
+ if (strchr(buf, 'e'))
+ cc = 'e';
+ precision = decimal_places(buf);
+
+ width1 = sprintf(buf, "%g", first);
+ if (strchr(buf, 'e'))
+ cc = 'e';
+ if ((places = decimal_places(buf)))
+ width1 -= (places + strlen(decimal_point));
+
+ precision = MAX(places, precision);
+
+ width2 = sprintf(buf, "%g", last);
+ if (strchr(buf, 'e'))
+ cc = 'e';
+ if ((places = decimal_places(buf)))
+ width2 -= (places + strlen(decimal_point));
+
+ if (precision) {
+ sprintf(buf, "%%%c%d.%d%c", pad,
+ MAX(width1, width2) + (int) strlen(decimal_point) +
+ precision, precision, (cc) ? cc : 'f');
+ } else {
+ sprintf(buf, "%%%c%d%c", pad, MAX(width1, width2),
+ (cc) ? cc : 'g');
+ }
+
+ return (buf);
+}
diff --git a/shell_cmds/sh/Makefile b/shell_cmds/sh/Makefile
new file mode 100644
index 0000000..8d08662
--- /dev/null
+++ b/shell_cmds/sh/Makefile
@@ -0,0 +1,70 @@
+# @(#)Makefile 8.4 (Berkeley) 5/5/95
+# $FreeBSD: head/bin/sh/Makefile 322515 2017-08-14 19:21:37Z ngie $
+
+.include <src.opts.mk>
+
+PACKAGE=runtime
+PROG= sh
+INSTALLFLAGS= -S
+SHSRCS= alias.c arith_yacc.c arith_yylex.c cd.c echo.c error.c eval.c \
+ exec.c expand.c \
+ histedit.c input.c jobs.c kill.c mail.c main.c memalloc.c miscbltin.c \
+ mystring.c options.c output.c parser.c printf.c redir.c show.c \
+ test.c trap.c var.c
+GENSRCS= builtins.c nodes.c syntax.c
+GENHDRS= builtins.h nodes.h syntax.h token.h
+SRCS= ${SHSRCS} ${GENSRCS} ${GENHDRS}
+
+# MLINKS for Shell built in commands for which there are no userland
+# utilities of the same name are handled with the associated manpage,
+# builtin.1 in share/man/man1/.
+
+LIBADD= edit
+
+CFLAGS+=-DSHELL -I. -I${.CURDIR}
+# for debug:
+# DEBUG_FLAGS+= -g -DDEBUG=2 -fno-inline
+WARNS?= 2
+WFORMAT=0
+
+.PATH: ${.CURDIR}/bltin \
+ ${.CURDIR:H}/kill \
+ ${.CURDIR:H}/test \
+ ${SRCTOP}/usr.bin/printf
+
+CLEANFILES+= mknodes mknodes.o \
+ mksyntax mksyntax.o
+CLEANFILES+= ${GENSRCS} ${GENHDRS}
+
+build-tools: mknodes mksyntax
+
+.ORDER: builtins.c builtins.h
+builtins.h: .NOMETA
+builtins.c builtins.h: mkbuiltins builtins.def
+ sh ${.CURDIR}/mkbuiltins ${.CURDIR}
+
+# XXX this is just to stop the default .c rule being used, so that the
+# intermediate object has a fixed name.
+# XXX we have a default .c rule, but no default .o rule.
+mknodes.o mksyntax.o: ${BUILD_TOOLS_META}
+ ${CC} ${CFLAGS} ${LDFLAGS} ${.IMPSRC} ${LDLIBS} -o ${.TARGET}
+mknodes: mknodes.o ${BUILD_TOOLS_META}
+mksyntax: mksyntax.o ${BUILD_TOOLS_META}
+
+.ORDER: nodes.c nodes.h
+nodes.h: .NOMETA
+nodes.c nodes.h: mknodes nodetypes nodes.c.pat
+ ${BTOOLSPATH:U.}/mknodes ${.CURDIR}/nodetypes ${.CURDIR}/nodes.c.pat
+
+.ORDER: syntax.c syntax.h
+syntax.h: .NOMETA
+syntax.c syntax.h: mksyntax
+ ${BTOOLSPATH:U.}/mksyntax
+
+token.h: mktokens
+ sh ${.CURDIR}/mktokens
+
+HAS_TESTS=
+SUBDIR.${MK_TESTS}+= tests
+
+.include <bsd.prog.mk>
diff --git a/shell_cmds/sh/Makefile.depend b/shell_cmds/sh/Makefile.depend
new file mode 100644
index 0000000..189c031
--- /dev/null
+++ b/shell_cmds/sh/Makefile.depend
@@ -0,0 +1,19 @@
+# $FreeBSD: head/bin/sh/Makefile.depend 325188 2017-10-31 00:07:04Z bdrewery $
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ gnu/lib/csu \
+ include \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libedit \
+ lib/ncurses/ncursesw \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/shell_cmds/sh/TOUR b/shell_cmds/sh/TOUR
new file mode 100644
index 0000000..82215f3
--- /dev/null
+++ b/shell_cmds/sh/TOUR
@@ -0,0 +1,301 @@
+# @(#)TOUR 8.1 (Berkeley) 5/31/93
+# $FreeBSD: head/bin/sh/TOUR 317882 2017-05-06 13:28:42Z jilles $
+
+NOTE -- This is the original TOUR paper distributed with ash and
+does not represent the current state of the shell. It is provided anyway
+since it provides helpful information for how the shell is structured,
+but be warned that things have changed -- the current shell is
+still under development.
+
+================================================================
+
+ A Tour through Ash
+
+ Copyright 1989 by Kenneth Almquist.
+
+
+DIRECTORIES: The subdirectory bltin contains commands which can
+be compiled stand-alone. The rest of the source is in the main
+ash directory.
+
+SOURCE CODE GENERATORS: Files whose names begin with "mk" are
+programs that generate source code. A complete list of these
+programs is:
+
+ program input files generates
+ ------- ----------- ---------
+ mkbuiltins builtins.def builtins.h builtins.c
+ mknodes nodetypes nodes.h nodes.c
+ mksyntax - syntax.h syntax.c
+ mktokens - token.h
+
+There are undoubtedly too many of these.
+
+EXCEPTIONS: Code for dealing with exceptions appears in
+exceptions.c. The C language doesn't include exception handling,
+so I implement it using setjmp and longjmp. The global variable
+exception contains the type of exception. EXERROR is raised by
+calling error. EXINT is an interrupt.
+
+INTERRUPTS: In an interactive shell, an interrupt will cause an
+EXINT exception to return to the main command loop. (Exception:
+EXINT is not raised if the user traps interrupts using the trap
+command.) The INTOFF and INTON macros (defined in exception.h)
+provide uninterruptible critical sections. Between the execution
+of INTOFF and the execution of INTON, interrupt signals will be
+held for later delivery. INTOFF and INTON can be nested.
+
+MEMALLOC.C: Memalloc.c defines versions of malloc and realloc
+which call error when there is no memory left. It also defines a
+stack oriented memory allocation scheme. Allocating off a stack
+is probably more efficient than allocation using malloc, but the
+big advantage is that when an exception occurs all we have to do
+to free up the memory in use at the time of the exception is to
+restore the stack pointer. The stack is implemented using a
+linked list of blocks.
+
+STPUTC: If the stack were contiguous, it would be easy to store
+strings on the stack without knowing in advance how long the
+string was going to be:
+ p = stackptr;
+ *p++ = c; /* repeated as many times as needed */
+ stackptr = p;
+The following three macros (defined in memalloc.h) perform these
+operations, but grow the stack if you run off the end:
+ STARTSTACKSTR(p);
+ STPUTC(c, p); /* repeated as many times as needed */
+ grabstackstr(p);
+
+We now start a top-down look at the code:
+
+MAIN.C: The main routine performs some initialization, executes
+the user's profile if necessary, and calls cmdloop. Cmdloop
+repeatedly parses and executes commands.
+
+OPTIONS.C: This file contains the option processing code. It is
+called from main to parse the shell arguments when the shell is
+invoked, and it also contains the set builtin. The -i and -m op-
+tions (the latter turns on job control) require changes in signal
+handling. The routines setjobctl (in jobs.c) and setinteractive
+(in trap.c) are called to handle changes to these options.
+
+PARSING: The parser code is all in parser.c. A recursive des-
+cent parser is used. Syntax tables (generated by mksyntax) are
+used to classify characters during lexical analysis. There are
+four tables: one for normal use, one for use when inside single
+quotes and dollar single quotes, one for use when inside double
+quotes and one for use in arithmetic. The tables are machine
+dependent because they are indexed by character variables and
+the range of a char varies from machine to machine.
+
+PARSE OUTPUT: The output of the parser consists of a tree of
+nodes. The various types of nodes are defined in the file node-
+types.
+
+Nodes of type NARG are used to represent both words and the con-
+tents of here documents. An early version of ash kept the con-
+tents of here documents in temporary files, but keeping here do-
+cuments in memory typically results in significantly better per-
+formance. It would have been nice to make it an option to use
+temporary files for here documents, for the benefit of small
+machines, but the code to keep track of when to delete the tem-
+porary files was complex and I never fixed all the bugs in it.
+(AT&T has been maintaining the Bourne shell for more than ten
+years, and to the best of my knowledge they still haven't gotten
+it to handle temporary files correctly in obscure cases.)
+
+The text field of a NARG structure points to the text of the
+word. The text consists of ordinary characters and a number of
+special codes defined in parser.h. The special codes are:
+
+ CTLVAR Parameter expansion
+ CTLENDVAR End of parameter expansion
+ CTLBACKQ Command substitution
+ CTLBACKQ|CTLQUOTE Command substitution inside double quotes
+ CTLARI Arithmetic expansion
+ CTLENDARI End of arithmetic expansion
+ CTLESC Escape next character
+
+A variable substitution contains the following elements:
+
+ CTLVAR type name '=' [ alternative-text CTLENDVAR ]
+
+The type field is a single character specifying the type of sub-
+stitution. The possible types are:
+
+ VSNORMAL $var
+ VSMINUS ${var-text}
+ VSMINUS|VSNUL ${var:-text}
+ VSPLUS ${var+text}
+ VSPLUS|VSNUL ${var:+text}
+ VSQUESTION ${var?text}
+ VSQUESTION|VSNUL ${var:?text}
+ VSASSIGN ${var=text}
+ VSASSIGN|VSNUL ${var:=text}
+ VSTRIMLEFT ${var#text}
+ VSTRIMLEFTMAX ${var##text}
+ VSTRIMRIGHT ${var%text}
+ VSTRIMRIGHTMAX ${var%%text}
+ VSLENGTH ${#var}
+ VSERROR delayed error
+
+In addition, the type field will have the VSQUOTE flag set if the
+variable is enclosed in double quotes and the VSLINENO flag if
+LINENO is being expanded (the parameter name is the decimal line
+number). The parameter's name comes next, terminated by an equals
+sign. If the type is not VSNORMAL (including when it is VSLENGTH),
+then the text field in the substitution follows, terminated by a
+CTLENDVAR byte.
+
+The type VSERROR is used to allow parsing bad substitutions like
+${var[7]} and generate an error when they are expanded.
+
+Commands in back quotes are parsed and stored in a linked list.
+The locations of these commands in the string are indicated by
+CTLBACKQ and CTLBACKQ+CTLQUOTE characters, depending upon whether
+the back quotes were enclosed in double quotes.
+
+Arithmetic expansion starts with CTLARI and ends with CTLENDARI.
+
+The character CTLESC escapes the next character, so that in case
+any of the CTL characters mentioned above appear in the input,
+they can be passed through transparently. CTLESC is also used to
+escape '*', '?', '[', and '!' characters which were quoted by the
+user and thus should not be used for file name generation.
+
+CTLESC characters have proved to be particularly tricky to get
+right. In the case of here documents which are not subject to
+variable and command substitution, the parser doesn't insert any
+CTLESC characters to begin with (so the contents of the text
+field can be written without any processing). Other here docu-
+ments, and words which are not subject to file name generation,
+have the CTLESC characters removed during the variable and command
+substitution phase. Words which are subject to file name
+generation have the CTLESC characters removed as part of the file
+name phase.
+
+EXECUTION: Command execution is handled by the following files:
+ eval.c The top level routines.
+ redir.c Code to handle redirection of input and output.
+ jobs.c Code to handle forking, waiting, and job control.
+ exec.c Code to do path searches and the actual exec sys call.
+ expand.c Code to evaluate arguments.
+ var.c Maintains the variable symbol table. Called from expand.c.
+
+EVAL.C: Evaltree recursively executes a parse tree. The exit
+status is returned in the global variable exitstatus. The alter-
+native entry evalbackcmd is called to evaluate commands in back
+quotes. It saves the result in memory if the command is a buil-
+tin; otherwise it forks off a child to execute the command and
+connects the standard output of the child to a pipe.
+
+JOBS.C: To create a process, you call makejob to return a job
+structure, and then call forkshell (passing the job structure as
+an argument) to create the process. Waitforjob waits for a job
+to complete. These routines take care of process groups if job
+control is defined.
+
+REDIR.C: Ash allows file descriptors to be redirected and then
+restored without forking off a child process. This is accom-
+plished by duplicating the original file descriptors. The redir-
+tab structure records where the file descriptors have been dupli-
+cated to.
+
+EXEC.C: The routine find_command locates a command, and enters
+the command in the hash table if it is not already there. The
+third argument specifies whether it is to print an error message
+if the command is not found. (When a pipeline is set up,
+find_command is called for all the commands in the pipeline be-
+fore any forking is done, so to get the commands into the hash
+table of the parent process. But to make command hashing as
+transparent as possible, we silently ignore errors at that point
+and only print error messages if the command cannot be found
+later.)
+
+The routine shellexec is the interface to the exec system call.
+
+EXPAND.C: As the routine argstr generates words by parameter
+expansion, command substitution and arithmetic expansion, it
+performs word splitting on the result. As each word is output,
+the routine expandmeta performs file name generation (if enabled).
+
+VAR.C: Variables are stored in a hash table. Probably we should
+switch to extensible hashing. The variable name is stored in the
+same string as the value (using the format "name=value") so that
+no string copying is needed to create the environment of a com-
+mand. Variables which the shell references internally are preal-
+located so that the shell can reference the values of these vari-
+ables without doing a lookup.
+
+When a program is run, the code in eval.c sticks any environment
+variables which precede the command (as in "PATH=xxx command") in
+the variable table as the simplest way to strip duplicates, and
+then calls "environment" to get the value of the environment.
+
+BUILTIN COMMANDS: The procedures for handling these are scat-
+tered throughout the code, depending on which location appears
+most appropriate. They can be recognized because their names al-
+ways end in "cmd". The mapping from names to procedures is
+specified in the file builtins.def, which is processed by the
+mkbuiltins command.
+
+A builtin command is invoked with argc and argv set up like a
+normal program. A builtin command is allowed to overwrite its
+arguments. Builtin routines can call nextopt to do option pars-
+ing. This is kind of like getopt, but you don't pass argc and
+argv to it. Builtin routines can also call error. This routine
+normally terminates the shell (or returns to the main command
+loop if the shell is interactive), but when called from a non-
+special builtin command it causes the builtin command to
+terminate with an exit status of 2.
+
+The directory bltins contains commands which can be compiled in-
+dependently but can also be built into the shell for efficiency
+reasons. The header file bltin.h takes care of most of the
+differences between the ash and the stand-alone environment.
+The user should call the main routine "main", and #define main to
+be the name of the routine to use when the program is linked into
+ash. This #define should appear before bltin.h is included;
+bltin.h will #undef main if the program is to be compiled
+stand-alone. A similar approach is used for a few utilities from
+bin and usr.bin.
+
+CD.C: This file defines the cd and pwd builtins.
+
+SIGNALS: Trap.c implements the trap command. The routine set-
+signal figures out what action should be taken when a signal is
+received and invokes the signal system call to set the signal ac-
+tion appropriately. When a signal that a user has set a trap for
+is caught, the routine "onsig" sets a flag. The routine dotrap
+is called at appropriate points to actually handle the signal.
+When an interrupt is caught and no trap has been set for that
+signal, the routine "onint" in error.c is called.
+
+OUTPUT: Ash uses its own output routines. There are three out-
+put structures allocated. "Output" represents the standard out-
+put, "errout" the standard error, and "memout" contains output
+which is to be stored in memory. This last is used when a buil-
+tin command appears in backquotes, to allow its output to be col-
+lected without doing any I/O through the UNIX operating system.
+The variables out1 and out2 normally point to output and errout,
+respectively, but they are set to point to memout when appropri-
+ate inside backquotes.
+
+INPUT: The basic input routine is pgetc, which reads from the
+current input file. There is a stack of input files; the current
+input file is the top file on this stack. The code allows the
+input to come from a string rather than a file. (This is for the
+-c option and the "." and eval builtin commands.) The global
+variable plinno is saved and restored when files are pushed and
+popped from the stack. The parser routines store the number of
+the current line in this variable.
+
+DEBUGGING: If DEBUG is defined in shell.h, then the shell will
+write debugging information to the file $HOME/trace. Most of
+this is done using the TRACE macro, which takes a set of printf
+arguments inside two sets of parenthesis. Example:
+"TRACE(("n=%d0, n))". The double parenthesis are necessary be-
+cause the preprocessor can't handle functions with a variable
+number of arguments. Defining DEBUG also causes the shell to
+generate a core dump if it is sent a quit signal. The tracing
+code is in show.c.
diff --git a/shell_cmds/sh/alias.c b/shell_cmds/sh/alias.c
new file mode 100644
index 0000000..a8fe82c
--- /dev/null
+++ b/shell_cmds/sh/alias.c
@@ -0,0 +1,256 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)alias.c 8.3 (Berkeley) 5/4/95";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/bin/sh/alias.c 317039 2017-04-16 22:10:02Z jilles $");
+
+#include <stdlib.h>
+#include "shell.h"
+#include "output.h"
+#include "error.h"
+#include "memalloc.h"
+#include "mystring.h"
+#include "alias.h"
+#include "options.h"
+#include "builtins.h"
+
+#define ATABSIZE 39
+
+static struct alias *atab[ATABSIZE];
+static int aliases;
+
+static void setalias(const char *, const char *);
+static int unalias(const char *);
+static struct alias **hashalias(const char *);
+
+static
+void
+setalias(const char *name, const char *val)
+{
+ struct alias *ap, **app;
+
+ unalias(name);
+ app = hashalias(name);
+ INTOFF;
+ ap = ckmalloc(sizeof (struct alias));
+ ap->name = savestr(name);
+ ap->val = savestr(val);
+ ap->flag = 0;
+ ap->next = *app;
+ *app = ap;
+ aliases++;
+ INTON;
+}
+
+static void
+freealias(struct alias *ap)
+{
+ ckfree(ap->name);
+ ckfree(ap->val);
+ ckfree(ap);
+}
+
+static int
+unalias(const char *name)
+{
+ struct alias *ap, **app;
+
+ app = hashalias(name);
+
+ for (ap = *app; ap; app = &(ap->next), ap = ap->next) {
+ if (equal(name, ap->name)) {
+ /*
+ * if the alias is currently in use (i.e. its
+ * buffer is being used by the input routine) we
+ * just null out the name instead of freeing it.
+ * We could clear it out later, but this situation
+ * is so rare that it hardly seems worth it.
+ */
+ if (ap->flag & ALIASINUSE)
+ *ap->name = '\0';
+ else {
+ INTOFF;
+ *app = ap->next;
+ freealias(ap);
+ INTON;
+ }
+ aliases--;
+ return (0);
+ }
+ }
+
+ return (1);
+}
+
+static void
+rmaliases(void)
+{
+ struct alias *ap, **app;
+ int i;
+
+ INTOFF;
+ for (i = 0; i < ATABSIZE; i++) {
+ app = &atab[i];
+ while (*app) {
+ ap = *app;
+ if (ap->flag & ALIASINUSE) {
+ *ap->name = '\0';
+ app = &(*app)->next;
+ } else {
+ *app = ap->next;
+ freealias(ap);
+ }
+ }
+ }
+ aliases = 0;
+ INTON;
+}
+
+struct alias *
+lookupalias(const char *name, int check)
+{
+ struct alias *ap;
+
+ if (aliases == 0)
+ return (NULL);
+ for (ap = *hashalias(name); ap; ap = ap->next) {
+ if (equal(name, ap->name)) {
+ if (check && (ap->flag & ALIASINUSE))
+ return (NULL);
+ return (ap);
+ }
+ }
+
+ return (NULL);
+}
+
+static int
+comparealiases(const void *p1, const void *p2)
+{
+ const struct alias *const *a1 = p1;
+ const struct alias *const *a2 = p2;
+
+ return strcmp((*a1)->name, (*a2)->name);
+}
+
+static void
+printalias(const struct alias *a)
+{
+ out1fmt("%s=", a->name);
+ out1qstr(a->val);
+ out1c('\n');
+}
+
+static void
+printaliases(void)
+{
+ int i, j;
+ struct alias **sorted, *ap;
+
+ INTOFF;
+ sorted = ckmalloc(aliases * sizeof(*sorted));
+ j = 0;
+ for (i = 0; i < ATABSIZE; i++)
+ for (ap = atab[i]; ap; ap = ap->next)
+ if (*ap->name != '\0')
+ sorted[j++] = ap;
+ qsort(sorted, aliases, sizeof(*sorted), comparealiases);
+ for (i = 0; i < aliases; i++) {
+ printalias(sorted[i]);
+ if (int_pending())
+ break;
+ }
+ ckfree(sorted);
+ INTON;
+}
+
+int
+aliascmd(int argc __unused, char **argv __unused)
+{
+ char *n, *v;
+ int ret = 0;
+ struct alias *ap;
+
+ nextopt("");
+
+ if (*argptr == NULL) {
+ printaliases();
+ return (0);
+ }
+ while ((n = *argptr++) != NULL) {
+ if ((v = strchr(n+1, '=')) == NULL) /* n+1: funny ksh stuff */
+ if ((ap = lookupalias(n, 0)) == NULL) {
+ warning("%s: not found", n);
+ ret = 1;
+ } else
+ printalias(ap);
+ else {
+ *v++ = '\0';
+ setalias(n, v);
+ }
+ }
+
+ return (ret);
+}
+
+int
+unaliascmd(int argc __unused, char **argv __unused)
+{
+ int i;
+
+ while ((i = nextopt("a")) != '\0') {
+ if (i == 'a') {
+ rmaliases();
+ return (0);
+ }
+ }
+ for (i = 0; *argptr; argptr++)
+ i |= unalias(*argptr);
+
+ return (i);
+}
+
+static struct alias **
+hashalias(const char *p)
+{
+ unsigned int hashval;
+
+ hashval = (unsigned char)*p << 4;
+ while (*p)
+ hashval+= *p++;
+ return &atab[hashval % ATABSIZE];
+}
diff --git a/shell_cmds/sh/alias.h b/shell_cmds/sh/alias.h
new file mode 100644
index 0000000..e08a9e8
--- /dev/null
+++ b/shell_cmds/sh/alias.h
@@ -0,0 +1,45 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)alias.h 8.2 (Berkeley) 5/4/95
+ * $FreeBSD: head/bin/sh/alias.h 314436 2017-02-28 23:42:47Z imp $
+ */
+
+#define ALIASINUSE 1
+
+struct alias {
+ struct alias *next;
+ char *name;
+ char *val;
+ int flag;
+};
+
+struct alias *lookupalias(const char *, int);
diff --git a/shell_cmds/sh/arith.h b/shell_cmds/sh/arith.h
new file mode 100644
index 0000000..9c2ef39
--- /dev/null
+++ b/shell_cmds/sh/arith.h
@@ -0,0 +1,37 @@
+/*-
+ * Copyright (c) 1995
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)arith.h 1.1 (Berkeley) 5/4/95
+ * $FreeBSD: head/bin/sh/arith.h 315511 2017-03-18 20:41:07Z jilles $
+ */
+
+#include "shell.h"
+
+#define DIGITS(var) (3 + (2 + CHAR_BIT * sizeof((var))) / 3)
+
+arith_t arith(const char *);
diff --git a/shell_cmds/sh/arith_yacc.c b/shell_cmds/sh/arith_yacc.c
new file mode 100644
index 0000000..20e1e43
--- /dev/null
+++ b/shell_cmds/sh/arith_yacc.c
@@ -0,0 +1,381 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 2007
+ * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/bin/sh/arith_yacc.c 270246 2014-08-20 20:15:43Z jilles $");
+
+#include <limits.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "arith.h"
+#include "arith_yacc.h"
+#include "expand.h"
+#include "shell.h"
+#include "error.h"
+#include "memalloc.h"
+#include "output.h"
+#include "options.h"
+#include "var.h"
+
+#if ARITH_BOR + 11 != ARITH_BORASS || ARITH_ASS + 11 != ARITH_EQ
+#error Arithmetic tokens are out of order.
+#endif
+
+static const char *arith_startbuf;
+
+const char *arith_buf;
+union yystype yylval;
+
+static int last_token;
+
+#define ARITH_PRECEDENCE(op, prec) [op - ARITH_BINOP_MIN] = prec
+
+static const char prec[ARITH_BINOP_MAX - ARITH_BINOP_MIN] = {
+ ARITH_PRECEDENCE(ARITH_MUL, 0),
+ ARITH_PRECEDENCE(ARITH_DIV, 0),
+ ARITH_PRECEDENCE(ARITH_REM, 0),
+ ARITH_PRECEDENCE(ARITH_ADD, 1),
+ ARITH_PRECEDENCE(ARITH_SUB, 1),
+ ARITH_PRECEDENCE(ARITH_LSHIFT, 2),
+ ARITH_PRECEDENCE(ARITH_RSHIFT, 2),
+ ARITH_PRECEDENCE(ARITH_LT, 3),
+ ARITH_PRECEDENCE(ARITH_LE, 3),
+ ARITH_PRECEDENCE(ARITH_GT, 3),
+ ARITH_PRECEDENCE(ARITH_GE, 3),
+ ARITH_PRECEDENCE(ARITH_EQ, 4),
+ ARITH_PRECEDENCE(ARITH_NE, 4),
+ ARITH_PRECEDENCE(ARITH_BAND, 5),
+ ARITH_PRECEDENCE(ARITH_BXOR, 6),
+ ARITH_PRECEDENCE(ARITH_BOR, 7),
+};
+
+#define ARITH_MAX_PREC 8
+
+int letcmd(int, char **);
+
+static __dead2 void yyerror(const char *s)
+{
+ error("arithmetic expression: %s: \"%s\"", s, arith_startbuf);
+ /* NOTREACHED */
+}
+
+static arith_t arith_lookupvarint(char *varname)
+{
+ const char *str;
+ char *p;
+ arith_t result;
+
+ str = lookupvar(varname);
+ if (uflag && str == NULL)
+ yyerror("variable not set");
+ if (str == NULL || *str == '\0')
+ str = "0";
+ errno = 0;
+ result = strtoarith_t(str, &p, 0);
+ if (errno != 0 || *p != '\0')
+ yyerror("variable conversion error");
+ return result;
+}
+
+static inline int arith_prec(int op)
+{
+ return prec[op - ARITH_BINOP_MIN];
+}
+
+static inline int higher_prec(int op1, int op2)
+{
+ return arith_prec(op1) < arith_prec(op2);
+}
+
+static arith_t do_binop(int op, arith_t a, arith_t b)
+{
+
+ switch (op) {
+ default:
+ case ARITH_REM:
+ case ARITH_DIV:
+ if (!b)
+ yyerror("division by zero");
+ if (a == ARITH_MIN && b == -1)
+ yyerror("divide error");
+ return op == ARITH_REM ? a % b : a / b;
+ case ARITH_MUL:
+ return (uintmax_t)a * (uintmax_t)b;
+ case ARITH_ADD:
+ return (uintmax_t)a + (uintmax_t)b;
+ case ARITH_SUB:
+ return (uintmax_t)a - (uintmax_t)b;
+ case ARITH_LSHIFT:
+ return (uintmax_t)a << (b & (sizeof(uintmax_t) * CHAR_BIT - 1));
+ case ARITH_RSHIFT:
+ return a >> (b & (sizeof(uintmax_t) * CHAR_BIT - 1));
+ case ARITH_LT:
+ return a < b;
+ case ARITH_LE:
+ return a <= b;
+ case ARITH_GT:
+ return a > b;
+ case ARITH_GE:
+ return a >= b;
+ case ARITH_EQ:
+ return a == b;
+ case ARITH_NE:
+ return a != b;
+ case ARITH_BAND:
+ return a & b;
+ case ARITH_BXOR:
+ return a ^ b;
+ case ARITH_BOR:
+ return a | b;
+ }
+}
+
+static arith_t assignment(int var, int noeval);
+
+static arith_t primary(int token, union yystype *val, int op, int noeval)
+{
+ arith_t result;
+
+again:
+ switch (token) {
+ case ARITH_LPAREN:
+ result = assignment(op, noeval);
+ if (last_token != ARITH_RPAREN)
+ yyerror("expecting ')'");
+ last_token = yylex();
+ return result;
+ case ARITH_NUM:
+ last_token = op;
+ return val->val;
+ case ARITH_VAR:
+ last_token = op;
+ return noeval ? val->val : arith_lookupvarint(val->name);
+ case ARITH_ADD:
+ token = op;
+ *val = yylval;
+ op = yylex();
+ goto again;
+ case ARITH_SUB:
+ *val = yylval;
+ return -primary(op, val, yylex(), noeval);
+ case ARITH_NOT:
+ *val = yylval;
+ return !primary(op, val, yylex(), noeval);
+ case ARITH_BNOT:
+ *val = yylval;
+ return ~primary(op, val, yylex(), noeval);
+ default:
+ yyerror("expecting primary");
+ }
+}
+
+static arith_t binop2(arith_t a, int op, int precedence, int noeval)
+{
+ for (;;) {
+ union yystype val;
+ arith_t b;
+ int op2;
+ int token;
+
+ token = yylex();
+ val = yylval;
+
+ b = primary(token, &val, yylex(), noeval);
+
+ op2 = last_token;
+ if (op2 >= ARITH_BINOP_MIN && op2 < ARITH_BINOP_MAX &&
+ higher_prec(op2, op)) {
+ b = binop2(b, op2, arith_prec(op), noeval);
+ op2 = last_token;
+ }
+
+ a = noeval ? b : do_binop(op, a, b);
+
+ if (op2 < ARITH_BINOP_MIN || op2 >= ARITH_BINOP_MAX ||
+ arith_prec(op2) >= precedence)
+ return a;
+
+ op = op2;
+ }
+}
+
+static arith_t binop(int token, union yystype *val, int op, int noeval)
+{
+ arith_t a = primary(token, val, op, noeval);
+
+ op = last_token;
+ if (op < ARITH_BINOP_MIN || op >= ARITH_BINOP_MAX)
+ return a;
+
+ return binop2(a, op, ARITH_MAX_PREC, noeval);
+}
+
+static arith_t and(int token, union yystype *val, int op, int noeval)
+{
+ arith_t a = binop(token, val, op, noeval);
+ arith_t b;
+
+ op = last_token;
+ if (op != ARITH_AND)
+ return a;
+
+ token = yylex();
+ *val = yylval;
+
+ b = and(token, val, yylex(), noeval | !a);
+
+ return a && b;
+}
+
+static arith_t or(int token, union yystype *val, int op, int noeval)
+{
+ arith_t a = and(token, val, op, noeval);
+ arith_t b;
+
+ op = last_token;
+ if (op != ARITH_OR)
+ return a;
+
+ token = yylex();
+ *val = yylval;
+
+ b = or(token, val, yylex(), noeval | !!a);
+
+ return a || b;
+}
+
+static arith_t cond(int token, union yystype *val, int op, int noeval)
+{
+ arith_t a = or(token, val, op, noeval);
+ arith_t b;
+ arith_t c;
+
+ if (last_token != ARITH_QMARK)
+ return a;
+
+ b = assignment(yylex(), noeval | !a);
+
+ if (last_token != ARITH_COLON)
+ yyerror("expecting ':'");
+
+ token = yylex();
+ *val = yylval;
+
+ c = cond(token, val, yylex(), noeval | !!a);
+
+ return a ? b : c;
+}
+
+static arith_t assignment(int var, int noeval)
+{
+ union yystype val = yylval;
+ int op = yylex();
+ arith_t result;
+ char sresult[DIGITS(result) + 1];
+
+ if (var != ARITH_VAR)
+ return cond(var, &val, op, noeval);
+
+ if (op != ARITH_ASS && (op < ARITH_ASS_MIN || op >= ARITH_ASS_MAX))
+ return cond(var, &val, op, noeval);
+
+ result = assignment(yylex(), noeval);
+ if (noeval)
+ return result;
+
+ if (op != ARITH_ASS)
+ result = do_binop(op - 11, arith_lookupvarint(val.name), result);
+ snprintf(sresult, sizeof(sresult), ARITH_FORMAT_STR, result);
+ setvar(val.name, sresult, 0);
+ return result;
+}
+
+arith_t arith(const char *s)
+{
+ struct stackmark smark;
+ arith_t result;
+
+ setstackmark(&smark);
+
+ arith_buf = arith_startbuf = s;
+
+ result = assignment(yylex(), 0);
+
+ if (last_token)
+ yyerror("expecting EOF");
+
+ popstackmark(&smark);
+
+ return result;
+}
+
+/*
+ * The exp(1) builtin.
+ */
+int
+letcmd(int argc, char **argv)
+{
+ const char *p;
+ char *concat;
+ char **ap;
+ arith_t i;
+
+ if (argc > 1) {
+ p = argv[1];
+ if (argc > 2) {
+ /*
+ * Concatenate arguments.
+ */
+ STARTSTACKSTR(concat);
+ ap = argv + 2;
+ for (;;) {
+ while (*p)
+ STPUTC(*p++, concat);
+ if ((p = *ap++) == NULL)
+ break;
+ STPUTC(' ', concat);
+ }
+ STPUTC('\0', concat);
+ p = grabstackstr(concat);
+ }
+ } else
+ p = "";
+
+ i = arith(p);
+
+ out1fmt(ARITH_FORMAT_STR "\n", i);
+ return !i;
+}
diff --git a/shell_cmds/sh/arith_yacc.h b/shell_cmds/sh/arith_yacc.h
new file mode 100644
index 0000000..d386886
--- /dev/null
+++ b/shell_cmds/sh/arith_yacc.h
@@ -0,0 +1,93 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 2007
+ * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: head/bin/sh/arith_yacc.h 279503 2015-03-01 21:46:55Z jilles $
+ */
+
+#define ARITH_ASS 1
+
+#define ARITH_OR 2
+#define ARITH_AND 3
+#define ARITH_BAD 4
+#define ARITH_NUM 5
+#define ARITH_VAR 6
+#define ARITH_NOT 7
+
+#define ARITH_BINOP_MIN 8
+#define ARITH_LE 8
+#define ARITH_GE 9
+#define ARITH_LT 10
+#define ARITH_GT 11
+#define ARITH_EQ 12
+#define ARITH_REM 13
+#define ARITH_BAND 14
+#define ARITH_LSHIFT 15
+#define ARITH_RSHIFT 16
+#define ARITH_MUL 17
+#define ARITH_ADD 18
+#define ARITH_BOR 19
+#define ARITH_SUB 20
+#define ARITH_BXOR 21
+#define ARITH_DIV 22
+#define ARITH_NE 23
+#define ARITH_BINOP_MAX 24
+
+#define ARITH_ASS_MIN 24
+#define ARITH_REMASS 24
+#define ARITH_BANDASS 25
+#define ARITH_LSHIFTASS 26
+#define ARITH_RSHIFTASS 27
+#define ARITH_MULASS 28
+#define ARITH_ADDASS 29
+#define ARITH_BORASS 30
+#define ARITH_SUBASS 31
+#define ARITH_BXORASS 32
+#define ARITH_DIVASS 33
+#define ARITH_ASS_MAX 34
+
+#define ARITH_LPAREN 34
+#define ARITH_RPAREN 35
+#define ARITH_BNOT 36
+#define ARITH_QMARK 37
+#define ARITH_COLON 38
+
+extern const char *arith_buf;
+
+union yystype {
+ arith_t val;
+ char *name;
+};
+
+extern union yystype yylval;
+
+int yylex(void);
diff --git a/shell_cmds/sh/arith_yylex.c b/shell_cmds/sh/arith_yylex.c
new file mode 100644
index 0000000..9936852
--- /dev/null
+++ b/shell_cmds/sh/arith_yylex.c
@@ -0,0 +1,248 @@
+/*-
+ * Copyright (c) 2002
+ * Herbert Xu.
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/bin/sh/arith_yylex.c 279503 2015-03-01 21:46:55Z jilles $");
+
+#include <inttypes.h>
+#include <stdlib.h>
+#include <string.h>
+#include "shell.h"
+#include "arith_yacc.h"
+#include "expand.h"
+#include "error.h"
+#include "memalloc.h"
+#include "parser.h"
+#include "syntax.h"
+
+#if ARITH_BOR + 11 != ARITH_BORASS || ARITH_ASS + 11 != ARITH_EQ
+#error Arithmetic tokens are out of order.
+#endif
+
+int
+yylex(void)
+{
+ int value;
+ const char *buf = arith_buf;
+ char *end;
+ const char *p;
+
+ for (;;) {
+ value = *buf;
+ switch (value) {
+ case ' ':
+ case '\t':
+ case '\n':
+ buf++;
+ continue;
+ default:
+ return ARITH_BAD;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ yylval.val = strtoarith_t(buf, &end, 0);
+ arith_buf = end;
+ return ARITH_NUM;
+ case 'A':
+ case 'B':
+ case 'C':
+ case 'D':
+ case 'E':
+ case 'F':
+ case 'G':
+ case 'H':
+ case 'I':
+ case 'J':
+ case 'K':
+ case 'L':
+ case 'M':
+ case 'N':
+ case 'O':
+ case 'P':
+ case 'Q':
+ case 'R':
+ case 'S':
+ case 'T':
+ case 'U':
+ case 'V':
+ case 'W':
+ case 'X':
+ case 'Y':
+ case 'Z':
+ case '_':
+ case 'a':
+ case 'b':
+ case 'c':
+ case 'd':
+ case 'e':
+ case 'f':
+ case 'g':
+ case 'h':
+ case 'i':
+ case 'j':
+ case 'k':
+ case 'l':
+ case 'm':
+ case 'n':
+ case 'o':
+ case 'p':
+ case 'q':
+ case 'r':
+ case 's':
+ case 't':
+ case 'u':
+ case 'v':
+ case 'w':
+ case 'x':
+ case 'y':
+ case 'z':
+ p = buf;
+ while (buf++, is_in_name(*buf))
+ ;
+ yylval.name = stalloc(buf - p + 1);
+ memcpy(yylval.name, p, buf - p);
+ yylval.name[buf - p] = '\0';
+ value = ARITH_VAR;
+ goto out;
+ case '=':
+ value += ARITH_ASS - '=';
+checkeq:
+ buf++;
+checkeqcur:
+ if (*buf != '=')
+ goto out;
+ value += 11;
+ break;
+ case '>':
+ switch (*++buf) {
+ case '=':
+ value += ARITH_GE - '>';
+ break;
+ case '>':
+ value += ARITH_RSHIFT - '>';
+ goto checkeq;
+ default:
+ value += ARITH_GT - '>';
+ goto out;
+ }
+ break;
+ case '<':
+ switch (*++buf) {
+ case '=':
+ value += ARITH_LE - '<';
+ break;
+ case '<':
+ value += ARITH_LSHIFT - '<';
+ goto checkeq;
+ default:
+ value += ARITH_LT - '<';
+ goto out;
+ }
+ break;
+ case '|':
+ if (*++buf != '|') {
+ value += ARITH_BOR - '|';
+ goto checkeqcur;
+ }
+ value += ARITH_OR - '|';
+ break;
+ case '&':
+ if (*++buf != '&') {
+ value += ARITH_BAND - '&';
+ goto checkeqcur;
+ }
+ value += ARITH_AND - '&';
+ break;
+ case '!':
+ if (*++buf != '=') {
+ value += ARITH_NOT - '!';
+ goto out;
+ }
+ value += ARITH_NE - '!';
+ break;
+ case 0:
+ goto out;
+ case '(':
+ value += ARITH_LPAREN - '(';
+ break;
+ case ')':
+ value += ARITH_RPAREN - ')';
+ break;
+ case '*':
+ value += ARITH_MUL - '*';
+ goto checkeq;
+ case '/':
+ value += ARITH_DIV - '/';
+ goto checkeq;
+ case '%':
+ value += ARITH_REM - '%';
+ goto checkeq;
+ case '+':
+ if (buf[1] == '+')
+ return ARITH_BAD;
+ value += ARITH_ADD - '+';
+ goto checkeq;
+ case '-':
+ if (buf[1] == '-')
+ return ARITH_BAD;
+ value += ARITH_SUB - '-';
+ goto checkeq;
+ case '~':
+ value += ARITH_BNOT - '~';
+ break;
+ case '^':
+ value += ARITH_BXOR - '^';
+ goto checkeq;
+ case '?':
+ value += ARITH_QMARK - '?';
+ break;
+ case ':':
+ value += ARITH_COLON - ':';
+ break;
+ }
+ break;
+ }
+
+ buf++;
+out:
+ arith_buf = buf;
+ return value;
+}
diff --git a/shell_cmds/sh/bltin/bltin.h b/shell_cmds/sh/bltin/bltin.h
new file mode 100644
index 0000000..b8c2087
--- /dev/null
+++ b/shell_cmds/sh/bltin/bltin.h
@@ -0,0 +1,81 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)bltin.h 8.2 (Berkeley) 5/4/95
+ * $FreeBSD: head/bin/sh/bltin/bltin.h 326025 2017-11-20 19:49:47Z pfg $
+ */
+
+/*
+ * This file is included by programs which are optionally built into the
+ * shell. If SHELL is defined, we try to map the standard UNIX library
+ * routines to ash routines using defines.
+ */
+
+#include "../shell.h"
+#include "../mystring.h"
+#ifdef SHELL
+#include "../error.h"
+#include "../output.h"
+#include "builtins.h"
+#define FILE struct output
+#undef stdout
+#define stdout out1
+#undef stderr
+#define stderr out2
+#define printf out1fmt
+#undef putc
+#define putc(c, file) outc(c, file)
+#undef putchar
+#define putchar(c) out1c(c)
+#define fprintf outfmt
+#define fputs outstr
+#define fwrite(ptr, size, nmemb, file) outbin(ptr, (size) * (nmemb), file)
+#define fflush flushout
+#define INITARGS(argv)
+#define warnx warning
+#define warn(fmt, ...) warning(fmt ": %s", __VA_ARGS__, strerror(errno))
+#define errx(exitstatus, ...) error(__VA_ARGS__)
+
+#else
+#undef NULL
+#include <stdio.h>
+#undef main
+#define INITARGS(argv) if ((commandname = argv[0]) == NULL) {fputs("Argc is zero\n", stderr); exit(2);} else
+#endif
+
+#include <unistd.h>
+
+pointer stalloc(int);
+int killjob(const char *, int);
+
+extern char *commandname;
diff --git a/shell_cmds/sh/bltin/echo.c b/shell_cmds/sh/bltin/echo.c
new file mode 100644
index 0000000..1bb64c6
--- /dev/null
+++ b/shell_cmds/sh/bltin/echo.c
@@ -0,0 +1,109 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)echo.c 8.2 (Berkeley) 5/4/95
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/bin/sh/bltin/echo.c 326025 2017-11-20 19:49:47Z pfg $");
+
+/*
+ * Echo command.
+ */
+
+#define main echocmd
+
+#include "bltin.h"
+
+/* #define eflag 1 */
+
+int
+main(int argc, char *argv[])
+{
+ char **ap;
+ char *p;
+ char c;
+ int count;
+ int nflag = 0;
+#ifndef eflag
+ int eflag = 0;
+#endif
+
+ ap = argv;
+ if (argc)
+ ap++;
+ if ((p = *ap) != NULL) {
+ if (equal(p, "-n")) {
+ nflag++;
+ ap++;
+ } else if (equal(p, "-e")) {
+#ifndef eflag
+ eflag++;
+#endif
+ ap++;
+ }
+ }
+ while ((p = *ap++) != NULL) {
+ while ((c = *p++) != '\0') {
+ if (c == '\\' && eflag) {
+ switch (*p++) {
+ case 'a': c = '\a'; break;
+ case 'b': c = '\b'; break;
+ case 'c': return 0; /* exit */
+ case 'e': c = '\033'; break;
+ case 'f': c = '\f'; break;
+ case 'n': c = '\n'; break;
+ case 'r': c = '\r'; break;
+ case 't': c = '\t'; break;
+ case 'v': c = '\v'; break;
+ case '\\': break; /* c = '\\' */
+ case '0':
+ c = 0;
+ count = 3;
+ while (--count >= 0 && (unsigned)(*p - '0') < 8)
+ c = (c << 3) + (*p++ - '0');
+ break;
+ default:
+ p--;
+ break;
+ }
+ }
+ putchar(c);
+ }
+ if (*ap)
+ putchar(' ');
+ }
+ if (! nflag)
+ putchar('\n');
+ return 0;
+}
diff --git a/shell_cmds/sh/builtins.def b/shell_cmds/sh/builtins.def
new file mode 100644
index 0000000..39cab13
--- /dev/null
+++ b/shell_cmds/sh/builtins.def
@@ -0,0 +1,96 @@
+#!/bin/sh -
+
+#-
+# Copyright (c) 1991, 1993
+# The Regents of the University of California. All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Kenneth Almquist.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of the University nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# @(#)builtins.def 8.4 (Berkeley) 5/4/95
+# $FreeBSD: head/bin/sh/builtins.def 319576 2017-06-04 21:02:48Z bdrewery $
+
+#
+# This file lists all the builtin commands. The first column is the name
+# of a C routine.
+# The -j flag specifies that this command is to be excluded from systems
+# without job control.
+# The -h flag specifies that this command is to be excluded from systems
+# based on the NO_HISTORY compile-time symbol.
+# The -n flag specifies that this command can safely be run in the same
+# process when it is the only command in a command substitution. Some
+# commands have special logic defined in safe_builtin().
+# The -s flag specifies that this is a POSIX 'special built-in' command.
+# The rest of the line specifies the command name or names used to run the
+# command. The entry for bltincmd, which is run when the user does not specify
+# a command, must come first.
+#
+# NOTE: bltincmd must come first!
+
+bltincmd -n builtin
+aliascmd alias
+bgcmd -j bg
+bindcmd bind
+breakcmd -s break -s continue
+cdcmd cd chdir
+commandcmd -n command
+dotcmd -s .
+echocmd -n echo
+evalcmd -s eval
+execcmd -s exec
+exitcmd -s exit
+letcmd let
+exportcmd -s export -s readonly
+#exprcmd expr
+falsecmd -n false
+fgcmd -j fg
+freebsd_wordexpcmd freebsd_wordexp
+getoptscmd getopts
+hashcmd hash
+histcmd -h fc
+jobidcmd -n jobid
+jobscmd -n jobs
+killcmd -n kill
+localcmd local
+printfcmd -n printf
+pwdcmd -n pwd
+readcmd read
+returncmd -s return
+setcmd -s set
+setvarcmd setvar
+shiftcmd -s shift
+testcmd -n test [
+timescmd -n -s times
+trapcmd -s trap
+truecmd -n -s : true
+typecmd -n type
+ulimitcmd ulimit
+umaskcmd umask
+unaliascmd unalias
+unsetcmd -s unset
+waitcmd wait
+wordexpcmd wordexp
diff --git a/shell_cmds/sh/cd.c b/shell_cmds/sh/cd.c
new file mode 100644
index 0000000..cf63681
--- /dev/null
+++ b/shell_cmds/sh/cd.c
@@ -0,0 +1,430 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)cd.c 8.2 (Berkeley) 5/4/95";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/bin/sh/cd.c 320340 2017-06-25 21:53:08Z jilles $");
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <limits.h>
+
+/*
+ * The cd and pwd commands.
+ */
+
+#include "shell.h"
+#include "var.h"
+#include "nodes.h" /* for jobs.h */
+#include "jobs.h"
+#include "options.h"
+#include "output.h"
+#include "memalloc.h"
+#include "error.h"
+#include "exec.h"
+#include "redir.h"
+#include "mystring.h"
+#include "show.h"
+#include "cd.h"
+#include "builtins.h"
+
+static int cdlogical(char *);
+static int cdphysical(char *);
+static int docd(char *, int, int);
+static char *getcomponent(char **);
+static char *findcwd(char *);
+static void updatepwd(char *);
+static char *getpwd(void);
+static char *getpwd2(void);
+
+static char *curdir = NULL; /* current working directory */
+
+int
+cdcmd(int argc __unused, char **argv __unused)
+{
+ const char *dest;
+ const char *path;
+ char *p;
+ struct stat statb;
+ int ch, phys, print = 0, getcwderr = 0;
+ int rc;
+ int errno1 = ENOENT;
+
+ phys = Pflag;
+ while ((ch = nextopt("eLP")) != '\0') {
+ switch (ch) {
+ case 'e':
+ getcwderr = 1;
+ break;
+ case 'L':
+ phys = 0;
+ break;
+ case 'P':
+ phys = 1;
+ break;
+ }
+ }
+
+ if (*argptr != NULL && argptr[1] != NULL)
+ error("too many arguments");
+
+ if ((dest = *argptr) == NULL && (dest = bltinlookup("HOME", 1)) == NULL)
+ error("HOME not set");
+ if (*dest == '\0')
+ dest = ".";
+ if (dest[0] == '-' && dest[1] == '\0') {
+ dest = bltinlookup("OLDPWD", 1);
+ if (dest == NULL)
+ error("OLDPWD not set");
+ print = 1;
+ }
+ if (dest[0] == '/' ||
+ (dest[0] == '.' && (dest[1] == '/' || dest[1] == '\0')) ||
+ (dest[0] == '.' && dest[1] == '.' && (dest[2] == '/' || dest[2] == '\0')) ||
+ (path = bltinlookup("CDPATH", 1)) == NULL)
+ path = "";
+ while ((p = padvance(&path, dest)) != NULL) {
+ if (stat(p, &statb) < 0) {
+ if (errno != ENOENT)
+ errno1 = errno;
+ } else if (!S_ISDIR(statb.st_mode))
+ errno1 = ENOTDIR;
+ else {
+ if (!print) {
+ /*
+ * XXX - rethink
+ */
+ if (p[0] == '.' && p[1] == '/' && p[2] != '\0')
+ print = strcmp(p + 2, dest);
+ else
+ print = strcmp(p, dest);
+ }
+ rc = docd(p, print, phys);
+ if (rc >= 0)
+ return getcwderr ? rc : 0;
+ if (errno != ENOENT)
+ errno1 = errno;
+ }
+ }
+ error("%s: %s", dest, strerror(errno1));
+ /*NOTREACHED*/
+ return 0;
+}
+
+
+/*
+ * Actually change the directory. In an interactive shell, print the
+ * directory name if "print" is nonzero.
+ */
+static int
+docd(char *dest, int print, int phys)
+{
+ int rc;
+
+ TRACE(("docd(\"%s\", %d, %d) called\n", dest, print, phys));
+
+ /* If logical cd fails, fall back to physical. */
+ if ((phys || (rc = cdlogical(dest)) < 0) && (rc = cdphysical(dest)) < 0)
+ return (-1);
+
+ if (print && iflag && curdir) {
+ out1fmt("%s\n", curdir);
+ /*
+ * Ignore write errors to preserve the invariant that the
+ * current directory is changed iff the exit status is 0
+ * (or 1 if -e was given and the full pathname could not be
+ * determined).
+ */
+ flushout(out1);
+ outclearerror(out1);
+ }
+
+ return (rc);
+}
+
+static int
+cdlogical(char *dest)
+{
+ char *p;
+ char *q;
+ char *component;
+ char *path;
+ struct stat statb;
+ int first;
+ int badstat;
+
+ /*
+ * Check each component of the path. If we find a symlink or
+ * something we can't stat, clear curdir to force a getcwd()
+ * next time we get the value of the current directory.
+ */
+ badstat = 0;
+ path = stsavestr(dest);
+ STARTSTACKSTR(p);
+ if (*dest == '/') {
+ STPUTC('/', p);
+ path++;
+ }
+ first = 1;
+ while ((q = getcomponent(&path)) != NULL) {
+ if (q[0] == '\0' || (q[0] == '.' && q[1] == '\0'))
+ continue;
+ if (! first)
+ STPUTC('/', p);
+ first = 0;
+ component = q;
+ STPUTS(q, p);
+ if (equal(component, ".."))
+ continue;
+ STACKSTRNUL(p);
+ if (lstat(stackblock(), &statb) < 0) {
+ badstat = 1;
+ break;
+ }
+ }
+
+ INTOFF;
+ if ((p = findcwd(badstat ? NULL : dest)) == NULL || chdir(p) < 0) {
+ INTON;
+ return (-1);
+ }
+ updatepwd(p);
+ INTON;
+ return (0);
+}
+
+static int
+cdphysical(char *dest)
+{
+ char *p;
+ int rc = 0;
+
+ INTOFF;
+ if (chdir(dest) < 0) {
+ INTON;
+ return (-1);
+ }
+ p = findcwd(NULL);
+ if (p == NULL) {
+ warning("warning: failed to get name of current directory");
+ rc = 1;
+ }
+ updatepwd(p);
+ INTON;
+ return (rc);
+}
+
+/*
+ * Get the next component of the path name pointed to by *path.
+ * This routine overwrites *path and the string pointed to by it.
+ */
+static char *
+getcomponent(char **path)
+{
+ char *p;
+ char *start;
+
+ if ((p = *path) == NULL)
+ return NULL;
+ start = *path;
+ while (*p != '/' && *p != '\0')
+ p++;
+ if (*p == '\0') {
+ *path = NULL;
+ } else {
+ *p++ = '\0';
+ *path = p;
+ }
+ return start;
+}
+
+
+static char *
+findcwd(char *dir)
+{
+ char *new;
+ char *p;
+ char *path;
+
+ /*
+ * If our argument is NULL, we don't know the current directory
+ * any more because we traversed a symbolic link or something
+ * we couldn't stat().
+ */
+ if (dir == NULL || curdir == NULL)
+ return getpwd2();
+ path = stsavestr(dir);
+ STARTSTACKSTR(new);
+ if (*dir != '/') {
+ STPUTS(curdir, new);
+ if (STTOPC(new) == '/')
+ STUNPUTC(new);
+ }
+ while ((p = getcomponent(&path)) != NULL) {
+ if (equal(p, "..")) {
+ while (new > stackblock() && (STUNPUTC(new), *new) != '/');
+ } else if (*p != '\0' && ! equal(p, ".")) {
+ STPUTC('/', new);
+ STPUTS(p, new);
+ }
+ }
+ if (new == stackblock())
+ STPUTC('/', new);
+ STACKSTRNUL(new);
+ return stackblock();
+}
+
+/*
+ * Update curdir (the name of the current directory) in response to a
+ * cd command. We also call hashcd to let the routines in exec.c know
+ * that the current directory has changed.
+ */
+static void
+updatepwd(char *dir)
+{
+ char *prevdir;
+
+ hashcd(); /* update command hash table */
+
+ setvar("PWD", dir, VEXPORT);
+ setvar("OLDPWD", curdir, VEXPORT);
+ prevdir = curdir;
+ curdir = dir ? savestr(dir) : NULL;
+ ckfree(prevdir);
+}
+
+int
+pwdcmd(int argc __unused, char **argv __unused)
+{
+ char *p;
+ int ch, phys;
+
+ phys = Pflag;
+ while ((ch = nextopt("LP")) != '\0') {
+ switch (ch) {
+ case 'L':
+ phys = 0;
+ break;
+ case 'P':
+ phys = 1;
+ break;
+ }
+ }
+
+ if (*argptr != NULL)
+ error("too many arguments");
+
+ if (!phys && getpwd()) {
+ out1str(curdir);
+ out1c('\n');
+ } else {
+ if ((p = getpwd2()) == NULL)
+ error(".: %s", strerror(errno));
+ out1str(p);
+ out1c('\n');
+ }
+
+ return 0;
+}
+
+/*
+ * Get the current directory and cache the result in curdir.
+ */
+static char *
+getpwd(void)
+{
+ char *p;
+
+ if (curdir)
+ return curdir;
+
+ p = getpwd2();
+ if (p != NULL)
+ curdir = savestr(p);
+
+ return curdir;
+}
+
+#define MAXPWD 256
+
+/*
+ * Return the current directory.
+ */
+static char *
+getpwd2(void)
+{
+ char *pwd;
+ int i;
+
+ for (i = MAXPWD;; i *= 2) {
+ pwd = stalloc(i);
+ if (getcwd(pwd, i) != NULL)
+ return pwd;
+ stunalloc(pwd);
+ if (errno != ERANGE)
+ break;
+ }
+
+ return NULL;
+}
+
+/*
+ * Initialize PWD in a new shell.
+ * If the shell is interactive, we need to warn if this fails.
+ */
+void
+pwd_init(int warn)
+{
+ char *pwd;
+ struct stat stdot, stpwd;
+
+ pwd = lookupvar("PWD");
+ if (pwd && *pwd == '/' && stat(".", &stdot) != -1 &&
+ stat(pwd, &stpwd) != -1 &&
+ stdot.st_dev == stpwd.st_dev &&
+ stdot.st_ino == stpwd.st_ino) {
+ if (curdir)
+ ckfree(curdir);
+ curdir = savestr(pwd);
+ }
+ if (getpwd() == NULL && warn)
+ out2fmt_flush("sh: cannot determine working directory\n");
+ setvar("PWD", curdir, VEXPORT);
+}
diff --git a/shell_cmds/sh/cd.h b/shell_cmds/sh/cd.h
new file mode 100644
index 0000000..0745d97
--- /dev/null
+++ b/shell_cmds/sh/cd.h
@@ -0,0 +1,32 @@
+/*-
+ * Copyright (c) 1995
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: head/bin/sh/cd.h 314436 2017-02-28 23:42:47Z imp $
+ */
+
+void pwd_init(int);
diff --git a/shell_cmds/sh/error.c b/shell_cmds/sh/error.c
new file mode 100644
index 0000000..7f184ac
--- /dev/null
+++ b/shell_cmds/sh/error.c
@@ -0,0 +1,199 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)error.c 8.2 (Berkeley) 5/4/95";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/bin/sh/error.c 314436 2017-02-28 23:42:47Z imp $");
+
+/*
+ * Errors and exceptions.
+ */
+
+#include "shell.h"
+#include "eval.h"
+#include "main.h"
+#include "options.h"
+#include "output.h"
+#include "error.h"
+#include "nodes.h" /* show.h needs nodes.h */
+#include "show.h"
+#include "trap.h"
+#include <signal.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+
+
+/*
+ * Code to handle exceptions in C.
+ */
+
+struct jmploc *handler;
+volatile sig_atomic_t exception;
+volatile sig_atomic_t suppressint;
+volatile sig_atomic_t intpending;
+
+
+static void exverror(int, const char *, va_list) __printf0like(2, 0) __dead2;
+
+/*
+ * Called to raise an exception. Since C doesn't include exceptions, we
+ * just do a longjmp to the exception handler. The type of exception is
+ * stored in the global variable "exception".
+ *
+ * Interrupts are disabled; they should be reenabled when the exception is
+ * caught.
+ */
+
+void
+exraise(int e)
+{
+ INTOFF;
+ if (handler == NULL)
+ abort();
+ exception = e;
+ longjmp(handler->loc, 1);
+}
+
+
+/*
+ * Called from trap.c when a SIGINT is received and not suppressed, or when
+ * an interrupt is pending and interrupts are re-enabled using INTON.
+ * (If the user specifies that SIGINT is to be trapped or ignored using the
+ * trap builtin, then this routine is not called.) Suppressint is nonzero
+ * when interrupts are held using the INTOFF macro. If SIGINTs are not
+ * suppressed and the shell is not a root shell, then we want to be
+ * terminated if we get here, as if we were terminated directly by a SIGINT.
+ * Arrange for this here.
+ */
+
+void
+onint(void)
+{
+ sigset_t sigs;
+
+ intpending = 0;
+ sigemptyset(&sigs);
+ sigprocmask(SIG_SETMASK, &sigs, NULL);
+
+ /*
+ * This doesn't seem to be needed, since main() emits a newline.
+ */
+#if 0
+ if (tcgetpgrp(0) == getpid())
+ write(STDERR_FILENO, "\n", 1);
+#endif
+ if (rootshell && iflag)
+ exraise(EXINT);
+ else {
+ signal(SIGINT, SIG_DFL);
+ kill(getpid(), SIGINT);
+ _exit(128 + SIGINT);
+ }
+}
+
+
+static void
+vwarning(const char *msg, va_list ap)
+{
+ if (commandname)
+ outfmt(out2, "%s: ", commandname);
+ else if (arg0)
+ outfmt(out2, "%s: ", arg0);
+ doformat(out2, msg, ap);
+ out2fmt_flush("\n");
+}
+
+
+void
+warning(const char *msg, ...)
+{
+ va_list ap;
+ va_start(ap, msg);
+ vwarning(msg, ap);
+ va_end(ap);
+}
+
+
+/*
+ * Exverror is called to raise the error exception. If the first argument
+ * is not NULL then error prints an error message using printf style
+ * formatting. It then raises the error exception.
+ */
+static void
+exverror(int cond, const char *msg, va_list ap)
+{
+ /*
+ * An interrupt trumps an error. Certain places catch error
+ * exceptions or transform them to a plain nonzero exit code
+ * in child processes, and if an error exception can be handled,
+ * an interrupt can be handled as well.
+ *
+ * exraise() will disable interrupts for the exception handler.
+ */
+ FORCEINTON;
+
+#ifdef DEBUG
+ if (msg)
+ TRACE(("exverror(%d, \"%s\") pid=%d\n", cond, msg, getpid()));
+ else
+ TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
+#endif
+ if (msg)
+ vwarning(msg, ap);
+ flushall();
+ exraise(cond);
+}
+
+
+void
+error(const char *msg, ...)
+{
+ va_list ap;
+ va_start(ap, msg);
+ exverror(EXERROR, msg, ap);
+ va_end(ap);
+}
+
+
+void
+exerror(int cond, const char *msg, ...)
+{
+ va_list ap;
+ va_start(ap, msg);
+ exverror(cond, msg, ap);
+ va_end(ap);
+}
diff --git a/shell_cmds/sh/error.h b/shell_cmds/sh/error.h
new file mode 100644
index 0000000..e962c4f
--- /dev/null
+++ b/shell_cmds/sh/error.h
@@ -0,0 +1,95 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)error.h 8.2 (Berkeley) 5/4/95
+ * $FreeBSD: head/bin/sh/error.h 319591 2017-06-04 21:58:02Z jilles $
+ */
+
+/*
+ * We enclose jmp_buf in a structure so that we can declare pointers to
+ * jump locations. The global variable handler contains the location to
+ * jump to when an exception occurs, and the global variable exception
+ * contains a code identifying the exception. To implement nested
+ * exception handlers, the user should save the value of handler on entry
+ * to an inner scope, set handler to point to a jmploc structure for the
+ * inner scope, and restore handler on exit from the scope.
+ */
+
+#include <setjmp.h>
+#include <signal.h>
+
+struct jmploc {
+ jmp_buf loc;
+};
+
+extern struct jmploc *handler;
+extern volatile sig_atomic_t exception;
+
+/* exceptions */
+#define EXINT 0 /* SIGINT received */
+#define EXERROR 1 /* a generic error */
+#define EXEXEC 2 /* command execution failed */
+#define EXEXIT 3 /* call exitshell(exitstatus) */
+
+
+/*
+ * These macros allow the user to suspend the handling of interrupt signals
+ * over a period of time. This is similar to SIGHOLD to or sigblock, but
+ * much more efficient and portable. (But hacking the kernel is so much
+ * more fun than worrying about efficiency and portability. :-))
+ */
+
+extern volatile sig_atomic_t suppressint;
+extern volatile sig_atomic_t intpending;
+
+#define INTOFF suppressint++
+#define INTON { if (--suppressint == 0 && intpending) onint(); }
+#define is_int_on() suppressint
+#define SETINTON(s) do { suppressint = (s); if (suppressint == 0 && intpending) onint(); } while (0)
+#define FORCEINTON {suppressint = 0; if (intpending) onint();}
+#define SET_PENDING_INT intpending = 1
+#define CLEAR_PENDING_INT intpending = 0
+#define int_pending() intpending
+
+void exraise(int) __dead2;
+void onint(void) __dead2;
+void warning(const char *, ...) __printflike(1, 2);
+void error(const char *, ...) __printf0like(1, 2) __dead2;
+void exerror(int, const char *, ...) __printf0like(2, 3) __dead2;
+
+
+/*
+ * BSD setjmp saves the signal mask, which violates ANSI C and takes time,
+ * so we use _setjmp instead.
+ */
+
+#define setjmp(jmploc) _setjmp(jmploc)
+#define longjmp(jmploc, val) _longjmp(jmploc, val)
diff --git a/shell_cmds/sh/eval.c b/shell_cmds/sh/eval.c
new file mode 100644
index 0000000..bb5f3cc
--- /dev/null
+++ b/shell_cmds/sh/eval.c
@@ -0,0 +1,1381 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)eval.c 8.9 (Berkeley) 6/8/95";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/bin/sh/eval.c 327212 2017-12-26 16:23:18Z jilles $");
+
+#include <paths.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/resource.h>
+#include <errno.h>
+
+/*
+ * Evaluate a command.
+ */
+
+#include "shell.h"
+#include "nodes.h"
+#include "syntax.h"
+#include "expand.h"
+#include "parser.h"
+#include "jobs.h"
+#include "eval.h"
+#include "builtins.h"
+#include "options.h"
+#include "exec.h"
+#include "redir.h"
+#include "input.h"
+#include "output.h"
+#include "trap.h"
+#include "var.h"
+#include "memalloc.h"
+#include "error.h"
+#include "show.h"
+#include "mystring.h"
+#ifndef NO_HISTORY
+#include "myhistedit.h"
+#endif
+
+
+int evalskip; /* set if we are skipping commands */
+int skipcount; /* number of levels to skip */
+static int loopnest; /* current loop nesting level */
+int funcnest; /* depth of function calls */
+static int builtin_flags; /* evalcommand flags for builtins */
+
+
+char *commandname;
+struct arglist *cmdenviron;
+int exitstatus; /* exit status of last command */
+int oexitstatus; /* saved exit status */
+
+
+static void evalloop(union node *, int);
+static void evalfor(union node *, int);
+static union node *evalcase(union node *);
+static void evalsubshell(union node *, int);
+static void evalredir(union node *, int);
+static void exphere(union node *, struct arglist *);
+static void expredir(union node *);
+static void evalpipe(union node *);
+static int is_valid_fast_cmdsubst(union node *n);
+static void evalcommand(union node *, int, struct backcmd *);
+static void prehash(union node *);
+
+
+/*
+ * Called to reset things after an exception.
+ */
+
+void
+reseteval(void)
+{
+ evalskip = 0;
+ loopnest = 0;
+}
+
+
+/*
+ * The eval command.
+ */
+
+int
+evalcmd(int argc, char **argv)
+{
+ char *p;
+ char *concat;
+ char **ap;
+
+ if (argc > 1) {
+ p = argv[1];
+ if (argc > 2) {
+ STARTSTACKSTR(concat);
+ ap = argv + 2;
+ for (;;) {
+ STPUTS(p, concat);
+ if ((p = *ap++) == NULL)
+ break;
+ STPUTC(' ', concat);
+ }
+ STPUTC('\0', concat);
+ p = grabstackstr(concat);
+ }
+ evalstring(p, builtin_flags);
+ } else
+ exitstatus = 0;
+ return exitstatus;
+}
+
+
+/*
+ * Execute a command or commands contained in a string.
+ */
+
+void
+evalstring(const char *s, int flags)
+{
+ union node *n;
+ struct stackmark smark;
+ int flags_exit;
+ int any;
+
+ flags_exit = flags & EV_EXIT;
+ flags &= ~EV_EXIT;
+ any = 0;
+ setstackmark(&smark);
+ setinputstring(s, 1);
+ while ((n = parsecmd(0)) != NEOF) {
+ if (n != NULL && !nflag) {
+ if (flags_exit && preadateof())
+ evaltree(n, flags | EV_EXIT);
+ else
+ evaltree(n, flags);
+ any = 1;
+ if (evalskip)
+ break;
+ }
+ popstackmark(&smark);
+ setstackmark(&smark);
+ }
+ popfile();
+ popstackmark(&smark);
+ if (!any)
+ exitstatus = 0;
+ if (flags_exit)
+ exraise(EXEXIT);
+}
+
+
+/*
+ * Evaluate a parse tree. The value is left in the global variable
+ * exitstatus.
+ */
+
+void
+evaltree(union node *n, int flags)
+{
+ int do_etest;
+ union node *next;
+ struct stackmark smark;
+
+ setstackmark(&smark);
+ do_etest = 0;
+ if (n == NULL) {
+ TRACE(("evaltree(NULL) called\n"));
+ exitstatus = 0;
+ goto out;
+ }
+ do {
+ next = NULL;
+#ifndef NO_HISTORY
+ displayhist = 1; /* show history substitutions done with fc */
+#endif
+ TRACE(("evaltree(%p: %d) called\n", (void *)n, n->type));
+ switch (n->type) {
+ case NSEMI:
+ evaltree(n->nbinary.ch1, flags & ~EV_EXIT);
+ if (evalskip)
+ goto out;
+ next = n->nbinary.ch2;
+ break;
+ case NAND:
+ evaltree(n->nbinary.ch1, EV_TESTED);
+ if (evalskip || exitstatus != 0) {
+ goto out;
+ }
+ next = n->nbinary.ch2;
+ break;
+ case NOR:
+ evaltree(n->nbinary.ch1, EV_TESTED);
+ if (evalskip || exitstatus == 0)
+ goto out;
+ next = n->nbinary.ch2;
+ break;
+ case NREDIR:
+ evalredir(n, flags);
+ break;
+ case NSUBSHELL:
+ evalsubshell(n, flags);
+ do_etest = !(flags & EV_TESTED);
+ break;
+ case NBACKGND:
+ evalsubshell(n, flags);
+ break;
+ case NIF: {
+ evaltree(n->nif.test, EV_TESTED);
+ if (evalskip)
+ goto out;
+ if (exitstatus == 0)
+ next = n->nif.ifpart;
+ else if (n->nif.elsepart)
+ next = n->nif.elsepart;
+ else
+ exitstatus = 0;
+ break;
+ }
+ case NWHILE:
+ case NUNTIL:
+ evalloop(n, flags & ~EV_EXIT);
+ break;
+ case NFOR:
+ evalfor(n, flags & ~EV_EXIT);
+ break;
+ case NCASE:
+ next = evalcase(n);
+ break;
+ case NCLIST:
+ next = n->nclist.body;
+ break;
+ case NCLISTFALLTHRU:
+ if (n->nclist.body) {
+ evaltree(n->nclist.body, flags & ~EV_EXIT);
+ if (evalskip)
+ goto out;
+ }
+ next = n->nclist.next;
+ break;
+ case NDEFUN:
+ defun(n->narg.text, n->narg.next);
+ exitstatus = 0;
+ break;
+ case NNOT:
+ evaltree(n->nnot.com, EV_TESTED);
+ if (evalskip)
+ goto out;
+ exitstatus = !exitstatus;
+ break;
+
+ case NPIPE:
+ evalpipe(n);
+ do_etest = !(flags & EV_TESTED);
+ break;
+ case NCMD:
+ evalcommand(n, flags, (struct backcmd *)NULL);
+ do_etest = !(flags & EV_TESTED);
+ break;
+ default:
+ out1fmt("Node type = %d\n", n->type);
+ flushout(&output);
+ break;
+ }
+ n = next;
+ popstackmark(&smark);
+ setstackmark(&smark);
+ } while (n != NULL);
+out:
+ popstackmark(&smark);
+ if (pendingsig)
+ dotrap();
+ if (eflag && exitstatus != 0 && do_etest)
+ exitshell(exitstatus);
+ if (flags & EV_EXIT)
+ exraise(EXEXIT);
+}
+
+
+static void
+evalloop(union node *n, int flags)
+{
+ int status;
+
+ loopnest++;
+ status = 0;
+ for (;;) {
+ if (!evalskip)
+ evaltree(n->nbinary.ch1, EV_TESTED);
+ if (evalskip) {
+ if (evalskip == SKIPCONT && --skipcount <= 0) {
+ evalskip = 0;
+ continue;
+ }
+ if (evalskip == SKIPBREAK && --skipcount <= 0)
+ evalskip = 0;
+ if (evalskip == SKIPRETURN)
+ status = exitstatus;
+ break;
+ }
+ if (n->type == NWHILE) {
+ if (exitstatus != 0)
+ break;
+ } else {
+ if (exitstatus == 0)
+ break;
+ }
+ evaltree(n->nbinary.ch2, flags);
+ status = exitstatus;
+ }
+ loopnest--;
+ exitstatus = status;
+}
+
+
+
+static void
+evalfor(union node *n, int flags)
+{
+ struct arglist arglist;
+ union node *argp;
+ int i;
+ int status;
+
+ emptyarglist(&arglist);
+ for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
+ oexitstatus = exitstatus;
+ expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
+ }
+
+ loopnest++;
+ status = 0;
+ for (i = 0; i < arglist.count; i++) {
+ setvar(n->nfor.var, arglist.args[i], 0);
+ evaltree(n->nfor.body, flags);
+ status = exitstatus;
+ if (evalskip) {
+ if (evalskip == SKIPCONT && --skipcount <= 0) {
+ evalskip = 0;
+ continue;
+ }
+ if (evalskip == SKIPBREAK && --skipcount <= 0)
+ evalskip = 0;
+ break;
+ }
+ }
+ loopnest--;
+ exitstatus = status;
+}
+
+
+/*
+ * Evaluate a case statement, returning the selected tree.
+ *
+ * The exit status needs care to get right.
+ */
+
+static union node *
+evalcase(union node *n)
+{
+ union node *cp;
+ union node *patp;
+ struct arglist arglist;
+
+ emptyarglist(&arglist);
+ oexitstatus = exitstatus;
+ expandarg(n->ncase.expr, &arglist, EXP_TILDE);
+ for (cp = n->ncase.cases ; cp ; cp = cp->nclist.next) {
+ for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
+ if (casematch(patp, arglist.args[0])) {
+ while (cp->nclist.next &&
+ cp->type == NCLISTFALLTHRU &&
+ cp->nclist.body == NULL)
+ cp = cp->nclist.next;
+ if (cp->nclist.next &&
+ cp->type == NCLISTFALLTHRU)
+ return (cp);
+ if (cp->nclist.body == NULL)
+ exitstatus = 0;
+ return (cp->nclist.body);
+ }
+ }
+ }
+ exitstatus = 0;
+ return (NULL);
+}
+
+
+
+/*
+ * Kick off a subshell to evaluate a tree.
+ */
+
+static void
+evalsubshell(union node *n, int flags)
+{
+ struct job *jp;
+ int backgnd = (n->type == NBACKGND);
+
+ oexitstatus = exitstatus;
+ expredir(n->nredir.redirect);
+ if ((!backgnd && flags & EV_EXIT && !have_traps()) ||
+ forkshell(jp = makejob(n, 1), n, backgnd) == 0) {
+ if (backgnd)
+ flags &=~ EV_TESTED;
+ redirect(n->nredir.redirect, 0);
+ evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */
+ } else if (! backgnd) {
+ INTOFF;
+ exitstatus = waitforjob(jp, (int *)NULL);
+ INTON;
+ } else
+ exitstatus = 0;
+}
+
+
+/*
+ * Evaluate a redirected compound command.
+ */
+
+static void
+evalredir(union node *n, int flags)
+{
+ struct jmploc jmploc;
+ struct jmploc *savehandler;
+ volatile int in_redirect = 1;
+
+ oexitstatus = exitstatus;
+ expredir(n->nredir.redirect);
+ savehandler = handler;
+ if (setjmp(jmploc.loc)) {
+ int e;
+
+ handler = savehandler;
+ e = exception;
+ popredir();
+ if (e == EXERROR || e == EXEXEC) {
+ if (in_redirect) {
+ exitstatus = 2;
+ FORCEINTON;
+ return;
+ }
+ }
+ longjmp(handler->loc, 1);
+ } else {
+ INTOFF;
+ handler = &jmploc;
+ redirect(n->nredir.redirect, REDIR_PUSH);
+ in_redirect = 0;
+ INTON;
+ evaltree(n->nredir.n, flags);
+ }
+ INTOFF;
+ handler = savehandler;
+ popredir();
+ INTON;
+}
+
+
+static void
+exphere(union node *redir, struct arglist *fn)
+{
+ struct jmploc jmploc;
+ struct jmploc *savehandler;
+ struct localvar *savelocalvars;
+ int need_longjmp = 0;
+ unsigned char saveoptreset;
+
+ redir->nhere.expdoc = "";
+ savelocalvars = localvars;
+ localvars = NULL;
+ saveoptreset = shellparam.reset;
+ forcelocal++;
+ savehandler = handler;
+ if (setjmp(jmploc.loc))
+ need_longjmp = exception != EXERROR && exception != EXEXEC;
+ else {
+ handler = &jmploc;
+ expandarg(redir->nhere.doc, fn, 0);
+ redir->nhere.expdoc = fn->args[0];
+ INTOFF;
+ }
+ handler = savehandler;
+ forcelocal--;
+ poplocalvars();
+ localvars = savelocalvars;
+ shellparam.reset = saveoptreset;
+ if (need_longjmp)
+ longjmp(handler->loc, 1);
+ INTON;
+}
+
+
+/*
+ * Compute the names of the files in a redirection list.
+ */
+
+static void
+expredir(union node *n)
+{
+ union node *redir;
+
+ for (redir = n ; redir ; redir = redir->nfile.next) {
+ struct arglist fn;
+ emptyarglist(&fn);
+ switch (redir->type) {
+ case NFROM:
+ case NTO:
+ case NFROMTO:
+ case NAPPEND:
+ case NCLOBBER:
+ expandarg(redir->nfile.fname, &fn, EXP_TILDE);
+ redir->nfile.expfname = fn.args[0];
+ break;
+ case NFROMFD:
+ case NTOFD:
+ if (redir->ndup.vname) {
+ expandarg(redir->ndup.vname, &fn, EXP_TILDE);
+ fixredir(redir, fn.args[0], 1);
+ }
+ break;
+ case NXHERE:
+ exphere(redir, &fn);
+ break;
+ }
+ }
+}
+
+
+
+/*
+ * Evaluate a pipeline. All the processes in the pipeline are children
+ * of the process creating the pipeline. (This differs from some versions
+ * of the shell, which make the last process in a pipeline the parent
+ * of all the rest.)
+ */
+
+static void
+evalpipe(union node *n)
+{
+ struct job *jp;
+ struct nodelist *lp;
+ int pipelen;
+ int prevfd;
+ int pip[2];
+
+ TRACE(("evalpipe(%p) called\n", (void *)n));
+ pipelen = 0;
+ for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
+ pipelen++;
+ INTOFF;
+ jp = makejob(n, pipelen);
+ prevfd = -1;
+ for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
+ prehash(lp->n);
+ pip[1] = -1;
+ if (lp->next) {
+ if (pipe(pip) < 0) {
+ if (prevfd >= 0)
+ close(prevfd);
+ error("Pipe call failed: %s", strerror(errno));
+ }
+ }
+ if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
+ INTON;
+ if (prevfd > 0) {
+ dup2(prevfd, 0);
+ close(prevfd);
+ }
+ if (pip[1] >= 0) {
+ if (!(prevfd >= 0 && pip[0] == 0))
+ close(pip[0]);
+ if (pip[1] != 1) {
+ dup2(pip[1], 1);
+ close(pip[1]);
+ }
+ }
+ evaltree(lp->n, EV_EXIT);
+ }
+ if (prevfd >= 0)
+ close(prevfd);
+ prevfd = pip[0];
+ if (pip[1] != -1)
+ close(pip[1]);
+ }
+ INTON;
+ if (n->npipe.backgnd == 0) {
+ INTOFF;
+ exitstatus = waitforjob(jp, (int *)NULL);
+ TRACE(("evalpipe: job done exit status %d\n", exitstatus));
+ INTON;
+ } else
+ exitstatus = 0;
+}
+
+
+
+static int
+is_valid_fast_cmdsubst(union node *n)
+{
+
+ return (n->type == NCMD);
+}
+
+/*
+ * Execute a command inside back quotes. If it's a builtin command, we
+ * want to save its output in a block obtained from malloc. Otherwise
+ * we fork off a subprocess and get the output of the command via a pipe.
+ * Should be called with interrupts off.
+ */
+
+void
+evalbackcmd(union node *n, struct backcmd *result)
+{
+ int pip[2];
+ struct job *jp;
+ struct stackmark smark;
+ struct jmploc jmploc;
+ struct jmploc *savehandler;
+ struct localvar *savelocalvars;
+ unsigned char saveoptreset;
+
+ result->fd = -1;
+ result->buf = NULL;
+ result->nleft = 0;
+ result->jp = NULL;
+ if (n == NULL) {
+ exitstatus = 0;
+ return;
+ }
+ setstackmark(&smark);
+ exitstatus = oexitstatus;
+ if (is_valid_fast_cmdsubst(n)) {
+ savelocalvars = localvars;
+ localvars = NULL;
+ saveoptreset = shellparam.reset;
+ forcelocal++;
+ savehandler = handler;
+ if (setjmp(jmploc.loc)) {
+ if (exception == EXERROR || exception == EXEXEC)
+ exitstatus = 2;
+ else if (exception != 0) {
+ handler = savehandler;
+ forcelocal--;
+ poplocalvars();
+ localvars = savelocalvars;
+ shellparam.reset = saveoptreset;
+ longjmp(handler->loc, 1);
+ }
+ } else {
+ handler = &jmploc;
+ evalcommand(n, EV_BACKCMD, result);
+ }
+ handler = savehandler;
+ forcelocal--;
+ poplocalvars();
+ localvars = savelocalvars;
+ shellparam.reset = saveoptreset;
+ } else {
+ if (pipe(pip) < 0)
+ error("Pipe call failed: %s", strerror(errno));
+ jp = makejob(n, 1);
+ if (forkshell(jp, n, FORK_NOJOB) == 0) {
+ FORCEINTON;
+ close(pip[0]);
+ if (pip[1] != 1) {
+ dup2(pip[1], 1);
+ close(pip[1]);
+ }
+ evaltree(n, EV_EXIT);
+ }
+ close(pip[1]);
+ result->fd = pip[0];
+ result->jp = jp;
+ }
+ popstackmark(&smark);
+ TRACE(("evalbackcmd done: fd=%d buf=%p nleft=%d jp=%p\n",
+ result->fd, result->buf, result->nleft, result->jp));
+}
+
+static int
+mustexpandto(const char *argtext, const char *mask)
+{
+ for (;;) {
+ if (*argtext == CTLQUOTEMARK || *argtext == CTLQUOTEEND) {
+ argtext++;
+ continue;
+ }
+ if (*argtext == CTLESC)
+ argtext++;
+ else if (BASESYNTAX[(int)*argtext] == CCTL)
+ return (0);
+ if (*argtext != *mask)
+ return (0);
+ if (*argtext == '\0')
+ return (1);
+ argtext++;
+ mask++;
+ }
+}
+
+static int
+isdeclarationcmd(struct narg *arg)
+{
+ int have_command = 0;
+
+ if (arg == NULL)
+ return (0);
+ while (mustexpandto(arg->text, "command")) {
+ have_command = 1;
+ arg = &arg->next->narg;
+ if (arg == NULL)
+ return (0);
+ /*
+ * To also allow "command -p" and "command --" as part of
+ * a declaration command, add code here.
+ * We do not do this, as ksh does not do it either and it
+ * is not required by POSIX.
+ */
+ }
+ return (mustexpandto(arg->text, "export") ||
+ mustexpandto(arg->text, "readonly") ||
+ (mustexpandto(arg->text, "local") &&
+ (have_command || !isfunc("local"))));
+}
+
+static void
+xtracecommand(struct arglist *varlist, int argc, char **argv)
+{
+ char sep = 0;
+ const char *text, *p, *ps4;
+ int i;
+
+ ps4 = expandstr(ps4val());
+ out2str(ps4 != NULL ? ps4 : ps4val());
+ for (i = 0; i < varlist->count; i++) {
+ text = varlist->args[i];
+ if (sep != 0)
+ out2c(' ');
+ p = strchr(text, '=');
+ if (p != NULL) {
+ p++;
+ outbin(text, p - text, out2);
+ out2qstr(p);
+ } else
+ out2qstr(text);
+ sep = ' ';
+ }
+ for (i = 0; i < argc; i++) {
+ text = argv[i];
+ if (sep != 0)
+ out2c(' ');
+ out2qstr(text);
+ sep = ' ';
+ }
+ out2c('\n');
+ flushout(&errout);
+}
+
+/*
+ * Check if a builtin can safely be executed in the same process,
+ * even though it should be in a subshell (command substitution).
+ * Note that jobid, jobs, times and trap can show information not
+ * available in a child process; this is deliberate.
+ * The arguments should already have been expanded.
+ */
+static int
+safe_builtin(int idx, int argc, char **argv)
+{
+ /* Generated from builtins.def. */
+ if (safe_builtin_always(idx))
+ return (1);
+ if (idx == EXPORTCMD || idx == TRAPCMD || idx == ULIMITCMD ||
+ idx == UMASKCMD)
+ return (argc <= 1 || (argc == 2 && argv[1][0] == '-'));
+ if (idx == SETCMD)
+ return (argc <= 1 || (argc == 2 && (argv[1][0] == '-' ||
+ argv[1][0] == '+') && argv[1][1] == 'o' &&
+ argv[1][2] == '\0'));
+ return (0);
+}
+
+/*
+ * Execute a simple command.
+ * Note: This may or may not return if (flags & EV_EXIT).
+ */
+
+static void
+evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
+{
+ union node *argp;
+ struct arglist arglist;
+ struct arglist varlist;
+ char **argv;
+ int argc;
+ char **envp;
+ int varflag;
+ int mode;
+ int pip[2];
+ struct cmdentry cmdentry;
+ struct job *jp;
+ struct jmploc jmploc;
+ struct jmploc *savehandler;
+ char *savecmdname;
+ struct shparam saveparam;
+ struct localvar *savelocalvars;
+ struct parsefile *savetopfile;
+ volatile int e;
+ char *lastarg;
+ int signaled;
+ int do_clearcmdentry;
+ const char *path = pathval();
+ int i;
+
+ /* First expand the arguments. */
+ TRACE(("evalcommand(%p, %d) called\n", (void *)cmd, flags));
+ emptyarglist(&arglist);
+ emptyarglist(&varlist);
+ varflag = 1;
+ jp = NULL;
+ do_clearcmdentry = 0;
+ oexitstatus = exitstatus;
+ exitstatus = 0;
+ /* Add one slot at the beginning for tryexec(). */
+ appendarglist(&arglist, nullstr);
+ for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) {
+ if (varflag && isassignment(argp->narg.text)) {
+ expandarg(argp, varflag == 1 ? &varlist : &arglist,
+ EXP_VARTILDE);
+ continue;
+ } else if (varflag == 1)
+ varflag = isdeclarationcmd(&argp->narg) ? 2 : 0;
+ expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
+ }
+ appendarglist(&arglist, nullstr);
+ expredir(cmd->ncmd.redirect);
+ argc = arglist.count - 2;
+ argv = &arglist.args[1];
+
+ argv[argc] = NULL;
+ lastarg = NULL;
+ if (iflag && funcnest == 0 && argc > 0)
+ lastarg = argv[argc - 1];
+
+ /* Print the command if xflag is set. */
+ if (xflag)
+ xtracecommand(&varlist, argc, argv);
+
+ /* Now locate the command. */
+ if (argc == 0) {
+ /* Variable assignment(s) without command */
+ cmdentry.cmdtype = CMDBUILTIN;
+ cmdentry.u.index = BLTINCMD;
+ cmdentry.special = 0;
+ } else {
+ static const char PATH[] = "PATH=";
+ int cmd_flags = 0, bltinonly = 0;
+
+ /*
+ * Modify the command lookup path, if a PATH= assignment
+ * is present
+ */
+ for (i = 0; i < varlist.count; i++)
+ if (strncmp(varlist.args[i], PATH, sizeof(PATH) - 1) == 0) {
+ path = varlist.args[i] + sizeof(PATH) - 1;
+ /*
+ * On `PATH=... command`, we need to make
+ * sure that the command isn't using the
+ * non-updated hash table of the outer PATH
+ * setting and we need to make sure that
+ * the hash table isn't filled with items
+ * from the temporary setting.
+ *
+ * It would be better to forbit using and
+ * updating the table while this command
+ * runs, by the command finding mechanism
+ * is heavily integrated with hash handling,
+ * so we just delete the hash before and after
+ * the command runs. Partly deleting like
+ * changepatch() does doesn't seem worth the
+ * bookinging effort, since most such runs add
+ * directories in front of the new PATH.
+ */
+ clearcmdentry();
+ do_clearcmdentry = 1;
+ }
+
+ for (;;) {
+ if (bltinonly) {
+ cmdentry.u.index = find_builtin(*argv, &cmdentry.special);
+ if (cmdentry.u.index < 0) {
+ cmdentry.u.index = BLTINCMD;
+ argv--;
+ argc++;
+ break;
+ }
+ } else
+ find_command(argv[0], &cmdentry, cmd_flags, path);
+ /* implement the bltin and command builtins here */
+ if (cmdentry.cmdtype != CMDBUILTIN)
+ break;
+ if (cmdentry.u.index == BLTINCMD) {
+ if (argc == 1)
+ break;
+ argv++;
+ argc--;
+ bltinonly = 1;
+ } else if (cmdentry.u.index == COMMANDCMD) {
+ if (argc == 1)
+ break;
+ if (!strcmp(argv[1], "-p")) {
+ if (argc == 2)
+ break;
+ if (argv[2][0] == '-') {
+ if (strcmp(argv[2], "--"))
+ break;
+ if (argc == 3)
+ break;
+ argv += 3;
+ argc -= 3;
+ } else {
+ argv += 2;
+ argc -= 2;
+ }
+ path = _PATH_STDPATH;
+ clearcmdentry();
+ do_clearcmdentry = 1;
+ } else if (!strcmp(argv[1], "--")) {
+ if (argc == 2)
+ break;
+ argv += 2;
+ argc -= 2;
+ } else if (argv[1][0] == '-')
+ break;
+ else {
+ argv++;
+ argc--;
+ }
+ cmd_flags |= DO_NOFUNC;
+ bltinonly = 0;
+ } else
+ break;
+ }
+ /*
+ * Special builtins lose their special properties when
+ * called via 'command'.
+ */
+ if (cmd_flags & DO_NOFUNC)
+ cmdentry.special = 0;
+ }
+
+ /* Fork off a child process if necessary. */
+ if (((cmdentry.cmdtype == CMDNORMAL || cmdentry.cmdtype == CMDUNKNOWN)
+ && ((flags & EV_EXIT) == 0 || have_traps()))
+ || ((flags & EV_BACKCMD) != 0
+ && (cmdentry.cmdtype != CMDBUILTIN ||
+ !safe_builtin(cmdentry.u.index, argc, argv)))) {
+ jp = makejob(cmd, 1);
+ mode = FORK_FG;
+ if (flags & EV_BACKCMD) {
+ mode = FORK_NOJOB;
+ if (pipe(pip) < 0)
+ error("Pipe call failed: %s", strerror(errno));
+ }
+ if (cmdentry.cmdtype == CMDNORMAL &&
+ cmd->ncmd.redirect == NULL &&
+ varlist.count == 0 &&
+ (mode == FORK_FG || mode == FORK_NOJOB) &&
+ !disvforkset() && !iflag && !mflag) {
+ vforkexecshell(jp, argv, environment(), path,
+ cmdentry.u.index, flags & EV_BACKCMD ? pip : NULL);
+ goto parent;
+ }
+ if (forkshell(jp, cmd, mode) != 0)
+ goto parent; /* at end of routine */
+ if (flags & EV_BACKCMD) {
+ FORCEINTON;
+ close(pip[0]);
+ if (pip[1] != 1) {
+ dup2(pip[1], 1);
+ close(pip[1]);
+ }
+ flags &= ~EV_BACKCMD;
+ }
+ flags |= EV_EXIT;
+ }
+
+ /* This is the child process if a fork occurred. */
+ /* Execute the command. */
+ if (cmdentry.cmdtype == CMDFUNCTION) {
+#ifdef DEBUG
+ trputs("Shell function: "); trargs(argv);
+#endif
+ saveparam = shellparam;
+ shellparam.malloc = 0;
+ shellparam.reset = 1;
+ shellparam.nparam = argc - 1;
+ shellparam.p = argv + 1;
+ shellparam.optp = NULL;
+ shellparam.optnext = NULL;
+ INTOFF;
+ savelocalvars = localvars;
+ localvars = NULL;
+ reffunc(cmdentry.u.func);
+ savehandler = handler;
+ if (setjmp(jmploc.loc)) {
+ popredir();
+ unreffunc(cmdentry.u.func);
+ poplocalvars();
+ localvars = savelocalvars;
+ freeparam(&shellparam);
+ shellparam = saveparam;
+ funcnest--;
+ handler = savehandler;
+ longjmp(handler->loc, 1);
+ }
+ handler = &jmploc;
+ funcnest++;
+ redirect(cmd->ncmd.redirect, REDIR_PUSH);
+ INTON;
+ for (i = 0; i < varlist.count; i++)
+ mklocal(varlist.args[i]);
+ exitstatus = oexitstatus;
+ evaltree(getfuncnode(cmdentry.u.func),
+ flags & (EV_TESTED | EV_EXIT));
+ INTOFF;
+ unreffunc(cmdentry.u.func);
+ poplocalvars();
+ localvars = savelocalvars;
+ freeparam(&shellparam);
+ shellparam = saveparam;
+ handler = savehandler;
+ funcnest--;
+ popredir();
+ INTON;
+ if (evalskip == SKIPRETURN) {
+ evalskip = 0;
+ skipcount = 0;
+ }
+ if (jp)
+ exitshell(exitstatus);
+ } else if (cmdentry.cmdtype == CMDBUILTIN) {
+#ifdef DEBUG
+ trputs("builtin command: "); trargs(argv);
+#endif
+ mode = (cmdentry.u.index == EXECCMD)? 0 : REDIR_PUSH;
+ if (flags == EV_BACKCMD) {
+ memout.nextc = memout.buf;
+ mode |= REDIR_BACKQ;
+ }
+ savecmdname = commandname;
+ savetopfile = getcurrentfile();
+ cmdenviron = &varlist;
+ e = -1;
+ savehandler = handler;
+ if (setjmp(jmploc.loc)) {
+ e = exception;
+ if (e == EXINT)
+ exitstatus = SIGINT+128;
+ else if (e != EXEXIT)
+ exitstatus = 2;
+ goto cmddone;
+ }
+ handler = &jmploc;
+ redirect(cmd->ncmd.redirect, mode);
+ outclearerror(out1);
+ /*
+ * If there is no command word, redirection errors should
+ * not be fatal but assignment errors should.
+ */
+ if (argc == 0)
+ cmdentry.special = 1;
+ listsetvar(cmdenviron, cmdentry.special ? 0 : VNOSET);
+ if (argc > 0)
+ bltinsetlocale();
+ commandname = argv[0];
+ argptr = argv + 1;
+ nextopt_optptr = NULL; /* initialize nextopt */
+ builtin_flags = flags;
+ exitstatus = (*builtinfunc[cmdentry.u.index])(argc, argv);
+ flushall();
+ if (outiserror(out1)) {
+ warning("write error on stdout");
+ if (exitstatus == 0 || exitstatus == 1)
+ exitstatus = 2;
+ }
+cmddone:
+ if (argc > 0)
+ bltinunsetlocale();
+ cmdenviron = NULL;
+ out1 = &output;
+ out2 = &errout;
+ freestdout();
+ handler = savehandler;
+ commandname = savecmdname;
+ if (jp)
+ exitshell(exitstatus);
+ if (flags == EV_BACKCMD) {
+ backcmd->buf = memout.buf;
+ backcmd->nleft = memout.buf != NULL ?
+ memout.nextc - memout.buf : 0;
+ memout.buf = NULL;
+ memout.nextc = NULL;
+ memout.bufend = NULL;
+ memout.bufsize = 64;
+ }
+ if (cmdentry.u.index != EXECCMD)
+ popredir();
+ if (e != -1) {
+ if ((e != EXERROR && e != EXEXEC)
+ || cmdentry.special)
+ exraise(e);
+ popfilesupto(savetopfile);
+ if (flags != EV_BACKCMD)
+ FORCEINTON;
+ }
+ } else {
+#ifdef DEBUG
+ trputs("normal command: "); trargs(argv);
+#endif
+ redirect(cmd->ncmd.redirect, 0);
+ for (i = 0; i < varlist.count; i++)
+ setvareq(varlist.args[i], VEXPORT|VSTACK);
+ envp = environment();
+ shellexec(argv, envp, path, cmdentry.u.index);
+ /*NOTREACHED*/
+ }
+ goto out;
+
+parent: /* parent process gets here (if we forked) */
+ if (mode == FORK_FG) { /* argument to fork */
+ INTOFF;
+ exitstatus = waitforjob(jp, &signaled);
+ INTON;
+ if (iflag && loopnest > 0 && signaled) {
+ evalskip = SKIPBREAK;
+ skipcount = loopnest;
+ }
+ } else if (mode == FORK_NOJOB) {
+ backcmd->fd = pip[0];
+ close(pip[1]);
+ backcmd->jp = jp;
+ }
+
+out:
+ if (lastarg)
+ setvar("_", lastarg, 0);
+ if (do_clearcmdentry)
+ clearcmdentry();
+}
+
+
+
+/*
+ * Search for a command. This is called before we fork so that the
+ * location of the command will be available in the parent as well as
+ * the child. The check for "goodname" is an overly conservative
+ * check that the name will not be subject to expansion.
+ */
+
+static void
+prehash(union node *n)
+{
+ struct cmdentry entry;
+
+ if (n && n->type == NCMD && n->ncmd.args)
+ if (goodname(n->ncmd.args->narg.text))
+ find_command(n->ncmd.args->narg.text, &entry, 0,
+ pathval());
+}
+
+
+
+/*
+ * Builtin commands. Builtin commands whose functions are closely
+ * tied to evaluation are implemented here.
+ */
+
+/*
+ * No command given, a bltin command with no arguments, or a bltin command
+ * with an invalid name.
+ */
+
+int
+bltincmd(int argc, char **argv)
+{
+ if (argc > 1) {
+ out2fmt_flush("%s: not found\n", argv[1]);
+ return 127;
+ }
+ /*
+ * Preserve exitstatus of a previous possible command substitution
+ * as POSIX mandates
+ */
+ return exitstatus;
+}
+
+
+/*
+ * Handle break and continue commands. Break, continue, and return are
+ * all handled by setting the evalskip flag. The evaluation routines
+ * above all check this flag, and if it is set they start skipping
+ * commands rather than executing them. The variable skipcount is
+ * the number of loops to break/continue, or the number of function
+ * levels to return. (The latter is always 1.) It should probably
+ * be an error to break out of more loops than exist, but it isn't
+ * in the standard shell so we don't make it one here.
+ */
+
+int
+breakcmd(int argc, char **argv)
+{
+ long n;
+ char *end;
+
+ if (argc > 1) {
+ /* Allow arbitrarily large numbers. */
+ n = strtol(argv[1], &end, 10);
+ if (!is_digit(argv[1][0]) || *end != '\0')
+ error("Illegal number: %s", argv[1]);
+ } else
+ n = 1;
+ if (n > loopnest)
+ n = loopnest;
+ if (n > 0) {
+ evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
+ skipcount = n;
+ }
+ return 0;
+}
+
+/*
+ * The `command' command.
+ */
+int
+commandcmd(int argc __unused, char **argv __unused)
+{
+ const char *path;
+ int ch;
+ int cmd = -1;
+
+ path = bltinlookup("PATH", 1);
+
+ while ((ch = nextopt("pvV")) != '\0') {
+ switch (ch) {
+ case 'p':
+ path = _PATH_STDPATH;
+ break;
+ case 'v':
+ cmd = TYPECMD_SMALLV;
+ break;
+ case 'V':
+ cmd = TYPECMD_BIGV;
+ break;
+ }
+ }
+
+ if (cmd != -1) {
+ if (*argptr == NULL || argptr[1] != NULL)
+ error("wrong number of arguments");
+ return typecmd_impl(2, argptr - 1, cmd, path);
+ }
+ if (*argptr != NULL)
+ error("commandcmd bad call");
+
+ /*
+ * Do nothing successfully if no command was specified;
+ * ksh also does this.
+ */
+ return 0;
+}
+
+
+/*
+ * The return command.
+ */
+
+int
+returncmd(int argc, char **argv)
+{
+ int ret = argc > 1 ? number(argv[1]) : oexitstatus;
+
+ evalskip = SKIPRETURN;
+ skipcount = 1;
+ return ret;
+}
+
+
+int
+falsecmd(int argc __unused, char **argv __unused)
+{
+ return 1;
+}
+
+
+int
+truecmd(int argc __unused, char **argv __unused)
+{
+ return 0;
+}
+
+
+int
+execcmd(int argc, char **argv)
+{
+ int i;
+
+ /*
+ * Because we have historically not supported any options,
+ * only treat "--" specially.
+ */
+ if (argc > 1 && strcmp(argv[1], "--") == 0)
+ argc--, argv++;
+ if (argc > 1) {
+ iflag = 0; /* exit on error */
+ mflag = 0;
+ optschanged();
+ for (i = 0; i < cmdenviron->count; i++)
+ setvareq(cmdenviron->args[i], VEXPORT|VSTACK);
+ shellexec(argv + 1, environment(), pathval(), 0);
+
+ }
+ return 0;
+}
+
+
+int
+timescmd(int argc __unused, char **argv __unused)
+{
+ struct rusage ru;
+ long shumins, shsmins, chumins, chsmins;
+ double shusecs, shssecs, chusecs, chssecs;
+
+ if (getrusage(RUSAGE_SELF, &ru) < 0)
+ return 1;
+ shumins = ru.ru_utime.tv_sec / 60;
+ shusecs = ru.ru_utime.tv_sec % 60 + ru.ru_utime.tv_usec / 1000000.;
+ shsmins = ru.ru_stime.tv_sec / 60;
+ shssecs = ru.ru_stime.tv_sec % 60 + ru.ru_stime.tv_usec / 1000000.;
+ if (getrusage(RUSAGE_CHILDREN, &ru) < 0)
+ return 1;
+ chumins = ru.ru_utime.tv_sec / 60;
+ chusecs = ru.ru_utime.tv_sec % 60 + ru.ru_utime.tv_usec / 1000000.;
+ chsmins = ru.ru_stime.tv_sec / 60;
+ chssecs = ru.ru_stime.tv_sec % 60 + ru.ru_stime.tv_usec / 1000000.;
+ out1fmt("%ldm%.3fs %ldm%.3fs\n%ldm%.3fs %ldm%.3fs\n", shumins,
+ shusecs, shsmins, shssecs, chumins, chusecs, chsmins, chssecs);
+ return 0;
+}
diff --git a/shell_cmds/sh/eval.h b/shell_cmds/sh/eval.h
new file mode 100644
index 0000000..18b39f9
--- /dev/null
+++ b/shell_cmds/sh/eval.h
@@ -0,0 +1,70 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)eval.h 8.2 (Berkeley) 5/4/95
+ * $FreeBSD: head/bin/sh/eval.h 314436 2017-02-28 23:42:47Z imp $
+ */
+
+extern char *commandname; /* currently executing command */
+extern int exitstatus; /* exit status of last command */
+extern int oexitstatus; /* saved exit status */
+extern struct arglist *cmdenviron; /* environment for builtin command */
+
+
+struct backcmd { /* result of evalbackcmd */
+ int fd; /* file descriptor to read from */
+ char *buf; /* buffer */
+ int nleft; /* number of chars in buffer */
+ struct job *jp; /* job structure for command */
+};
+
+void reseteval(void);
+
+/* flags in argument to evaltree/evalstring */
+#define EV_EXIT 01 /* exit after evaluating tree */
+#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
+#define EV_BACKCMD 04 /* command executing within back quotes */
+
+void evalstring(const char *, int);
+union node; /* BLETCH for ansi C */
+void evaltree(union node *, int);
+void evalbackcmd(union node *, struct backcmd *);
+
+/* in_function returns nonzero if we are currently evaluating a function */
+#define in_function() funcnest
+extern int funcnest;
+extern int evalskip;
+extern int skipcount;
+
+/* reasons for skipping commands (see comment on breakcmd routine) */
+#define SKIPBREAK 1
+#define SKIPCONT 2
+#define SKIPRETURN 3
diff --git a/shell_cmds/sh/exec.c b/shell_cmds/sh/exec.c
new file mode 100644
index 0000000..ae3cf6e
--- /dev/null
+++ b/shell_cmds/sh/exec.c
@@ -0,0 +1,780 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)exec.c 8.4 (Berkeley) 6/8/95";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/bin/sh/exec.c 317882 2017-05-06 13:28:42Z jilles $");
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <paths.h>
+#include <stdlib.h>
+
+/*
+ * When commands are first encountered, they are entered in a hash table.
+ * This ensures that a full path search will not have to be done for them
+ * on each invocation.
+ *
+ * We should investigate converting to a linear search, even though that
+ * would make the command name "hash" a misnomer.
+ */
+
+#include "shell.h"
+#include "main.h"
+#include "nodes.h"
+#include "parser.h"
+#include "redir.h"
+#include "eval.h"
+#include "exec.h"
+#include "builtins.h"
+#include "var.h"
+#include "options.h"
+#include "input.h"
+#include "output.h"
+#include "syntax.h"
+#include "memalloc.h"
+#include "error.h"
+#include "mystring.h"
+#include "show.h"
+#include "jobs.h"
+#include "alias.h"
+
+
+#ifdef __APPLE__
+#define eaccess(path, mode) faccessat(AT_FDCWD, path, mode, AT_EACCESS)
+#endif /* __APPLE__ */
+
+#define CMDTABLESIZE 31 /* should be prime */
+
+
+
+struct tblentry {
+ struct tblentry *next; /* next entry in hash chain */
+ union param param; /* definition of builtin function */
+ int special; /* flag for special builtin commands */
+ signed char cmdtype; /* index identifying command */
+ char cmdname[]; /* name of command */
+};
+
+
+static struct tblentry *cmdtable[CMDTABLESIZE];
+static int cmdtable_cd = 0; /* cmdtable contains cd-dependent entries */
+int exerrno = 0; /* Last exec error */
+
+
+static void tryexec(char *, char **, char **);
+static void printentry(struct tblentry *, int);
+static struct tblentry *cmdlookup(const char *, int);
+static void delete_cmd_entry(void);
+static void addcmdentry(const char *, struct cmdentry *);
+
+
+
+/*
+ * Exec a program. Never returns. If you change this routine, you may
+ * have to change the find_command routine as well.
+ *
+ * The argv array may be changed and element argv[-1] should be writable.
+ */
+
+void
+shellexec(char **argv, char **envp, const char *path, int idx)
+{
+ char *cmdname;
+ int e;
+
+ if (strchr(argv[0], '/') != NULL) {
+ tryexec(argv[0], argv, envp);
+ e = errno;
+ } else {
+ e = ENOENT;
+ while ((cmdname = padvance(&path, argv[0])) != NULL) {
+ if (--idx < 0 && pathopt == NULL) {
+ tryexec(cmdname, argv, envp);
+ if (errno != ENOENT && errno != ENOTDIR)
+ e = errno;
+ if (e == ENOEXEC)
+ break;
+ }
+ stunalloc(cmdname);
+ }
+ }
+
+ /* Map to POSIX errors */
+ if (e == ENOENT || e == ENOTDIR) {
+ exerrno = 127;
+ exerror(EXEXEC, "%s: not found", argv[0]);
+ } else {
+ exerrno = 126;
+ exerror(EXEXEC, "%s: %s", argv[0], strerror(e));
+ }
+}
+
+
+static void
+tryexec(char *cmd, char **argv, char **envp)
+{
+ int e, in;
+ ssize_t n;
+ char buf[256];
+
+ execve(cmd, argv, envp);
+ e = errno;
+ if (e == ENOEXEC) {
+ INTOFF;
+ in = open(cmd, O_RDONLY | O_NONBLOCK);
+ if (in != -1) {
+ n = pread(in, buf, sizeof buf, 0);
+ close(in);
+ if (n > 0 && memchr(buf, '\0', n) != NULL) {
+ errno = ENOEXEC;
+ return;
+ }
+ }
+ *argv = cmd;
+ *--argv = __DECONST(char *, _PATH_BSHELL);
+ execve(_PATH_BSHELL, argv, envp);
+ }
+ errno = e;
+}
+
+/*
+ * Do a path search. The variable path (passed by reference) should be
+ * set to the start of the path before the first call; padvance will update
+ * this value as it proceeds. Successive calls to padvance will return
+ * the possible path expansions in sequence. If an option (indicated by
+ * a percent sign) appears in the path entry then the global variable
+ * pathopt will be set to point to it; otherwise pathopt will be set to
+ * NULL.
+ */
+
+const char *pathopt;
+
+char *
+padvance(const char **path, const char *name)
+{
+ const char *p, *start;
+ char *q;
+ size_t len, namelen;
+
+ if (*path == NULL)
+ return NULL;
+ start = *path;
+ for (p = start; *p && *p != ':' && *p != '%'; p++)
+ ; /* nothing */
+ namelen = strlen(name);
+ len = p - start + namelen + 2; /* "2" is for '/' and '\0' */
+ STARTSTACKSTR(q);
+ CHECKSTRSPACE(len, q);
+ if (p != start) {
+ memcpy(q, start, p - start);
+ q += p - start;
+ *q++ = '/';
+ }
+ memcpy(q, name, namelen + 1);
+ pathopt = NULL;
+ if (*p == '%') {
+ pathopt = ++p;
+ while (*p && *p != ':') p++;
+ }
+ if (*p == ':')
+ *path = p + 1;
+ else
+ *path = NULL;
+ return stalloc(len);
+}
+
+
+
+/*** Command hashing code ***/
+
+
+int
+hashcmd(int argc __unused, char **argv __unused)
+{
+ struct tblentry **pp;
+ struct tblentry *cmdp;
+ int c;
+ int verbose;
+ struct cmdentry entry;
+ char *name;
+ int errors;
+
+ errors = 0;
+ verbose = 0;
+ while ((c = nextopt("rv")) != '\0') {
+ if (c == 'r') {
+ clearcmdentry();
+ } else if (c == 'v') {
+ verbose++;
+ }
+ }
+ if (*argptr == NULL) {
+ for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
+ for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
+ if (cmdp->cmdtype == CMDNORMAL)
+ printentry(cmdp, verbose);
+ }
+ }
+ return 0;
+ }
+ while ((name = *argptr) != NULL) {
+ if ((cmdp = cmdlookup(name, 0)) != NULL
+ && cmdp->cmdtype == CMDNORMAL)
+ delete_cmd_entry();
+ find_command(name, &entry, DO_ERR, pathval());
+ if (entry.cmdtype == CMDUNKNOWN)
+ errors = 1;
+ else if (verbose) {
+ cmdp = cmdlookup(name, 0);
+ if (cmdp != NULL)
+ printentry(cmdp, verbose);
+ else {
+ outfmt(out2, "%s: not found\n", name);
+ errors = 1;
+ }
+ flushall();
+ }
+ argptr++;
+ }
+ return errors;
+}
+
+
+static void
+printentry(struct tblentry *cmdp, int verbose)
+{
+ int idx;
+ const char *path;
+ char *name;
+
+ if (cmdp->cmdtype == CMDNORMAL) {
+ idx = cmdp->param.index;
+ path = pathval();
+ do {
+ name = padvance(&path, cmdp->cmdname);
+ stunalloc(name);
+ } while (--idx >= 0);
+ out1str(name);
+ } else if (cmdp->cmdtype == CMDBUILTIN) {
+ out1fmt("builtin %s", cmdp->cmdname);
+ } else if (cmdp->cmdtype == CMDFUNCTION) {
+ out1fmt("function %s", cmdp->cmdname);
+ if (verbose) {
+ INTOFF;
+ name = commandtext(getfuncnode(cmdp->param.func));
+ out1c(' ');
+ out1str(name);
+ ckfree(name);
+ INTON;
+ }
+#ifdef DEBUG
+ } else {
+ error("internal error: cmdtype %d", cmdp->cmdtype);
+#endif
+ }
+ out1c('\n');
+}
+
+
+
+/*
+ * Resolve a command name. If you change this routine, you may have to
+ * change the shellexec routine as well.
+ */
+
+void
+find_command(const char *name, struct cmdentry *entry, int act,
+ const char *path)
+{
+ struct tblentry *cmdp, loc_cmd;
+ int idx;
+ char *fullname;
+ struct stat statb;
+ int e;
+ int i;
+ int spec;
+ int cd;
+
+ /* If name contains a slash, don't use the hash table */
+ if (strchr(name, '/') != NULL) {
+ entry->cmdtype = CMDNORMAL;
+ entry->u.index = 0;
+ entry->special = 0;
+ return;
+ }
+
+ cd = 0;
+
+ /* If name is in the table, we're done */
+ if ((cmdp = cmdlookup(name, 0)) != NULL) {
+ if (cmdp->cmdtype == CMDFUNCTION && act & DO_NOFUNC)
+ cmdp = NULL;
+ else
+ goto success;
+ }
+
+ /* Check for builtin next */
+ if ((i = find_builtin(name, &spec)) >= 0) {
+ INTOFF;
+ cmdp = cmdlookup(name, 1);
+ if (cmdp->cmdtype == CMDFUNCTION)
+ cmdp = &loc_cmd;
+ cmdp->cmdtype = CMDBUILTIN;
+ cmdp->param.index = i;
+ cmdp->special = spec;
+ INTON;
+ goto success;
+ }
+
+ /* We have to search path. */
+
+ e = ENOENT;
+ idx = -1;
+ for (;(fullname = padvance(&path, name)) != NULL; stunalloc(fullname)) {
+ idx++;
+ if (pathopt) {
+ if (strncmp(pathopt, "func", 4) == 0) {
+ /* handled below */
+ } else {
+ continue; /* ignore unimplemented options */
+ }
+ }
+ if (fullname[0] != '/')
+ cd = 1;
+ if (stat(fullname, &statb) < 0) {
+ if (errno != ENOENT && errno != ENOTDIR)
+ e = errno;
+ continue;
+ }
+ e = EACCES; /* if we fail, this will be the error */
+ if (!S_ISREG(statb.st_mode))
+ continue;
+ if (pathopt) { /* this is a %func directory */
+ readcmdfile(fullname);
+ if ((cmdp = cmdlookup(name, 0)) == NULL || cmdp->cmdtype != CMDFUNCTION)
+ error("%s not defined in %s", name, fullname);
+ stunalloc(fullname);
+ goto success;
+ }
+#ifdef notdef
+ if (statb.st_uid == geteuid()) {
+ if ((statb.st_mode & 0100) == 0)
+ goto loop;
+ } else if (statb.st_gid == getegid()) {
+ if ((statb.st_mode & 010) == 0)
+ goto loop;
+ } else {
+ if ((statb.st_mode & 01) == 0)
+ goto loop;
+ }
+#endif
+ TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
+ INTOFF;
+ stunalloc(fullname);
+ cmdp = cmdlookup(name, 1);
+ if (cmdp->cmdtype == CMDFUNCTION)
+ cmdp = &loc_cmd;
+ cmdp->cmdtype = CMDNORMAL;
+ cmdp->param.index = idx;
+ cmdp->special = 0;
+ INTON;
+ goto success;
+ }
+
+ if (act & DO_ERR) {
+ if (e == ENOENT || e == ENOTDIR)
+ outfmt(out2, "%s: not found\n", name);
+ else
+ outfmt(out2, "%s: %s\n", name, strerror(e));
+ }
+ entry->cmdtype = CMDUNKNOWN;
+ entry->u.index = 0;
+ entry->special = 0;
+ return;
+
+success:
+ if (cd)
+ cmdtable_cd = 1;
+ entry->cmdtype = cmdp->cmdtype;
+ entry->u = cmdp->param;
+ entry->special = cmdp->special;
+}
+
+
+
+/*
+ * Search the table of builtin commands.
+ */
+
+int
+find_builtin(const char *name, int *special)
+{
+ const unsigned char *bp;
+ size_t len;
+
+ len = strlen(name);
+ for (bp = builtincmd ; *bp ; bp += 2 + bp[0]) {
+ if (bp[0] == len && memcmp(bp + 2, name, len) == 0) {
+ *special = (bp[1] & BUILTIN_SPECIAL) != 0;
+ return bp[1] & ~BUILTIN_SPECIAL;
+ }
+ }
+ return -1;
+}
+
+
+
+/*
+ * Called when a cd is done. If any entry in cmdtable depends on the current
+ * directory, simply clear cmdtable completely.
+ */
+
+void
+hashcd(void)
+{
+ if (cmdtable_cd)
+ clearcmdentry();
+}
+
+
+
+/*
+ * Called before PATH is changed. The argument is the new value of PATH;
+ * pathval() still returns the old value at this point. Called with
+ * interrupts off.
+ */
+
+void
+changepath(const char *newval __unused)
+{
+ clearcmdentry();
+}
+
+
+/*
+ * Clear out cached utility locations.
+ */
+
+void
+clearcmdentry(void)
+{
+ struct tblentry **tblp;
+ struct tblentry **pp;
+ struct tblentry *cmdp;
+
+ INTOFF;
+ for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
+ pp = tblp;
+ while ((cmdp = *pp) != NULL) {
+ if (cmdp->cmdtype == CMDNORMAL) {
+ *pp = cmdp->next;
+ ckfree(cmdp);
+ } else {
+ pp = &cmdp->next;
+ }
+ }
+ }
+ cmdtable_cd = 0;
+ INTON;
+}
+
+
+/*
+ * Locate a command in the command hash table. If "add" is nonzero,
+ * add the command to the table if it is not already present. The
+ * variable "lastcmdentry" is set to point to the address of the link
+ * pointing to the entry, so that delete_cmd_entry can delete the
+ * entry.
+ */
+
+static struct tblentry **lastcmdentry;
+
+
+static struct tblentry *
+cmdlookup(const char *name, int add)
+{
+ unsigned int hashval;
+ const char *p;
+ struct tblentry *cmdp;
+ struct tblentry **pp;
+ size_t len;
+
+ p = name;
+ hashval = (unsigned char)*p << 4;
+ while (*p)
+ hashval += *p++;
+ pp = &cmdtable[hashval % CMDTABLESIZE];
+ for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
+ if (equal(cmdp->cmdname, name))
+ break;
+ pp = &cmdp->next;
+ }
+ if (add && cmdp == NULL) {
+ INTOFF;
+ len = strlen(name);
+ cmdp = *pp = ckmalloc(sizeof (struct tblentry) + len + 1);
+ cmdp->next = NULL;
+ cmdp->cmdtype = CMDUNKNOWN;
+ memcpy(cmdp->cmdname, name, len + 1);
+ INTON;
+ }
+ lastcmdentry = pp;
+ return cmdp;
+}
+
+/*
+ * Delete the command entry returned on the last lookup.
+ */
+
+static void
+delete_cmd_entry(void)
+{
+ struct tblentry *cmdp;
+
+ INTOFF;
+ cmdp = *lastcmdentry;
+ *lastcmdentry = cmdp->next;
+ ckfree(cmdp);
+ INTON;
+}
+
+
+
+/*
+ * Add a new command entry, replacing any existing command entry for
+ * the same name.
+ */
+
+static void
+addcmdentry(const char *name, struct cmdentry *entry)
+{
+ struct tblentry *cmdp;
+
+ INTOFF;
+ cmdp = cmdlookup(name, 1);
+ if (cmdp->cmdtype == CMDFUNCTION) {
+ unreffunc(cmdp->param.func);
+ }
+ cmdp->cmdtype = entry->cmdtype;
+ cmdp->param = entry->u;
+ cmdp->special = entry->special;
+ INTON;
+}
+
+
+/*
+ * Define a shell function.
+ */
+
+void
+defun(const char *name, union node *func)
+{
+ struct cmdentry entry;
+
+ INTOFF;
+ entry.cmdtype = CMDFUNCTION;
+ entry.u.func = copyfunc(func);
+ entry.special = 0;
+ addcmdentry(name, &entry);
+ INTON;
+}
+
+
+/*
+ * Delete a function if it exists.
+ * Called with interrupts off.
+ */
+
+int
+unsetfunc(const char *name)
+{
+ struct tblentry *cmdp;
+
+ if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->cmdtype == CMDFUNCTION) {
+ unreffunc(cmdp->param.func);
+ delete_cmd_entry();
+ return (0);
+ }
+ return (0);
+}
+
+
+/*
+ * Check if a function by a certain name exists.
+ */
+int
+isfunc(const char *name)
+{
+ struct tblentry *cmdp;
+ cmdp = cmdlookup(name, 0);
+ return (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION);
+}
+
+
+/*
+ * Shared code for the following builtin commands:
+ * type, command -v, command -V
+ */
+
+int
+typecmd_impl(int argc, char **argv, int cmd, const char *path)
+{
+ struct cmdentry entry;
+ struct tblentry *cmdp;
+ const char *const *pp;
+ struct alias *ap;
+ int i;
+ int error1 = 0;
+
+ if (path != pathval())
+ clearcmdentry();
+
+ for (i = 1; i < argc; i++) {
+ /* First look at the keywords */
+ for (pp = parsekwd; *pp; pp++)
+ if (**pp == *argv[i] && equal(*pp, argv[i]))
+ break;
+
+ if (*pp) {
+ if (cmd == TYPECMD_SMALLV)
+ out1fmt("%s\n", argv[i]);
+ else
+ out1fmt("%s is a shell keyword\n", argv[i]);
+ continue;
+ }
+
+ /* Then look at the aliases */
+ if ((ap = lookupalias(argv[i], 1)) != NULL) {
+ if (cmd == TYPECMD_SMALLV) {
+ out1fmt("alias %s=", argv[i]);
+ out1qstr(ap->val);
+ outcslow('\n', out1);
+ } else
+ out1fmt("%s is an alias for %s\n", argv[i],
+ ap->val);
+ continue;
+ }
+
+ /* Then check if it is a tracked alias */
+ if ((cmdp = cmdlookup(argv[i], 0)) != NULL) {
+ entry.cmdtype = cmdp->cmdtype;
+ entry.u = cmdp->param;
+ entry.special = cmdp->special;
+ }
+ else {
+ /* Finally use brute force */
+ find_command(argv[i], &entry, 0, path);
+ }
+
+ switch (entry.cmdtype) {
+ case CMDNORMAL: {
+ if (strchr(argv[i], '/') == NULL) {
+ const char *path2 = path;
+ char *name;
+ int j = entry.u.index;
+ do {
+ name = padvance(&path2, argv[i]);
+ stunalloc(name);
+ } while (--j >= 0);
+ if (cmd == TYPECMD_SMALLV)
+ out1fmt("%s\n", name);
+ else
+ out1fmt("%s is%s %s\n", argv[i],
+ (cmdp && cmd == TYPECMD_TYPE) ?
+ " a tracked alias for" : "",
+ name);
+ } else {
+ if (eaccess(argv[i], X_OK) == 0) {
+ if (cmd == TYPECMD_SMALLV)
+ out1fmt("%s\n", argv[i]);
+ else
+ out1fmt("%s is %s\n", argv[i],
+ argv[i]);
+ } else {
+ if (cmd != TYPECMD_SMALLV)
+ outfmt(out2, "%s: %s\n",
+ argv[i], strerror(errno));
+ error1 |= 127;
+ }
+ }
+ break;
+ }
+ case CMDFUNCTION:
+ if (cmd == TYPECMD_SMALLV)
+ out1fmt("%s\n", argv[i]);
+ else
+ out1fmt("%s is a shell function\n", argv[i]);
+ break;
+
+ case CMDBUILTIN:
+ if (cmd == TYPECMD_SMALLV)
+ out1fmt("%s\n", argv[i]);
+ else if (entry.special)
+ out1fmt("%s is a special shell builtin\n",
+ argv[i]);
+ else
+ out1fmt("%s is a shell builtin\n", argv[i]);
+ break;
+
+ default:
+ if (cmd != TYPECMD_SMALLV)
+ outfmt(out2, "%s: not found\n", argv[i]);
+ error1 |= 127;
+ break;
+ }
+ }
+
+ if (path != pathval())
+ clearcmdentry();
+
+ return error1;
+}
+
+/*
+ * Locate and print what a word is...
+ */
+
+int
+typecmd(int argc, char **argv)
+{
+ if (argc > 2 && strcmp(argv[1], "--") == 0)
+ argc--, argv++;
+ return typecmd_impl(argc, argv, TYPECMD_TYPE, bltinlookup("PATH", 1));
+}
diff --git a/shell_cmds/sh/exec.h b/shell_cmds/sh/exec.h
new file mode 100644
index 0000000..352077f
--- /dev/null
+++ b/shell_cmds/sh/exec.h
@@ -0,0 +1,77 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)exec.h 8.3 (Berkeley) 6/8/95
+ * $FreeBSD: head/bin/sh/exec.h 314436 2017-02-28 23:42:47Z imp $
+ */
+
+/* values of cmdtype */
+#define CMDUNKNOWN -1 /* no entry in table for command */
+#define CMDNORMAL 0 /* command is an executable program */
+#define CMDBUILTIN 1 /* command is a shell builtin */
+#define CMDFUNCTION 2 /* command is a shell function */
+
+/* values for typecmd_impl's third parameter */
+enum {
+ TYPECMD_SMALLV, /* command -v */
+ TYPECMD_BIGV, /* command -V */
+ TYPECMD_TYPE /* type */
+};
+
+union node;
+struct cmdentry {
+ int cmdtype;
+ union param {
+ int index;
+ struct funcdef *func;
+ } u;
+ int special;
+};
+
+
+/* action to find_command() */
+#define DO_ERR 0x01 /* prints errors */
+#define DO_NOFUNC 0x02 /* don't return shell functions, for command */
+
+extern const char *pathopt; /* set by padvance */
+extern int exerrno; /* last exec error */
+
+void shellexec(char **, char **, const char *, int) __dead2;
+char *padvance(const char **, const char *);
+void find_command(const char *, struct cmdentry *, int, const char *);
+int find_builtin(const char *, int *);
+void hashcd(void);
+void changepath(const char *);
+void defun(const char *, union node *);
+int unsetfunc(const char *);
+int isfunc(const char *);
+int typecmd_impl(int, char **, int, const char *);
+void clearcmdentry(void);
diff --git a/shell_cmds/sh/expand.c b/shell_cmds/sh/expand.c
new file mode 100644
index 0000000..7a31c95
--- /dev/null
+++ b/shell_cmds/sh/expand.c
@@ -0,0 +1,1550 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1997-2005
+ * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+ * Copyright (c) 2010-2015
+ * Jilles Tjoelker <jilles@stack.nl>. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)expand.c 8.5 (Berkeley) 5/15/95";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/bin/sh/expand.c 318269 2017-05-14 13:14:19Z jilles $");
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <wchar.h>
+#include <wctype.h>
+
+/*
+ * Routines to expand arguments to commands. We have to deal with
+ * backquotes, shell variables, and file metacharacters.
+ */
+
+#include "shell.h"
+#include "main.h"
+#include "nodes.h"
+#include "eval.h"
+#include "expand.h"
+#include "syntax.h"
+#include "parser.h"
+#include "jobs.h"
+#include "options.h"
+#include "var.h"
+#include "input.h"
+#include "output.h"
+#include "memalloc.h"
+#include "error.h"
+#include "mystring.h"
+#include "arith.h"
+#include "show.h"
+#include "builtins.h"
+
+enum wordstate { WORD_IDLE, WORD_WS_DELIMITED, WORD_QUOTEMARK };
+
+struct worddest {
+ struct arglist *list;
+ enum wordstate state;
+};
+
+static char *expdest; /* output of current string */
+
+static const char *argstr(const char *, struct nodelist **restrict, int,
+ struct worddest *);
+static const char *exptilde(const char *, int);
+static const char *expari(const char *, struct nodelist **restrict, int,
+ struct worddest *);
+static void expbackq(union node *, int, int, struct worddest *);
+static const char *subevalvar_trim(const char *, struct nodelist **restrict,
+ int, int, int);
+static const char *subevalvar_misc(const char *, struct nodelist **restrict,
+ const char *, int, int, int);
+static const char *evalvar(const char *, struct nodelist **restrict, int,
+ struct worddest *);
+static int varisset(const char *, int);
+static void strtodest(const char *, int, int, int, struct worddest *);
+static void reprocess(int, int, int, int, struct worddest *);
+static void varvalue(const char *, int, int, int, struct worddest *);
+static void expandmeta(char *, struct arglist *);
+static void expmeta(char *, char *, struct arglist *);
+static int expsortcmp(const void *, const void *);
+static int patmatch(const char *, const char *);
+static void cvtnum(int, char *);
+static int collate_range_cmp(wchar_t, wchar_t);
+
+void
+emptyarglist(struct arglist *list)
+{
+
+ list->args = list->smallarg;
+ list->count = 0;
+ list->capacity = sizeof(list->smallarg) / sizeof(list->smallarg[0]);
+}
+
+void
+appendarglist(struct arglist *list, char *str)
+{
+ char **newargs;
+ int newcapacity;
+
+ if (list->count >= list->capacity) {
+ newcapacity = list->capacity * 2;
+ if (newcapacity < 16)
+ newcapacity = 16;
+ if (newcapacity > INT_MAX / (int)sizeof(newargs[0]))
+ error("Too many entries in arglist");
+ newargs = stalloc(newcapacity * sizeof(newargs[0]));
+ memcpy(newargs, list->args, list->count * sizeof(newargs[0]));
+ list->args = newargs;
+ list->capacity = newcapacity;
+ }
+ list->args[list->count++] = str;
+}
+
+static int
+collate_range_cmp(wchar_t c1, wchar_t c2)
+{
+ wchar_t s1[2], s2[2];
+
+ s1[0] = c1;
+ s1[1] = L'\0';
+ s2[0] = c2;
+ s2[1] = L'\0';
+ return (wcscoll(s1, s2));
+}
+
+static char *
+stputs_quotes(const char *data, const char *syntax, char *p)
+{
+ while (*data) {
+ CHECKSTRSPACE(2, p);
+ if (syntax[(int)*data] == CCTL)
+ USTPUTC(CTLESC, p);
+ USTPUTC(*data++, p);
+ }
+ return (p);
+}
+#define STPUTS_QUOTES(data, syntax, p) p = stputs_quotes((data), syntax, p)
+
+static char *
+nextword(char c, int flag, char *p, struct worddest *dst)
+{
+ int is_ws;
+
+ is_ws = c == '\t' || c == '\n' || c == ' ';
+ if (p != stackblock() || (is_ws ? dst->state == WORD_QUOTEMARK :
+ dst->state != WORD_WS_DELIMITED) || c == '\0') {
+ STPUTC('\0', p);
+ if (flag & EXP_GLOB)
+ expandmeta(grabstackstr(p), dst->list);
+ else
+ appendarglist(dst->list, grabstackstr(p));
+ dst->state = is_ws ? WORD_WS_DELIMITED : WORD_IDLE;
+ } else if (!is_ws && dst->state == WORD_WS_DELIMITED)
+ dst->state = WORD_IDLE;
+ /* Reserve space while the stack string is empty. */
+ appendarglist(dst->list, NULL);
+ dst->list->count--;
+ STARTSTACKSTR(p);
+ return p;
+}
+#define NEXTWORD(c, flag, p, dstlist) p = nextword(c, flag, p, dstlist)
+
+static char *
+stputs_split(const char *data, const char *syntax, int flag, char *p,
+ struct worddest *dst)
+{
+ const char *ifs;
+ char c;
+
+ ifs = ifsset() ? ifsval() : " \t\n";
+ while (*data) {
+ CHECKSTRSPACE(2, p);
+ c = *data++;
+ if (strchr(ifs, c) != NULL) {
+ NEXTWORD(c, flag, p, dst);
+ continue;
+ }
+ if (flag & EXP_GLOB && syntax[(int)c] == CCTL)
+ USTPUTC(CTLESC, p);
+ USTPUTC(c, p);
+ }
+ return (p);
+}
+#define STPUTS_SPLIT(data, syntax, flag, p, dst) p = stputs_split((data), syntax, flag, p, dst)
+
+/*
+ * Perform expansions on an argument, placing the resulting list of arguments
+ * in arglist. Parameter expansion, command substitution and arithmetic
+ * expansion are always performed; additional expansions can be requested
+ * via flag (EXP_*).
+ * The result is left in the stack string.
+ * When arglist is NULL, perform here document expansion.
+ *
+ * When doing something that may cause this to be re-entered, make sure
+ * the stack string is empty via grabstackstr() and do not assume expdest
+ * remains valid.
+ */
+void
+expandarg(union node *arg, struct arglist *arglist, int flag)
+{
+ struct worddest exparg;
+ struct nodelist *argbackq;
+
+ if (fflag)
+ flag &= ~EXP_GLOB;
+ argbackq = arg->narg.backquote;
+ exparg.list = arglist;
+ exparg.state = WORD_IDLE;
+ STARTSTACKSTR(expdest);
+ argstr(arg->narg.text, &argbackq, flag, &exparg);
+ if (arglist == NULL) {
+ STACKSTRNUL(expdest);
+ return; /* here document expanded */
+ }
+ if ((flag & EXP_SPLIT) == 0 || expdest != stackblock() ||
+ exparg.state == WORD_QUOTEMARK) {
+ STPUTC('\0', expdest);
+ if (flag & EXP_SPLIT) {
+ if (flag & EXP_GLOB)
+ expandmeta(grabstackstr(expdest), exparg.list);
+ else
+ appendarglist(exparg.list, grabstackstr(expdest));
+ }
+ }
+ if ((flag & EXP_SPLIT) == 0)
+ appendarglist(arglist, grabstackstr(expdest));
+}
+
+
+
+/*
+ * Perform parameter expansion, command substitution and arithmetic
+ * expansion, and tilde expansion if requested via EXP_TILDE/EXP_VARTILDE.
+ * Processing ends at a CTLENDVAR or CTLENDARI character as well as '\0'.
+ * This is used to expand word in ${var+word} etc.
+ * If EXP_GLOB or EXP_CASE are set, keep and/or generate CTLESC
+ * characters to allow for further processing.
+ *
+ * If EXP_SPLIT is set, dst receives any complete words produced.
+ */
+static const char *
+argstr(const char *p, struct nodelist **restrict argbackq, int flag,
+ struct worddest *dst)
+{
+ char c;
+ int quotes = flag & (EXP_GLOB | EXP_CASE); /* do CTLESC */
+ int firsteq = 1;
+ int split_lit;
+ int lit_quoted;
+
+ split_lit = flag & EXP_SPLIT_LIT;
+ lit_quoted = flag & EXP_LIT_QUOTED;
+ flag &= ~(EXP_SPLIT_LIT | EXP_LIT_QUOTED);
+ if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE)))
+ p = exptilde(p, flag);
+ for (;;) {
+ CHECKSTRSPACE(2, expdest);
+ switch (c = *p++) {
+ case '\0':
+ return (p - 1);
+ case CTLENDVAR:
+ case CTLENDARI:
+ return (p);
+ case CTLQUOTEMARK:
+ lit_quoted = 1;
+ /* "$@" syntax adherence hack */
+ if (p[0] == CTLVAR && (p[1] & VSQUOTE) != 0 &&
+ p[2] == '@' && p[3] == '=')
+ break;
+ if ((flag & EXP_SPLIT) != 0 && expdest == stackblock())
+ dst->state = WORD_QUOTEMARK;
+ break;
+ case CTLQUOTEEND:
+ lit_quoted = 0;
+ break;
+ case CTLESC:
+ c = *p++;
+ if (split_lit && !lit_quoted &&
+ strchr(ifsset() ? ifsval() : " \t\n", c) != NULL) {
+ NEXTWORD(c, flag, expdest, dst);
+ break;
+ }
+ if (quotes)
+ USTPUTC(CTLESC, expdest);
+ USTPUTC(c, expdest);
+ break;
+ case CTLVAR:
+ p = evalvar(p, argbackq, flag, dst);
+ break;
+ case CTLBACKQ:
+ case CTLBACKQ|CTLQUOTE:
+ expbackq((*argbackq)->n, c & CTLQUOTE, flag, dst);
+ *argbackq = (*argbackq)->next;
+ break;
+ case CTLARI:
+ p = expari(p, argbackq, flag, dst);
+ break;
+ case ':':
+ case '=':
+ /*
+ * sort of a hack - expand tildes in variable
+ * assignments (after the first '=' and after ':'s).
+ */
+ if (split_lit && !lit_quoted &&
+ strchr(ifsset() ? ifsval() : " \t\n", c) != NULL) {
+ NEXTWORD(c, flag, expdest, dst);
+ break;
+ }
+ USTPUTC(c, expdest);
+ if (flag & EXP_VARTILDE && *p == '~' &&
+ (c != '=' || firsteq)) {
+ if (c == '=')
+ firsteq = 0;
+ p = exptilde(p, flag);
+ }
+ break;
+ default:
+ if (split_lit && !lit_quoted &&
+ strchr(ifsset() ? ifsval() : " \t\n", c) != NULL) {
+ NEXTWORD(c, flag, expdest, dst);
+ break;
+ }
+ USTPUTC(c, expdest);
+ }
+ }
+}
+
+/*
+ * Perform tilde expansion, placing the result in the stack string and
+ * returning the next position in the input string to process.
+ */
+static const char *
+exptilde(const char *p, int flag)
+{
+ char c;
+ const char *startp = p;
+ const char *user;
+ struct passwd *pw;
+ char *home;
+ int len;
+
+ for (;;) {
+ c = *p;
+ switch(c) {
+ case CTLESC: /* This means CTL* are always considered quoted. */
+ case CTLVAR:
+ case CTLBACKQ:
+ case CTLBACKQ | CTLQUOTE:
+ case CTLARI:
+ case CTLENDARI:
+ case CTLQUOTEMARK:
+ return (startp);
+ case ':':
+ if ((flag & EXP_VARTILDE) == 0)
+ break;
+ /* FALLTHROUGH */
+ case '\0':
+ case '/':
+ case CTLENDVAR:
+ len = p - startp - 1;
+ STPUTBIN(startp + 1, len, expdest);
+ STACKSTRNUL(expdest);
+ user = expdest - len;
+ if (*user == '\0') {
+ home = lookupvar("HOME");
+ } else {
+ pw = getpwnam(user);
+ home = pw != NULL ? pw->pw_dir : NULL;
+ }
+ STADJUST(-len, expdest);
+ if (home == NULL || *home == '\0')
+ return (startp);
+ strtodest(home, flag, VSNORMAL, 1, NULL);
+ return (p);
+ }
+ p++;
+ }
+}
+
+
+/*
+ * Expand arithmetic expression.
+ */
+static const char *
+expari(const char *p, struct nodelist **restrict argbackq, int flag,
+ struct worddest *dst)
+{
+ char *q, *start;
+ arith_t result;
+ int begoff;
+ int quoted;
+ int adj;
+
+ quoted = *p++ == '"';
+ begoff = expdest - stackblock();
+ p = argstr(p, argbackq, 0, NULL);
+ STPUTC('\0', expdest);
+ start = stackblock() + begoff;
+
+ q = grabstackstr(expdest);
+ result = arith(start);
+ ungrabstackstr(q, expdest);
+
+ start = stackblock() + begoff;
+ adj = start - expdest;
+ STADJUST(adj, expdest);
+
+ CHECKSTRSPACE((int)(DIGITS(result) + 1), expdest);
+ fmtstr(expdest, DIGITS(result), ARITH_FORMAT_STR, result);
+ adj = strlen(expdest);
+ STADJUST(adj, expdest);
+ /*
+ * If this is quoted, a '-' must not indicate a range in [...].
+ * If this is not quoted, splitting may occur.
+ */
+ if (quoted ?
+ result < 0 && begoff > 1 && flag & (EXP_GLOB | EXP_CASE) :
+ flag & EXP_SPLIT)
+ reprocess(expdest - adj - stackblock(), flag, VSNORMAL, quoted,
+ dst);
+ return p;
+}
+
+
+/*
+ * Perform command substitution.
+ */
+static void
+expbackq(union node *cmd, int quoted, int flag, struct worddest *dst)
+{
+ struct backcmd in;
+ int i;
+ char buf[128];
+ char *p;
+ char *dest = expdest;
+ char lastc;
+ char const *syntax = quoted? DQSYNTAX : BASESYNTAX;
+ int quotes = flag & (EXP_GLOB | EXP_CASE);
+ size_t nnl;
+ const char *ifs;
+ int startloc;
+
+ INTOFF;
+ p = grabstackstr(dest);
+ evalbackcmd(cmd, &in);
+ ungrabstackstr(p, dest);
+
+ p = in.buf;
+ startloc = dest - stackblock();
+ nnl = 0;
+ if (!quoted && flag & EXP_SPLIT)
+ ifs = ifsset() ? ifsval() : " \t\n";
+ else
+ ifs = "";
+ /* Remove trailing newlines */
+ for (;;) {
+ if (--in.nleft < 0) {
+ if (in.fd < 0)
+ break;
+ while ((i = read(in.fd, buf, sizeof buf)) < 0 && errno == EINTR)
+ ;
+ TRACE(("expbackq: read returns %d\n", i));
+ if (i <= 0)
+ break;
+ p = buf;
+ in.nleft = i - 1;
+ }
+ lastc = *p++;
+ if (lastc == '\0')
+ continue;
+ if (nnl > 0 && lastc != '\n') {
+ NEXTWORD('\n', flag, dest, dst);
+ nnl = 0;
+ }
+ if (strchr(ifs, lastc) != NULL) {
+ if (lastc == '\n')
+ nnl++;
+ else
+ NEXTWORD(lastc, flag, dest, dst);
+ } else {
+ CHECKSTRSPACE(2, dest);
+ if (quotes && syntax[(int)lastc] == CCTL)
+ USTPUTC(CTLESC, dest);
+ USTPUTC(lastc, dest);
+ }
+ }
+ while (dest > stackblock() + startloc && STTOPC(dest) == '\n')
+ STUNPUTC(dest);
+
+ if (in.fd >= 0)
+ close(in.fd);
+ if (in.buf)
+ ckfree(in.buf);
+ if (in.jp) {
+ p = grabstackstr(dest);
+ exitstatus = waitforjob(in.jp, (int *)NULL);
+ ungrabstackstr(p, dest);
+ }
+ TRACE(("expbackq: done\n"));
+ expdest = dest;
+ INTON;
+}
+
+
+
+static void
+recordleft(const char *str, const char *loc, char *startp)
+{
+ int amount;
+
+ amount = ((str - 1) - (loc - startp)) - expdest;
+ STADJUST(amount, expdest);
+ while (loc != str - 1)
+ *startp++ = *loc++;
+}
+
+static const char *
+subevalvar_trim(const char *p, struct nodelist **restrict argbackq, int strloc,
+ int subtype, int startloc)
+{
+ char *startp;
+ char *loc = NULL;
+ char *str;
+ int c = 0;
+ int amount;
+
+ p = argstr(p, argbackq, EXP_CASE | EXP_TILDE, NULL);
+ STACKSTRNUL(expdest);
+ startp = stackblock() + startloc;
+ str = stackblock() + strloc;
+
+ switch (subtype) {
+ case VSTRIMLEFT:
+ for (loc = startp; loc < str; loc++) {
+ c = *loc;
+ *loc = '\0';
+ if (patmatch(str, startp)) {
+ *loc = c;
+ recordleft(str, loc, startp);
+ return p;
+ }
+ *loc = c;
+ }
+ break;
+
+ case VSTRIMLEFTMAX:
+ for (loc = str - 1; loc >= startp;) {
+ c = *loc;
+ *loc = '\0';
+ if (patmatch(str, startp)) {
+ *loc = c;
+ recordleft(str, loc, startp);
+ return p;
+ }
+ *loc = c;
+ loc--;
+ }
+ break;
+
+ case VSTRIMRIGHT:
+ for (loc = str - 1; loc >= startp;) {
+ if (patmatch(str, loc)) {
+ amount = loc - expdest;
+ STADJUST(amount, expdest);
+ return p;
+ }
+ loc--;
+ }
+ break;
+
+ case VSTRIMRIGHTMAX:
+ for (loc = startp; loc < str - 1; loc++) {
+ if (patmatch(str, loc)) {
+ amount = loc - expdest;
+ STADJUST(amount, expdest);
+ return p;
+ }
+ }
+ break;
+
+
+ default:
+ abort();
+ }
+ amount = (expdest - stackblock() - strloc) + 1;
+ STADJUST(-amount, expdest);
+ return p;
+}
+
+
+static const char *
+subevalvar_misc(const char *p, struct nodelist **restrict argbackq,
+ const char *var, int subtype, int startloc, int varflags)
+{
+ char *startp;
+ int amount;
+
+ p = argstr(p, argbackq, EXP_TILDE, NULL);
+ STACKSTRNUL(expdest);
+ startp = stackblock() + startloc;
+
+ switch (subtype) {
+ case VSASSIGN:
+ setvar(var, startp, 0);
+ amount = startp - expdest;
+ STADJUST(amount, expdest);
+ return p;
+
+ case VSQUESTION:
+ if (*p != CTLENDVAR) {
+ outfmt(out2, "%s\n", startp);
+ error((char *)NULL);
+ }
+ error("%.*s: parameter %snot set", (int)(p - var - 1),
+ var, (varflags & VSNUL) ? "null or " : "");
+
+ default:
+ abort();
+ }
+}
+
+
+/*
+ * Expand a variable, and return a pointer to the next character in the
+ * input string.
+ */
+
+static const char *
+evalvar(const char *p, struct nodelist **restrict argbackq, int flag,
+ struct worddest *dst)
+{
+ int subtype;
+ int varflags;
+ const char *var;
+ const char *val;
+ int patloc;
+ int c;
+ int set;
+ int special;
+ int startloc;
+ int varlen;
+ int varlenb;
+ char buf[21];
+
+ varflags = (unsigned char)*p++;
+ subtype = varflags & VSTYPE;
+ var = p;
+ special = 0;
+ if (! is_name(*p))
+ special = 1;
+ p = strchr(p, '=') + 1;
+ if (varflags & VSLINENO) {
+ set = 1;
+ special = 1;
+ val = NULL;
+ } else if (special) {
+ set = varisset(var, varflags & VSNUL);
+ val = NULL;
+ } else {
+ val = bltinlookup(var, 1);
+ if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) {
+ val = NULL;
+ set = 0;
+ } else
+ set = 1;
+ }
+ varlen = 0;
+ startloc = expdest - stackblock();
+ if (!set && uflag && *var != '@' && *var != '*') {
+ switch (subtype) {
+ case VSNORMAL:
+ case VSTRIMLEFT:
+ case VSTRIMLEFTMAX:
+ case VSTRIMRIGHT:
+ case VSTRIMRIGHTMAX:
+ case VSLENGTH:
+ error("%.*s: parameter not set", (int)(p - var - 1),
+ var);
+ }
+ }
+ if (set && subtype != VSPLUS) {
+ /* insert the value of the variable */
+ if (special) {
+ if (varflags & VSLINENO) {
+ if (p - var > (ptrdiff_t)sizeof(buf))
+ abort();
+ memcpy(buf, var, p - var - 1);
+ buf[p - var - 1] = '\0';
+ strtodest(buf, flag, subtype,
+ varflags & VSQUOTE, dst);
+ } else
+ varvalue(var, varflags & VSQUOTE, subtype, flag,
+ dst);
+ if (subtype == VSLENGTH) {
+ varlenb = expdest - stackblock() - startloc;
+ varlen = varlenb;
+ if (localeisutf8) {
+ val = stackblock() + startloc;
+ for (;val != expdest; val++)
+ if ((*val & 0xC0) == 0x80)
+ varlen--;
+ }
+ STADJUST(-varlenb, expdest);
+ }
+ } else {
+ if (subtype == VSLENGTH) {
+ for (;*val; val++)
+ if (!localeisutf8 ||
+ (*val & 0xC0) != 0x80)
+ varlen++;
+ }
+ else
+ strtodest(val, flag, subtype,
+ varflags & VSQUOTE, dst);
+ }
+ }
+
+ if (subtype == VSPLUS)
+ set = ! set;
+
+ switch (subtype) {
+ case VSLENGTH:
+ cvtnum(varlen, buf);
+ strtodest(buf, flag, VSNORMAL, varflags & VSQUOTE, dst);
+ break;
+
+ case VSNORMAL:
+ return p;
+
+ case VSPLUS:
+ case VSMINUS:
+ if (!set) {
+ return argstr(p, argbackq,
+ flag | (flag & EXP_SPLIT ? EXP_SPLIT_LIT : 0) |
+ (varflags & VSQUOTE ? EXP_LIT_QUOTED : 0), dst);
+ }
+ break;
+
+ case VSTRIMLEFT:
+ case VSTRIMLEFTMAX:
+ case VSTRIMRIGHT:
+ case VSTRIMRIGHTMAX:
+ if (!set)
+ break;
+ /*
+ * Terminate the string and start recording the pattern
+ * right after it
+ */
+ STPUTC('\0', expdest);
+ patloc = expdest - stackblock();
+ p = subevalvar_trim(p, argbackq, patloc, subtype, startloc);
+ reprocess(startloc, flag, VSNORMAL, varflags & VSQUOTE, dst);
+ if (flag & EXP_SPLIT && *var == '@' && varflags & VSQUOTE)
+ dst->state = WORD_QUOTEMARK;
+ return p;
+
+ case VSASSIGN:
+ case VSQUESTION:
+ if (!set) {
+ p = subevalvar_misc(p, argbackq, var, subtype,
+ startloc, varflags);
+ /* assert(subtype == VSASSIGN); */
+ val = lookupvar(var);
+ strtodest(val, flag, subtype, varflags & VSQUOTE, dst);
+ return p;
+ }
+ break;
+
+ case VSERROR:
+ c = p - var - 1;
+ error("${%.*s%s}: Bad substitution", c, var,
+ (c > 0 && *p != CTLENDVAR) ? "..." : "");
+
+ default:
+ abort();
+ }
+
+ { /* skip to end of alternative */
+ int nesting = 1;
+ for (;;) {
+ if ((c = *p++) == CTLESC)
+ p++;
+ else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE))
+ *argbackq = (*argbackq)->next;
+ else if (c == CTLVAR) {
+ if ((*p++ & VSTYPE) != VSNORMAL)
+ nesting++;
+ } else if (c == CTLENDVAR) {
+ if (--nesting == 0)
+ break;
+ }
+ }
+ }
+ return p;
+}
+
+
+
+/*
+ * Test whether a special or positional parameter is set.
+ */
+
+static int
+varisset(const char *name, int nulok)
+{
+
+ if (*name == '!')
+ return backgndpidset();
+ else if (*name == '@' || *name == '*') {
+ if (*shellparam.p == NULL)
+ return 0;
+
+ if (nulok) {
+ char **av;
+
+ for (av = shellparam.p; *av; av++)
+ if (**av != '\0')
+ return 1;
+ return 0;
+ }
+ } else if (is_digit(*name)) {
+ char *ap;
+ long num;
+
+ errno = 0;
+ num = strtol(name, NULL, 10);
+ if (errno != 0 || num > shellparam.nparam)
+ return 0;
+
+ if (num == 0)
+ ap = arg0;
+ else
+ ap = shellparam.p[num - 1];
+
+ if (nulok && (ap == NULL || *ap == '\0'))
+ return 0;
+ }
+ return 1;
+}
+
+static void
+strtodest(const char *p, int flag, int subtype, int quoted,
+ struct worddest *dst)
+{
+ if (subtype == VSLENGTH || subtype == VSTRIMLEFT ||
+ subtype == VSTRIMLEFTMAX || subtype == VSTRIMRIGHT ||
+ subtype == VSTRIMRIGHTMAX)
+ STPUTS(p, expdest);
+ else if (flag & EXP_SPLIT && !quoted && dst != NULL)
+ STPUTS_SPLIT(p, BASESYNTAX, flag, expdest, dst);
+ else if (flag & (EXP_GLOB | EXP_CASE))
+ STPUTS_QUOTES(p, quoted ? DQSYNTAX : BASESYNTAX, expdest);
+ else
+ STPUTS(p, expdest);
+}
+
+static void
+reprocess(int startloc, int flag, int subtype, int quoted,
+ struct worddest *dst)
+{
+ static char *buf = NULL;
+ static size_t buflen = 0;
+ char *startp;
+ size_t len, zpos, zlen;
+
+ startp = stackblock() + startloc;
+ len = expdest - startp;
+ if (len >= SIZE_MAX / 2)
+ abort();
+ INTOFF;
+ if (len >= buflen) {
+ ckfree(buf);
+ buf = NULL;
+ }
+ if (buflen < 128)
+ buflen = 128;
+ while (len >= buflen)
+ buflen <<= 1;
+ if (buf == NULL)
+ buf = ckmalloc(buflen);
+ INTON;
+ memcpy(buf, startp, len);
+ buf[len] = '\0';
+ STADJUST(-len, expdest);
+ for (zpos = 0;;) {
+ zlen = strlen(buf + zpos);
+ strtodest(buf + zpos, flag, subtype, quoted, dst);
+ zpos += zlen + 1;
+ if (zpos == len + 1)
+ break;
+ if (flag & EXP_SPLIT && (quoted || (zlen > 0 && zpos < len)))
+ NEXTWORD('\0', flag, expdest, dst);
+ }
+}
+
+/*
+ * Add the value of a special or positional parameter to the stack string.
+ */
+
+static void
+varvalue(const char *name, int quoted, int subtype, int flag,
+ struct worddest *dst)
+{
+ int num;
+ char *p;
+ int i;
+ int splitlater;
+ char sep[2];
+ char **ap;
+ char buf[(NSHORTOPTS > 10 ? NSHORTOPTS : 10) + 1];
+
+ if (subtype == VSLENGTH)
+ flag &= ~EXP_FULL;
+ splitlater = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX ||
+ subtype == VSTRIMRIGHT || subtype == VSTRIMRIGHTMAX;
+
+ switch (*name) {
+ case '$':
+ num = rootpid;
+ break;
+ case '?':
+ num = oexitstatus;
+ break;
+ case '#':
+ num = shellparam.nparam;
+ break;
+ case '!':
+ num = backgndpidval();
+ break;
+ case '-':
+ p = buf;
+ for (i = 0 ; i < NSHORTOPTS ; i++) {
+ if (optval[i])
+ *p++ = optletter[i];
+ }
+ *p = '\0';
+ strtodest(buf, flag, subtype, quoted, dst);
+ return;
+ case '@':
+ if (flag & EXP_SPLIT && quoted) {
+ for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
+ strtodest(p, flag, subtype, quoted, dst);
+ if (*ap) {
+ if (splitlater)
+ STPUTC('\0', expdest);
+ else
+ NEXTWORD('\0', flag, expdest,
+ dst);
+ }
+ }
+ if (shellparam.nparam > 0)
+ dst->state = WORD_QUOTEMARK;
+ return;
+ }
+ /* FALLTHROUGH */
+ case '*':
+ if (ifsset())
+ sep[0] = ifsval()[0];
+ else
+ sep[0] = ' ';
+ sep[1] = '\0';
+ for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
+ strtodest(p, flag, subtype, quoted, dst);
+ if (!*ap)
+ break;
+ if (sep[0])
+ strtodest(sep, flag, subtype, quoted, dst);
+ else if (flag & EXP_SPLIT && !quoted && **ap != '\0') {
+ if (splitlater)
+ STPUTC('\0', expdest);
+ else
+ NEXTWORD('\0', flag, expdest, dst);
+ }
+ }
+ return;
+ default:
+ if (is_digit(*name)) {
+ num = atoi(name);
+ if (num == 0)
+ p = arg0;
+ else if (num > 0 && num <= shellparam.nparam)
+ p = shellparam.p[num - 1];
+ else
+ return;
+ strtodest(p, flag, subtype, quoted, dst);
+ }
+ return;
+ }
+ cvtnum(num, buf);
+ strtodest(buf, flag, subtype, quoted, dst);
+}
+
+
+
+static char expdir[PATH_MAX];
+#define expdir_end (expdir + sizeof(expdir))
+
+/*
+ * Perform pathname generation and remove control characters.
+ * At this point, the only control characters should be CTLESC.
+ * The results are stored in the list dstlist.
+ */
+static void
+expandmeta(char *pattern, struct arglist *dstlist)
+{
+ char *p;
+ int firstmatch;
+ char c;
+
+ firstmatch = dstlist->count;
+ p = pattern;
+ for (; (c = *p) != '\0'; p++) {
+ /* fast check for meta chars */
+ if (c == '*' || c == '?' || c == '[') {
+ INTOFF;
+ expmeta(expdir, pattern, dstlist);
+ INTON;
+ break;
+ }
+ }
+ if (dstlist->count == firstmatch) {
+ /*
+ * no matches
+ */
+ rmescapes(pattern);
+ appendarglist(dstlist, pattern);
+ } else {
+ qsort(&dstlist->args[firstmatch],
+ dstlist->count - firstmatch,
+ sizeof(dstlist->args[0]), expsortcmp);
+ }
+}
+
+
+/*
+ * Do metacharacter (i.e. *, ?, [...]) expansion.
+ */
+
+static void
+expmeta(char *enddir, char *name, struct arglist *arglist)
+{
+ const char *p;
+ const char *q;
+ const char *start;
+ char *endname;
+ int metaflag;
+ struct stat statb;
+ DIR *dirp;
+ struct dirent *dp;
+ int atend;
+ int matchdot;
+ int esc;
+ int namlen;
+
+ metaflag = 0;
+ start = name;
+ for (p = name; esc = 0, *p; p += esc + 1) {
+ if (*p == '*' || *p == '?')
+ metaflag = 1;
+ else if (*p == '[') {
+ q = p + 1;
+ if (*q == '!' || *q == '^')
+ q++;
+ for (;;) {
+ if (*q == CTLESC)
+ q++;
+ if (*q == '/' || *q == '\0')
+ break;
+ if (*++q == ']') {
+ metaflag = 1;
+ break;
+ }
+ }
+ } else if (*p == '\0')
+ break;
+ else {
+ if (*p == CTLESC)
+ esc++;
+ if (p[esc] == '/') {
+ if (metaflag)
+ break;
+ start = p + esc + 1;
+ }
+ }
+ }
+ if (metaflag == 0) { /* we've reached the end of the file name */
+ if (enddir != expdir)
+ metaflag++;
+ for (p = name ; ; p++) {
+ if (*p == CTLESC)
+ p++;
+ *enddir++ = *p;
+ if (*p == '\0')
+ break;
+ if (enddir == expdir_end)
+ return;
+ }
+ if (metaflag == 0 || lstat(expdir, &statb) >= 0)
+ appendarglist(arglist, stsavestr(expdir));
+ return;
+ }
+ endname = name + (p - name);
+ if (start != name) {
+ p = name;
+ while (p < start) {
+ if (*p == CTLESC)
+ p++;
+ *enddir++ = *p++;
+ if (enddir == expdir_end)
+ return;
+ }
+ }
+ if (enddir == expdir) {
+ p = ".";
+ } else if (enddir == expdir + 1 && *expdir == '/') {
+ p = "/";
+ } else {
+ p = expdir;
+ enddir[-1] = '\0';
+ }
+ if ((dirp = opendir(p)) == NULL)
+ return;
+ if (enddir != expdir)
+ enddir[-1] = '/';
+ if (*endname == 0) {
+ atend = 1;
+ } else {
+ atend = 0;
+ *endname = '\0';
+ endname += esc + 1;
+ }
+ matchdot = 0;
+ p = start;
+ if (*p == CTLESC)
+ p++;
+ if (*p == '.')
+ matchdot++;
+ while (! int_pending() && (dp = readdir(dirp)) != NULL) {
+ if (dp->d_name[0] == '.' && ! matchdot)
+ continue;
+ if (patmatch(start, dp->d_name)) {
+ namlen = dp->d_namlen;
+ if (enddir + namlen + 1 > expdir_end)
+ continue;
+ memcpy(enddir, dp->d_name, namlen + 1);
+ if (atend)
+ appendarglist(arglist, stsavestr(expdir));
+ else {
+ if (dp->d_type != DT_UNKNOWN &&
+ dp->d_type != DT_DIR &&
+ dp->d_type != DT_LNK)
+ continue;
+ if (enddir + namlen + 2 > expdir_end)
+ continue;
+ enddir[namlen] = '/';
+ enddir[namlen + 1] = '\0';
+ expmeta(enddir + namlen + 1, endname, arglist);
+ }
+ }
+ }
+ closedir(dirp);
+ if (! atend)
+ endname[-esc - 1] = esc ? CTLESC : '/';
+}
+
+
+static int
+expsortcmp(const void *p1, const void *p2)
+{
+ const char *s1 = *(const char * const *)p1;
+ const char *s2 = *(const char * const *)p2;
+
+ return (strcoll(s1, s2));
+}
+
+
+
+static wchar_t
+get_wc(const char **p)
+{
+ wchar_t c;
+ int chrlen;
+
+ chrlen = mbtowc(&c, *p, 4);
+ if (chrlen == 0)
+ return 0;
+ else if (chrlen == -1)
+ c = 0;
+ else
+ *p += chrlen;
+ return c;
+}
+
+
+/*
+ * See if a character matches a character class, starting at the first colon
+ * of "[:class:]".
+ * If a valid character class is recognized, a pointer to the next character
+ * after the final closing bracket is stored into *end, otherwise a null
+ * pointer is stored into *end.
+ */
+static int
+match_charclass(const char *p, wchar_t chr, const char **end)
+{
+ char name[20];
+ const char *nameend;
+ wctype_t cclass;
+
+ *end = NULL;
+ p++;
+ nameend = strstr(p, ":]");
+ if (nameend == NULL || (size_t)(nameend - p) >= sizeof(name) ||
+ nameend == p)
+ return 0;
+ memcpy(name, p, nameend - p);
+ name[nameend - p] = '\0';
+ *end = nameend + 2;
+ cclass = wctype(name);
+ /* An unknown class matches nothing but is valid nevertheless. */
+ if (cclass == 0)
+ return 0;
+ return iswctype(chr, cclass);
+}
+
+
+/*
+ * Returns true if the pattern matches the string.
+ */
+
+static int
+patmatch(const char *pattern, const char *string)
+{
+ const char *p, *q, *end;
+ const char *bt_p, *bt_q;
+ char c;
+ wchar_t wc, wc2;
+
+ p = pattern;
+ q = string;
+ bt_p = NULL;
+ bt_q = NULL;
+ for (;;) {
+ switch (c = *p++) {
+ case '\0':
+ if (*q != '\0')
+ goto backtrack;
+ return 1;
+ case CTLESC:
+ if (*q++ != *p++)
+ goto backtrack;
+ break;
+ case '?':
+ if (*q == '\0')
+ return 0;
+ if (localeisutf8) {
+ wc = get_wc(&q);
+ /*
+ * A '?' does not match invalid UTF-8 but a
+ * '*' does, so backtrack.
+ */
+ if (wc == 0)
+ goto backtrack;
+ } else
+ q++;
+ break;
+ case '*':
+ c = *p;
+ while (c == '*')
+ c = *++p;
+ /*
+ * If the pattern ends here, we know the string
+ * matches without needing to look at the rest of it.
+ */
+ if (c == '\0')
+ return 1;
+ /*
+ * First try the shortest match for the '*' that
+ * could work. We can forget any earlier '*' since
+ * there is no way having it match more characters
+ * can help us, given that we are already here.
+ */
+ bt_p = p;
+ bt_q = q;
+ break;
+ case '[': {
+ const char *savep, *saveq;
+ int invert, found;
+ wchar_t chr;
+
+ savep = p, saveq = q;
+ invert = 0;
+ if (*p == '!' || *p == '^') {
+ invert++;
+ p++;
+ }
+ found = 0;
+ if (*q == '\0')
+ return 0;
+ if (localeisutf8) {
+ chr = get_wc(&q);
+ if (chr == 0)
+ goto backtrack;
+ } else
+ chr = (unsigned char)*q++;
+ c = *p++;
+ do {
+ if (c == '\0') {
+ p = savep, q = saveq;
+ c = '[';
+ goto dft;
+ }
+ if (c == '[' && *p == ':') {
+ found |= match_charclass(p, chr, &end);
+ if (end != NULL)
+ p = end;
+ }
+ if (c == CTLESC)
+ c = *p++;
+ if (localeisutf8 && c & 0x80) {
+ p--;
+ wc = get_wc(&p);
+ if (wc == 0) /* bad utf-8 */
+ return 0;
+ } else
+ wc = (unsigned char)c;
+ if (*p == '-' && p[1] != ']') {
+ p++;
+ if (*p == CTLESC)
+ p++;
+ if (localeisutf8) {
+ wc2 = get_wc(&p);
+ if (wc2 == 0) /* bad utf-8 */
+ return 0;
+ } else
+ wc2 = (unsigned char)*p++;
+ if ( collate_range_cmp(chr, wc) >= 0
+ && collate_range_cmp(chr, wc2) <= 0
+ )
+ found = 1;
+ } else {
+ if (chr == wc)
+ found = 1;
+ }
+ } while ((c = *p++) != ']');
+ if (found == invert)
+ goto backtrack;
+ break;
+ }
+dft: default:
+ if (*q == '\0')
+ return 0;
+ if (*q++ == c)
+ break;
+backtrack:
+ /*
+ * If we have a mismatch (other than hitting the end
+ * of the string), go back to the last '*' seen and
+ * have it match one additional character.
+ */
+ if (bt_p == NULL)
+ return 0;
+ if (*bt_q == '\0')
+ return 0;
+ bt_q++;
+ p = bt_p;
+ q = bt_q;
+ break;
+ }
+ }
+}
+
+
+
+/*
+ * Remove any CTLESC and CTLQUOTEMARK characters from a string.
+ */
+
+void
+rmescapes(char *str)
+{
+ char *p, *q;
+
+ p = str;
+ while (*p != CTLESC && *p != CTLQUOTEMARK && *p != CTLQUOTEEND) {
+ if (*p++ == '\0')
+ return;
+ }
+ q = p;
+ while (*p) {
+ if (*p == CTLQUOTEMARK || *p == CTLQUOTEEND) {
+ p++;
+ continue;
+ }
+ if (*p == CTLESC)
+ p++;
+ *q++ = *p++;
+ }
+ *q = '\0';
+}
+
+
+
+/*
+ * See if a pattern matches in a case statement.
+ */
+
+int
+casematch(union node *pattern, const char *val)
+{
+ struct stackmark smark;
+ struct nodelist *argbackq;
+ int result;
+ char *p;
+
+ setstackmark(&smark);
+ argbackq = pattern->narg.backquote;
+ STARTSTACKSTR(expdest);
+ argstr(pattern->narg.text, &argbackq, EXP_TILDE | EXP_CASE, NULL);
+ STPUTC('\0', expdest);
+ p = grabstackstr(expdest);
+ result = patmatch(p, val);
+ popstackmark(&smark);
+ return result;
+}
+
+/*
+ * Our own itoa().
+ */
+
+static void
+cvtnum(int num, char *buf)
+{
+ char temp[32];
+ int neg = num < 0;
+ char *p = temp + 31;
+
+ temp[31] = '\0';
+
+ do {
+ *--p = num % 10 + '0';
+ } while ((num /= 10) != 0);
+
+ if (neg)
+ *--p = '-';
+
+ memcpy(buf, p, temp + 32 - p);
+}
+
+/*
+ * Do most of the work for wordexp(3).
+ */
+
+int
+wordexpcmd(int argc, char **argv)
+{
+ size_t len;
+ int i;
+
+ out1fmt("%08x", argc - 1);
+ for (i = 1, len = 0; i < argc; i++)
+ len += strlen(argv[i]);
+ out1fmt("%08x", (int)len);
+ for (i = 1; i < argc; i++)
+ outbin(argv[i], strlen(argv[i]) + 1, out1);
+ return (0);
+}
+
+/*
+ * Do most of the work for wordexp(3), new version.
+ */
+
+int
+freebsd_wordexpcmd(int argc __unused, char **argv __unused)
+{
+ struct arglist arglist;
+ union node *args, *n;
+ size_t len;
+ int ch;
+ int protected = 0;
+ int fd = -1;
+ int i;
+
+ while ((ch = nextopt("f:p")) != '\0') {
+ switch (ch) {
+ case 'f':
+ fd = number(shoptarg);
+ break;
+ case 'p':
+ protected = 1;
+ break;
+ }
+ }
+ if (*argptr != NULL)
+ error("wrong number of arguments");
+ if (fd < 0)
+ error("missing fd");
+ INTOFF;
+ setinputfd(fd, 1);
+ INTON;
+ args = parsewordexp();
+ popfile(); /* will also close fd */
+ if (protected)
+ for (n = args; n != NULL; n = n->narg.next) {
+ if (n->narg.backquote != NULL) {
+ outcslow('C', out1);
+ error("command substitution disabled");
+ }
+ }
+ outcslow(' ', out1);
+ emptyarglist(&arglist);
+ for (n = args; n != NULL; n = n->narg.next)
+ expandarg(n, &arglist, EXP_FULL | EXP_TILDE);
+ for (i = 0, len = 0; i < arglist.count; i++)
+ len += strlen(arglist.args[i]);
+ out1fmt("%016x %016zx", arglist.count, len);
+ for (i = 0; i < arglist.count; i++)
+ outbin(arglist.args[i], strlen(arglist.args[i]) + 1, out1);
+ return (0);
+}
diff --git a/shell_cmds/sh/expand.h b/shell_cmds/sh/expand.h
new file mode 100644
index 0000000..e959174
--- /dev/null
+++ b/shell_cmds/sh/expand.h
@@ -0,0 +1,62 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)expand.h 8.2 (Berkeley) 5/4/95
+ * $FreeBSD: head/bin/sh/expand.h 314436 2017-02-28 23:42:47Z imp $
+ */
+
+struct arglist {
+ char **args;
+ int count;
+ int capacity;
+ char *smallarg[1];
+};
+
+/*
+ * expandarg() flags
+ */
+#define EXP_SPLIT 0x1 /* perform word splitting */
+#define EXP_TILDE 0x2 /* do normal tilde expansion */
+#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
+#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
+#define EXP_SPLIT_LIT 0x20 /* IFS split literal text ${v+-a b c} */
+#define EXP_LIT_QUOTED 0x40 /* for EXP_SPLIT_LIT, start off quoted */
+#define EXP_GLOB 0x80 /* perform file globbing */
+
+#define EXP_FULL (EXP_SPLIT | EXP_GLOB)
+
+
+void emptyarglist(struct arglist *);
+void appendarglist(struct arglist *, char *);
+union node;
+void expandarg(union node *, struct arglist *, int);
+void rmescapes(char *);
+int casematch(union node *, const char *);
diff --git a/shell_cmds/sh/funcs/cmv b/shell_cmds/sh/funcs/cmv
new file mode 100644
index 0000000..01728ca
--- /dev/null
+++ b/shell_cmds/sh/funcs/cmv
@@ -0,0 +1,49 @@
+#!/bin/sh
+
+#-
+# Copyright (c) 1991, 1993
+# The Regents of the University of California. All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Kenneth Almquist.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of the University nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# @(#)cmv 8.2 (Berkeley) 5/4/95
+# $FreeBSD: head/bin/sh/funcs/cmv 314436 2017-02-28 23:42:47Z imp $
+
+# Conditional move--don't replace an existing file.
+
+cmv() {
+ if test $# != 2
+ then echo "cmv: arg count"
+ return 2
+ fi
+ if test -f "$2" -o -w "$2"
+ then echo "$2 exists"
+ return 2
+ fi
+ /bin/mv "$1" "$2"
+}
diff --git a/shell_cmds/sh/funcs/dirs b/shell_cmds/sh/funcs/dirs
new file mode 100644
index 0000000..88c20f4
--- /dev/null
+++ b/shell_cmds/sh/funcs/dirs
@@ -0,0 +1,73 @@
+#!/bin/sh
+
+#-
+# Copyright (c) 1991, 1993
+# The Regents of the University of California. All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Kenneth Almquist.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of the University nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# @(#)dirs 8.2 (Berkeley) 5/4/95
+# $FreeBSD: head/bin/sh/funcs/dirs 314436 2017-02-28 23:42:47Z imp $
+
+# pushd, popd, and dirs --- written by Chris Bertin
+# Pixel Computer Inc. ...!wjh12!pixel!pixutl!chris
+# as modified by Patrick Elam of GTRI and Kenneth Almquist at UW
+
+pushd () {
+ SAVE=`pwd`
+ if [ "$1" = "" ]
+ then if [ "$DSTACK" = "" ]
+ then echo "pushd: directory stack empty."
+ return 1
+ fi
+ set $DSTACK
+ cd $1 || return
+ shift 1
+ DSTACK="$*"
+ else cd $1 > /dev/null || return
+ fi
+ DSTACK="$SAVE $DSTACK"
+ dirs
+}
+
+popd () {
+ if [ "$DSTACK" = "" ]
+ then echo "popd: directory stack empty."
+ return 1
+ fi
+ set $DSTACK
+ cd $1
+ shift
+ DSTACK=$*
+ dirs
+}
+
+dirs () {
+ echo "`pwd` $DSTACK"
+ return 0
+}
diff --git a/shell_cmds/sh/funcs/login b/shell_cmds/sh/funcs/login
new file mode 100644
index 0000000..e3c1154
--- /dev/null
+++ b/shell_cmds/sh/funcs/login
@@ -0,0 +1,38 @@
+#!/bin/sh
+
+#-
+# Copyright (c) 1991, 1993
+# The Regents of the University of California. All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Kenneth Almquist.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of the University nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# @(#)login 8.2 (Berkeley) 5/4/95
+# $FreeBSD: head/bin/sh/funcs/login 314436 2017-02-28 23:42:47Z imp $
+
+# replaces the login builtin in the BSD shell
+login () exec login "$@"
diff --git a/shell_cmds/sh/funcs/newgrp b/shell_cmds/sh/funcs/newgrp
new file mode 100644
index 0000000..5f9f861
--- /dev/null
+++ b/shell_cmds/sh/funcs/newgrp
@@ -0,0 +1,37 @@
+#!/bin/sh
+
+#-
+# Copyright (c) 1991, 1993
+# The Regents of the University of California. All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Kenneth Almquist.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of the University nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# @(#)newgrp 8.2 (Berkeley) 5/4/95
+# $FreeBSD: head/bin/sh/funcs/newgrp 314436 2017-02-28 23:42:47Z imp $
+
+newgrp() exec newgrp "$@"
diff --git a/shell_cmds/sh/funcs/popd b/shell_cmds/sh/funcs/popd
new file mode 100644
index 0000000..7a46b4e
--- /dev/null
+++ b/shell_cmds/sh/funcs/popd
@@ -0,0 +1,73 @@
+#!/bin/sh
+
+#-
+# Copyright (c) 1991, 1993
+# The Regents of the University of California. All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Kenneth Almquist.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of the University nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# @(#)popd 8.2 (Berkeley) 5/4/95
+# $FreeBSD: head/bin/sh/funcs/popd 314436 2017-02-28 23:42:47Z imp $
+
+# pushd, popd, and dirs --- written by Chris Bertin
+# Pixel Computer Inc. ...!wjh12!pixel!pixutl!chris
+# as modified by Patrick Elam of GTRI and Kenneth Almquist at UW
+
+pushd () {
+ SAVE=`pwd`
+ if [ "$1" = "" ]
+ then if [ "$DSTACK" = "" ]
+ then echo "pushd: directory stack empty."
+ return 1
+ fi
+ set $DSTACK
+ cd $1 || return
+ shift 1
+ DSTACK="$*"
+ else cd $1 > /dev/null || return
+ fi
+ DSTACK="$SAVE $DSTACK"
+ dirs
+}
+
+popd () {
+ if [ "$DSTACK" = "" ]
+ then echo "popd: directory stack empty."
+ return 1
+ fi
+ set $DSTACK
+ cd $1
+ shift
+ DSTACK=$*
+ dirs
+}
+
+dirs () {
+ echo "`pwd` $DSTACK"
+ return 0
+}
diff --git a/shell_cmds/sh/funcs/pushd b/shell_cmds/sh/funcs/pushd
new file mode 100644
index 0000000..8d4f10d
--- /dev/null
+++ b/shell_cmds/sh/funcs/pushd
@@ -0,0 +1,73 @@
+#!/bin/sh
+
+#-
+# Copyright (c) 1991, 1993
+# The Regents of the University of California. All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Kenneth Almquist.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of the University nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# @(#)pushd 8.2 (Berkeley) 5/4/95
+# $FreeBSD: head/bin/sh/funcs/pushd 314436 2017-02-28 23:42:47Z imp $
+
+# pushd, popd, and dirs --- written by Chris Bertin
+# Pixel Computer Inc. ...!wjh12!pixel!pixutl!chris
+# as modified by Patrick Elam of GTRI and Kenneth Almquist at UW
+
+pushd () {
+ SAVE=`pwd`
+ if [ "$1" = "" ]
+ then if [ "$DSTACK" = "" ]
+ then echo "pushd: directory stack empty."
+ return 1
+ fi
+ set $DSTACK
+ cd $1 || return
+ shift 1
+ DSTACK="$*"
+ else cd $1 > /dev/null || return
+ fi
+ DSTACK="$SAVE $DSTACK"
+ dirs
+}
+
+popd () {
+ if [ "$DSTACK" = "" ]
+ then echo "popd: directory stack empty."
+ return 1
+ fi
+ set $DSTACK
+ cd $1
+ shift
+ DSTACK=$*
+ dirs
+}
+
+dirs () {
+ echo "`pwd` $DSTACK"
+ return 0
+}
diff --git a/shell_cmds/sh/funcs/suspend b/shell_cmds/sh/funcs/suspend
new file mode 100644
index 0000000..99d3109
--- /dev/null
+++ b/shell_cmds/sh/funcs/suspend
@@ -0,0 +1,39 @@
+#-
+# Copyright (c) 1991, 1993
+# The Regents of the University of California. All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Kenneth Almquist.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of the University nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# @(#)suspend 8.2 (Berkeley) 5/4/95
+# $FreeBSD: head/bin/sh/funcs/suspend 314436 2017-02-28 23:42:47Z imp $
+
+suspend() {
+ local -
+ set +m
+ kill -TSTP 0
+}
diff --git a/shell_cmds/sh/histedit.c b/shell_cmds/sh/histedit.c
new file mode 100644
index 0000000..f01cabd
--- /dev/null
+++ b/shell_cmds/sh/histedit.c
@@ -0,0 +1,502 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)histedit.c 8.2 (Berkeley) 5/4/95";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/bin/sh/histedit.c 319635 2017-06-06 21:08:05Z jilles $");
+
+#include <sys/param.h>
+#include <limits.h>
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+/*
+ * Editline and history functions (and glue).
+ */
+#include "shell.h"
+#include "parser.h"
+#include "var.h"
+#include "options.h"
+#include "main.h"
+#include "output.h"
+#include "mystring.h"
+#ifndef NO_HISTORY
+#include "myhistedit.h"
+#include "error.h"
+#include "eval.h"
+#include "memalloc.h"
+#include "builtins.h"
+
+#define MAXHISTLOOPS 4 /* max recursions through fc */
+#define DEFEDITOR "ed" /* default editor *should* be $EDITOR */
+
+History *hist; /* history cookie */
+EditLine *el; /* editline cookie */
+int displayhist;
+static FILE *el_in, *el_out, *el_err;
+
+static char *fc_replace(const char *, char *, char *);
+static int not_fcnumber(const char *);
+static int str_to_event(const char *, int);
+
+/*
+ * Set history and editing status. Called whenever the status may
+ * have changed (figures out what to do).
+ */
+void
+histedit(void)
+{
+
+#define editing (Eflag || Vflag)
+
+ if (iflag) {
+ if (!hist) {
+ /*
+ * turn history on
+ */
+ INTOFF;
+ hist = history_init();
+ INTON;
+
+ if (hist != NULL)
+ sethistsize(histsizeval());
+ else
+ out2fmt_flush("sh: can't initialize history\n");
+ }
+ if (editing && !el && isatty(0)) { /* && isatty(2) ??? */
+ /*
+ * turn editing on
+ */
+ char *term;
+
+ INTOFF;
+ if (el_in == NULL)
+ el_in = fdopen(0, "r");
+ if (el_err == NULL)
+ el_err = fdopen(1, "w");
+ if (el_out == NULL)
+ el_out = fdopen(2, "w");
+ if (el_in == NULL || el_err == NULL || el_out == NULL)
+ goto bad;
+ term = lookupvar("TERM");
+ if (term)
+ setenv("TERM", term, 1);
+ else
+ unsetenv("TERM");
+ el = el_init(arg0, el_in, el_out, el_err);
+ if (el != NULL) {
+ if (hist)
+ el_set(el, EL_HIST, history, hist);
+ el_set(el, EL_PROMPT, getprompt);
+ el_set(el, EL_ADDFN, "sh-complete",
+ "Filename completion",
+ _el_fn_sh_complete);
+ } else {
+bad:
+ out2fmt_flush("sh: can't initialize editing\n");
+ }
+ INTON;
+ } else if (!editing && el) {
+ INTOFF;
+ el_end(el);
+ el = NULL;
+ INTON;
+ }
+ if (el) {
+ if (Vflag)
+ el_set(el, EL_EDITOR, "vi");
+ else if (Eflag)
+ el_set(el, EL_EDITOR, "emacs");
+ el_set(el, EL_BIND, "^I", "sh-complete", NULL);
+ el_source(el, NULL);
+ }
+ } else {
+ INTOFF;
+ if (el) { /* no editing if not interactive */
+ el_end(el);
+ el = NULL;
+ }
+ if (hist) {
+ history_end(hist);
+ hist = NULL;
+ }
+ INTON;
+ }
+}
+
+
+void
+sethistsize(const char *hs)
+{
+ int histsize;
+ HistEvent he;
+
+ if (hist != NULL) {
+ if (hs == NULL || !is_number(hs))
+ histsize = 100;
+ else
+ histsize = atoi(hs);
+ history(hist, &he, H_SETSIZE, histsize);
+ history(hist, &he, H_SETUNIQUE, 1);
+ }
+}
+
+void
+setterm(const char *term)
+{
+ if (rootshell && el != NULL && term != NULL)
+ el_set(el, EL_TERMINAL, term);
+}
+
+int
+histcmd(int argc, char **argv __unused)
+{
+ int ch;
+ const char *editor = NULL;
+ HistEvent he;
+ int lflg = 0, nflg = 0, rflg = 0, sflg = 0;
+ int i, retval;
+ const char *firststr, *laststr;
+ int first, last, direction;
+ char *pat = NULL, *repl = NULL;
+ static int active = 0;
+ struct jmploc jmploc;
+ struct jmploc *savehandler;
+ char editfilestr[PATH_MAX];
+ char *volatile editfile;
+ FILE *efp = NULL;
+ int oldhistnum;
+
+ if (hist == NULL)
+ error("history not active");
+
+ if (argc == 1)
+ error("missing history argument");
+
+ while (not_fcnumber(*argptr) && (ch = nextopt("e:lnrs")) != '\0')
+ switch ((char)ch) {
+ case 'e':
+ editor = shoptarg;
+ break;
+ case 'l':
+ lflg = 1;
+ break;
+ case 'n':
+ nflg = 1;
+ break;
+ case 'r':
+ rflg = 1;
+ break;
+ case 's':
+ sflg = 1;
+ break;
+ }
+
+ savehandler = handler;
+ /*
+ * If executing...
+ */
+ if (lflg == 0 || editor || sflg) {
+ lflg = 0; /* ignore */
+ editfile = NULL;
+ /*
+ * Catch interrupts to reset active counter and
+ * cleanup temp files.
+ */
+ if (setjmp(jmploc.loc)) {
+ active = 0;
+ if (editfile)
+ unlink(editfile);
+ handler = savehandler;
+ longjmp(handler->loc, 1);
+ }
+ handler = &jmploc;
+ if (++active > MAXHISTLOOPS) {
+ active = 0;
+ displayhist = 0;
+ error("called recursively too many times");
+ }
+ /*
+ * Set editor.
+ */
+ if (sflg == 0) {
+ if (editor == NULL &&
+ (editor = bltinlookup("FCEDIT", 1)) == NULL &&
+ (editor = bltinlookup("EDITOR", 1)) == NULL)
+ editor = DEFEDITOR;
+ if (editor[0] == '-' && editor[1] == '\0') {
+ sflg = 1; /* no edit */
+ editor = NULL;
+ }
+ }
+ }
+
+ /*
+ * If executing, parse [old=new] now
+ */
+ if (lflg == 0 && *argptr != NULL &&
+ ((repl = strchr(*argptr, '=')) != NULL)) {
+ pat = *argptr;
+ *repl++ = '\0';
+ argptr++;
+ }
+ /*
+ * determine [first] and [last]
+ */
+ if (*argptr == NULL) {
+ firststr = lflg ? "-16" : "-1";
+ laststr = "-1";
+ } else if (argptr[1] == NULL) {
+ firststr = argptr[0];
+ laststr = lflg ? "-1" : argptr[0];
+ } else if (argptr[2] == NULL) {
+ firststr = argptr[0];
+ laststr = argptr[1];
+ } else
+ error("too many arguments");
+ /*
+ * Turn into event numbers.
+ */
+ first = str_to_event(firststr, 0);
+ last = str_to_event(laststr, 1);
+
+ if (rflg) {
+ i = last;
+ last = first;
+ first = i;
+ }
+ /*
+ * XXX - this should not depend on the event numbers
+ * always increasing. Add sequence numbers or offset
+ * to the history element in next (diskbased) release.
+ */
+ direction = first < last ? H_PREV : H_NEXT;
+
+ /*
+ * If editing, grab a temp file.
+ */
+ if (editor) {
+ int fd;
+ INTOFF; /* easier */
+ sprintf(editfilestr, "%s/_shXXXXXX", _PATH_TMP);
+ if ((fd = mkstemp(editfilestr)) < 0)
+ error("can't create temporary file %s", editfile);
+ editfile = editfilestr;
+ if ((efp = fdopen(fd, "w")) == NULL) {
+ close(fd);
+ error("Out of space");
+ }
+ }
+
+ /*
+ * Loop through selected history events. If listing or executing,
+ * do it now. Otherwise, put into temp file and call the editor
+ * after.
+ *
+ * The history interface needs rethinking, as the following
+ * convolutions will demonstrate.
+ */
+ history(hist, &he, H_FIRST);
+ retval = history(hist, &he, H_NEXT_EVENT, first);
+ for (;retval != -1; retval = history(hist, &he, direction)) {
+ if (lflg) {
+ if (!nflg)
+ out1fmt("%5d ", he.num);
+ out1str(he.str);
+ } else {
+ const char *s = pat ?
+ fc_replace(he.str, pat, repl) : he.str;
+
+ if (sflg) {
+ if (displayhist) {
+ out2str(s);
+ flushout(out2);
+ }
+ evalstring(s, 0);
+ if (displayhist && hist) {
+ /*
+ * XXX what about recursive and
+ * relative histnums.
+ */
+ oldhistnum = he.num;
+ history(hist, &he, H_ENTER, s);
+ /*
+ * XXX H_ENTER moves the internal
+ * cursor, set it back to the current
+ * entry.
+ */
+ history(hist, &he,
+ H_NEXT_EVENT, oldhistnum);
+ }
+ } else
+ fputs(s, efp);
+ }
+ /*
+ * At end? (if we were to lose last, we'd sure be
+ * messed up).
+ */
+ if (he.num == last)
+ break;
+ }
+ if (editor) {
+ char *editcmd;
+
+ fclose(efp);
+ INTON;
+ editcmd = stalloc(strlen(editor) + strlen(editfile) + 2);
+ sprintf(editcmd, "%s %s", editor, editfile);
+ evalstring(editcmd, 0); /* XXX - should use no JC command */
+ readcmdfile(editfile); /* XXX - should read back - quick tst */
+ unlink(editfile);
+ }
+
+ if (lflg == 0 && active > 0)
+ --active;
+ if (displayhist)
+ displayhist = 0;
+ handler = savehandler;
+ return 0;
+}
+
+static char *
+fc_replace(const char *s, char *p, char *r)
+{
+ char *dest;
+ int plen = strlen(p);
+
+ STARTSTACKSTR(dest);
+ while (*s) {
+ if (*s == *p && strncmp(s, p, plen) == 0) {
+ STPUTS(r, dest);
+ s += plen;
+ *p = '\0'; /* so no more matches */
+ } else
+ STPUTC(*s++, dest);
+ }
+ STPUTC('\0', dest);
+ dest = grabstackstr(dest);
+
+ return (dest);
+}
+
+static int
+not_fcnumber(const char *s)
+{
+ if (s == NULL)
+ return (0);
+ if (*s == '-')
+ s++;
+ return (!is_number(s));
+}
+
+static int
+str_to_event(const char *str, int last)
+{
+ HistEvent he;
+ const char *s = str;
+ int relative = 0;
+ int i, retval;
+
+ retval = history(hist, &he, H_FIRST);
+ switch (*s) {
+ case '-':
+ relative = 1;
+ /*FALLTHROUGH*/
+ case '+':
+ s++;
+ }
+ if (is_number(s)) {
+ i = atoi(s);
+ if (relative) {
+ while (retval != -1 && i--) {
+ retval = history(hist, &he, H_NEXT);
+ }
+ if (retval == -1)
+ retval = history(hist, &he, H_LAST);
+ } else {
+ retval = history(hist, &he, H_NEXT_EVENT, i);
+ if (retval == -1) {
+ /*
+ * the notion of first and last is
+ * backwards to that of the history package
+ */
+ retval = history(hist, &he, last ? H_FIRST : H_LAST);
+ }
+ }
+ if (retval == -1)
+ error("history number %s not found (internal error)",
+ str);
+ } else {
+ /*
+ * pattern
+ */
+ retval = history(hist, &he, H_PREV_STR, str);
+ if (retval == -1)
+ error("history pattern not found: %s", str);
+ }
+ return (he.num);
+}
+
+int
+bindcmd(int argc, char **argv)
+{
+
+ if (el == NULL)
+ error("line editing is disabled");
+ return (el_parse(el, argc, __DECONST(const char **, argv)));
+}
+
+#else
+#include "error.h"
+
+int
+histcmd(int argc, char **argv)
+{
+
+ error("not compiled with history support");
+ /*NOTREACHED*/
+ return (0);
+}
+
+int
+bindcmd(int argc, char **argv)
+{
+
+ error("not compiled with line editing support");
+ return (0);
+}
+#endif
diff --git a/shell_cmds/sh/input.c b/shell_cmds/sh/input.c
new file mode 100644
index 0000000..53376f8
--- /dev/null
+++ b/shell_cmds/sh/input.c
@@ -0,0 +1,536 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)input.c 8.3 (Berkeley) 6/9/95";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/bin/sh/input.c 314436 2017-02-28 23:42:47Z imp $");
+
+#include <stdio.h> /* defines BUFSIZ */
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * This file implements the input routines used by the parser.
+ */
+
+#include "shell.h"
+#include "redir.h"
+#include "syntax.h"
+#include "input.h"
+#include "output.h"
+#include "options.h"
+#include "memalloc.h"
+#include "error.h"
+#include "alias.h"
+#include "parser.h"
+#include "myhistedit.h"
+#include "trap.h"
+
+#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
+
+struct strpush {
+ struct strpush *prev; /* preceding string on stack */
+ const char *prevstring;
+ int prevnleft;
+ int prevlleft;
+ struct alias *ap; /* if push was associated with an alias */
+};
+
+/*
+ * The parsefile structure pointed to by the global variable parsefile
+ * contains information about the current file being read.
+ */
+
+struct parsefile {
+ struct parsefile *prev; /* preceding file on stack */
+ int linno; /* current line */
+ int fd; /* file descriptor (or -1 if string) */
+ int nleft; /* number of chars left in this line */
+ int lleft; /* number of lines left in this buffer */
+ const char *nextc; /* next char in buffer */
+ char *buf; /* input buffer */
+ struct strpush *strpush; /* for pushing strings at this level */
+ struct strpush basestrpush; /* so pushing one is fast */
+};
+
+
+int plinno = 1; /* input line number */
+int parsenleft; /* copy of parsefile->nleft */
+static int parselleft; /* copy of parsefile->lleft */
+const char *parsenextc; /* copy of parsefile->nextc */
+static char basebuf[BUFSIZ + 1];/* buffer for top level input file */
+static struct parsefile basepf = { /* top level input file */
+ .nextc = basebuf,
+ .buf = basebuf
+};
+static struct parsefile *parsefile = &basepf; /* current input file */
+int whichprompt; /* 1 == PS1, 2 == PS2 */
+
+#ifndef __APPLE__
+EditLine *el; /* cookie for editline package */
+#endif /* !__APPLE__ */
+
+static void pushfile(void);
+static int preadfd(void);
+static void popstring(void);
+
+#ifdef __APPLE__
+// Remove when 28988691 is fixed. Added _ to avoid conflict with future libc definition.
+static char *
+strchrnul_(const char *p, int ch)
+{
+ char c;
+
+ c = ch;
+ for (;; ++p) {
+ if (*p == c || *p == '\0')
+ return ((char *)p);
+ }
+ /* NOTREACHED */
+}
+#endif /* __APPLE__ */
+
+void
+resetinput(void)
+{
+ popallfiles();
+ parselleft = parsenleft = 0; /* clear input buffer */
+}
+
+
+
+/*
+ * Read a character from the script, returning PEOF on end of file.
+ * Nul characters in the input are silently discarded.
+ */
+
+int
+pgetc(void)
+{
+ return pgetc_macro();
+}
+
+
+static int
+preadfd(void)
+{
+ int nr;
+ parsenextc = parsefile->buf;
+
+retry:
+#ifndef NO_HISTORY
+ if (parsefile->fd == 0 && el) {
+ static const char *rl_cp;
+ static int el_len;
+
+ if (rl_cp == NULL) {
+ el_resize(el);
+ rl_cp = el_gets(el, &el_len);
+ }
+ if (rl_cp == NULL)
+ nr = el_len == 0 ? 0 : -1;
+ else {
+ nr = el_len;
+ if (nr > BUFSIZ)
+ nr = BUFSIZ;
+ memcpy(parsefile->buf, rl_cp, nr);
+ if (nr != el_len) {
+ el_len -= nr;
+ rl_cp += nr;
+ } else
+ rl_cp = NULL;
+ }
+ } else
+#endif
+ nr = read(parsefile->fd, parsefile->buf, BUFSIZ);
+
+ if (nr <= 0) {
+ if (nr < 0) {
+ if (errno == EINTR)
+ goto retry;
+ if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
+ int flags = fcntl(0, F_GETFL, 0);
+ if (flags >= 0 && flags & O_NONBLOCK) {
+ flags &=~ O_NONBLOCK;
+ if (fcntl(0, F_SETFL, flags) >= 0) {
+ out2fmt_flush("sh: turning off NDELAY mode\n");
+ goto retry;
+ }
+ }
+ }
+ }
+ nr = -1;
+ }
+ return nr;
+}
+
+/*
+ * Refill the input buffer and return the next input character:
+ *
+ * 1) If a string was pushed back on the input, pop it;
+ * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
+ * from a string so we can't refill the buffer, return EOF.
+ * 3) If there is more in this buffer, use it else call read to fill it.
+ * 4) Process input up to the next newline, deleting nul characters.
+ */
+
+int
+preadbuffer(void)
+{
+ char *p, *q, *r, *end;
+ char savec;
+
+ while (parsefile->strpush) {
+ /*
+ * Add a space to the end of an alias to ensure that the
+ * alias remains in use while parsing its last word.
+ * This avoids alias recursions.
+ */
+ if (parsenleft == -1 && parsefile->strpush->ap != NULL)
+ return ' ';
+ popstring();
+ if (--parsenleft >= 0)
+ return (*parsenextc++);
+ }
+ if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
+ return PEOF;
+
+again:
+ if (parselleft <= 0) {
+ if ((parselleft = preadfd()) == -1) {
+ parselleft = parsenleft = EOF_NLEFT;
+ return PEOF;
+ }
+ }
+
+ p = parsefile->buf + (parsenextc - parsefile->buf);
+ end = p + parselleft;
+ *end = '\0';
+ q = strchrnul_(p, '\n');
+ if (q != end && *q == '\0') {
+ /* delete nul characters */
+ for (r = q; q != end; q++) {
+ if (*q != '\0')
+ *r++ = *q;
+ }
+ parselleft -= end - r;
+ if (parselleft == 0)
+ goto again;
+ end = p + parselleft;
+ *end = '\0';
+ q = strchrnul_(p, '\n');
+ }
+ if (q == end) {
+ parsenleft = parselleft;
+ parselleft = 0;
+ } else /* *q == '\n' */ {
+ q++;
+ parsenleft = q - parsenextc;
+ parselleft -= parsenleft;
+ }
+ parsenleft--;
+
+ savec = *q;
+ *q = '\0';
+
+#ifndef NO_HISTORY
+ if (parsefile->fd == 0 && hist &&
+ parsenextc[strspn(parsenextc, " \t\n")] != '\0') {
+ HistEvent he;
+ INTOFF;
+ history(hist, &he, whichprompt == 1 ? H_ENTER : H_ADD,
+ parsenextc);
+ INTON;
+ }
+#endif
+
+ if (vflag) {
+ out2str(parsenextc);
+ flushout(out2);
+ }
+
+ *q = savec;
+
+ return *parsenextc++;
+}
+
+/*
+ * Returns if we are certain we are at EOF. Does not cause any more input
+ * to be read from the outside world.
+ */
+
+int
+preadateof(void)
+{
+ if (parsenleft > 0)
+ return 0;
+ if (parsefile->strpush)
+ return 0;
+ if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
+ return 1;
+ return 0;
+}
+
+/*
+ * Undo the last call to pgetc. Only one character may be pushed back.
+ * PEOF may be pushed back.
+ */
+
+void
+pungetc(void)
+{
+ parsenleft++;
+ parsenextc--;
+}
+
+/*
+ * Push a string back onto the input at this current parsefile level.
+ * We handle aliases this way.
+ */
+void
+pushstring(const char *s, int len, struct alias *ap)
+{
+ struct strpush *sp;
+
+ INTOFF;
+/*out2fmt_flush("*** calling pushstring: %s, %d\n", s, len);*/
+ if (parsefile->strpush) {
+ sp = ckmalloc(sizeof (struct strpush));
+ sp->prev = parsefile->strpush;
+ parsefile->strpush = sp;
+ } else
+ sp = parsefile->strpush = &(parsefile->basestrpush);
+ sp->prevstring = parsenextc;
+ sp->prevnleft = parsenleft;
+ sp->prevlleft = parselleft;
+ sp->ap = ap;
+ if (ap)
+ ap->flag |= ALIASINUSE;
+ parsenextc = s;
+ parsenleft = len;
+ INTON;
+}
+
+static void
+popstring(void)
+{
+ struct strpush *sp = parsefile->strpush;
+
+ INTOFF;
+ if (sp->ap) {
+ if (parsenextc != sp->ap->val &&
+ (parsenextc[-1] == ' ' || parsenextc[-1] == '\t'))
+ forcealias();
+ sp->ap->flag &= ~ALIASINUSE;
+ }
+ parsenextc = sp->prevstring;
+ parsenleft = sp->prevnleft;
+ parselleft = sp->prevlleft;
+/*out2fmt_flush("*** calling popstring: restoring to '%s'\n", parsenextc);*/
+ parsefile->strpush = sp->prev;
+ if (sp != &(parsefile->basestrpush))
+ ckfree(sp);
+ INTON;
+}
+
+/*
+ * Set the input to take input from a file. If push is set, push the
+ * old input onto the stack first.
+ */
+
+void
+setinputfile(const char *fname, int push)
+{
+ int fd;
+ int fd2;
+
+ INTOFF;
+ if ((fd = open(fname, O_RDONLY | O_CLOEXEC)) < 0)
+ error("cannot open %s: %s", fname, strerror(errno));
+ if (fd < 10) {
+ fd2 = fcntl(fd, F_DUPFD_CLOEXEC, 10);
+ close(fd);
+ if (fd2 < 0)
+ error("Out of file descriptors");
+ fd = fd2;
+ }
+ setinputfd(fd, push);
+ INTON;
+}
+
+
+/*
+ * Like setinputfile, but takes an open file descriptor (which should have
+ * its FD_CLOEXEC flag already set). Call this with interrupts off.
+ */
+
+void
+setinputfd(int fd, int push)
+{
+ if (push) {
+ pushfile();
+ parsefile->buf = ckmalloc(BUFSIZ + 1);
+ }
+ if (parsefile->fd > 0)
+ close(parsefile->fd);
+ parsefile->fd = fd;
+ if (parsefile->buf == NULL)
+ parsefile->buf = ckmalloc(BUFSIZ + 1);
+ parselleft = parsenleft = 0;
+ plinno = 1;
+}
+
+
+/*
+ * Like setinputfile, but takes input from a string.
+ */
+
+void
+setinputstring(const char *string, int push)
+{
+ INTOFF;
+ if (push)
+ pushfile();
+ parsenextc = string;
+ parselleft = parsenleft = strlen(string);
+ parsefile->buf = NULL;
+ plinno = 1;
+ INTON;
+}
+
+
+
+/*
+ * To handle the "." command, a stack of input files is used. Pushfile
+ * adds a new entry to the stack and popfile restores the previous level.
+ */
+
+static void
+pushfile(void)
+{
+ struct parsefile *pf;
+
+ parsefile->nleft = parsenleft;
+ parsefile->lleft = parselleft;
+ parsefile->nextc = parsenextc;
+ parsefile->linno = plinno;
+ pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
+ pf->prev = parsefile;
+ pf->fd = -1;
+ pf->strpush = NULL;
+ pf->basestrpush.prev = NULL;
+ parsefile = pf;
+}
+
+
+void
+popfile(void)
+{
+ struct parsefile *pf = parsefile;
+
+ INTOFF;
+ if (pf->fd >= 0)
+ close(pf->fd);
+ if (pf->buf)
+ ckfree(pf->buf);
+ while (pf->strpush)
+ popstring();
+ parsefile = pf->prev;
+ ckfree(pf);
+ parsenleft = parsefile->nleft;
+ parselleft = parsefile->lleft;
+ parsenextc = parsefile->nextc;
+ plinno = parsefile->linno;
+ INTON;
+}
+
+
+/*
+ * Return current file (to go back to it later using popfilesupto()).
+ */
+
+struct parsefile *
+getcurrentfile(void)
+{
+ return parsefile;
+}
+
+
+/*
+ * Pop files until the given file is on top again. Useful for regular
+ * builtins that read shell commands from files or strings.
+ * If the given file is not an active file, an error is raised.
+ */
+
+void
+popfilesupto(struct parsefile *file)
+{
+ while (parsefile != file && parsefile != &basepf)
+ popfile();
+ if (parsefile != file)
+ error("popfilesupto() misused");
+}
+
+/*
+ * Return to top level.
+ */
+
+void
+popallfiles(void)
+{
+ while (parsefile != &basepf)
+ popfile();
+}
+
+
+
+/*
+ * Close the file(s) that the shell is reading commands from. Called
+ * after a fork is done.
+ */
+
+void
+closescript(void)
+{
+ popallfiles();
+ if (parsefile->fd > 0) {
+ close(parsefile->fd);
+ parsefile->fd = 0;
+ }
+}
diff --git a/shell_cmds/sh/input.h b/shell_cmds/sh/input.h
new file mode 100644
index 0000000..5a47e4b
--- /dev/null
+++ b/shell_cmds/sh/input.h
@@ -0,0 +1,65 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)input.h 8.2 (Berkeley) 5/4/95
+ * $FreeBSD: head/bin/sh/input.h 314436 2017-02-28 23:42:47Z imp $
+ */
+
+/* PEOF (the end of file marker) is defined in syntax.h */
+
+/*
+ * The input line number. Input.c just defines this variable, and saves
+ * and restores it when files are pushed and popped. The user of this
+ * package must set its value.
+ */
+extern int plinno;
+extern int parsenleft; /* number of characters left in input buffer */
+extern const char *parsenextc; /* next character in input buffer */
+
+struct alias;
+struct parsefile;
+
+void resetinput(void);
+int pgetc(void);
+int preadbuffer(void);
+int preadateof(void);
+void pungetc(void);
+void pushstring(const char *, int, struct alias *);
+void setinputfile(const char *, int);
+void setinputfd(int, int);
+void setinputstring(const char *, int);
+void popfile(void);
+struct parsefile *getcurrentfile(void);
+void popfilesupto(struct parsefile *);
+void popallfiles(void);
+void closescript(void);
+
+#define pgetc_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
diff --git a/shell_cmds/sh/jobs.c b/shell_cmds/sh/jobs.c
new file mode 100644
index 0000000..358153b
--- /dev/null
+++ b/shell_cmds/sh/jobs.c
@@ -0,0 +1,1552 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)jobs.c 8.5 (Berkeley) 5/4/95";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/bin/sh/jobs.c 328818 2018-02-02 22:53:58Z jilles $");
+
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#include <sys/resource.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <signal.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "shell.h"
+#if JOBS
+#include <termios.h>
+#undef CEOF /* syntax.h redefines this */
+#endif
+#include "redir.h"
+#include "exec.h"
+#include "show.h"
+#include "main.h"
+#include "parser.h"
+#include "nodes.h"
+#include "jobs.h"
+#include "options.h"
+#include "trap.h"
+#include "syntax.h"
+#include "input.h"
+#include "output.h"
+#include "memalloc.h"
+#include "error.h"
+#include "mystring.h"
+#include "var.h"
+#include "builtins.h"
+
+
+/*
+ * A job structure contains information about a job. A job is either a
+ * single process or a set of processes contained in a pipeline. In the
+ * latter case, pidlist will be non-NULL, and will point to a -1 terminated
+ * array of pids.
+ */
+
+struct procstat {
+ pid_t pid; /* process id */
+ int status; /* status flags (defined above) */
+ char *cmd; /* text of command being run */
+};
+
+
+/* states */
+#define JOBSTOPPED 1 /* all procs are stopped */
+#define JOBDONE 2 /* all procs are completed */
+
+
+struct job {
+ struct procstat ps0; /* status of process */
+ struct procstat *ps; /* status or processes when more than one */
+ short nprocs; /* number of processes */
+ pid_t pgrp; /* process group of this job */
+ char state; /* true if job is finished */
+ char used; /* true if this entry is in used */
+ char changed; /* true if status has changed */
+ char foreground; /* true if running in the foreground */
+ char remembered; /* true if $! referenced */
+#if JOBS
+ char jobctl; /* job running under job control */
+ struct job *next; /* job used after this one */
+#endif
+};
+
+
+static struct job *jobtab; /* array of jobs */
+static int njobs; /* size of array */
+static pid_t backgndpid = -1; /* pid of last background process */
+static struct job *bgjob = NULL; /* last background process */
+#if JOBS
+static struct job *jobmru; /* most recently used job list */
+static pid_t initialpgrp; /* pgrp of shell on invocation */
+#endif
+static int ttyfd = -1;
+
+/* mode flags for dowait */
+#define DOWAIT_BLOCK 0x1 /* wait until a child exits */
+#define DOWAIT_SIG 0x2 /* if DOWAIT_BLOCK, abort on signal */
+#define DOWAIT_SIG_TRAP 0x4 /* if DOWAIT_SIG, abort on trapped signal only */
+
+#if JOBS
+static void restartjob(struct job *);
+#endif
+static void freejob(struct job *);
+static int waitcmdloop(struct job *);
+static struct job *getjob_nonotfound(const char *);
+static struct job *getjob(const char *);
+pid_t killjob(const char *, int);
+static pid_t dowait(int, struct job *);
+static void checkzombies(void);
+static void cmdtxt(union node *);
+static void cmdputs(const char *);
+#if JOBS
+static void setcurjob(struct job *);
+static void deljob(struct job *);
+static struct job *getcurjob(struct job *);
+#endif
+static void printjobcmd(struct job *);
+static void showjob(struct job *, int);
+
+
+/*
+ * Turn job control on and off.
+ */
+
+static int jobctl;
+
+#if JOBS
+static void
+jobctl_notty(void)
+{
+ if (ttyfd >= 0) {
+ close(ttyfd);
+ ttyfd = -1;
+ }
+ if (!iflag) {
+ setsignal(SIGTSTP);
+ setsignal(SIGTTOU);
+ setsignal(SIGTTIN);
+ jobctl = 1;
+ return;
+ }
+ out2fmt_flush("sh: can't access tty; job control turned off\n");
+ mflag = 0;
+}
+
+void
+setjobctl(int on)
+{
+ int i;
+
+ if (on == jobctl || rootshell == 0)
+ return;
+ if (on) {
+ if (ttyfd != -1)
+ close(ttyfd);
+ if ((ttyfd = open(_PATH_TTY, O_RDWR | O_CLOEXEC)) < 0) {
+ i = 0;
+ while (i <= 2 && !isatty(i))
+ i++;
+ if (i > 2 ||
+ (ttyfd = fcntl(i, F_DUPFD_CLOEXEC, 10)) < 0) {
+ jobctl_notty();
+ return;
+ }
+ }
+ if (ttyfd < 10) {
+ /*
+ * Keep our TTY file descriptor out of the way of
+ * the user's redirections.
+ */
+ if ((i = fcntl(ttyfd, F_DUPFD_CLOEXEC, 10)) < 0) {
+ jobctl_notty();
+ return;
+ }
+ close(ttyfd);
+ ttyfd = i;
+ }
+ do { /* while we are in the background */
+ initialpgrp = tcgetpgrp(ttyfd);
+ if (initialpgrp < 0) {
+ jobctl_notty();
+ return;
+ }
+ if (initialpgrp != getpgrp()) {
+ if (!iflag) {
+ initialpgrp = -1;
+ jobctl_notty();
+ return;
+ }
+ kill(0, SIGTTIN);
+ continue;
+ }
+ } while (0);
+ setsignal(SIGTSTP);
+ setsignal(SIGTTOU);
+ setsignal(SIGTTIN);
+ setpgid(0, rootpid);
+ tcsetpgrp(ttyfd, rootpid);
+ } else { /* turning job control off */
+ setpgid(0, initialpgrp);
+ if (ttyfd >= 0) {
+ tcsetpgrp(ttyfd, initialpgrp);
+ close(ttyfd);
+ ttyfd = -1;
+ }
+ setsignal(SIGTSTP);
+ setsignal(SIGTTOU);
+ setsignal(SIGTTIN);
+ }
+ jobctl = on;
+}
+#endif
+
+
+#if JOBS
+int
+fgcmd(int argc __unused, char **argv __unused)
+{
+ struct job *jp;
+ pid_t pgrp;
+ int status;
+
+ nextopt("");
+ jp = getjob(*argptr);
+ if (jp->jobctl == 0)
+ error("job not created under job control");
+ printjobcmd(jp);
+ flushout(&output);
+ pgrp = jp->ps[0].pid;
+ if (ttyfd >= 0)
+ tcsetpgrp(ttyfd, pgrp);
+ restartjob(jp);
+ jp->foreground = 1;
+ INTOFF;
+ status = waitforjob(jp, (int *)NULL);
+ INTON;
+ return status;
+}
+
+
+int
+bgcmd(int argc __unused, char **argv __unused)
+{
+ struct job *jp;
+
+ nextopt("");
+ do {
+ jp = getjob(*argptr);
+ if (jp->jobctl == 0)
+ error("job not created under job control");
+ if (jp->state == JOBDONE)
+ continue;
+ restartjob(jp);
+ jp->foreground = 0;
+ out1fmt("[%td] ", jp - jobtab + 1);
+ printjobcmd(jp);
+ } while (*argptr != NULL && *++argptr != NULL);
+ return 0;
+}
+
+
+static void
+restartjob(struct job *jp)
+{
+ struct procstat *ps;
+ int i;
+
+ if (jp->state == JOBDONE)
+ return;
+ setcurjob(jp);
+ INTOFF;
+ kill(-jp->ps[0].pid, SIGCONT);
+ for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) {
+ if (WIFSTOPPED(ps->status)) {
+ ps->status = -1;
+ jp->state = 0;
+ }
+ }
+ INTON;
+}
+#endif
+
+
+int
+jobscmd(int argc __unused, char *argv[] __unused)
+{
+ char *id;
+ int ch, mode;
+
+ mode = SHOWJOBS_DEFAULT;
+ while ((ch = nextopt("lps")) != '\0') {
+ switch (ch) {
+ case 'l':
+ mode = SHOWJOBS_VERBOSE;
+ break;
+ case 'p':
+ mode = SHOWJOBS_PGIDS;
+ break;
+ case 's':
+ mode = SHOWJOBS_PIDS;
+ break;
+ }
+ }
+
+ if (*argptr == NULL)
+ showjobs(0, mode);
+ else
+ while ((id = *argptr++) != NULL)
+ showjob(getjob(id), mode);
+
+ return (0);
+}
+
+static void
+printjobcmd(struct job *jp)
+{
+ struct procstat *ps;
+ int i;
+
+ for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) {
+ out1str(ps->cmd);
+ if (i > 0)
+ out1str(" | ");
+ }
+ out1c('\n');
+}
+
+static void
+showjob(struct job *jp, int mode)
+{
+ char s[64];
+ char statebuf[16];
+ const char *statestr, *coredump;
+ struct procstat *ps;
+ struct job *j;
+ int col, curr, i, jobno, prev, procno, status;
+ char c;
+
+ procno = (mode == SHOWJOBS_PGIDS) ? 1 : jp->nprocs;
+ jobno = jp - jobtab + 1;
+ curr = prev = 0;
+#if JOBS
+ if ((j = getcurjob(NULL)) != NULL) {
+ curr = j - jobtab + 1;
+ if ((j = getcurjob(j)) != NULL)
+ prev = j - jobtab + 1;
+ }
+#endif
+ coredump = "";
+ status = jp->ps[jp->nprocs - 1].status;
+ if (jp->state == 0) {
+ statestr = "Running";
+#if JOBS
+ } else if (jp->state == JOBSTOPPED) {
+ ps = jp->ps + jp->nprocs - 1;
+ while (!WIFSTOPPED(ps->status) && ps > jp->ps)
+ ps--;
+ if (WIFSTOPPED(ps->status))
+ i = WSTOPSIG(ps->status);
+ else
+ i = -1;
+ statestr = strsignal(i);
+ if (statestr == NULL)
+ statestr = "Suspended";
+#endif
+ } else if (WIFEXITED(status)) {
+ if (WEXITSTATUS(status) == 0)
+ statestr = "Done";
+ else {
+ fmtstr(statebuf, sizeof(statebuf), "Done(%d)",
+ WEXITSTATUS(status));
+ statestr = statebuf;
+ }
+ } else {
+ i = WTERMSIG(status);
+ statestr = strsignal(i);
+ if (statestr == NULL)
+ statestr = "Unknown signal";
+ if (WCOREDUMP(status))
+ coredump = " (core dumped)";
+ }
+
+ for (ps = jp->ps ; procno > 0 ; ps++, procno--) { /* for each process */
+ if (mode == SHOWJOBS_PIDS || mode == SHOWJOBS_PGIDS) {
+ out1fmt("%d\n", (int)ps->pid);
+ continue;
+ }
+ if (mode != SHOWJOBS_VERBOSE && ps != jp->ps)
+ continue;
+ if (jobno == curr && ps == jp->ps)
+ c = '+';
+ else if (jobno == prev && ps == jp->ps)
+ c = '-';
+ else
+ c = ' ';
+ if (ps == jp->ps)
+ fmtstr(s, 64, "[%d] %c ", jobno, c);
+ else
+ fmtstr(s, 64, " %c ", c);
+ out1str(s);
+ col = strlen(s);
+ if (mode == SHOWJOBS_VERBOSE) {
+ fmtstr(s, 64, "%d ", (int)ps->pid);
+ out1str(s);
+ col += strlen(s);
+ }
+ if (ps == jp->ps) {
+ out1str(statestr);
+ out1str(coredump);
+ col += strlen(statestr) + strlen(coredump);
+ }
+ do {
+ out1c(' ');
+ col++;
+ } while (col < 30);
+ if (mode == SHOWJOBS_VERBOSE) {
+ out1str(ps->cmd);
+ out1c('\n');
+ } else
+ printjobcmd(jp);
+ }
+}
+
+/*
+ * Print a list of jobs. If "change" is nonzero, only print jobs whose
+ * statuses have changed since the last call to showjobs.
+ *
+ * If the shell is interrupted in the process of creating a job, the
+ * result may be a job structure containing zero processes. Such structures
+ * will be freed here.
+ */
+
+void
+showjobs(int change, int mode)
+{
+ int jobno;
+ struct job *jp;
+
+ TRACE(("showjobs(%d) called\n", change));
+ checkzombies();
+ for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) {
+ if (! jp->used)
+ continue;
+ if (jp->nprocs == 0) {
+ freejob(jp);
+ continue;
+ }
+ if (change && ! jp->changed)
+ continue;
+ showjob(jp, mode);
+ if (mode == SHOWJOBS_DEFAULT || mode == SHOWJOBS_VERBOSE) {
+ jp->changed = 0;
+ /* Hack: discard jobs for which $! has not been
+ * referenced in interactive mode when they terminate.
+ */
+ if (jp->state == JOBDONE && !jp->remembered &&
+ (iflag || jp != bgjob)) {
+ freejob(jp);
+ }
+ }
+ }
+}
+
+
+/*
+ * Mark a job structure as unused.
+ */
+
+static void
+freejob(struct job *jp)
+{
+ struct procstat *ps;
+ int i;
+
+ INTOFF;
+ if (bgjob == jp)
+ bgjob = NULL;
+ for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
+ if (ps->cmd != nullstr)
+ ckfree(ps->cmd);
+ }
+ if (jp->ps != &jp->ps0)
+ ckfree(jp->ps);
+ jp->used = 0;
+#if JOBS
+ deljob(jp);
+#endif
+ INTON;
+}
+
+
+
+int
+waitcmd(int argc __unused, char **argv __unused)
+{
+ struct job *job;
+ int retval;
+
+ nextopt("");
+ if (*argptr == NULL)
+ return (waitcmdloop(NULL));
+
+ do {
+ job = getjob_nonotfound(*argptr);
+ if (job == NULL)
+ retval = 127;
+ else
+ retval = waitcmdloop(job);
+ argptr++;
+ } while (*argptr != NULL);
+
+ return (retval);
+}
+
+static int
+waitcmdloop(struct job *job)
+{
+ int status, retval, sig;
+ struct job *jp;
+
+ /*
+ * Loop until a process is terminated or stopped, or a SIGINT is
+ * received.
+ */
+
+ do {
+ if (job != NULL) {
+ if (job->state == JOBDONE) {
+ status = job->ps[job->nprocs - 1].status;
+ if (WIFEXITED(status))
+ retval = WEXITSTATUS(status);
+ else
+ retval = WTERMSIG(status) + 128;
+ if (! iflag || ! job->changed)
+ freejob(job);
+ else {
+ job->remembered = 0;
+ if (job == bgjob)
+ bgjob = NULL;
+ }
+ return retval;
+ }
+ } else {
+ for (jp = jobtab ; jp < jobtab + njobs; jp++)
+ if (jp->used && jp->state == JOBDONE) {
+ if (! iflag || ! jp->changed)
+ freejob(jp);
+ else {
+ jp->remembered = 0;
+ if (jp == bgjob)
+ bgjob = NULL;
+ }
+ }
+ for (jp = jobtab ; ; jp++) {
+ if (jp >= jobtab + njobs) { /* no running procs */
+ return 0;
+ }
+ if (jp->used && jp->state == 0)
+ break;
+ }
+ }
+ } while (dowait(DOWAIT_BLOCK | DOWAIT_SIG, (struct job *)NULL) != -1);
+
+ sig = pendingsig_waitcmd;
+ pendingsig_waitcmd = 0;
+ return sig + 128;
+}
+
+
+
+int
+jobidcmd(int argc __unused, char **argv __unused)
+{
+ struct job *jp;
+ int i;
+
+ nextopt("");
+ jp = getjob(*argptr);
+ for (i = 0 ; i < jp->nprocs ; ) {
+ out1fmt("%d", (int)jp->ps[i].pid);
+ out1c(++i < jp->nprocs? ' ' : '\n');
+ }
+ return 0;
+}
+
+
+
+/*
+ * Convert a job name to a job structure.
+ */
+
+static struct job *
+getjob_nonotfound(const char *name)
+{
+ int jobno;
+ struct job *found, *jp;
+ size_t namelen;
+ pid_t pid;
+ int i;
+
+ if (name == NULL) {
+#if JOBS
+ name = "%+";
+#else
+ error("No current job");
+#endif
+ }
+ if (name[0] == '%') {
+ if (is_digit(name[1])) {
+ jobno = number(name + 1);
+ if (jobno > 0 && jobno <= njobs
+ && jobtab[jobno - 1].used != 0)
+ return &jobtab[jobno - 1];
+#if JOBS
+ } else if ((name[1] == '%' || name[1] == '+') &&
+ name[2] == '\0') {
+ if ((jp = getcurjob(NULL)) == NULL)
+ error("No current job");
+ return (jp);
+ } else if (name[1] == '-' && name[2] == '\0') {
+ if ((jp = getcurjob(NULL)) == NULL ||
+ (jp = getcurjob(jp)) == NULL)
+ error("No previous job");
+ return (jp);
+#endif
+ } else if (name[1] == '?') {
+ found = NULL;
+ for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
+ if (jp->used && jp->nprocs > 0
+ && strstr(jp->ps[0].cmd, name + 2) != NULL) {
+ if (found)
+ error("%s: ambiguous", name);
+ found = jp;
+ }
+ }
+ if (found != NULL)
+ return (found);
+ } else {
+ namelen = strlen(name);
+ found = NULL;
+ for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
+ if (jp->used && jp->nprocs > 0
+ && strncmp(jp->ps[0].cmd, name + 1,
+ namelen - 1) == 0) {
+ if (found)
+ error("%s: ambiguous", name);
+ found = jp;
+ }
+ }
+ if (found)
+ return found;
+ }
+ } else if (is_number(name)) {
+ pid = (pid_t)number(name);
+ for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
+ if (jp->used && jp->nprocs > 0
+ && jp->ps[jp->nprocs - 1].pid == pid)
+ return jp;
+ }
+ }
+ return NULL;
+}
+
+
+static struct job *
+getjob(const char *name)
+{
+ struct job *jp;
+
+ jp = getjob_nonotfound(name);
+ if (jp == NULL)
+ error("No such job: %s", name);
+ return (jp);
+}
+
+
+int
+killjob(const char *name, int sig)
+{
+ struct job *jp;
+ int i, ret;
+
+ jp = getjob(name);
+ if (jp->state == JOBDONE)
+ return 0;
+ if (jp->jobctl)
+ return kill(-jp->ps[0].pid, sig);
+ ret = -1;
+ errno = ESRCH;
+ for (i = 0; i < jp->nprocs; i++)
+ if (jp->ps[i].status == -1 || WIFSTOPPED(jp->ps[i].status)) {
+ if (kill(jp->ps[i].pid, sig) == 0)
+ ret = 0;
+ } else
+ ret = 0;
+ return ret;
+}
+
+/*
+ * Return a new job structure,
+ */
+
+struct job *
+makejob(union node *node __unused, int nprocs)
+{
+ int i;
+ struct job *jp;
+
+ for (i = njobs, jp = jobtab ; ; jp++) {
+ if (--i < 0) {
+ INTOFF;
+ if (njobs == 0) {
+ jobtab = ckmalloc(4 * sizeof jobtab[0]);
+#if JOBS
+ jobmru = NULL;
+#endif
+ } else {
+ jp = ckmalloc((njobs + 4) * sizeof jobtab[0]);
+ memcpy(jp, jobtab, njobs * sizeof jp[0]);
+#if JOBS
+ /* Relocate `next' pointers and list head */
+ if (jobmru != NULL)
+ jobmru = &jp[jobmru - jobtab];
+ for (i = 0; i < njobs; i++)
+ if (jp[i].next != NULL)
+ jp[i].next = &jp[jp[i].next -
+ jobtab];
+#endif
+ if (bgjob != NULL)
+ bgjob = &jp[bgjob - jobtab];
+ /* Relocate `ps' pointers */
+ for (i = 0; i < njobs; i++)
+ if (jp[i].ps == &jobtab[i].ps0)
+ jp[i].ps = &jp[i].ps0;
+ ckfree(jobtab);
+ jobtab = jp;
+ }
+ jp = jobtab + njobs;
+ for (i = 4 ; --i >= 0 ; jobtab[njobs++].used = 0)
+ ;
+ INTON;
+ break;
+ }
+ if (jp->used == 0)
+ break;
+ }
+ INTOFF;
+ jp->state = 0;
+ jp->used = 1;
+ jp->changed = 0;
+ jp->nprocs = 0;
+ jp->foreground = 0;
+ jp->remembered = 0;
+#if JOBS
+ jp->jobctl = jobctl;
+ jp->next = NULL;
+#endif
+ if (nprocs > 1) {
+ jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
+ } else {
+ jp->ps = &jp->ps0;
+ }
+ INTON;
+ TRACE(("makejob(%p, %d) returns %%%td\n", (void *)node, nprocs,
+ jp - jobtab + 1));
+ return jp;
+}
+
+#if JOBS
+static void
+setcurjob(struct job *cj)
+{
+ struct job *jp, *prev;
+
+ for (prev = NULL, jp = jobmru; jp != NULL; prev = jp, jp = jp->next) {
+ if (jp == cj) {
+ if (prev != NULL)
+ prev->next = jp->next;
+ else
+ jobmru = jp->next;
+ jp->next = jobmru;
+ jobmru = cj;
+ return;
+ }
+ }
+ cj->next = jobmru;
+ jobmru = cj;
+}
+
+static void
+deljob(struct job *j)
+{
+ struct job *jp, *prev;
+
+ for (prev = NULL, jp = jobmru; jp != NULL; prev = jp, jp = jp->next) {
+ if (jp == j) {
+ if (prev != NULL)
+ prev->next = jp->next;
+ else
+ jobmru = jp->next;
+ return;
+ }
+ }
+}
+
+/*
+ * Return the most recently used job that isn't `nj', and preferably one
+ * that is stopped.
+ */
+static struct job *
+getcurjob(struct job *nj)
+{
+ struct job *jp;
+
+ /* Try to find a stopped one.. */
+ for (jp = jobmru; jp != NULL; jp = jp->next)
+ if (jp->used && jp != nj && jp->state == JOBSTOPPED)
+ return (jp);
+ /* Otherwise the most recently used job that isn't `nj' */
+ for (jp = jobmru; jp != NULL; jp = jp->next)
+ if (jp->used && jp != nj)
+ return (jp);
+
+ return (NULL);
+}
+
+#endif
+
+/*
+ * Fork of a subshell. If we are doing job control, give the subshell its
+ * own process group. Jp is a job structure that the job is to be added to.
+ * N is the command that will be evaluated by the child. Both jp and n may
+ * be NULL. The mode parameter can be one of the following:
+ * FORK_FG - Fork off a foreground process.
+ * FORK_BG - Fork off a background process.
+ * FORK_NOJOB - Like FORK_FG, but don't give the process its own
+ * process group even if job control is on.
+ *
+ * When job control is turned off, background processes have their standard
+ * input redirected to /dev/null (except for the second and later processes
+ * in a pipeline).
+ */
+
+pid_t
+forkshell(struct job *jp, union node *n, int mode)
+{
+ pid_t pid;
+ pid_t pgrp;
+
+ TRACE(("forkshell(%%%td, %p, %d) called\n", jp - jobtab, (void *)n,
+ mode));
+ INTOFF;
+ if (mode == FORK_BG && (jp == NULL || jp->nprocs == 0))
+ checkzombies();
+ flushall();
+ pid = fork();
+ if (pid == -1) {
+ TRACE(("Fork failed, errno=%d\n", errno));
+ INTON;
+ error("Cannot fork: %s", strerror(errno));
+ }
+ if (pid == 0) {
+ struct job *p;
+ int wasroot;
+ int i;
+
+ TRACE(("Child shell %d\n", (int)getpid()));
+ wasroot = rootshell;
+ rootshell = 0;
+ handler = &main_handler;
+ closescript();
+ INTON;
+ forcelocal = 0;
+ clear_traps();
+#if JOBS
+ jobctl = 0; /* do job control only in root shell */
+ if (wasroot && mode != FORK_NOJOB && mflag) {
+ if (jp == NULL || jp->nprocs == 0)
+ pgrp = getpid();
+ else
+ pgrp = jp->ps[0].pid;
+ if (setpgid(0, pgrp) == 0 && mode == FORK_FG &&
+ ttyfd >= 0) {
+ /*** this causes superfluous TIOCSPGRPS ***/
+ if (tcsetpgrp(ttyfd, pgrp) < 0)
+ error("tcsetpgrp failed, errno=%d", errno);
+ }
+ setsignal(SIGTSTP);
+ setsignal(SIGTTOU);
+ } else if (mode == FORK_BG) {
+ ignoresig(SIGINT);
+ ignoresig(SIGQUIT);
+ if ((jp == NULL || jp->nprocs == 0) &&
+ ! fd0_redirected_p ()) {
+ close(0);
+ if (open(_PATH_DEVNULL, O_RDONLY) != 0)
+ error("cannot open %s: %s",
+ _PATH_DEVNULL, strerror(errno));
+ }
+ }
+#else
+ if (mode == FORK_BG) {
+ ignoresig(SIGINT);
+ ignoresig(SIGQUIT);
+ if ((jp == NULL || jp->nprocs == 0) &&
+ ! fd0_redirected_p ()) {
+ close(0);
+ if (open(_PATH_DEVNULL, O_RDONLY) != 0)
+ error("cannot open %s: %s",
+ _PATH_DEVNULL, strerror(errno));
+ }
+ }
+#endif
+ INTOFF;
+ for (i = njobs, p = jobtab ; --i >= 0 ; p++)
+ if (p->used)
+ freejob(p);
+ INTON;
+ if (wasroot && iflag) {
+ setsignal(SIGINT);
+ setsignal(SIGQUIT);
+ setsignal(SIGTERM);
+ }
+ return pid;
+ }
+ if (rootshell && mode != FORK_NOJOB && mflag) {
+ if (jp == NULL || jp->nprocs == 0)
+ pgrp = pid;
+ else
+ pgrp = jp->ps[0].pid;
+ setpgid(pid, pgrp);
+ }
+ if (mode == FORK_BG) {
+ if (bgjob != NULL && bgjob->state == JOBDONE &&
+ !bgjob->remembered && !iflag)
+ freejob(bgjob);
+ backgndpid = pid; /* set $! */
+ bgjob = jp;
+ }
+ if (jp) {
+ struct procstat *ps = &jp->ps[jp->nprocs++];
+ ps->pid = pid;
+ ps->status = -1;
+ ps->cmd = nullstr;
+ if (iflag && rootshell && n)
+ ps->cmd = commandtext(n);
+ jp->foreground = mode == FORK_FG;
+#if JOBS
+ setcurjob(jp);
+#endif
+ }
+ INTON;
+ TRACE(("In parent shell: child = %d\n", (int)pid));
+ return pid;
+}
+
+
+pid_t
+vforkexecshell(struct job *jp, char **argv, char **envp, const char *path, int idx, int pip[2])
+{
+ pid_t pid;
+ struct jmploc jmploc;
+ struct jmploc *savehandler;
+
+ TRACE(("vforkexecshell(%%%td, %s, %p) called\n", jp - jobtab, argv[0],
+ (void *)pip));
+ INTOFF;
+ flushall();
+ savehandler = handler;
+ pid = vfork();
+ if (pid == -1) {
+ TRACE(("Vfork failed, errno=%d\n", errno));
+ INTON;
+ error("Cannot fork: %s", strerror(errno));
+ }
+ if (pid == 0) {
+ TRACE(("Child shell %d\n", (int)getpid()));
+ if (setjmp(jmploc.loc))
+ _exit(exception == EXEXEC ? exerrno : 2);
+ if (pip != NULL) {
+ close(pip[0]);
+ if (pip[1] != 1) {
+ dup2(pip[1], 1);
+ close(pip[1]);
+ }
+ }
+ handler = &jmploc;
+ shellexec(argv, envp, path, idx);
+ }
+ handler = savehandler;
+ if (jp) {
+ struct procstat *ps = &jp->ps[jp->nprocs++];
+ ps->pid = pid;
+ ps->status = -1;
+ ps->cmd = nullstr;
+ jp->foreground = 1;
+#if JOBS
+ setcurjob(jp);
+#endif
+ }
+ INTON;
+ TRACE(("In parent shell: child = %d\n", (int)pid));
+ return pid;
+}
+
+
+/*
+ * Wait for job to finish.
+ *
+ * Under job control we have the problem that while a child process is
+ * running interrupts generated by the user are sent to the child but not
+ * to the shell. This means that an infinite loop started by an inter-
+ * active user may be hard to kill. With job control turned off, an
+ * interactive user may place an interactive program inside a loop. If
+ * the interactive program catches interrupts, the user doesn't want
+ * these interrupts to also abort the loop. The approach we take here
+ * is to have the shell ignore interrupt signals while waiting for a
+ * foreground process to terminate, and then send itself an interrupt
+ * signal if the child process was terminated by an interrupt signal.
+ * Unfortunately, some programs want to do a bit of cleanup and then
+ * exit on interrupt; unless these processes terminate themselves by
+ * sending a signal to themselves (instead of calling exit) they will
+ * confuse this approach.
+ */
+
+int
+waitforjob(struct job *jp, int *signaled)
+{
+#if JOBS
+ int propagate_int = jp->jobctl && jp->foreground;
+#endif
+ int status;
+ int st;
+
+ INTOFF;
+ TRACE(("waitforjob(%%%td) called\n", jp - jobtab + 1));
+ while (jp->state == 0)
+ if (dowait(DOWAIT_BLOCK | (Tflag ? DOWAIT_SIG |
+ DOWAIT_SIG_TRAP : 0), jp) == -1)
+ dotrap();
+#if JOBS
+ if (jp->jobctl) {
+ if (ttyfd >= 0 && tcsetpgrp(ttyfd, rootpid) < 0)
+ error("tcsetpgrp failed, errno=%d\n", errno);
+ }
+ if (jp->state == JOBSTOPPED)
+ setcurjob(jp);
+#endif
+ status = jp->ps[jp->nprocs - 1].status;
+ if (signaled != NULL)
+ *signaled = WIFSIGNALED(status);
+ /* convert to 8 bits */
+ if (WIFEXITED(status))
+ st = WEXITSTATUS(status);
+#if JOBS
+ else if (WIFSTOPPED(status))
+ st = WSTOPSIG(status) + 128;
+#endif
+ else
+ st = WTERMSIG(status) + 128;
+ if (! JOBS || jp->state == JOBDONE)
+ freejob(jp);
+ if (int_pending()) {
+ if (!WIFSIGNALED(status) || WTERMSIG(status) != SIGINT)
+ CLEAR_PENDING_INT;
+ }
+#if JOBS
+ else if (rootshell && propagate_int &&
+ WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
+ kill(getpid(), SIGINT);
+#endif
+ INTON;
+ return st;
+}
+
+
+static void
+dummy_handler(int sig __unused)
+{
+}
+
+/*
+ * Wait for a process to terminate.
+ */
+
+static pid_t
+dowait(int mode, struct job *job)
+{
+ struct sigaction sa, osa;
+ sigset_t mask, omask;
+ pid_t pid;
+ int status;
+ struct procstat *sp;
+ struct job *jp;
+ struct job *thisjob;
+ const char *sigstr;
+ int done;
+ int stopped;
+ int sig;
+ int coredump;
+ int wflags;
+ int restore_sigchld;
+
+ TRACE(("dowait(%d, %p) called\n", mode, job));
+ restore_sigchld = 0;
+ if ((mode & DOWAIT_SIG) != 0) {
+ sigfillset(&mask);
+ sigprocmask(SIG_BLOCK, &mask, &omask);
+ INTOFF;
+ if (!issigchldtrapped()) {
+ restore_sigchld = 1;
+ sa.sa_handler = dummy_handler;
+ sa.sa_flags = 0;
+ sigemptyset(&sa.sa_mask);
+ sigaction(SIGCHLD, &sa, &osa);
+ }
+ }
+ do {
+#if JOBS
+ if (iflag)
+ wflags = WUNTRACED | WCONTINUED;
+ else
+#endif
+ wflags = 0;
+ if ((mode & (DOWAIT_BLOCK | DOWAIT_SIG)) != DOWAIT_BLOCK)
+ wflags |= WNOHANG;
+ pid = wait3(&status, wflags, (struct rusage *)NULL);
+ TRACE(("wait returns %d, status=%d\n", (int)pid, status));
+ if (pid == 0 && (mode & DOWAIT_SIG) != 0) {
+ pid = -1;
+ if (((mode & DOWAIT_SIG_TRAP) != 0 ?
+ pendingsig : pendingsig_waitcmd) != 0) {
+ errno = EINTR;
+ break;
+ }
+ sigsuspend(&omask);
+ if (int_pending())
+ break;
+ }
+ } while (pid == -1 && errno == EINTR);
+ if (pid == -1 && errno == ECHILD && job != NULL)
+ job->state = JOBDONE;
+ if ((mode & DOWAIT_SIG) != 0) {
+ if (restore_sigchld)
+ sigaction(SIGCHLD, &osa, NULL);
+ sigprocmask(SIG_SETMASK, &omask, NULL);
+ INTON;
+ }
+ if (pid <= 0)
+ return pid;
+ INTOFF;
+ thisjob = NULL;
+ for (jp = jobtab ; jp < jobtab + njobs ; jp++) {
+ if (jp->used && jp->nprocs > 0) {
+ done = 1;
+ stopped = 1;
+ for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {
+ if (sp->pid == -1)
+ continue;
+ if (sp->pid == pid && (sp->status == -1 ||
+ WIFSTOPPED(sp->status))) {
+ TRACE(("Changing status of proc %d from 0x%x to 0x%x\n",
+ (int)pid, sp->status,
+ status));
+ if (WIFCONTINUED(status)) {
+ sp->status = -1;
+ jp->state = 0;
+ } else
+ sp->status = status;
+ thisjob = jp;
+ }
+ if (sp->status == -1)
+ stopped = 0;
+ else if (WIFSTOPPED(sp->status))
+ done = 0;
+ }
+ if (stopped) { /* stopped or done */
+ int state = done? JOBDONE : JOBSTOPPED;
+ if (jp->state != state) {
+ TRACE(("Job %td: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state));
+ jp->state = state;
+ if (jp != job) {
+ if (done && !jp->remembered &&
+ !iflag && jp != bgjob)
+ freejob(jp);
+#if JOBS
+ else if (done)
+ deljob(jp);
+#endif
+ }
+ }
+ }
+ }
+ }
+ INTON;
+ if (!thisjob || thisjob->state == 0)
+ ;
+ else if ((!rootshell || !iflag || thisjob == job) &&
+ thisjob->foreground && thisjob->state != JOBSTOPPED) {
+ sig = 0;
+ coredump = 0;
+ for (sp = thisjob->ps; sp < thisjob->ps + thisjob->nprocs; sp++)
+ if (WIFSIGNALED(sp->status)) {
+ sig = WTERMSIG(sp->status);
+ coredump = WCOREDUMP(sp->status);
+ }
+ if (sig > 0 && sig != SIGINT && sig != SIGPIPE) {
+ sigstr = strsignal(sig);
+ if (sigstr != NULL)
+ out2str(sigstr);
+ else
+ out2str("Unknown signal");
+ if (coredump)
+ out2str(" (core dumped)");
+ out2c('\n');
+ flushout(out2);
+ }
+ } else {
+ TRACE(("Not printing status, rootshell=%d, job=%p\n", rootshell, job));
+ thisjob->changed = 1;
+ }
+ return pid;
+}
+
+
+
+/*
+ * return 1 if there are stopped jobs, otherwise 0
+ */
+int job_warning = 0;
+int
+stoppedjobs(void)
+{
+ int jobno;
+ struct job *jp;
+
+ if (job_warning)
+ return (0);
+ for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {
+ if (jp->used == 0)
+ continue;
+ if (jp->state == JOBSTOPPED) {
+ out2fmt_flush("You have stopped jobs.\n");
+ job_warning = 2;
+ return (1);
+ }
+ }
+
+ return (0);
+}
+
+
+static void
+checkzombies(void)
+{
+ while (njobs > 0 && dowait(0, NULL) > 0)
+ ;
+}
+
+
+int
+backgndpidset(void)
+{
+ return backgndpid != -1;
+}
+
+
+pid_t
+backgndpidval(void)
+{
+ if (bgjob != NULL && !forcelocal)
+ bgjob->remembered = 1;
+ return backgndpid;
+}
+
+/*
+ * Return a string identifying a command (to be printed by the
+ * jobs command.
+ */
+
+static char *cmdnextc;
+static int cmdnleft;
+#define MAXCMDTEXT 200
+
+char *
+commandtext(union node *n)
+{
+ char *name;
+
+ cmdnextc = name = ckmalloc(MAXCMDTEXT);
+ cmdnleft = MAXCMDTEXT - 4;
+ cmdtxt(n);
+ *cmdnextc = '\0';
+ return name;
+}
+
+
+static void
+cmdtxtdogroup(union node *n)
+{
+ cmdputs("; do ");
+ cmdtxt(n);
+ cmdputs("; done");
+}
+
+
+static void
+cmdtxtredir(union node *n, const char *op, int deffd)
+{
+ char s[2];
+
+ if (n->nfile.fd != deffd) {
+ s[0] = n->nfile.fd + '0';
+ s[1] = '\0';
+ cmdputs(s);
+ }
+ cmdputs(op);
+ if (n->type == NTOFD || n->type == NFROMFD) {
+ if (n->ndup.dupfd >= 0)
+ s[0] = n->ndup.dupfd + '0';
+ else
+ s[0] = '-';
+ s[1] = '\0';
+ cmdputs(s);
+ } else {
+ cmdtxt(n->nfile.fname);
+ }
+}
+
+
+static void
+cmdtxt(union node *n)
+{
+ union node *np;
+ struct nodelist *lp;
+
+ if (n == NULL)
+ return;
+ switch (n->type) {
+ case NSEMI:
+ cmdtxt(n->nbinary.ch1);
+ cmdputs("; ");
+ cmdtxt(n->nbinary.ch2);
+ break;
+ case NAND:
+ cmdtxt(n->nbinary.ch1);
+ cmdputs(" && ");
+ cmdtxt(n->nbinary.ch2);
+ break;
+ case NOR:
+ cmdtxt(n->nbinary.ch1);
+ cmdputs(" || ");
+ cmdtxt(n->nbinary.ch2);
+ break;
+ case NPIPE:
+ for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
+ cmdtxt(lp->n);
+ if (lp->next)
+ cmdputs(" | ");
+ }
+ break;
+ case NSUBSHELL:
+ cmdputs("(");
+ cmdtxt(n->nredir.n);
+ cmdputs(")");
+ break;
+ case NREDIR:
+ case NBACKGND:
+ cmdtxt(n->nredir.n);
+ break;
+ case NIF:
+ cmdputs("if ");
+ cmdtxt(n->nif.test);
+ cmdputs("; then ");
+ cmdtxt(n->nif.ifpart);
+ cmdputs("...");
+ break;
+ case NWHILE:
+ cmdputs("while ");
+ cmdtxt(n->nbinary.ch1);
+ cmdtxtdogroup(n->nbinary.ch2);
+ break;
+ case NUNTIL:
+ cmdputs("until ");
+ cmdtxt(n->nbinary.ch1);
+ cmdtxtdogroup(n->nbinary.ch2);
+ break;
+ case NFOR:
+ cmdputs("for ");
+ cmdputs(n->nfor.var);
+ cmdputs(" in ...");
+ break;
+ case NCASE:
+ cmdputs("case ");
+ cmdputs(n->ncase.expr->narg.text);
+ cmdputs(" in ...");
+ break;
+ case NDEFUN:
+ cmdputs(n->narg.text);
+ cmdputs("() ...");
+ break;
+ case NNOT:
+ cmdputs("! ");
+ cmdtxt(n->nnot.com);
+ break;
+ case NCMD:
+ for (np = n->ncmd.args ; np ; np = np->narg.next) {
+ cmdtxt(np);
+ if (np->narg.next)
+ cmdputs(" ");
+ }
+ for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
+ cmdputs(" ");
+ cmdtxt(np);
+ }
+ break;
+ case NARG:
+ cmdputs(n->narg.text);
+ break;
+ case NTO:
+ cmdtxtredir(n, ">", 1);
+ break;
+ case NAPPEND:
+ cmdtxtredir(n, ">>", 1);
+ break;
+ case NTOFD:
+ cmdtxtredir(n, ">&", 1);
+ break;
+ case NCLOBBER:
+ cmdtxtredir(n, ">|", 1);
+ break;
+ case NFROM:
+ cmdtxtredir(n, "<", 0);
+ break;
+ case NFROMTO:
+ cmdtxtredir(n, "<>", 0);
+ break;
+ case NFROMFD:
+ cmdtxtredir(n, "<&", 0);
+ break;
+ case NHERE:
+ case NXHERE:
+ cmdputs("<<...");
+ break;
+ default:
+ cmdputs("???");
+ break;
+ }
+}
+
+
+
+static void
+cmdputs(const char *s)
+{
+ const char *p;
+ char *q;
+ char c;
+ int subtype = 0;
+
+ if (cmdnleft <= 0)
+ return;
+ p = s;
+ q = cmdnextc;
+ while ((c = *p++) != '\0') {
+ if (c == CTLESC)
+ *q++ = *p++;
+ else if (c == CTLVAR) {
+ *q++ = '$';
+ if (--cmdnleft > 0)
+ *q++ = '{';
+ subtype = *p++;
+ if ((subtype & VSTYPE) == VSLENGTH && --cmdnleft > 0)
+ *q++ = '#';
+ } else if (c == '=' && subtype != 0) {
+ *q = "}-+?=##%%\0X"[(subtype & VSTYPE) - VSNORMAL];
+ if (*q)
+ q++;
+ else
+ cmdnleft++;
+ if (((subtype & VSTYPE) == VSTRIMLEFTMAX ||
+ (subtype & VSTYPE) == VSTRIMRIGHTMAX) &&
+ --cmdnleft > 0)
+ *q = q[-1], q++;
+ subtype = 0;
+ } else if (c == CTLENDVAR) {
+ *q++ = '}';
+ } else if (c == CTLBACKQ || c == CTLBACKQ+CTLQUOTE) {
+ cmdnleft -= 5;
+ if (cmdnleft > 0) {
+ *q++ = '$';
+ *q++ = '(';
+ *q++ = '.';
+ *q++ = '.';
+ *q++ = '.';
+ *q++ = ')';
+ }
+ } else if (c == CTLARI) {
+ cmdnleft -= 2;
+ if (cmdnleft > 0) {
+ *q++ = '$';
+ *q++ = '(';
+ *q++ = '(';
+ }
+ p++;
+ } else if (c == CTLENDARI) {
+ if (--cmdnleft > 0) {
+ *q++ = ')';
+ *q++ = ')';
+ }
+ } else if (c == CTLQUOTEMARK || c == CTLQUOTEEND)
+ cmdnleft++; /* ignore */
+ else
+ *q++ = c;
+ if (--cmdnleft <= 0) {
+ *q++ = '.';
+ *q++ = '.';
+ *q++ = '.';
+ break;
+ }
+ }
+ cmdnextc = q;
+}
diff --git a/shell_cmds/sh/jobs.h b/shell_cmds/sh/jobs.h
new file mode 100644
index 0000000..f6d90a8
--- /dev/null
+++ b/shell_cmds/sh/jobs.h
@@ -0,0 +1,67 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)jobs.h 8.2 (Berkeley) 5/4/95
+ * $FreeBSD: head/bin/sh/jobs.h 327475 2018-01-01 22:31:52Z jilles $
+ */
+
+/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
+#define FORK_FG 0
+#define FORK_BG 1
+#define FORK_NOJOB 2
+
+#include <signal.h> /* for sig_atomic_t */
+
+struct job;
+
+enum {
+ SHOWJOBS_DEFAULT, /* job number, status, command */
+ SHOWJOBS_VERBOSE, /* job number, PID, status, command */
+ SHOWJOBS_PIDS, /* PID only */
+ SHOWJOBS_PGIDS /* PID of the group leader only */
+};
+
+extern int job_warning; /* user was warned about stopped jobs */
+
+void setjobctl(int);
+void showjobs(int, int);
+struct job *makejob(union node *, int);
+pid_t forkshell(struct job *, union node *, int);
+pid_t vforkexecshell(struct job *, char **, char **, const char *, int, int []);
+int waitforjob(struct job *, int *);
+int stoppedjobs(void);
+int backgndpidset(void);
+pid_t backgndpidval(void);
+char *commandtext(union node *);
+
+#if ! JOBS
+#define setjobctl(on) /* do nothing */
+#endif
diff --git a/shell_cmds/sh/mail.c b/shell_cmds/sh/mail.c
new file mode 100644
index 0000000..607b407
--- /dev/null
+++ b/shell_cmds/sh/mail.c
@@ -0,0 +1,117 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)mail.c 8.2 (Berkeley) 5/4/95";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/bin/sh/mail.c 314436 2017-02-28 23:42:47Z imp $");
+
+/*
+ * Routines to check for mail. (Perhaps make part of main.c?)
+ */
+
+#include "shell.h"
+#include "exec.h" /* defines padvance() */
+#include "mail.h"
+#include "var.h"
+#include "output.h"
+#include "memalloc.h"
+#include "error.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+
+
+#define MAXMBOXES 10
+
+
+static int nmboxes; /* number of mailboxes */
+static time_t mailtime[MAXMBOXES]; /* times of mailboxes */
+
+
+
+/*
+ * Print appropriate message(s) if mail has arrived. If the argument is
+ * nozero, then the value of MAIL has changed, so we just update the
+ * values.
+ */
+
+void
+chkmail(int silent)
+{
+ int i;
+ const char *mpath;
+ char *p;
+ char *q;
+ struct stackmark smark;
+ struct stat statb;
+
+ if (silent)
+ nmboxes = 10;
+ if (nmboxes == 0)
+ return;
+ setstackmark(&smark);
+ mpath = mpathset()? mpathval() : mailval();
+ for (i = 0 ; i < nmboxes ; i++) {
+ p = padvance(&mpath, "");
+ if (p == NULL)
+ break;
+ if (*p == '\0')
+ continue;
+ for (q = p ; *q ; q++);
+ if (q[-1] != '/')
+ abort();
+ q[-1] = '\0'; /* delete trailing '/' */
+#ifdef notdef /* this is what the System V shell claims to do (it lies) */
+ if (stat(p, &statb) < 0)
+ statb.st_mtime = 0;
+ if (statb.st_mtime > mailtime[i] && ! silent) {
+ out2str(pathopt? pathopt : "you have mail");
+ out2c('\n');
+ }
+ mailtime[i] = statb.st_mtime;
+#else /* this is what it should do */
+ if (stat(p, &statb) < 0)
+ statb.st_size = 0;
+ if (statb.st_size > mailtime[i] && ! silent) {
+ out2str(pathopt? pathopt : "you have mail");
+ out2c('\n');
+ }
+ mailtime[i] = statb.st_size;
+#endif
+ }
+ nmboxes = i;
+ popstackmark(&smark);
+}
diff --git a/shell_cmds/sh/mail.h b/shell_cmds/sh/mail.h
new file mode 100644
index 0000000..509f11c
--- /dev/null
+++ b/shell_cmds/sh/mail.h
@@ -0,0 +1,38 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)mail.h 8.2 (Berkeley) 5/4/95
+ * $FreeBSD: head/bin/sh/mail.h 326025 2017-11-20 19:49:47Z pfg $
+ */
+
+void chkmail(int);
diff --git a/shell_cmds/sh/main.c b/shell_cmds/sh/main.c
new file mode 100644
index 0000000..338f97c
--- /dev/null
+++ b/shell_cmds/sh/main.c
@@ -0,0 +1,351 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char const copyright[] =
+"@(#) Copyright (c) 1991, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)main.c 8.6 (Berkeley) 5/28/95";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/bin/sh/main.c 326025 2017-11-20 19:49:47Z pfg $");
+
+#include <stdio.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <locale.h>
+#include <errno.h>
+
+#include "shell.h"
+#include "main.h"
+#include "mail.h"
+#include "options.h"
+#include "output.h"
+#include "parser.h"
+#include "nodes.h"
+#include "expand.h"
+#include "eval.h"
+#include "jobs.h"
+#include "input.h"
+#include "trap.h"
+#include "var.h"
+#include "show.h"
+#include "memalloc.h"
+#include "error.h"
+#include "mystring.h"
+#include "exec.h"
+#include "cd.h"
+#include "redir.h"
+#include "builtins.h"
+
+int rootpid;
+int rootshell;
+struct jmploc main_handler;
+int localeisutf8, initial_localeisutf8;
+
+static void reset(void);
+static void cmdloop(int);
+static void read_profile(const char *);
+static char *find_dot_file(char *);
+
+/*
+ * Main routine. We initialize things, parse the arguments, execute
+ * profiles if we're a login shell, and then call cmdloop to execute
+ * commands. The setjmp call sets up the location to jump to when an
+ * exception occurs. When an exception occurs the variable "state"
+ * is used to figure out how far we had gotten.
+ */
+
+int
+main(int argc, char *argv[])
+{
+ struct stackmark smark, smark2;
+ volatile int state;
+ char *shinit;
+
+ (void) setlocale(LC_ALL, "");
+ initcharset();
+ state = 0;
+ if (setjmp(main_handler.loc)) {
+ switch (exception) {
+ case EXEXEC:
+ exitstatus = exerrno;
+ break;
+
+ case EXERROR:
+ exitstatus = 2;
+ break;
+
+ default:
+ break;
+ }
+
+ if (state == 0 || iflag == 0 || ! rootshell ||
+ exception == EXEXIT)
+ exitshell(exitstatus);
+ reset();
+ if (exception == EXINT)
+ out2fmt_flush("\n");
+ popstackmark(&smark);
+ FORCEINTON; /* enable interrupts */
+ if (state == 1)
+ goto state1;
+ else if (state == 2)
+ goto state2;
+ else if (state == 3)
+ goto state3;
+ else
+ goto state4;
+ }
+ handler = &main_handler;
+#ifdef DEBUG
+ opentrace();
+ trputs("Shell args: "); trargs(argv);
+#endif
+ rootpid = getpid();
+ rootshell = 1;
+ INTOFF;
+ initvar();
+ setstackmark(&smark);
+ setstackmark(&smark2);
+ procargs(argc, argv);
+ pwd_init(iflag);
+ INTON;
+ if (iflag)
+ chkmail(1);
+ if (argv[0] && argv[0][0] == '-') {
+ state = 1;
+ read_profile("/etc/profile");
+state1:
+ state = 2;
+ if (privileged == 0)
+ read_profile("${HOME-}/.profile");
+ else
+ read_profile("/etc/suid_profile");
+ }
+state2:
+ state = 3;
+ if (!privileged && iflag) {
+ if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
+ state = 3;
+ read_profile(shinit);
+ }
+ }
+state3:
+ state = 4;
+ popstackmark(&smark2);
+ if (minusc) {
+ evalstring(minusc, sflag ? 0 : EV_EXIT);
+ }
+state4:
+ if (sflag || minusc == NULL) {
+ cmdloop(1);
+ }
+ exitshell(exitstatus);
+ /*NOTREACHED*/
+ return 0;
+}
+
+static void
+reset(void)
+{
+ reseteval();
+ resetinput();
+}
+
+/*
+ * Read and execute commands. "Top" is nonzero for the top level command
+ * loop; it turns on prompting if the shell is interactive.
+ */
+
+static void
+cmdloop(int top)
+{
+ union node *n;
+ struct stackmark smark;
+ int inter;
+ int numeof = 0;
+
+ TRACE(("cmdloop(%d) called\n", top));
+ setstackmark(&smark);
+ for (;;) {
+ if (pendingsig)
+ dotrap();
+ inter = 0;
+ if (iflag && top) {
+ inter++;
+ showjobs(1, SHOWJOBS_DEFAULT);
+ chkmail(0);
+ flushout(&output);
+ }
+ n = parsecmd(inter);
+ /* showtree(n); DEBUG */
+ if (n == NEOF) {
+ if (!top || numeof >= 50)
+ break;
+ if (!stoppedjobs()) {
+ if (!Iflag)
+ break;
+ out2fmt_flush("\nUse \"exit\" to leave shell.\n");
+ }
+ numeof++;
+ } else if (n != NULL && nflag == 0) {
+ job_warning = (job_warning == 2) ? 1 : 0;
+ numeof = 0;
+ evaltree(n, 0);
+ }
+ popstackmark(&smark);
+ setstackmark(&smark);
+ if (evalskip != 0) {
+ if (evalskip == SKIPRETURN)
+ evalskip = 0;
+ break;
+ }
+ }
+ popstackmark(&smark);
+}
+
+
+
+/*
+ * Read /etc/profile or .profile. Return on error.
+ */
+
+static void
+read_profile(const char *name)
+{
+ int fd;
+ const char *expandedname;
+
+ expandedname = expandstr(name);
+ if (expandedname == NULL)
+ return;
+ INTOFF;
+ if ((fd = open(expandedname, O_RDONLY | O_CLOEXEC)) >= 0)
+ setinputfd(fd, 1);
+ INTON;
+ if (fd < 0)
+ return;
+ cmdloop(0);
+ popfile();
+}
+
+
+
+/*
+ * Read a file containing shell functions.
+ */
+
+void
+readcmdfile(const char *name)
+{
+ setinputfile(name, 1);
+ cmdloop(0);
+ popfile();
+}
+
+
+
+/*
+ * Take commands from a file. To be compatible we should do a path
+ * search for the file, which is necessary to find sub-commands.
+ */
+
+
+static char *
+find_dot_file(char *basename)
+{
+ char *fullname;
+ const char *path = pathval();
+ struct stat statb;
+
+ /* don't try this for absolute or relative paths */
+ if( strchr(basename, '/'))
+ return basename;
+
+ while ((fullname = padvance(&path, basename)) != NULL) {
+ if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
+ /*
+ * Don't bother freeing here, since it will
+ * be freed by the caller.
+ */
+ return fullname;
+ }
+ stunalloc(fullname);
+ }
+ return basename;
+}
+
+int
+dotcmd(int argc, char **argv)
+{
+ char *filename, *fullname;
+
+ if (argc < 2)
+ error("missing filename");
+
+ exitstatus = 0;
+
+ /*
+ * Because we have historically not supported any options,
+ * only treat "--" specially.
+ */
+ filename = argc > 2 && strcmp(argv[1], "--") == 0 ? argv[2] : argv[1];
+
+ fullname = find_dot_file(filename);
+ setinputfile(fullname, 1);
+ commandname = fullname;
+ cmdloop(0);
+ popfile();
+ return exitstatus;
+}
+
+
+int
+exitcmd(int argc, char **argv)
+{
+ if (stoppedjobs())
+ return 0;
+ if (argc > 1)
+ exitshell(number(argv[1]));
+ else
+ exitshell_savedstatus();
+}
diff --git a/shell_cmds/sh/main.h b/shell_cmds/sh/main.h
new file mode 100644
index 0000000..ed160cd
--- /dev/null
+++ b/shell_cmds/sh/main.h
@@ -0,0 +1,42 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)main.h 8.2 (Berkeley) 5/4/95
+ * $FreeBSD: head/bin/sh/main.h 326025 2017-11-20 19:49:47Z pfg $
+ */
+
+extern int rootpid; /* pid of main shell */
+extern int rootshell; /* true if we aren't a child of the main shell */
+extern struct jmploc main_handler; /* top level exception handler */
+
+void readcmdfile(const char *);
diff --git a/shell_cmds/sh/memalloc.c b/shell_cmds/sh/memalloc.c
new file mode 100644
index 0000000..7b5f325
--- /dev/null
+++ b/shell_cmds/sh/memalloc.c
@@ -0,0 +1,344 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)memalloc.c 8.3 (Berkeley) 5/4/95";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/bin/sh/memalloc.c 326025 2017-11-20 19:49:47Z pfg $");
+
+#include <sys/param.h>
+#include "shell.h"
+#include "output.h"
+#include "memalloc.h"
+#include "error.h"
+#include "mystring.h"
+#include "expand.h"
+#include <stdlib.h>
+#include <unistd.h>
+
+/*
+ * Like malloc, but returns an error when out of space.
+ */
+
+pointer
+ckmalloc(size_t nbytes)
+{
+ pointer p;
+
+ INTOFF;
+ p = malloc(nbytes);
+ INTON;
+ if (p == NULL)
+ error("Out of space");
+ return p;
+}
+
+
+/*
+ * Same for realloc.
+ */
+
+pointer
+ckrealloc(pointer p, int nbytes)
+{
+ INTOFF;
+ p = realloc(p, nbytes);
+ INTON;
+ if (p == NULL)
+ error("Out of space");
+ return p;
+}
+
+void
+ckfree(pointer p)
+{
+ INTOFF;
+ free(p);
+ INTON;
+}
+
+
+/*
+ * Make a copy of a string in safe storage.
+ */
+
+char *
+savestr(const char *s)
+{
+ char *p;
+ size_t len;
+
+ len = strlen(s);
+ p = ckmalloc(len + 1);
+ memcpy(p, s, len + 1);
+ return p;
+}
+
+
+/*
+ * Parse trees for commands are allocated in lifo order, so we use a stack
+ * to make this more efficient, and also to avoid all sorts of exception
+ * handling code to handle interrupts in the middle of a parse.
+ *
+ * The size 496 was chosen because with 16-byte alignment the total size
+ * for the allocated block is 512.
+ */
+
+#define MINSIZE 496 /* minimum size of a block. */
+
+
+struct stack_block {
+ struct stack_block *prev;
+ /* Data follows */
+};
+#define SPACE(sp) ((char*)(sp) + ALIGN(sizeof(struct stack_block)))
+
+static struct stack_block *stackp;
+char *stacknxt;
+int stacknleft;
+char *sstrend;
+
+
+static void
+stnewblock(int nbytes)
+{
+ struct stack_block *sp;
+ int allocsize;
+
+ if (nbytes < MINSIZE)
+ nbytes = MINSIZE;
+
+ allocsize = ALIGN(sizeof(struct stack_block)) + ALIGN(nbytes);
+
+ INTOFF;
+ sp = ckmalloc(allocsize);
+ sp->prev = stackp;
+ stacknxt = SPACE(sp);
+ stacknleft = allocsize - (stacknxt - (char*)sp);
+ sstrend = stacknxt + stacknleft;
+ stackp = sp;
+ INTON;
+}
+
+
+pointer
+stalloc(int nbytes)
+{
+ char *p;
+
+ nbytes = ALIGN(nbytes);
+ if (nbytes > stacknleft)
+ stnewblock(nbytes);
+ p = stacknxt;
+ stacknxt += nbytes;
+ stacknleft -= nbytes;
+ return p;
+}
+
+
+void
+stunalloc(pointer p)
+{
+ if (p == NULL) { /*DEBUG */
+ write(STDERR_FILENO, "stunalloc\n", 10);
+ abort();
+ }
+ stacknleft += stacknxt - (char *)p;
+ stacknxt = p;
+}
+
+
+char *
+stsavestr(const char *s)
+{
+ char *p;
+ size_t len;
+
+ len = strlen(s);
+ p = stalloc(len + 1);
+ memcpy(p, s, len + 1);
+ return p;
+}
+
+
+void
+setstackmark(struct stackmark *mark)
+{
+ mark->stackp = stackp;
+ mark->stacknxt = stacknxt;
+ mark->stacknleft = stacknleft;
+ /* Ensure this block stays in place. */
+ if (stackp != NULL && stacknxt == SPACE(stackp))
+ stalloc(1);
+}
+
+
+void
+popstackmark(struct stackmark *mark)
+{
+ struct stack_block *sp;
+
+ INTOFF;
+ while (stackp != mark->stackp) {
+ sp = stackp;
+ stackp = sp->prev;
+ ckfree(sp);
+ }
+ stacknxt = mark->stacknxt;
+ stacknleft = mark->stacknleft;
+ sstrend = stacknxt + stacknleft;
+ INTON;
+}
+
+
+/*
+ * When the parser reads in a string, it wants to stick the string on the
+ * stack and only adjust the stack pointer when it knows how big the
+ * string is. Stackblock (defined in stack.h) returns a pointer to a block
+ * of space on top of the stack and stackblocklen returns the length of
+ * this block. Growstackblock will grow this space by at least one byte,
+ * possibly moving it (like realloc). Grabstackblock actually allocates the
+ * part of the block that has been used.
+ */
+
+static void
+growstackblock(int min)
+{
+ char *p;
+ int newlen;
+ char *oldspace;
+ int oldlen;
+ struct stack_block *sp;
+ struct stack_block *oldstackp;
+
+ if (min < stacknleft)
+ min = stacknleft;
+ if ((unsigned int)min >=
+ INT_MAX / 2 - ALIGN(sizeof(struct stack_block)))
+ error("Out of space");
+ min += stacknleft;
+ min += ALIGN(sizeof(struct stack_block));
+ newlen = 512;
+ while (newlen < min)
+ newlen <<= 1;
+ oldspace = stacknxt;
+ oldlen = stacknleft;
+
+ if (stackp != NULL && stacknxt == SPACE(stackp)) {
+ INTOFF;
+ oldstackp = stackp;
+ stackp = oldstackp->prev;
+ sp = ckrealloc((pointer)oldstackp, newlen);
+ sp->prev = stackp;
+ stackp = sp;
+ stacknxt = SPACE(sp);
+ stacknleft = newlen - (stacknxt - (char*)sp);
+ sstrend = stacknxt + stacknleft;
+ INTON;
+ } else {
+ newlen -= ALIGN(sizeof(struct stack_block));
+ p = stalloc(newlen);
+ if (oldlen != 0)
+ memcpy(p, oldspace, oldlen);
+ stunalloc(p);
+ }
+}
+
+
+
+/*
+ * The following routines are somewhat easier to use that the above.
+ * The user declares a variable of type STACKSTR, which may be declared
+ * to be a register. The macro STARTSTACKSTR initializes things. Then
+ * the user uses the macro STPUTC to add characters to the string. In
+ * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
+ * grown as necessary. When the user is done, she can just leave the
+ * string there and refer to it using stackblock(). Or she can allocate
+ * the space for it using grabstackstr(). If it is necessary to allow
+ * someone else to use the stack temporarily and then continue to grow
+ * the string, the user should use grabstack to allocate the space, and
+ * then call ungrabstr(p) to return to the previous mode of operation.
+ *
+ * USTPUTC is like STPUTC except that it doesn't check for overflow.
+ * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
+ * is space for at least one character.
+ */
+
+static char *
+growstrstackblock(int n, int min)
+{
+ growstackblock(min);
+ return stackblock() + n;
+}
+
+char *
+growstackstr(void)
+{
+ int len;
+
+ len = stackblocksize();
+ return (growstrstackblock(len, 0));
+}
+
+
+/*
+ * Called from CHECKSTRSPACE.
+ */
+
+char *
+makestrspace(int min, char *p)
+{
+ int len;
+
+ len = p - stackblock();
+ return (growstrstackblock(len, min));
+}
+
+
+char *
+stputbin(const char *data, size_t len, char *p)
+{
+ CHECKSTRSPACE(len, p);
+ memcpy(p, data, len);
+ return (p + len);
+}
+
+char *
+stputs(const char *data, char *p)
+{
+ return (stputbin(data, strlen(data), p));
+}
diff --git a/shell_cmds/sh/memalloc.h b/shell_cmds/sh/memalloc.h
new file mode 100644
index 0000000..180abfd
--- /dev/null
+++ b/shell_cmds/sh/memalloc.h
@@ -0,0 +1,88 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)memalloc.h 8.2 (Berkeley) 5/4/95
+ * $FreeBSD: head/bin/sh/memalloc.h 326025 2017-11-20 19:49:47Z pfg $
+ */
+
+#include <string.h>
+
+struct stackmark {
+ struct stack_block *stackp;
+ char *stacknxt;
+ int stacknleft;
+};
+
+
+extern char *stacknxt;
+extern int stacknleft;
+extern char *sstrend;
+
+pointer ckmalloc(size_t);
+pointer ckrealloc(pointer, int);
+void ckfree(pointer);
+char *savestr(const char *);
+pointer stalloc(int);
+void stunalloc(pointer);
+char *stsavestr(const char *);
+void setstackmark(struct stackmark *);
+void popstackmark(struct stackmark *);
+char *growstackstr(void);
+char *makestrspace(int, char *);
+char *stputbin(const char *data, size_t len, char *p);
+char *stputs(const char *data, char *p);
+
+
+
+#define stackblock() stacknxt
+#define stackblocksize() stacknleft
+#define grabstackblock(n) stalloc(n)
+#define STARTSTACKSTR(p) p = stackblock()
+#define STPUTC(c, p) do { if (p == sstrend) p = growstackstr(); *p++ = (c); } while(0)
+#define CHECKSTRSPACE(n, p) { if ((size_t)(sstrend - p) < n) p = makestrspace(n, p); }
+#define USTPUTC(c, p) (*p++ = (c))
+/*
+ * STACKSTRNUL's use is where we want to be able to turn a stack
+ * (non-sentinel, character counting string) into a C string,
+ * and later pretend the NUL is not there.
+ * Note: Because of STACKSTRNUL's semantics, STACKSTRNUL cannot be used
+ * on a stack that will grabstackstr()ed.
+ */
+#define STACKSTRNUL(p) (p == sstrend ? (p = growstackstr(), *p = '\0') : (*p = '\0'))
+#define STUNPUTC(p) (--p)
+#define STTOPC(p) p[-1]
+#define STADJUST(amount, p) (p += (amount))
+#define grabstackstr(p) stalloc((char *)p - stackblock())
+#define ungrabstackstr(s, p) stunalloc((s))
+#define STPUTBIN(s, len, p) p = stputbin((s), (len), p)
+#define STPUTS(s, p) p = stputs((s), p)
diff --git a/shell_cmds/sh/miscbltin.c b/shell_cmds/sh/miscbltin.c
new file mode 100644
index 0000000..52a810a
--- /dev/null
+++ b/shell_cmds/sh/miscbltin.c
@@ -0,0 +1,534 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)miscbltin.c 8.4 (Berkeley) 5/4/95";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/bin/sh/miscbltin.c 326025 2017-11-20 19:49:47Z pfg $");
+
+/*
+ * Miscellaneous builtins.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "shell.h"
+#include "options.h"
+#include "var.h"
+#include "output.h"
+#include "memalloc.h"
+#include "error.h"
+#include "mystring.h"
+#include "syntax.h"
+#include "trap.h"
+
+#undef eflag
+
+int readcmd(int, char **);
+int umaskcmd(int, char **);
+int ulimitcmd(int, char **);
+
+/*
+ * The read builtin. The -r option causes backslashes to be treated like
+ * ordinary characters.
+ *
+ * This uses unbuffered input, which may be avoidable in some cases.
+ *
+ * Note that if IFS=' :' then read x y should work so that:
+ * 'a b' x='a', y='b'
+ * ' a b ' x='a', y='b'
+ * ':b' x='', y='b'
+ * ':' x='', y=''
+ * '::' x='', y=''
+ * ': :' x='', y=''
+ * ':::' x='', y='::'
+ * ':b c:' x='', y='b c:'
+ */
+
+int
+readcmd(int argc __unused, char **argv __unused)
+{
+ char **ap;
+ int backslash;
+ char c;
+ int rflag;
+ char *prompt;
+ const char *ifs;
+ char *p;
+ int startword;
+ int status;
+ int i;
+ int is_ifs;
+ int saveall = 0;
+ ptrdiff_t lastnonifs, lastnonifsws;
+ struct timeval tv;
+ char *tvptr;
+ fd_set ifds;
+ ssize_t nread;
+ int sig;
+
+ rflag = 0;
+ prompt = NULL;
+ tv.tv_sec = -1;
+ tv.tv_usec = 0;
+ while ((i = nextopt("erp:t:")) != '\0') {
+ switch(i) {
+ case 'p':
+ prompt = shoptarg;
+ break;
+ case 'e':
+ break;
+ case 'r':
+ rflag = 1;
+ break;
+ case 't':
+ tv.tv_sec = strtol(shoptarg, &tvptr, 0);
+ if (tvptr == shoptarg)
+ error("timeout value");
+ switch(*tvptr) {
+ case 0:
+ case 's':
+ break;
+ case 'h':
+ tv.tv_sec *= 60;
+ /* FALLTHROUGH */
+ case 'm':
+ tv.tv_sec *= 60;
+ break;
+ default:
+ error("timeout unit");
+ }
+ break;
+ }
+ }
+ if (prompt && isatty(0)) {
+ out2str(prompt);
+ flushall();
+ }
+ if (*(ap = argptr) == NULL)
+ error("arg count");
+ if ((ifs = bltinlookup("IFS", 1)) == NULL)
+ ifs = " \t\n";
+
+ if (tv.tv_sec >= 0) {
+ /*
+ * Wait for something to become available.
+ */
+ FD_ZERO(&ifds);
+ FD_SET(0, &ifds);
+ status = select(1, &ifds, NULL, NULL, &tv);
+ /*
+ * If there's nothing ready, return an error.
+ */
+ if (status <= 0) {
+ sig = pendingsig;
+ return (128 + (sig != 0 ? sig : SIGALRM));
+ }
+ }
+
+ status = 0;
+ startword = 2;
+ backslash = 0;
+ STARTSTACKSTR(p);
+ lastnonifs = lastnonifsws = -1;
+ for (;;) {
+ nread = read(STDIN_FILENO, &c, 1);
+ if (nread == -1) {
+ if (errno == EINTR) {
+ sig = pendingsig;
+ if (sig == 0)
+ continue;
+ status = 128 + sig;
+ break;
+ }
+ warning("read error: %s", strerror(errno));
+ status = 2;
+ break;
+ } else if (nread != 1) {
+ status = 1;
+ break;
+ }
+ if (c == '\0')
+ continue;
+ CHECKSTRSPACE(1, p);
+ if (backslash) {
+ backslash = 0;
+ if (c != '\n') {
+ startword = 0;
+ lastnonifs = lastnonifsws = p - stackblock();
+ USTPUTC(c, p);
+ }
+ continue;
+ }
+ if (!rflag && c == '\\') {
+ backslash++;
+ continue;
+ }
+ if (c == '\n')
+ break;
+ if (strchr(ifs, c))
+ is_ifs = strchr(" \t\n", c) ? 1 : 2;
+ else
+ is_ifs = 0;
+
+ if (startword != 0) {
+ if (is_ifs == 1) {
+ /* Ignore leading IFS whitespace */
+ if (saveall)
+ USTPUTC(c, p);
+ continue;
+ }
+ if (is_ifs == 2 && startword == 1) {
+ /* Only one non-whitespace IFS per word */
+ startword = 2;
+ if (saveall) {
+ lastnonifsws = p - stackblock();
+ USTPUTC(c, p);
+ }
+ continue;
+ }
+ }
+
+ if (is_ifs == 0) {
+ /* append this character to the current variable */
+ startword = 0;
+ if (saveall)
+ /* Not just a spare terminator */
+ saveall++;
+ lastnonifs = lastnonifsws = p - stackblock();
+ USTPUTC(c, p);
+ continue;
+ }
+
+ /* end of variable... */
+ startword = is_ifs;
+
+ if (ap[1] == NULL) {
+ /* Last variable needs all IFS chars */
+ saveall++;
+ if (is_ifs == 2)
+ lastnonifsws = p - stackblock();
+ USTPUTC(c, p);
+ continue;
+ }
+
+ STACKSTRNUL(p);
+ setvar(*ap, stackblock(), 0);
+ ap++;
+ STARTSTACKSTR(p);
+ lastnonifs = lastnonifsws = -1;
+ }
+ STACKSTRNUL(p);
+
+ /*
+ * Remove trailing IFS chars: always remove whitespace, don't remove
+ * non-whitespace unless it was naked
+ */
+ if (saveall <= 1)
+ lastnonifsws = lastnonifs;
+ stackblock()[lastnonifsws + 1] = '\0';
+ setvar(*ap, stackblock(), 0);
+
+ /* Set any remaining args to "" */
+ while (*++ap != NULL)
+ setvar(*ap, "", 0);
+ return status;
+}
+
+
+
+int
+umaskcmd(int argc __unused, char **argv __unused)
+{
+ char *ap;
+ int mask;
+ int i;
+ int symbolic_mode = 0;
+
+ while ((i = nextopt("S")) != '\0') {
+ symbolic_mode = 1;
+ }
+
+ INTOFF;
+ mask = umask(0);
+ umask(mask);
+ INTON;
+
+ if ((ap = *argptr) == NULL) {
+ if (symbolic_mode) {
+ char u[4], g[4], o[4];
+
+ i = 0;
+ if ((mask & S_IRUSR) == 0)
+ u[i++] = 'r';
+ if ((mask & S_IWUSR) == 0)
+ u[i++] = 'w';
+ if ((mask & S_IXUSR) == 0)
+ u[i++] = 'x';
+ u[i] = '\0';
+
+ i = 0;
+ if ((mask & S_IRGRP) == 0)
+ g[i++] = 'r';
+ if ((mask & S_IWGRP) == 0)
+ g[i++] = 'w';
+ if ((mask & S_IXGRP) == 0)
+ g[i++] = 'x';
+ g[i] = '\0';
+
+ i = 0;
+ if ((mask & S_IROTH) == 0)
+ o[i++] = 'r';
+ if ((mask & S_IWOTH) == 0)
+ o[i++] = 'w';
+ if ((mask & S_IXOTH) == 0)
+ o[i++] = 'x';
+ o[i] = '\0';
+
+ out1fmt("u=%s,g=%s,o=%s\n", u, g, o);
+ } else {
+ out1fmt("%.4o\n", mask);
+ }
+ } else {
+ if (is_digit(*ap)) {
+ mask = 0;
+ do {
+ if (*ap >= '8' || *ap < '0')
+ error("Illegal number: %s", *argptr);
+ mask = (mask << 3) + (*ap - '0');
+ } while (*++ap != '\0');
+ umask(mask);
+ } else {
+ void *set;
+ INTOFF;
+ if ((set = setmode (ap)) == NULL)
+ error("Illegal number: %s", ap);
+
+ mask = getmode (set, ~mask & 0777);
+ umask(~mask & 0777);
+ free(set);
+ INTON;
+ }
+ }
+ return 0;
+}
+
+/*
+ * ulimit builtin
+ *
+ * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
+ * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
+ * ash by J.T. Conklin.
+ *
+ * Public domain.
+ */
+
+struct limits {
+ const char *name;
+ const char *units;
+ int cmd;
+ short factor; /* multiply by to get rlim_{cur,max} values */
+ char option;
+};
+
+static const struct limits limits[] = {
+#ifdef RLIMIT_CPU
+ { "cpu time", "seconds", RLIMIT_CPU, 1, 't' },
+#endif
+#ifdef RLIMIT_FSIZE
+ { "file size", "512-blocks", RLIMIT_FSIZE, 512, 'f' },
+#endif
+#ifdef RLIMIT_DATA
+ { "data seg size", "kbytes", RLIMIT_DATA, 1024, 'd' },
+#endif
+#ifdef RLIMIT_STACK
+ { "stack size", "kbytes", RLIMIT_STACK, 1024, 's' },
+#endif
+#ifdef RLIMIT_CORE
+ { "core file size", "512-blocks", RLIMIT_CORE, 512, 'c' },
+#endif
+#ifdef RLIMIT_RSS
+ { "max memory size", "kbytes", RLIMIT_RSS, 1024, 'm' },
+#endif
+#ifdef RLIMIT_MEMLOCK
+ { "locked memory", "kbytes", RLIMIT_MEMLOCK, 1024, 'l' },
+#endif
+#ifdef RLIMIT_NPROC
+ { "max user processes", (char *)0, RLIMIT_NPROC, 1, 'u' },
+#endif
+#ifdef RLIMIT_NOFILE
+ { "open files", (char *)0, RLIMIT_NOFILE, 1, 'n' },
+#endif
+#ifdef RLIMIT_VMEM
+ { "virtual mem size", "kbytes", RLIMIT_VMEM, 1024, 'v' },
+#endif
+#ifdef RLIMIT_SWAP
+ { "swap limit", "kbytes", RLIMIT_SWAP, 1024, 'w' },
+#endif
+#ifdef RLIMIT_SBSIZE
+ { "socket buffer size", "bytes", RLIMIT_SBSIZE, 1, 'b' },
+#endif
+#ifdef RLIMIT_NPTS
+ { "pseudo-terminals", (char *)0, RLIMIT_NPTS, 1, 'p' },
+#endif
+#ifdef RLIMIT_KQUEUES
+ { "kqueues", (char *)0, RLIMIT_KQUEUES, 1, 'k' },
+#endif
+#ifdef RLIMIT_UMTXP
+ { "umtx shared locks", (char *)0, RLIMIT_UMTXP, 1, 'o' },
+#endif
+ { (char *) 0, (char *)0, 0, 0, '\0' }
+};
+
+enum limithow { SOFT = 0x1, HARD = 0x2 };
+
+static void
+printlimit(enum limithow how, const struct rlimit *limit,
+ const struct limits *l)
+{
+ rlim_t val = 0;
+
+ if (how & SOFT)
+ val = limit->rlim_cur;
+ else if (how & HARD)
+ val = limit->rlim_max;
+ if (val == RLIM_INFINITY)
+ out1str("unlimited\n");
+ else
+ {
+ val /= l->factor;
+ out1fmt("%jd\n", (intmax_t)val);
+ }
+}
+
+int
+ulimitcmd(int argc __unused, char **argv __unused)
+{
+ rlim_t val = 0;
+ enum limithow how = SOFT | HARD;
+ const struct limits *l;
+ int set, all = 0;
+ int optc, what;
+ struct rlimit limit;
+
+ what = 'f';
+ while ((optc = nextopt("HSatfdsmcnuvlbpwko")) != '\0')
+ switch (optc) {
+ case 'H':
+ how = HARD;
+ break;
+ case 'S':
+ how = SOFT;
+ break;
+ case 'a':
+ all = 1;
+ break;
+ default:
+ what = optc;
+ }
+
+ for (l = limits; l->name && l->option != what; l++)
+ ;
+ if (!l->name)
+ error("internal error (%c)", what);
+
+ set = *argptr ? 1 : 0;
+ if (set) {
+ char *p = *argptr;
+
+ if (all || argptr[1])
+ error("too many arguments");
+ if (strcmp(p, "unlimited") == 0)
+ val = RLIM_INFINITY;
+ else {
+ char *end;
+ uintmax_t uval;
+
+ if (*p < '0' || *p > '9')
+ error("bad number");
+ errno = 0;
+ uval = strtoumax(p, &end, 10);
+ if (errno != 0 || *end != '\0')
+ error("bad number");
+ if (uval > UINTMAX_MAX / l->factor)
+ error("bad number");
+ uval *= l->factor;
+ val = (rlim_t)uval;
+ if ((uintmax_t)val != uval ||
+ val == RLIM_INFINITY)
+ error("bad number");
+ }
+ }
+ if (all) {
+ for (l = limits; l->name; l++) {
+ char optbuf[40];
+ if (getrlimit(l->cmd, &limit) < 0)
+ error("can't get limit: %s", strerror(errno));
+
+ if (l->units)
+ snprintf(optbuf, sizeof(optbuf),
+ "(%s, -%c) ", l->units, l->option);
+ else
+ snprintf(optbuf, sizeof(optbuf),
+ "(-%c) ", l->option);
+ out1fmt("%-18s %18s ", l->name, optbuf);
+ printlimit(how, &limit, l);
+ }
+ return 0;
+ }
+
+ if (getrlimit(l->cmd, &limit) < 0)
+ error("can't get limit: %s", strerror(errno));
+ if (set) {
+ if (how & SOFT)
+ limit.rlim_cur = val;
+ if (how & HARD)
+ limit.rlim_max = val;
+ if (setrlimit(l->cmd, &limit) < 0)
+ error("bad limit: %s", strerror(errno));
+ } else
+ printlimit(how, &limit, l);
+ return 0;
+}
diff --git a/shell_cmds/sh/mkbuiltins b/shell_cmds/sh/mkbuiltins
new file mode 100755
index 0000000..7c2cef1
--- /dev/null
+++ b/shell_cmds/sh/mkbuiltins
@@ -0,0 +1,137 @@
+#!/bin/sh -
+
+#-
+# Copyright (c) 1991, 1993
+# The Regents of the University of California. All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Kenneth Almquist.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of the University nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# @(#)mkbuiltins 8.2 (Berkeley) 5/4/95
+# $FreeBSD: head/bin/sh/mkbuiltins 328934 2018-02-06 15:41:35Z arichardson $
+
+temp=`mktemp -t ka`
+havehist=1
+if [ "X$1" = "X-h" ]; then
+ havehist=0
+ shift
+fi
+srcdir=$1
+havejobs=0
+if grep '^#define[ ]*JOBS[ ]*1' $srcdir/shell.h > /dev/null
+then havejobs=1
+fi
+exec > builtins.c
+cat <<\!
+/*
+ * This file was generated by the mkbuiltins program.
+ */
+
+#include <stdlib.h>
+#include "shell.h"
+#include "builtins.h"
+
+!
+awk '/^[^#]/ {if(('$havejobs' || $2 != "-j") && ('$havehist' || $2 != "-h")) \
+ print $0}' $srcdir/builtins.def | sed 's/-[hj]//' > $temp
+echo 'int (*const builtinfunc[])(int, char **) = {'
+awk '/^[^#]/ { printf "\t%s,\n", $1}' $temp
+echo '};
+
+const unsigned char builtincmd[] = {'
+awk '{ for (i = 2 ; i <= NF ; i++) {
+ if ($i == "-s") {
+ spc = 1;
+ } else if ($i == "-n") {
+ # Handled later for builtins.h
+ continue
+ } else {
+ printf "\t\"\\%03o\\%03o%s\"\n", length($i), (spc ? 128 : 0) + NR-1, $i
+ spc = 0;
+ }
+ }}' $temp
+echo '};'
+
+exec > builtins.h
+cat <<\!
+/*
+ * This file was generated by the mkbuiltins program.
+ */
+
+#include <sys/cdefs.h>
+!
+tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ < $temp |
+ awk '{ printf "#define %s %d\n", $1, NR-1}'
+echo '
+#define BUILTIN_SPECIAL 0x80
+
+extern int (*const builtinfunc[])(int, char **);
+extern const unsigned char builtincmd[];
+'
+awk '{ printf "int %s(int, char **);\n", $1}' $temp
+
+# Build safe_builtin_always()
+cat <<EOF
+
+static inline int
+safe_builtin_always(int idx)
+{
+EOF
+awk '
+BEGIN { printed = 0 }
+{
+ for (i = 2 ; i <= NF ; i++) {
+ if ($i == "-s") {
+ continue
+ } else if ($i == "-n") {
+ nofork = 1;
+ } else {
+ if (nofork == 0) {
+ continue
+ }
+ if (printed == 1) {
+ printf " || \n\t "
+ } else {
+ printf "\tif ("
+ }
+ printf "idx == " toupper($1)
+ printed = 1
+ nofork = 0;
+ # Only need to check each once
+ break
+ }
+ }
+}' $temp
+
+cat << EOF
+)
+ return (1);
+ return(0);
+}
+EOF
+
+rm -f $temp
diff --git a/shell_cmds/sh/mknodes.c b/shell_cmds/sh/mknodes.c
new file mode 100644
index 0000000..f289890
--- /dev/null
+++ b/shell_cmds/sh/mknodes.c
@@ -0,0 +1,467 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static char const copyright[] =
+"@(#) Copyright (c) 1991, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)mknodes.c 8.2 (Berkeley) 5/4/95";
+#endif /* not lint */
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/bin/sh/mknodes.c 326025 2017-11-20 19:49:47Z pfg $");
+
+/*
+ * This program reads the nodetypes file and nodes.c.pat file. It generates
+ * the files nodes.h and nodes.c.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdarg.h>
+
+// When building for iOS, we don't have a new enough OS X SDK.
+#ifndef __printf0like
+#define __printf0like(fmtarg, firstvararg) \
+__attribute__((__format__ (__printf0__, fmtarg, firstvararg)))
+#endif
+
+#define MAXTYPES 50 /* max number of node types */
+#define MAXFIELDS 20 /* max fields in a structure */
+#define BUFLEN 100 /* size of character buffers */
+
+/* field types */
+#define T_NODE 1 /* union node *field */
+#define T_NODELIST 2 /* struct nodelist *field */
+#define T_STRING 3
+#define T_INT 4 /* int field */
+#define T_OTHER 5 /* other */
+#define T_TEMP 6 /* don't copy this field */
+
+
+struct field { /* a structure field */
+ char *name; /* name of field */
+ int type; /* type of field */
+ char *decl; /* declaration of field */
+};
+
+
+struct str { /* struct representing a node structure */
+ char *tag; /* structure tag */
+ int nfields; /* number of fields in the structure */
+ struct field field[MAXFIELDS]; /* the fields of the structure */
+ int done; /* set if fully parsed */
+};
+
+
+static int ntypes; /* number of node types */
+static char *nodename[MAXTYPES]; /* names of the nodes */
+static struct str *nodestr[MAXTYPES]; /* type of structure used by the node */
+static int nstr; /* number of structures */
+static struct str str[MAXTYPES]; /* the structures */
+static struct str *curstr; /* current structure */
+static char line[1024];
+static int linno;
+static char *linep;
+
+static void parsenode(void);
+static void parsefield(void);
+static void output(char *);
+static void outsizes(FILE *);
+static void outfunc(FILE *, int);
+static void indent(int, FILE *);
+static int nextfield(char *);
+static void skipbl(void);
+static int readline(FILE *);
+static void error(const char *, ...) __printf0like(1, 2) __dead2;
+static char *savestr(const char *);
+
+
+int
+main(int argc, char *argv[])
+{
+ FILE *infp;
+
+ if (argc != 3)
+ error("usage: mknodes file");
+ if ((infp = fopen(argv[1], "r")) == NULL)
+ error("Can't open %s: %s", argv[1], strerror(errno));
+ while (readline(infp)) {
+ if (line[0] == ' ' || line[0] == '\t')
+ parsefield();
+ else if (line[0] != '\0')
+ parsenode();
+ }
+ fclose(infp);
+ output(argv[2]);
+ exit(0);
+}
+
+
+
+static void
+parsenode(void)
+{
+ char name[BUFLEN];
+ char tag[BUFLEN];
+ struct str *sp;
+
+ if (curstr && curstr->nfields > 0)
+ curstr->done = 1;
+ nextfield(name);
+ if (! nextfield(tag))
+ error("Tag expected");
+ if (*linep != '\0')
+ error("Garbage at end of line");
+ nodename[ntypes] = savestr(name);
+ for (sp = str ; sp < str + nstr ; sp++) {
+ if (strcmp(sp->tag, tag) == 0)
+ break;
+ }
+ if (sp >= str + nstr) {
+ sp->tag = savestr(tag);
+ sp->nfields = 0;
+ curstr = sp;
+ nstr++;
+ }
+ nodestr[ntypes] = sp;
+ ntypes++;
+}
+
+
+static void
+parsefield(void)
+{
+ char name[BUFLEN];
+ char type[BUFLEN];
+ char decl[2 * BUFLEN];
+ struct field *fp;
+
+ if (curstr == NULL || curstr->done)
+ error("No current structure to add field to");
+ if (! nextfield(name))
+ error("No field name");
+ if (! nextfield(type))
+ error("No field type");
+ fp = &curstr->field[curstr->nfields];
+ fp->name = savestr(name);
+ if (strcmp(type, "nodeptr") == 0) {
+ fp->type = T_NODE;
+ sprintf(decl, "union node *%s", name);
+ } else if (strcmp(type, "nodelist") == 0) {
+ fp->type = T_NODELIST;
+ sprintf(decl, "struct nodelist *%s", name);
+ } else if (strcmp(type, "string") == 0) {
+ fp->type = T_STRING;
+ sprintf(decl, "char *%s", name);
+ } else if (strcmp(type, "int") == 0) {
+ fp->type = T_INT;
+ sprintf(decl, "int %s", name);
+ } else if (strcmp(type, "other") == 0) {
+ fp->type = T_OTHER;
+ } else if (strcmp(type, "temp") == 0) {
+ fp->type = T_TEMP;
+ } else {
+ error("Unknown type %s", type);
+ }
+ if (fp->type == T_OTHER || fp->type == T_TEMP) {
+ skipbl();
+ fp->decl = savestr(linep);
+ } else {
+ if (*linep)
+ error("Garbage at end of line");
+ fp->decl = savestr(decl);
+ }
+ curstr->nfields++;
+}
+
+
+static const char writer[] = "\
+/*\n\
+ * This file was generated by the mknodes program.\n\
+ */\n\
+\n";
+
+static void
+output(char *file)
+{
+ FILE *hfile;
+ FILE *cfile;
+ FILE *patfile;
+ int i;
+ struct str *sp;
+ struct field *fp;
+ char *p;
+
+ if ((patfile = fopen(file, "r")) == NULL)
+ error("Can't open %s: %s", file, strerror(errno));
+ if ((hfile = fopen("nodes.h", "w")) == NULL)
+ error("Can't create nodes.h: %s", strerror(errno));
+ if ((cfile = fopen("nodes.c", "w")) == NULL)
+ error("Can't create nodes.c");
+ fputs(writer, hfile);
+ for (i = 0 ; i < ntypes ; i++)
+ fprintf(hfile, "#define %s %d\n", nodename[i], i);
+ fputs("\n\n\n", hfile);
+ for (sp = str ; sp < &str[nstr] ; sp++) {
+ fprintf(hfile, "struct %s {\n", sp->tag);
+ for (i = sp->nfields, fp = sp->field ; --i >= 0 ; fp++) {
+ fprintf(hfile, " %s;\n", fp->decl);
+ }
+ fputs("};\n\n\n", hfile);
+ }
+ fputs("union node {\n", hfile);
+ fprintf(hfile, " int type;\n");
+ for (sp = str ; sp < &str[nstr] ; sp++) {
+ fprintf(hfile, " struct %s %s;\n", sp->tag, sp->tag);
+ }
+ fputs("};\n\n\n", hfile);
+ fputs("struct nodelist {\n", hfile);
+ fputs("\tstruct nodelist *next;\n", hfile);
+ fputs("\tunion node *n;\n", hfile);
+ fputs("};\n\n\n", hfile);
+ fputs("struct funcdef;\n", hfile);
+ fputs("struct funcdef *copyfunc(union node *);\n", hfile);
+ fputs("union node *getfuncnode(struct funcdef *);\n", hfile);
+ fputs("void reffunc(struct funcdef *);\n", hfile);
+ fputs("void unreffunc(struct funcdef *);\n", hfile);
+ if (ferror(hfile))
+ error("Can't write to nodes.h");
+ if (fclose(hfile))
+ error("Can't close nodes.h");
+
+ fputs(writer, cfile);
+ while (fgets(line, sizeof line, patfile) != NULL) {
+ for (p = line ; *p == ' ' || *p == '\t' ; p++);
+ if (strcmp(p, "%SIZES\n") == 0)
+ outsizes(cfile);
+ else if (strcmp(p, "%CALCSIZE\n") == 0)
+ outfunc(cfile, 1);
+ else if (strcmp(p, "%COPY\n") == 0)
+ outfunc(cfile, 0);
+ else
+ fputs(line, cfile);
+ }
+ fclose(patfile);
+ if (ferror(cfile))
+ error("Can't write to nodes.c");
+ if (fclose(cfile))
+ error("Can't close nodes.c");
+}
+
+
+
+static void
+outsizes(FILE *cfile)
+{
+ int i;
+
+ fprintf(cfile, "static const short nodesize[%d] = {\n", ntypes);
+ for (i = 0 ; i < ntypes ; i++) {
+ fprintf(cfile, " ALIGN(sizeof (struct %s)),\n", nodestr[i]->tag);
+ }
+ fprintf(cfile, "};\n");
+}
+
+
+static void
+outfunc(FILE *cfile, int calcsize)
+{
+ struct str *sp;
+ struct field *fp;
+ int i;
+
+ fputs(" if (n == NULL)\n", cfile);
+ if (calcsize)
+ fputs(" return;\n", cfile);
+ else
+ fputs(" return NULL;\n", cfile);
+ if (calcsize)
+ fputs(" result->blocksize += nodesize[n->type];\n", cfile);
+ else {
+ fputs(" new = state->block;\n", cfile);
+ fputs(" state->block = (char *)state->block + nodesize[n->type];\n", cfile);
+ }
+ fputs(" switch (n->type) {\n", cfile);
+ for (sp = str ; sp < &str[nstr] ; sp++) {
+ for (i = 0 ; i < ntypes ; i++) {
+ if (nodestr[i] == sp)
+ fprintf(cfile, " case %s:\n", nodename[i]);
+ }
+ for (i = sp->nfields ; --i >= 1 ; ) {
+ fp = &sp->field[i];
+ switch (fp->type) {
+ case T_NODE:
+ if (calcsize) {
+ indent(12, cfile);
+ fprintf(cfile, "calcsize(n->%s.%s, result);\n",
+ sp->tag, fp->name);
+ } else {
+ indent(12, cfile);
+ fprintf(cfile, "new->%s.%s = copynode(n->%s.%s, state);\n",
+ sp->tag, fp->name, sp->tag, fp->name);
+ }
+ break;
+ case T_NODELIST:
+ if (calcsize) {
+ indent(12, cfile);
+ fprintf(cfile, "sizenodelist(n->%s.%s, result);\n",
+ sp->tag, fp->name);
+ } else {
+ indent(12, cfile);
+ fprintf(cfile, "new->%s.%s = copynodelist(n->%s.%s, state);\n",
+ sp->tag, fp->name, sp->tag, fp->name);
+ }
+ break;
+ case T_STRING:
+ if (calcsize) {
+ indent(12, cfile);
+ fprintf(cfile, "result->stringsize += strlen(n->%s.%s) + 1;\n",
+ sp->tag, fp->name);
+ } else {
+ indent(12, cfile);
+ fprintf(cfile, "new->%s.%s = nodesavestr(n->%s.%s, state);\n",
+ sp->tag, fp->name, sp->tag, fp->name);
+ }
+ break;
+ case T_INT:
+ case T_OTHER:
+ if (! calcsize) {
+ indent(12, cfile);
+ fprintf(cfile, "new->%s.%s = n->%s.%s;\n",
+ sp->tag, fp->name, sp->tag, fp->name);
+ }
+ break;
+ }
+ }
+ indent(12, cfile);
+ fputs("break;\n", cfile);
+ }
+ fputs(" };\n", cfile);
+ if (! calcsize)
+ fputs(" new->type = n->type;\n", cfile);
+}
+
+
+static void
+indent(int amount, FILE *fp)
+{
+ while (amount >= 8) {
+ putc('\t', fp);
+ amount -= 8;
+ }
+ while (--amount >= 0) {
+ putc(' ', fp);
+ }
+}
+
+
+static int
+nextfield(char *buf)
+{
+ char *p, *q;
+
+ p = linep;
+ while (*p == ' ' || *p == '\t')
+ p++;
+ q = buf;
+ while (*p != ' ' && *p != '\t' && *p != '\0')
+ *q++ = *p++;
+ *q = '\0';
+ linep = p;
+ return (q > buf);
+}
+
+
+static void
+skipbl(void)
+{
+ while (*linep == ' ' || *linep == '\t')
+ linep++;
+}
+
+
+static int
+readline(FILE *infp)
+{
+ char *p;
+
+ if (fgets(line, 1024, infp) == NULL)
+ return 0;
+ for (p = line ; *p != '#' && *p != '\n' && *p != '\0' ; p++);
+ while (p > line && (p[-1] == ' ' || p[-1] == '\t'))
+ p--;
+ *p = '\0';
+ linep = line;
+ linno++;
+ if (p - line > BUFLEN)
+ error("Line too long");
+ return 1;
+}
+
+
+
+static void
+error(const char *msg, ...)
+{
+ va_list va;
+ va_start(va, msg);
+
+ (void) fprintf(stderr, "line %d: ", linno);
+ (void) vfprintf(stderr, msg, va);
+ (void) fputc('\n', stderr);
+
+ va_end(va);
+
+ exit(2);
+}
+
+
+
+static char *
+savestr(const char *s)
+{
+ char *p;
+
+ if ((p = malloc(strlen(s) + 1)) == NULL)
+ error("Out of space");
+ (void) strcpy(p, s);
+ return p;
+}
diff --git a/shell_cmds/sh/mksyntax.c b/shell_cmds/sh/mksyntax.c
new file mode 100644
index 0000000..52c5631
--- /dev/null
+++ b/shell_cmds/sh/mksyntax.c
@@ -0,0 +1,331 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static char const copyright[] =
+"@(#) Copyright (c) 1991, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)mksyntax.c 8.2 (Berkeley) 5/4/95";
+#endif /* not lint */
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/bin/sh/mksyntax.c 326025 2017-11-20 19:49:47Z pfg $");
+
+/*
+ * This program creates syntax.h and syntax.c.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "parser.h"
+
+
+struct synclass {
+ const char *name;
+ const char *comment;
+};
+
+/* Syntax classes */
+static const struct synclass synclass[] = {
+ { "CWORD", "character is nothing special" },
+ { "CNL", "newline character" },
+ { "CBACK", "a backslash character" },
+ { "CSBACK", "a backslash character in single quotes" },
+ { "CSQUOTE", "single quote" },
+ { "CDQUOTE", "double quote" },
+ { "CENDQUOTE", "a terminating quote" },
+ { "CBQUOTE", "backwards single quote" },
+ { "CVAR", "a dollar sign" },
+ { "CENDVAR", "a '}' character" },
+ { "CLP", "a left paren in arithmetic" },
+ { "CRP", "a right paren in arithmetic" },
+ { "CEOF", "end of file" },
+ { "CCTL", "like CWORD, except it must be escaped" },
+ { "CSPCL", "these terminate a word" },
+ { "CIGN", "character should be ignored" },
+ { NULL, NULL }
+};
+
+
+/*
+ * Syntax classes for is_ functions. Warning: if you add new classes
+ * you may have to change the definition of the is_in_name macro.
+ */
+static const struct synclass is_entry[] = {
+ { "ISDIGIT", "a digit" },
+ { "ISUPPER", "an upper case letter" },
+ { "ISLOWER", "a lower case letter" },
+ { "ISUNDER", "an underscore" },
+ { "ISSPECL", "the name of a special parameter" },
+ { NULL, NULL }
+};
+
+static const char writer[] = "\
+/*\n\
+ * This file was generated by the mksyntax program.\n\
+ */\n\
+\n";
+
+
+static FILE *cfile;
+static FILE *hfile;
+
+static void add_default(void);
+static void finish(void);
+static void init(const char *);
+static void add(const char *, const char *);
+static void output_type_macros(void);
+
+int
+main(int argc __unused, char **argv __unused)
+{
+ int i;
+ char buf[80];
+ int pos;
+
+ /* Create output files */
+ if ((cfile = fopen("syntax.c", "w")) == NULL) {
+ perror("syntax.c");
+ exit(2);
+ }
+ if ((hfile = fopen("syntax.h", "w")) == NULL) {
+ perror("syntax.h");
+ exit(2);
+ }
+ fputs(writer, hfile);
+ fputs(writer, cfile);
+
+ fputs("#include <sys/cdefs.h>\n", hfile);
+ fputs("#include <limits.h>\n\n", hfile);
+
+ /* Generate the #define statements in the header file */
+ fputs("/* Syntax classes */\n", hfile);
+ for (i = 0 ; synclass[i].name ; i++) {
+ sprintf(buf, "#define %s %d", synclass[i].name, i);
+ fputs(buf, hfile);
+ for (pos = strlen(buf) ; pos < 32 ; pos = (pos + 8) & ~07)
+ putc('\t', hfile);
+ fprintf(hfile, "/* %s */\n", synclass[i].comment);
+ }
+ putc('\n', hfile);
+ fputs("/* Syntax classes for is_ functions */\n", hfile);
+ for (i = 0 ; is_entry[i].name ; i++) {
+ sprintf(buf, "#define %s %#o", is_entry[i].name, 1 << i);
+ fputs(buf, hfile);
+ for (pos = strlen(buf) ; pos < 32 ; pos = (pos + 8) & ~07)
+ putc('\t', hfile);
+ fprintf(hfile, "/* %s */\n", is_entry[i].comment);
+ }
+ putc('\n', hfile);
+ fputs("#define SYNBASE (1 - CHAR_MIN)\n", hfile);
+ fputs("#define PEOF -SYNBASE\n\n", hfile);
+ putc('\n', hfile);
+ fputs("#define BASESYNTAX (basesyntax + SYNBASE)\n", hfile);
+ fputs("#define DQSYNTAX (dqsyntax + SYNBASE)\n", hfile);
+ fputs("#define SQSYNTAX (sqsyntax + SYNBASE)\n", hfile);
+ fputs("#define ARISYNTAX (arisyntax + SYNBASE)\n", hfile);
+ putc('\n', hfile);
+ output_type_macros(); /* is_digit, etc. */
+ putc('\n', hfile);
+
+ /* Generate the syntax tables. */
+ fputs("#include \"parser.h\"\n", cfile);
+ fputs("#include \"shell.h\"\n", cfile);
+ fputs("#include \"syntax.h\"\n\n", cfile);
+
+ fputs("/* syntax table used when not in quotes */\n", cfile);
+ init("basesyntax");
+ add_default();
+ add("\n", "CNL");
+ add("\\", "CBACK");
+ add("'", "CSQUOTE");
+ add("\"", "CDQUOTE");
+ add("`", "CBQUOTE");
+ add("$", "CVAR");
+ add("}", "CENDVAR");
+ add("<>();&| \t", "CSPCL");
+ finish();
+
+ fputs("\n/* syntax table used when in double quotes */\n", cfile);
+ init("dqsyntax");
+ add_default();
+ add("\n", "CNL");
+ add("\\", "CBACK");
+ add("\"", "CENDQUOTE");
+ add("`", "CBQUOTE");
+ add("$", "CVAR");
+ add("}", "CENDVAR");
+ /* ':/' for tilde expansion, '-^]' for [a\-x] pattern ranges */
+ add("!*?[]=~:/-^", "CCTL");
+ finish();
+
+ fputs("\n/* syntax table used when in single quotes */\n", cfile);
+ init("sqsyntax");
+ add_default();
+ add("\n", "CNL");
+ add("\\", "CSBACK");
+ add("'", "CENDQUOTE");
+ /* ':/' for tilde expansion, '-^]' for [a\-x] pattern ranges */
+ add("!*?[]=~:/-^", "CCTL");
+ finish();
+
+ fputs("\n/* syntax table used when in arithmetic */\n", cfile);
+ init("arisyntax");
+ add_default();
+ add("\n", "CNL");
+ add("\\", "CBACK");
+ add("`", "CBQUOTE");
+ add("\"", "CIGN");
+ add("$", "CVAR");
+ add("}", "CENDVAR");
+ add("(", "CLP");
+ add(")", "CRP");
+ finish();
+
+ fputs("\n/* character classification table */\n", cfile);
+ init("is_type");
+ add("0123456789", "ISDIGIT");
+ add("abcdefghijklmnopqrstuvwxyz", "ISLOWER");
+ add("ABCDEFGHIJKLMNOPQRSTUVWXYZ", "ISUPPER");
+ add("_", "ISUNDER");
+ add("#?$!-*@", "ISSPECL");
+ finish();
+
+ exit(0);
+}
+
+
+/*
+ * Output the header and declaration of a syntax table.
+ */
+
+static void
+init(const char *name)
+{
+ fprintf(hfile, "extern const char %s[];\n", name);
+ fprintf(cfile, "const char %s[SYNBASE + CHAR_MAX + 1] = {\n", name);
+}
+
+
+static void
+add_one(const char *key, const char *type)
+{
+ fprintf(cfile, "\t[SYNBASE + %s] = %s,\n", key, type);
+}
+
+
+/*
+ * Add default values to the syntax table.
+ */
+
+static void
+add_default(void)
+{
+ add_one("PEOF", "CEOF");
+ add_one("CTLESC", "CCTL");
+ add_one("CTLVAR", "CCTL");
+ add_one("CTLENDVAR", "CCTL");
+ add_one("CTLBACKQ", "CCTL");
+ add_one("CTLBACKQ + CTLQUOTE", "CCTL");
+ add_one("CTLARI", "CCTL");
+ add_one("CTLENDARI", "CCTL");
+ add_one("CTLQUOTEMARK", "CCTL");
+ add_one("CTLQUOTEEND", "CCTL");
+}
+
+
+/*
+ * Output the footer of a syntax table.
+ */
+
+static void
+finish(void)
+{
+ fputs("};\n", cfile);
+}
+
+
+/*
+ * Add entries to the syntax table.
+ */
+
+static void
+add(const char *p, const char *type)
+{
+ for (; *p; ++p) {
+ char c = *p;
+ switch (c) {
+ case '\t': c = 't'; break;
+ case '\n': c = 'n'; break;
+ case '\'': c = '\''; break;
+ case '\\': c = '\\'; break;
+
+ default:
+ fprintf(cfile, "\t[SYNBASE + '%c'] = %s,\n", c, type);
+ continue;
+ }
+ fprintf(cfile, "\t[SYNBASE + '\\%c'] = %s,\n", c, type);
+ }
+}
+
+
+/*
+ * Output character classification macros (e.g. is_digit). If digits are
+ * contiguous, we can test for them quickly.
+ */
+
+static const char *macro[] = {
+ "#define is_digit(c)\t((unsigned int)((c) - '0') <= 9)",
+ "#define is_eof(c)\t((c) == PEOF)",
+ "#define is_alpha(c)\t((is_type+SYNBASE)[(int)c] & (ISUPPER|ISLOWER))",
+ "#define is_name(c)\t((is_type+SYNBASE)[(int)c] & (ISUPPER|ISLOWER|ISUNDER))",
+ "#define is_in_name(c)\t((is_type+SYNBASE)[(int)c] & (ISUPPER|ISLOWER|ISUNDER|ISDIGIT))",
+ "#define is_special(c)\t((is_type+SYNBASE)[(int)c] & (ISSPECL|ISDIGIT))",
+ "#define digit_val(c)\t((c) - '0')",
+ NULL
+};
+
+static void
+output_type_macros(void)
+{
+ const char **pp;
+
+ for (pp = macro ; *pp ; pp++)
+ fprintf(hfile, "%s\n", *pp);
+}
diff --git a/shell_cmds/sh/mktokens b/shell_cmds/sh/mktokens
new file mode 100644
index 0000000..98bcc26
--- /dev/null
+++ b/shell_cmds/sh/mktokens
@@ -0,0 +1,93 @@
+#!/bin/sh -
+
+#-
+# Copyright (c) 1991, 1993
+# The Regents of the University of California. All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Kenneth Almquist.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of the University nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# @(#)mktokens 8.1 (Berkeley) 5/31/93
+# $FreeBSD: head/bin/sh/mktokens 328934 2018-02-06 15:41:35Z arichardson $
+
+# The following is a list of tokens. The second column is nonzero if the
+# token marks the end of a list. The third column is the name to print in
+# error messages.
+
+temp=`mktemp -t ka`
+cat > $temp <<\!
+TEOF 1 end of file
+TNL 0 newline
+TSEMI 0 ";"
+TBACKGND 0 "&"
+TAND 0 "&&"
+TOR 0 "||"
+TPIPE 0 "|"
+TLP 0 "("
+TRP 1 ")"
+TENDCASE 1 ";;"
+TFALLTHRU 1 ";&"
+TREDIR 0 redirection
+TWORD 0 word
+TIF 0 "if"
+TTHEN 1 "then"
+TELSE 1 "else"
+TELIF 1 "elif"
+TFI 1 "fi"
+TWHILE 0 "while"
+TUNTIL 0 "until"
+TFOR 0 "for"
+TDO 1 "do"
+TDONE 1 "done"
+TBEGIN 0 "{"
+TEND 1 "}"
+TCASE 0 "case"
+TESAC 1 "esac"
+TNOT 0 "!"
+!
+nl=`wc -l $temp`
+exec > token.h
+awk '{print "#define " $1 " " NR-1}' $temp
+echo '
+/* Array indicating which tokens mark the end of a list */
+static const char tokendlist[] = {'
+awk '{print "\t" $2 ","}' $temp
+echo '};
+
+static const char *const tokname[] = {'
+sed -e 's/"/\\"/g' \
+ -e 's/[^ ]*[ ][ ]*[^ ]*[ ][ ]*\(.*\)/ "\1",/' \
+ $temp
+echo '};
+'
+sed 's/"//g' $temp | awk '
+/TIF/{print "#define KWDOFFSET " NR-1; print ""; print "const char *const parsekwd[] = {"}
+/TIF/,/neverfound/{print " \"" $3 "\","}'
+echo ' 0
+};'
+
+rm $temp
diff --git a/shell_cmds/sh/myhistedit.h b/shell_cmds/sh/myhistedit.h
new file mode 100644
index 0000000..3dbad7e
--- /dev/null
+++ b/shell_cmds/sh/myhistedit.h
@@ -0,0 +1,44 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)myhistedit.h 8.2 (Berkeley) 5/4/95
+ * $FreeBSD: head/bin/sh/myhistedit.h 326025 2017-11-20 19:49:47Z pfg $
+ */
+
+#include <histedit.h>
+
+extern History *hist;
+extern EditLine *el;
+extern int displayhist;
+
+void histedit(void);
+void sethistsize(const char *);
+void setterm(const char *);
+
diff --git a/shell_cmds/sh/mystring.c b/shell_cmds/sh/mystring.c
new file mode 100644
index 0000000..7e17e23
--- /dev/null
+++ b/shell_cmds/sh/mystring.c
@@ -0,0 +1,100 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)mystring.c 8.2 (Berkeley) 5/4/95";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/bin/sh/mystring.c 326025 2017-11-20 19:49:47Z pfg $");
+
+/*
+ * String functions.
+ *
+ * equal(s1, s2) Return true if strings are equal.
+ * number(s) Convert a string of digits to an integer.
+ * is_number(s) Return true if s is a string of digits.
+ */
+
+#include <stdlib.h>
+#include "shell.h"
+#include "syntax.h"
+#include "error.h"
+#include "mystring.h"
+
+
+char nullstr[1]; /* zero length string */
+
+/*
+ * equal - #defined in mystring.h
+ */
+
+
+/*
+ * Convert a string of digits to an integer, printing an error message on
+ * failure.
+ */
+
+int
+number(const char *s)
+{
+ if (! is_number(s))
+ error("Illegal number: %s", s);
+ return atoi(s);
+}
+
+
+
+/*
+ * Check for a valid number. This should be elsewhere.
+ */
+
+int
+is_number(const char *p)
+{
+ const char *q;
+
+ if (*p == '\0')
+ return 0;
+ while (*p == '0')
+ p++;
+ for (q = p; *q != '\0'; q++)
+ if (! is_digit(*q))
+ return 0;
+ if (q - p > 10 ||
+ (q - p == 10 && memcmp(p, "2147483647", 10) > 0))
+ return 0;
+ return 1;
+}
diff --git a/shell_cmds/sh/mystring.h b/shell_cmds/sh/mystring.h
new file mode 100644
index 0000000..31d7891
--- /dev/null
+++ b/shell_cmds/sh/mystring.h
@@ -0,0 +1,43 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)mystring.h 8.2 (Berkeley) 5/4/95
+ * $FreeBSD: head/bin/sh/mystring.h 326025 2017-11-20 19:49:47Z pfg $
+ */
+
+#include <string.h>
+
+int number(const char *);
+int is_number(const char *);
+
+#define equal(s1, s2) (strcmp(s1, s2) == 0)
diff --git a/shell_cmds/sh/nodes.c.pat b/shell_cmds/sh/nodes.c.pat
new file mode 100644
index 0000000..29d1563
--- /dev/null
+++ b/shell_cmds/sh/nodes.c.pat
@@ -0,0 +1,193 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)nodes.c.pat 8.2 (Berkeley) 5/4/95
+ * $FreeBSD: head/bin/sh/nodes.c.pat 314436 2017-02-28 23:42:47Z imp $
+ */
+
+#include <sys/param.h>
+#include <stdlib.h>
+#include <stddef.h>
+/*
+ * Routine for dealing with parsed shell commands.
+ */
+
+#include "shell.h"
+#include "nodes.h"
+#include "memalloc.h"
+#include "mystring.h"
+
+
+struct nodesize {
+ int blocksize; /* size of structures in function */
+ int stringsize; /* size of strings in node */
+};
+
+struct nodecopystate {
+ pointer block; /* block to allocate function from */
+ char *string; /* block to allocate strings from */
+};
+
+%SIZES
+
+
+static void calcsize(union node *, struct nodesize *);
+static void sizenodelist(struct nodelist *, struct nodesize *);
+static union node *copynode(union node *, struct nodecopystate *);
+static struct nodelist *copynodelist(struct nodelist *, struct nodecopystate *);
+static char *nodesavestr(const char *, struct nodecopystate *);
+
+
+struct funcdef {
+ unsigned int refcount;
+ union node n;
+};
+
+/*
+ * Make a copy of a parse tree.
+ */
+
+struct funcdef *
+copyfunc(union node *n)
+{
+ struct nodesize sz;
+ struct nodecopystate st;
+ struct funcdef *fn;
+
+ if (n == NULL)
+ return NULL;
+ sz.blocksize = offsetof(struct funcdef, n);
+ sz.stringsize = 0;
+ calcsize(n, &sz);
+ fn = ckmalloc(sz.blocksize + sz.stringsize);
+ fn->refcount = 1;
+ st.block = (char *)fn + offsetof(struct funcdef, n);
+ st.string = (char *)fn + sz.blocksize;
+ copynode(n, &st);
+ return fn;
+}
+
+
+union node *
+getfuncnode(struct funcdef *fn)
+{
+ return fn == NULL ? NULL : &fn->n;
+}
+
+
+static void
+calcsize(union node *n, struct nodesize *result)
+{
+ %CALCSIZE
+}
+
+
+
+static void
+sizenodelist(struct nodelist *lp, struct nodesize *result)
+{
+ while (lp) {
+ result->blocksize += ALIGN(sizeof(struct nodelist));
+ calcsize(lp->n, result);
+ lp = lp->next;
+ }
+}
+
+
+
+static union node *
+copynode(union node *n, struct nodecopystate *state)
+{
+ union node *new;
+
+ %COPY
+ return new;
+}
+
+
+static struct nodelist *
+copynodelist(struct nodelist *lp, struct nodecopystate *state)
+{
+ struct nodelist *start;
+ struct nodelist **lpp;
+
+ lpp = &start;
+ while (lp) {
+ *lpp = state->block;
+ state->block = (char *)state->block +
+ ALIGN(sizeof(struct nodelist));
+ (*lpp)->n = copynode(lp->n, state);
+ lp = lp->next;
+ lpp = &(*lpp)->next;
+ }
+ *lpp = NULL;
+ return start;
+}
+
+
+
+static char *
+nodesavestr(const char *s, struct nodecopystate *state)
+{
+ const char *p = s;
+ char *q = state->string;
+ char *rtn = state->string;
+
+ while ((*q++ = *p++) != '\0')
+ continue;
+ state->string = q;
+ return rtn;
+}
+
+
+void
+reffunc(struct funcdef *fn)
+{
+ if (fn)
+ fn->refcount++;
+}
+
+
+/*
+ * Decrement the reference count of a function definition, freeing it
+ * if it falls to 0.
+ */
+
+void
+unreffunc(struct funcdef *fn)
+{
+ if (fn) {
+ fn->refcount--;
+ if (fn->refcount > 0)
+ return;
+ ckfree(fn);
+ }
+}
diff --git a/shell_cmds/sh/nodetypes b/shell_cmds/sh/nodetypes
new file mode 100644
index 0000000..3ad95d6
--- /dev/null
+++ b/shell_cmds/sh/nodetypes
@@ -0,0 +1,145 @@
+#-
+# Copyright (c) 1991, 1993
+# The Regents of the University of California. All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Kenneth Almquist.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of the University nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# @(#)nodetypes 8.2 (Berkeley) 5/4/95
+# $FreeBSD: head/bin/sh/nodetypes 314436 2017-02-28 23:42:47Z imp $
+
+# This file describes the nodes used in parse trees. Unindented lines
+# contain a node type followed by a structure tag. Subsequent indented
+# lines specify the fields of the structure. Several node types can share
+# the same structure, in which case the fields of the structure should be
+# specified only once.
+#
+# A field of a structure is described by the name of the field followed
+# by a type. The currently implemented types are:
+# nodeptr - a pointer to a node
+# nodelist - a pointer to a list of nodes
+# string - a pointer to a nul terminated string
+# int - an integer
+# other - any type that can be copied by assignment
+# temp - a field that doesn't have to be copied when the node is copied
+# The last two types should be followed by the text of a C declaration for
+# the field.
+
+NSEMI nbinary # two commands separated by a semicolon
+ type int
+ ch1 nodeptr # the first child
+ ch2 nodeptr # the second child
+
+NCMD ncmd # a simple command
+ type int
+ args nodeptr # the arguments
+ redirect nodeptr # list of file redirections
+
+NPIPE npipe # a pipeline
+ type int
+ backgnd int # set to run pipeline in background
+ cmdlist nodelist # the commands in the pipeline
+
+NREDIR nredir # redirection (of a compex command)
+ type int
+ n nodeptr # the command
+ redirect nodeptr # list of file redirections
+
+NBACKGND nredir # run command in background
+NSUBSHELL nredir # run command in a subshell
+
+NAND nbinary # the && operator
+NOR nbinary # the || operator
+
+NIF nif # the if statement. Elif clauses are handled
+ type int # using multiple if nodes.
+ test nodeptr # if test
+ ifpart nodeptr # then ifpart
+ elsepart nodeptr # else elsepart
+
+NWHILE nbinary # the while statement. First child is the test
+NUNTIL nbinary # the until statement
+
+NFOR nfor # the for statement
+ type int
+ args nodeptr # for var in args
+ body nodeptr # do body; done
+ var string # the for variable
+
+NCASE ncase # a case statement
+ type int
+ expr nodeptr # the word to switch on
+ cases nodeptr # the list of cases (NCLIST nodes)
+
+NCLIST nclist # a case ending with ;;
+ type int
+ next nodeptr # the next case in list
+ pattern nodeptr # list of patterns for this case
+ body nodeptr # code to execute for this case
+
+NCLISTFALLTHRU nclist # a case ending with ;&
+
+NDEFUN narg # define a function. The "next" field contains
+ # the body of the function.
+
+NARG narg # represents a word
+ type int
+ next nodeptr # next word in list
+ text string # the text of the word
+ backquote nodelist # list of commands in back quotes
+
+NTO nfile # fd> fname
+NFROM nfile # fd< fname
+NFROMTO nfile # fd<> fname
+NAPPEND nfile # fd>> fname
+NCLOBBER nfile # fd>| fname
+ type int
+ fd int # file descriptor being redirected
+ next nodeptr # next redirection in list
+ fname nodeptr # file name, in a NARG node
+ expfname temp char *expfname # actual file name
+
+NTOFD ndup # fd<&dupfd
+NFROMFD ndup # fd>&dupfd
+ type int
+ fd int # file descriptor being redirected
+ next nodeptr # next redirection in list
+ dupfd int # file descriptor to duplicate
+ vname nodeptr # file name if fd>&$var
+
+
+NHERE nhere # fd<<\!
+NXHERE nhere # fd<<!
+ type int
+ fd int # file descriptor being redirected
+ next nodeptr # next redirection in list
+ doc nodeptr # input to command (NARG node)
+ expdoc temp const char *expdoc # actual document (for NXHERE)
+
+NNOT nnot # ! command (actually pipeline)
+ type int
+ com nodeptr
diff --git a/shell_cmds/sh/options.c b/shell_cmds/sh/options.c
new file mode 100644
index 0000000..0628e73
--- /dev/null
+++ b/shell_cmds/sh/options.c
@@ -0,0 +1,594 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)options.c 8.2 (Berkeley) 5/4/95";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/bin/sh/options.c 326025 2017-11-20 19:49:47Z pfg $");
+
+#include <signal.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include "shell.h"
+#define DEFINE_OPTIONS
+#include "options.h"
+#undef DEFINE_OPTIONS
+#include "nodes.h" /* for other header files */
+#include "eval.h"
+#include "jobs.h"
+#include "input.h"
+#include "output.h"
+#include "trap.h"
+#include "var.h"
+#include "memalloc.h"
+#include "error.h"
+#include "mystring.h"
+#include "builtins.h"
+#ifndef NO_HISTORY
+#include "myhistedit.h"
+#endif
+
+char *arg0; /* value of $0 */
+struct shparam shellparam; /* current positional parameters */
+char **argptr; /* argument list for builtin commands */
+char *shoptarg; /* set by nextopt (like getopt) */
+char *nextopt_optptr; /* used by nextopt */
+
+char *minusc; /* argument to -c option */
+
+
+static void options(int);
+static void minus_o(char *, int);
+static void setoption(int, int);
+static void setoptionbyindex(int, int);
+static void setparam(int, char **);
+static int getopts(char *, char *, char **, char ***, char **);
+
+
+/*
+ * Process the shell command line arguments.
+ */
+
+void
+procargs(int argc, char **argv)
+{
+ int i;
+ char *scriptname;
+
+ argptr = argv;
+ if (argc > 0)
+ argptr++;
+ for (i = 0; i < NOPTS; i++)
+ optval[i] = 2;
+ privileged = (getuid() != geteuid() || getgid() != getegid());
+ options(1);
+ if (*argptr == NULL && minusc == NULL)
+ sflag = 1;
+ if (iflag != 0 && sflag == 1 && isatty(0) && isatty(1)) {
+ iflag = 1;
+ if (Eflag == 2)
+ Eflag = 1;
+ }
+ if (mflag == 2)
+ mflag = iflag;
+ for (i = 0; i < NOPTS; i++)
+ if (optval[i] == 2)
+ optval[i] = 0;
+ arg0 = argv[0];
+ if (sflag == 0 && minusc == NULL) {
+ scriptname = *argptr++;
+ setinputfile(scriptname, 0);
+ commandname = arg0 = scriptname;
+ }
+ /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
+ if (argptr && minusc && *argptr)
+ arg0 = *argptr++;
+
+ shellparam.p = argptr;
+ shellparam.reset = 1;
+ /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
+ while (*argptr) {
+ shellparam.nparam++;
+ argptr++;
+ }
+ optschanged();
+}
+
+
+void
+optschanged(void)
+{
+ setinteractive();
+#ifndef NO_HISTORY
+ histedit();
+#endif
+ setjobctl(mflag);
+}
+
+/*
+ * Process shell options. The global variable argptr contains a pointer
+ * to the argument list; we advance it past the options.
+ * If cmdline is true, process the shell's argv; otherwise, process arguments
+ * to the set special builtin.
+ */
+
+static void
+options(int cmdline)
+{
+ char *kp, *p;
+ int val;
+ int c;
+
+ if (cmdline)
+ minusc = NULL;
+ while ((p = *argptr) != NULL) {
+ argptr++;
+ if ((c = *p++) == '-') {
+ val = 1;
+ /* A "-" or "--" terminates options */
+ if (p[0] == '\0')
+ goto end_options1;
+ if (p[0] == '-' && p[1] == '\0')
+ goto end_options2;
+ /**
+ * For the benefit of `#!' lines in shell scripts,
+ * treat a string of '-- *#.*' the same as '--'.
+ * This is needed so that a script starting with:
+ * #!/bin/sh -- # -*- perl -*-
+ * will continue to work after a change is made to
+ * kern/imgact_shell.c to NOT token-ize the options
+ * specified on a '#!' line. A bit of a kludge,
+ * but that trick is recommended in documentation
+ * for some scripting languages, and we might as
+ * well continue to support it.
+ */
+ if (p[0] == '-') {
+ kp = p + 1;
+ while (*kp == ' ' || *kp == '\t')
+ kp++;
+ if (*kp == '#' || *kp == '\0')
+ goto end_options2;
+ }
+ } else if (c == '+') {
+ val = 0;
+ } else {
+ argptr--;
+ break;
+ }
+ while ((c = *p++) != '\0') {
+ if (c == 'c' && cmdline) {
+ char *q;
+
+ q = *argptr++;
+ if (q == NULL || minusc != NULL)
+ error("Bad -c option");
+ minusc = q;
+ } else if (c == 'o') {
+ minus_o(*argptr, val);
+ if (*argptr)
+ argptr++;
+ } else
+ setoption(c, val);
+ }
+ }
+ return;
+
+ /* When processing `set', a single "-" means turn off -x and -v */
+end_options1:
+ if (!cmdline) {
+ xflag = vflag = 0;
+ return;
+ }
+
+ /*
+ * When processing `set', a "--" means the remaining arguments
+ * replace the positional parameters in the active shell. If
+ * there are no remaining options, then all the positional
+ * parameters are cleared (equivalent to doing ``shift $#'').
+ */
+end_options2:
+ if (!cmdline) {
+ if (*argptr == NULL)
+ setparam(0, argptr);
+ return;
+ }
+
+ /*
+ * At this point we are processing options given to 'sh' on a command
+ * line. If an end-of-options marker ("-" or "--") is followed by an
+ * arg of "#", then skip over all remaining arguments. Some scripting
+ * languages (e.g.: perl) document that /bin/sh will implement this
+ * behavior, and they recommend that users take advantage of it to
+ * solve certain issues that can come up when writing a perl script.
+ * Yes, this feature is in /bin/sh to help users write perl scripts.
+ */
+ p = *argptr;
+ if (p != NULL && p[0] == '#' && p[1] == '\0') {
+ while (*argptr != NULL)
+ argptr++;
+ /* We need to keep the final argument */
+ argptr--;
+ }
+}
+
+static void
+minus_o(char *name, int val)
+{
+ int i;
+ const unsigned char *on;
+ size_t len;
+
+ if (name == NULL) {
+ if (val) {
+ /* "Pretty" output. */
+ out1str("Current option settings\n");
+ for (i = 0, on = optname; i < NOPTS; i++, on += *on + 1)
+ out1fmt("%-16.*s%s\n", *on, on + 1,
+ optval[i] ? "on" : "off");
+ } else {
+ /* Output suitable for re-input to shell. */
+ for (i = 0, on = optname; i < NOPTS; i++, on += *on + 1)
+ out1fmt("%s %co %.*s%s",
+ i % 6 == 0 ? "set" : "",
+ optval[i] ? '-' : '+',
+ *on, on + 1,
+ i % 6 == 5 || i == NOPTS - 1 ? "\n" : "");
+ }
+ } else {
+ len = strlen(name);
+ for (i = 0, on = optname; i < NOPTS; i++, on += *on + 1)
+ if (*on == len && memcmp(on + 1, name, len) == 0) {
+ setoptionbyindex(i, val);
+ return;
+ }
+ error("Illegal option -o %s", name);
+ }
+}
+
+
+static void
+setoptionbyindex(int idx, int val)
+{
+ if (&optval[idx] == &privileged && !val && privileged) {
+ if (setgid(getgid()) == -1)
+ error("setgid");
+ if (setuid(getuid()) == -1)
+ error("setuid");
+ }
+ optval[idx] = val;
+ if (val) {
+ /* #%$ hack for ksh semantics */
+ if (&optval[idx] == &Vflag)
+ Eflag = 0;
+ else if (&optval[idx] == &Eflag)
+ Vflag = 0;
+ }
+}
+
+static void
+setoption(int flag, int val)
+{
+ int i;
+
+ for (i = 0; i < NSHORTOPTS; i++)
+ if (optletter[i] == flag) {
+ setoptionbyindex(i, val);
+ return;
+ }
+ error("Illegal option -%c", flag);
+}
+
+
+/*
+ * Set the shell parameters.
+ */
+
+static void
+setparam(int argc, char **argv)
+{
+ char **newparam;
+ char **ap;
+
+ ap = newparam = ckmalloc((argc + 1) * sizeof *ap);
+ while (*argv) {
+ *ap++ = savestr(*argv++);
+ }
+ *ap = NULL;
+ freeparam(&shellparam);
+ shellparam.malloc = 1;
+ shellparam.nparam = argc;
+ shellparam.p = newparam;
+ shellparam.optp = NULL;
+ shellparam.reset = 1;
+ shellparam.optnext = NULL;
+}
+
+
+/*
+ * Free the list of positional parameters.
+ */
+
+void
+freeparam(struct shparam *param)
+{
+ char **ap;
+
+ if (param->malloc) {
+ for (ap = param->p ; *ap ; ap++)
+ ckfree(*ap);
+ ckfree(param->p);
+ }
+ if (param->optp) {
+ for (ap = param->optp ; *ap ; ap++)
+ ckfree(*ap);
+ ckfree(param->optp);
+ }
+}
+
+
+
+/*
+ * The shift builtin command.
+ */
+
+int
+shiftcmd(int argc, char **argv)
+{
+ int i, n;
+
+ n = 1;
+ if (argc > 1)
+ n = number(argv[1]);
+ if (n > shellparam.nparam)
+ return 1;
+ INTOFF;
+ shellparam.nparam -= n;
+ if (shellparam.malloc)
+ for (i = 0; i < n; i++)
+ ckfree(shellparam.p[i]);
+ memmove(shellparam.p, shellparam.p + n,
+ (shellparam.nparam + 1) * sizeof(shellparam.p[0]));
+ shellparam.reset = 1;
+ INTON;
+ return 0;
+}
+
+
+
+/*
+ * The set builtin command.
+ */
+
+int
+setcmd(int argc, char **argv)
+{
+ if (argc == 1)
+ return showvarscmd(argc, argv);
+ INTOFF;
+ options(0);
+ optschanged();
+ if (*argptr != NULL) {
+ setparam(argc - (argptr - argv), argptr);
+ }
+ INTON;
+ return 0;
+}
+
+
+void
+getoptsreset(const char *value)
+{
+ while (*value == '0')
+ value++;
+ if (strcmp(value, "1") == 0)
+ shellparam.reset = 1;
+}
+
+/*
+ * The getopts builtin. Shellparam.optnext points to the next argument
+ * to be processed. Shellparam.optptr points to the next character to
+ * be processed in the current argument. If shellparam.optnext is NULL,
+ * then it's the first time getopts has been called.
+ */
+
+int
+getoptscmd(int argc, char **argv)
+{
+ char **optbase = NULL, **ap;
+ int i;
+
+ if (argc < 3)
+ error("usage: getopts optstring var [arg]");
+
+ if (shellparam.reset == 1) {
+ INTOFF;
+ if (shellparam.optp) {
+ for (ap = shellparam.optp ; *ap ; ap++)
+ ckfree(*ap);
+ ckfree(shellparam.optp);
+ shellparam.optp = NULL;
+ }
+ if (argc > 3) {
+ shellparam.optp = ckmalloc((argc - 2) * sizeof *ap);
+ memset(shellparam.optp, '\0', (argc - 2) * sizeof *ap);
+ for (i = 0; i < argc - 3; i++)
+ shellparam.optp[i] = savestr(argv[i + 3]);
+ }
+ INTON;
+ optbase = argc == 3 ? shellparam.p : shellparam.optp;
+ shellparam.optnext = optbase;
+ shellparam.optptr = NULL;
+ shellparam.reset = 0;
+ } else
+ optbase = shellparam.optp ? shellparam.optp : shellparam.p;
+
+ return getopts(argv[1], argv[2], optbase, &shellparam.optnext,
+ &shellparam.optptr);
+}
+
+static int
+getopts(char *optstr, char *optvar, char **optfirst, char ***optnext,
+ char **optptr)
+{
+ char *p, *q;
+ char c = '?';
+ int done = 0;
+ int ind = 0;
+ int err = 0;
+ char s[10];
+ const char *newoptarg = NULL;
+
+ if ((p = *optptr) == NULL || *p == '\0') {
+ /* Current word is done, advance */
+ if (*optnext == NULL)
+ return 1;
+ p = **optnext;
+ if (p == NULL || *p != '-' || *++p == '\0') {
+atend:
+ ind = *optnext - optfirst + 1;
+ *optnext = NULL;
+ p = NULL;
+ done = 1;
+ goto out;
+ }
+ (*optnext)++;
+ if (p[0] == '-' && p[1] == '\0') /* check for "--" */
+ goto atend;
+ }
+
+ c = *p++;
+ for (q = optstr; *q != c; ) {
+ if (*q == '\0') {
+ if (optstr[0] == ':') {
+ s[0] = c;
+ s[1] = '\0';
+ newoptarg = s;
+ }
+ else
+ out2fmt_flush("Illegal option -%c\n", c);
+ c = '?';
+ goto out;
+ }
+ if (*++q == ':')
+ q++;
+ }
+
+ if (*++q == ':') {
+ if (*p == '\0' && (p = **optnext) == NULL) {
+ if (optstr[0] == ':') {
+ s[0] = c;
+ s[1] = '\0';
+ newoptarg = s;
+ c = ':';
+ }
+ else {
+ out2fmt_flush("No arg for -%c option\n", c);
+ c = '?';
+ }
+ goto out;
+ }
+
+ if (p == **optnext)
+ (*optnext)++;
+ newoptarg = p;
+ p = NULL;
+ }
+
+out:
+ if (*optnext != NULL)
+ ind = *optnext - optfirst + 1;
+ *optptr = p;
+ if (newoptarg != NULL)
+ err |= setvarsafe("OPTARG", newoptarg, 0);
+ else {
+ INTOFF;
+ err |= unsetvar("OPTARG");
+ INTON;
+ }
+ fmtstr(s, sizeof(s), "%d", ind);
+ err |= setvarsafe("OPTIND", s, VNOFUNC);
+ s[0] = c;
+ s[1] = '\0';
+ err |= setvarsafe(optvar, s, 0);
+ if (err) {
+ *optnext = NULL;
+ *optptr = NULL;
+ flushall();
+ exraise(EXERROR);
+ }
+ return done;
+}
+
+/*
+ * Standard option processing (a la getopt) for builtin routines. The
+ * only argument that is passed to nextopt is the option string; the
+ * other arguments are unnecessary. It returns the option, or '\0' on
+ * end of input.
+ */
+
+int
+nextopt(const char *optstring)
+{
+ char *p;
+ const char *q;
+ char c;
+
+ if ((p = nextopt_optptr) == NULL || *p == '\0') {
+ p = *argptr;
+ if (p == NULL || *p != '-' || *++p == '\0')
+ return '\0';
+ argptr++;
+ if (p[0] == '-' && p[1] == '\0') /* check for "--" */
+ return '\0';
+ }
+ c = *p++;
+ for (q = optstring ; *q != c ; ) {
+ if (*q == '\0')
+ error("Illegal option -%c", c);
+ if (*++q == ':')
+ q++;
+ }
+ if (*++q == ':') {
+ if (*p == '\0' && (p = *argptr++) == NULL)
+ error("No arg for -%c option", c);
+ shoptarg = p;
+ p = NULL;
+ }
+ nextopt_optptr = p;
+ return c;
+}
diff --git a/shell_cmds/sh/options.h b/shell_cmds/sh/options.h
new file mode 100644
index 0000000..233e9c6
--- /dev/null
+++ b/shell_cmds/sh/options.h
@@ -0,0 +1,115 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)options.h 8.2 (Berkeley) 5/4/95
+ * $FreeBSD: head/bin/sh/options.h 326025 2017-11-20 19:49:47Z pfg $
+ */
+
+struct shparam {
+ int nparam; /* # of positional parameters (without $0) */
+ unsigned char malloc; /* if parameter list dynamically allocated */
+ unsigned char reset; /* if getopts has been reset */
+ char **p; /* parameter list */
+ char **optp; /* parameter list for getopts */
+ char **optnext; /* next parameter to be processed by getopts */
+ char *optptr; /* used by getopts */
+};
+
+
+
+#define eflag optval[0]
+#define fflag optval[1]
+#define Iflag optval[2]
+#define iflag optval[3]
+#define mflag optval[4]
+#define nflag optval[5]
+#define sflag optval[6]
+#define xflag optval[7]
+#define vflag optval[8]
+#define Vflag optval[9]
+#define Eflag optval[10]
+#define Cflag optval[11]
+#define aflag optval[12]
+#define bflag optval[13]
+#define uflag optval[14]
+#define privileged optval[15]
+#define Tflag optval[16]
+#define Pflag optval[17]
+#define hflag optval[18]
+#define nologflag optval[19]
+
+#define NSHORTOPTS 19
+#define NOPTS 20
+
+extern char optval[NOPTS];
+extern const char optletter[NSHORTOPTS];
+#ifdef DEFINE_OPTIONS
+char optval[NOPTS];
+const char optletter[NSHORTOPTS] = "efIimnsxvVECabupTPh";
+static const unsigned char optname[] =
+ "\007errexit"
+ "\006noglob"
+ "\011ignoreeof"
+ "\013interactive"
+ "\007monitor"
+ "\006noexec"
+ "\005stdin"
+ "\006xtrace"
+ "\007verbose"
+ "\002vi"
+ "\005emacs"
+ "\011noclobber"
+ "\011allexport"
+ "\006notify"
+ "\007nounset"
+ "\012privileged"
+ "\012trapsasync"
+ "\010physical"
+ "\010trackall"
+ "\005nolog"
+;
+#endif
+
+
+extern char *minusc; /* argument to -c option */
+extern char *arg0; /* $0 */
+extern struct shparam shellparam; /* $@ */
+extern char **argptr; /* argument list for builtin commands */
+extern char *shoptarg; /* set by nextopt */
+extern char *nextopt_optptr; /* used by nextopt */
+
+void procargs(int, char **);
+void optschanged(void);
+void freeparam(struct shparam *);
+int nextopt(const char *);
+void getoptsreset(const char *);
diff --git a/shell_cmds/sh/output.c b/shell_cmds/sh/output.c
new file mode 100644
index 0000000..737eb91
--- /dev/null
+++ b/shell_cmds/sh/output.c
@@ -0,0 +1,370 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)output.c 8.2 (Berkeley) 5/4/95";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/bin/sh/output.c 326025 2017-11-20 19:49:47Z pfg $");
+
+/*
+ * Shell output routines. We use our own output routines because:
+ * When a builtin command is interrupted we have to discard
+ * any pending output.
+ * When a builtin command appears in back quotes, we want to
+ * save the output of the command in a region obtained
+ * via malloc, rather than doing a fork and reading the
+ * output of the command via a pipe.
+ */
+
+#include <stdio.h> /* defines BUFSIZ */
+#include <string.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <wchar.h>
+#include <wctype.h>
+
+#include "shell.h"
+#include "syntax.h"
+#include "output.h"
+#include "memalloc.h"
+#include "error.h"
+#include "var.h"
+
+
+#define OUTBUFSIZ BUFSIZ
+#define MEM_OUT -2 /* output to dynamically allocated memory */
+#define OUTPUT_ERR 01 /* error occurred on output */
+
+static int doformat_wr(void *, const char *, int);
+
+struct output output = {NULL, NULL, NULL, OUTBUFSIZ, 1, 0};
+struct output errout = {NULL, NULL, NULL, 256, 2, 0};
+struct output memout = {NULL, NULL, NULL, 64, MEM_OUT, 0};
+struct output *out1 = &output;
+struct output *out2 = &errout;
+
+void
+outcslow(int c, struct output *file)
+{
+ outc(c, file);
+}
+
+void
+out1str(const char *p)
+{
+ outstr(p, out1);
+}
+
+void
+out1qstr(const char *p)
+{
+ outqstr(p, out1);
+}
+
+void
+out2str(const char *p)
+{
+ outstr(p, out2);
+}
+
+void
+out2qstr(const char *p)
+{
+ outqstr(p, out2);
+}
+
+void
+outstr(const char *p, struct output *file)
+{
+ outbin(p, strlen(p), file);
+}
+
+static void
+byteseq(int ch, struct output *file)
+{
+ char seq[4];
+
+ seq[0] = '\\';
+ seq[1] = (ch >> 6 & 0x3) + '0';
+ seq[2] = (ch >> 3 & 0x7) + '0';
+ seq[3] = (ch & 0x7) + '0';
+ outbin(seq, 4, file);
+}
+
+static void
+outdqstr(const char *p, struct output *file)
+{
+ const char *end;
+ mbstate_t mbs;
+ size_t clen;
+ wchar_t wc;
+
+ memset(&mbs, '\0', sizeof(mbs));
+ end = p + strlen(p);
+ outstr("$'", file);
+ while ((clen = mbrtowc(&wc, p, end - p + 1, &mbs)) != 0) {
+ if (clen == (size_t)-2) {
+ while (p < end)
+ byteseq(*p++, file);
+ break;
+ }
+ if (clen == (size_t)-1) {
+ memset(&mbs, '\0', sizeof(mbs));
+ byteseq(*p++, file);
+ continue;
+ }
+ if (wc == L'\n')
+ outcslow('\n', file), p++;
+ else if (wc == L'\r')
+ outstr("\\r", file), p++;
+ else if (wc == L'\t')
+ outstr("\\t", file), p++;
+ else if (!iswprint(wc)) {
+ for (; clen > 0; clen--)
+ byteseq(*p++, file);
+ } else {
+ if (wc == L'\'' || wc == L'\\')
+ outcslow('\\', file);
+ outbin(p, clen, file);
+ p += clen;
+ }
+ }
+ outcslow('\'', file);
+}
+
+/* Like outstr(), but quote for re-input into the shell. */
+void
+outqstr(const char *p, struct output *file)
+{
+ int i;
+
+ if (p[0] == '\0') {
+ outstr("''", file);
+ return;
+ }
+ for (i = 0; p[i] != '\0'; i++) {
+ if ((p[i] > '\0' && p[i] < ' ' && p[i] != '\n') ||
+ (p[i] & 0x80) != 0 || p[i] == '\'') {
+ outdqstr(p, file);
+ return;
+ }
+ }
+
+ if (p[strcspn(p, "|&;<>()$`\\\" \n*?[~#=")] == '\0' ||
+ strcmp(p, "[") == 0) {
+ outstr(p, file);
+ return;
+ }
+
+ outcslow('\'', file);
+ outstr(p, file);
+ outcslow('\'', file);
+}
+
+void
+outbin(const void *data, size_t len, struct output *file)
+{
+ const char *p;
+
+ p = data;
+ while (len-- > 0)
+ outc(*p++, file);
+}
+
+void
+emptyoutbuf(struct output *dest)
+{
+ int offset, newsize;
+
+ if (dest->buf == NULL) {
+ INTOFF;
+ dest->buf = ckmalloc(dest->bufsize);
+ dest->nextc = dest->buf;
+ dest->bufend = dest->buf + dest->bufsize;
+ INTON;
+ } else if (dest->fd == MEM_OUT) {
+ offset = dest->nextc - dest->buf;
+ newsize = dest->bufsize << 1;
+ INTOFF;
+ dest->buf = ckrealloc(dest->buf, newsize);
+ dest->bufsize = newsize;
+ dest->bufend = dest->buf + newsize;
+ dest->nextc = dest->buf + offset;
+ INTON;
+ } else {
+ flushout(dest);
+ }
+}
+
+
+void
+flushall(void)
+{
+ flushout(&output);
+ flushout(&errout);
+}
+
+
+void
+flushout(struct output *dest)
+{
+
+ if (dest->buf == NULL || dest->nextc == dest->buf || dest->fd < 0)
+ return;
+ if (xwrite(dest->fd, dest->buf, dest->nextc - dest->buf) < 0)
+ dest->flags |= OUTPUT_ERR;
+ dest->nextc = dest->buf;
+}
+
+
+void
+freestdout(void)
+{
+ output.nextc = output.buf;
+}
+
+
+int
+outiserror(struct output *file)
+{
+ return (file->flags & OUTPUT_ERR);
+}
+
+
+void
+outclearerror(struct output *file)
+{
+ file->flags &= ~OUTPUT_ERR;
+}
+
+
+void
+outfmt(struct output *file, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ doformat(file, fmt, ap);
+ va_end(ap);
+}
+
+
+void
+out1fmt(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ doformat(out1, fmt, ap);
+ va_end(ap);
+}
+
+void
+out2fmt_flush(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ doformat(out2, fmt, ap);
+ va_end(ap);
+ flushout(out2);
+}
+
+void
+fmtstr(char *outbuf, int length, const char *fmt, ...)
+{
+ va_list ap;
+
+ INTOFF;
+ va_start(ap, fmt);
+ vsnprintf(outbuf, length, fmt, ap);
+ va_end(ap);
+ INTON;
+}
+
+static int
+doformat_wr(void *cookie, const char *buf, int len)
+{
+ struct output *o;
+
+ o = (struct output *)cookie;
+ outbin(buf, len, o);
+
+ return (len);
+}
+
+void
+doformat(struct output *dest, const char *f, va_list ap)
+{
+ FILE *fp;
+
+ if ((fp = fwopen(dest, doformat_wr)) != NULL) {
+ vfprintf(fp, f, ap);
+ fclose(fp);
+ }
+}
+
+/*
+ * Version of write which resumes after a signal is caught.
+ */
+
+int
+xwrite(int fd, const char *buf, int nbytes)
+{
+ int ntry;
+ int i;
+ int n;
+
+ n = nbytes;
+ ntry = 0;
+ for (;;) {
+ i = write(fd, buf, n);
+ if (i > 0) {
+ if ((n -= i) <= 0)
+ return nbytes;
+ buf += i;
+ ntry = 0;
+ } else if (i == 0) {
+ if (++ntry > 10)
+ return nbytes - n;
+ } else if (errno != EINTR) {
+ return -1;
+ }
+ }
+}
diff --git a/shell_cmds/sh/output.h b/shell_cmds/sh/output.h
new file mode 100644
index 0000000..652187a
--- /dev/null
+++ b/shell_cmds/sh/output.h
@@ -0,0 +1,85 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)output.h 8.2 (Berkeley) 5/4/95
+ * $FreeBSD: head/bin/sh/output.h 326025 2017-11-20 19:49:47Z pfg $
+ */
+
+#ifndef OUTPUT_INCL
+
+#include <stdarg.h>
+#include <stddef.h>
+
+struct output {
+ char *nextc;
+ char *bufend;
+ char *buf;
+ int bufsize;
+ short fd;
+ short flags;
+};
+
+extern struct output output; /* to fd 1 */
+extern struct output errout; /* to fd 2 */
+extern struct output memout;
+extern struct output *out1; /* &memout if backquote, otherwise &output */
+extern struct output *out2; /* &memout if backquote with 2>&1, otherwise
+ &errout */
+
+void outcslow(int, struct output *);
+void out1str(const char *);
+void out1qstr(const char *);
+void out2str(const char *);
+void out2qstr(const char *);
+void outstr(const char *, struct output *);
+void outqstr(const char *, struct output *);
+void outbin(const void *, size_t, struct output *);
+void emptyoutbuf(struct output *);
+void flushall(void);
+void flushout(struct output *);
+void freestdout(void);
+int outiserror(struct output *);
+void outclearerror(struct output *);
+void outfmt(struct output *, const char *, ...) __printflike(2, 3);
+void out1fmt(const char *, ...) __printflike(1, 2);
+void out2fmt_flush(const char *, ...) __printflike(1, 2);
+void fmtstr(char *, int, const char *, ...) __printflike(3, 4);
+void doformat(struct output *, const char *, va_list) __printflike(2, 0);
+int xwrite(int, const char *, int);
+
+#define outc(c, file) ((file)->nextc == (file)->bufend ? (emptyoutbuf(file), *(file)->nextc++ = (c)) : (*(file)->nextc++ = (c)))
+#define out1c(c) outc(c, out1);
+#define out2c(c) outcslow(c, out2);
+
+#define OUTPUT_INCL
+#endif
diff --git a/shell_cmds/sh/parser.c b/shell_cmds/sh/parser.c
new file mode 100644
index 0000000..799e3b5
--- /dev/null
+++ b/shell_cmds/sh/parser.c
@@ -0,0 +1,2120 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)parser.c 8.7 (Berkeley) 5/16/95";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/bin/sh/parser.c 326025 2017-11-20 19:49:47Z pfg $");
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+
+#include "shell.h"
+#include "parser.h"
+#include "nodes.h"
+#include "expand.h" /* defines rmescapes() */
+#include "syntax.h"
+#include "options.h"
+#include "input.h"
+#include "output.h"
+#include "var.h"
+#include "error.h"
+#include "memalloc.h"
+#include "mystring.h"
+#include "alias.h"
+#include "show.h"
+#include "eval.h"
+#include "exec.h" /* to check for special builtins */
+#ifndef NO_HISTORY
+#include "myhistedit.h"
+#endif
+
+/*
+ * Shell command parser.
+ */
+
+#define PROMPTLEN 128
+
+/* values of checkkwd variable */
+#define CHKALIAS 0x1
+#define CHKKWD 0x2
+#define CHKNL 0x4
+
+/* values returned by readtoken */
+#include "token.h"
+
+
+
+struct heredoc {
+ struct heredoc *next; /* next here document in list */
+ union node *here; /* redirection node */
+ char *eofmark; /* string indicating end of input */
+ int striptabs; /* if set, strip leading tabs */
+};
+
+struct parser_temp {
+ struct parser_temp *next;
+ void *data;
+};
+
+
+static struct heredoc *heredoclist; /* list of here documents to read */
+static int doprompt; /* if set, prompt the user */
+static int needprompt; /* true if interactive and at start of line */
+static int lasttoken; /* last token read */
+static int tokpushback; /* last token pushed back */
+static char *wordtext; /* text of last word returned by readtoken */
+static int checkkwd;
+static struct nodelist *backquotelist;
+static union node *redirnode;
+static struct heredoc *heredoc;
+static int quoteflag; /* set if (part of) last token was quoted */
+static int startlinno; /* line # where last token started */
+static int funclinno; /* line # where the current function started */
+static struct parser_temp *parser_temp;
+
+#define NOEOFMARK ((const char *)&heredoclist)
+
+
+static union node *list(int);
+static union node *andor(void);
+static union node *pipeline(void);
+static union node *command(void);
+static union node *simplecmd(union node **, union node *);
+static union node *makename(void);
+static union node *makebinary(int type, union node *n1, union node *n2);
+static void parsefname(void);
+static void parseheredoc(void);
+static int peektoken(void);
+static int readtoken(void);
+static int xxreadtoken(void);
+static int readtoken1(int, const char *, const char *, int);
+static int noexpand(char *);
+static void consumetoken(int);
+static void synexpect(int) __dead2;
+static void synerror(const char *) __dead2;
+static void setprompt(int);
+static int pgetc_linecont(void);
+
+
+static void *
+parser_temp_alloc(size_t len)
+{
+ struct parser_temp *t;
+
+ INTOFF;
+ t = ckmalloc(sizeof(*t));
+ t->data = NULL;
+ t->next = parser_temp;
+ parser_temp = t;
+ t->data = ckmalloc(len);
+ INTON;
+ return t->data;
+}
+
+
+static void *
+parser_temp_realloc(void *ptr, size_t len)
+{
+ struct parser_temp *t;
+
+ INTOFF;
+ t = parser_temp;
+ if (ptr != t->data)
+ error("bug: parser_temp_realloc misused");
+ t->data = ckrealloc(t->data, len);
+ INTON;
+ return t->data;
+}
+
+
+static void
+parser_temp_free_upto(void *ptr)
+{
+ struct parser_temp *t;
+ int done = 0;
+
+ INTOFF;
+ while (parser_temp != NULL && !done) {
+ t = parser_temp;
+ parser_temp = t->next;
+ done = t->data == ptr;
+ ckfree(t->data);
+ ckfree(t);
+ }
+ INTON;
+ if (!done)
+ error("bug: parser_temp_free_upto misused");
+}
+
+
+static void
+parser_temp_free_all(void)
+{
+ struct parser_temp *t;
+
+ INTOFF;
+ while (parser_temp != NULL) {
+ t = parser_temp;
+ parser_temp = t->next;
+ ckfree(t->data);
+ ckfree(t);
+ }
+ INTON;
+}
+
+
+/*
+ * Read and parse a command. Returns NEOF on end of file. (NULL is a
+ * valid parse tree indicating a blank line.)
+ */
+
+union node *
+parsecmd(int interact)
+{
+ int t;
+
+ /* This assumes the parser is not re-entered,
+ * which could happen if we add command substitution on PS1/PS2.
+ */
+ parser_temp_free_all();
+ heredoclist = NULL;
+
+ tokpushback = 0;
+ checkkwd = 0;
+ doprompt = interact;
+ if (doprompt)
+ setprompt(1);
+ else
+ setprompt(0);
+ needprompt = 0;
+ t = readtoken();
+ if (t == TEOF)
+ return NEOF;
+ if (t == TNL)
+ return NULL;
+ tokpushback++;
+ return list(1);
+}
+
+
+/*
+ * Read and parse words for wordexp.
+ * Returns a list of NARG nodes; NULL if there are no words.
+ */
+union node *
+parsewordexp(void)
+{
+ union node *n, *first = NULL, **pnext;
+ int t;
+
+ /* This assumes the parser is not re-entered,
+ * which could happen if we add command substitution on PS1/PS2.
+ */
+ parser_temp_free_all();
+ heredoclist = NULL;
+
+ tokpushback = 0;
+ checkkwd = 0;
+ doprompt = 0;
+ setprompt(0);
+ needprompt = 0;
+ pnext = &first;
+ while ((t = readtoken()) != TEOF) {
+ if (t != TWORD)
+ synexpect(TWORD);
+ n = makename();
+ *pnext = n;
+ pnext = &n->narg.next;
+ }
+ return first;
+}
+
+
+static union node *
+list(int nlflag)
+{
+ union node *ntop, *n1, *n2, *n3;
+ int tok;
+
+ checkkwd = CHKNL | CHKKWD | CHKALIAS;
+ if (!nlflag && tokendlist[peektoken()])
+ return NULL;
+ ntop = n1 = NULL;
+ for (;;) {
+ n2 = andor();
+ tok = readtoken();
+ if (tok == TBACKGND) {
+ if (n2 != NULL && n2->type == NPIPE) {
+ n2->npipe.backgnd = 1;
+ } else if (n2 != NULL && n2->type == NREDIR) {
+ n2->type = NBACKGND;
+ } else {
+ n3 = (union node *)stalloc(sizeof (struct nredir));
+ n3->type = NBACKGND;
+ n3->nredir.n = n2;
+ n3->nredir.redirect = NULL;
+ n2 = n3;
+ }
+ }
+ if (ntop == NULL)
+ ntop = n2;
+ else if (n1 == NULL) {
+ n1 = makebinary(NSEMI, ntop, n2);
+ ntop = n1;
+ }
+ else {
+ n3 = makebinary(NSEMI, n1->nbinary.ch2, n2);
+ n1->nbinary.ch2 = n3;
+ n1 = n3;
+ }
+ switch (tok) {
+ case TBACKGND:
+ case TSEMI:
+ tok = readtoken();
+ /* FALLTHROUGH */
+ case TNL:
+ if (tok == TNL) {
+ parseheredoc();
+ if (nlflag)
+ return ntop;
+ } else if (tok == TEOF && nlflag) {
+ parseheredoc();
+ return ntop;
+ } else {
+ tokpushback++;
+ }
+ checkkwd = CHKNL | CHKKWD | CHKALIAS;
+ if (!nlflag && tokendlist[peektoken()])
+ return ntop;
+ break;
+ case TEOF:
+ if (heredoclist)
+ parseheredoc();
+ else
+ pungetc(); /* push back EOF on input */
+ return ntop;
+ default:
+ if (nlflag)
+ synexpect(-1);
+ tokpushback++;
+ return ntop;
+ }
+ }
+}
+
+
+
+static union node *
+andor(void)
+{
+ union node *n;
+ int t;
+
+ n = pipeline();
+ for (;;) {
+ if ((t = readtoken()) == TAND) {
+ t = NAND;
+ } else if (t == TOR) {
+ t = NOR;
+ } else {
+ tokpushback++;
+ return n;
+ }
+ n = makebinary(t, n, pipeline());
+ }
+}
+
+
+
+static union node *
+pipeline(void)
+{
+ union node *n1, *n2, *pipenode;
+ struct nodelist *lp, *prev;
+ int negate, t;
+
+ negate = 0;
+ checkkwd = CHKNL | CHKKWD | CHKALIAS;
+ TRACE(("pipeline: entered\n"));
+ while (readtoken() == TNOT)
+ negate = !negate;
+ tokpushback++;
+ n1 = command();
+ if (readtoken() == TPIPE) {
+ pipenode = (union node *)stalloc(sizeof (struct npipe));
+ pipenode->type = NPIPE;
+ pipenode->npipe.backgnd = 0;
+ lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
+ pipenode->npipe.cmdlist = lp;
+ lp->n = n1;
+ do {
+ prev = lp;
+ lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
+ checkkwd = CHKNL | CHKKWD | CHKALIAS;
+ t = readtoken();
+ tokpushback++;
+ if (t == TNOT)
+ lp->n = pipeline();
+ else
+ lp->n = command();
+ prev->next = lp;
+ } while (readtoken() == TPIPE);
+ lp->next = NULL;
+ n1 = pipenode;
+ }
+ tokpushback++;
+ if (negate) {
+ n2 = (union node *)stalloc(sizeof (struct nnot));
+ n2->type = NNOT;
+ n2->nnot.com = n1;
+ return n2;
+ } else
+ return n1;
+}
+
+
+
+static union node *
+command(void)
+{
+ union node *n1, *n2;
+ union node *ap, **app;
+ union node *cp, **cpp;
+ union node *redir, **rpp;
+ int t;
+ int is_subshell;
+
+ checkkwd = CHKNL | CHKKWD | CHKALIAS;
+ is_subshell = 0;
+ redir = NULL;
+ n1 = NULL;
+ rpp = &redir;
+
+ /* Check for redirection which may precede command */
+ while (readtoken() == TREDIR) {
+ *rpp = n2 = redirnode;
+ rpp = &n2->nfile.next;
+ parsefname();
+ }
+ tokpushback++;
+
+ switch (readtoken()) {
+ case TIF:
+ n1 = (union node *)stalloc(sizeof (struct nif));
+ n1->type = NIF;
+ if ((n1->nif.test = list(0)) == NULL)
+ synexpect(-1);
+ consumetoken(TTHEN);
+ n1->nif.ifpart = list(0);
+ n2 = n1;
+ while (readtoken() == TELIF) {
+ n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
+ n2 = n2->nif.elsepart;
+ n2->type = NIF;
+ if ((n2->nif.test = list(0)) == NULL)
+ synexpect(-1);
+ consumetoken(TTHEN);
+ n2->nif.ifpart = list(0);
+ }
+ if (lasttoken == TELSE)
+ n2->nif.elsepart = list(0);
+ else {
+ n2->nif.elsepart = NULL;
+ tokpushback++;
+ }
+ consumetoken(TFI);
+ checkkwd = CHKKWD | CHKALIAS;
+ break;
+ case TWHILE:
+ case TUNTIL:
+ t = lasttoken;
+ if ((n1 = list(0)) == NULL)
+ synexpect(-1);
+ consumetoken(TDO);
+ n1 = makebinary((t == TWHILE)? NWHILE : NUNTIL, n1, list(0));
+ consumetoken(TDONE);
+ checkkwd = CHKKWD | CHKALIAS;
+ break;
+ case TFOR:
+ if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
+ synerror("Bad for loop variable");
+ n1 = (union node *)stalloc(sizeof (struct nfor));
+ n1->type = NFOR;
+ n1->nfor.var = wordtext;
+ while (readtoken() == TNL)
+ ;
+ if (lasttoken == TWORD && ! quoteflag && equal(wordtext, "in")) {
+ app = &ap;
+ while (readtoken() == TWORD) {
+ n2 = makename();
+ *app = n2;
+ app = &n2->narg.next;
+ }
+ *app = NULL;
+ n1->nfor.args = ap;
+ if (lasttoken != TNL && lasttoken != TSEMI)
+ synexpect(-1);
+ } else {
+ static char argvars[5] = {
+ CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0'
+ };
+ n2 = (union node *)stalloc(sizeof (struct narg));
+ n2->type = NARG;
+ n2->narg.text = argvars;
+ n2->narg.backquote = NULL;
+ n2->narg.next = NULL;
+ n1->nfor.args = n2;
+ /*
+ * Newline or semicolon here is optional (but note
+ * that the original Bourne shell only allowed NL).
+ */
+ if (lasttoken != TNL && lasttoken != TSEMI)
+ tokpushback++;
+ }
+ checkkwd = CHKNL | CHKKWD | CHKALIAS;
+ if ((t = readtoken()) == TDO)
+ t = TDONE;
+ else if (t == TBEGIN)
+ t = TEND;
+ else
+ synexpect(-1);
+ n1->nfor.body = list(0);
+ consumetoken(t);
+ checkkwd = CHKKWD | CHKALIAS;
+ break;
+ case TCASE:
+ n1 = (union node *)stalloc(sizeof (struct ncase));
+ n1->type = NCASE;
+ consumetoken(TWORD);
+ n1->ncase.expr = makename();
+ while (readtoken() == TNL);
+ if (lasttoken != TWORD || ! equal(wordtext, "in"))
+ synerror("expecting \"in\"");
+ cpp = &n1->ncase.cases;
+ checkkwd = CHKNL | CHKKWD, readtoken();
+ while (lasttoken != TESAC) {
+ *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
+ cp->type = NCLIST;
+ app = &cp->nclist.pattern;
+ if (lasttoken == TLP)
+ readtoken();
+ for (;;) {
+ *app = ap = makename();
+ checkkwd = CHKNL | CHKKWD;
+ if (readtoken() != TPIPE)
+ break;
+ app = &ap->narg.next;
+ readtoken();
+ }
+ ap->narg.next = NULL;
+ if (lasttoken != TRP)
+ synexpect(TRP);
+ cp->nclist.body = list(0);
+
+ checkkwd = CHKNL | CHKKWD | CHKALIAS;
+ if ((t = readtoken()) != TESAC) {
+ if (t == TENDCASE)
+ ;
+ else if (t == TFALLTHRU)
+ cp->type = NCLISTFALLTHRU;
+ else
+ synexpect(TENDCASE);
+ checkkwd = CHKNL | CHKKWD, readtoken();
+ }
+ cpp = &cp->nclist.next;
+ }
+ *cpp = NULL;
+ checkkwd = CHKKWD | CHKALIAS;
+ break;
+ case TLP:
+ n1 = (union node *)stalloc(sizeof (struct nredir));
+ n1->type = NSUBSHELL;
+ n1->nredir.n = list(0);
+ n1->nredir.redirect = NULL;
+ consumetoken(TRP);
+ checkkwd = CHKKWD | CHKALIAS;
+ is_subshell = 1;
+ break;
+ case TBEGIN:
+ n1 = list(0);
+ consumetoken(TEND);
+ checkkwd = CHKKWD | CHKALIAS;
+ break;
+ /* A simple command must have at least one redirection or word. */
+ case TBACKGND:
+ case TSEMI:
+ case TAND:
+ case TOR:
+ case TPIPE:
+ case TENDCASE:
+ case TFALLTHRU:
+ case TEOF:
+ case TNL:
+ case TRP:
+ if (!redir)
+ synexpect(-1);
+ case TWORD:
+ tokpushback++;
+ n1 = simplecmd(rpp, redir);
+ return n1;
+ default:
+ synexpect(-1);
+ }
+
+ /* Now check for redirection which may follow command */
+ while (readtoken() == TREDIR) {
+ *rpp = n2 = redirnode;
+ rpp = &n2->nfile.next;
+ parsefname();
+ }
+ tokpushback++;
+ *rpp = NULL;
+ if (redir) {
+ if (!is_subshell) {
+ n2 = (union node *)stalloc(sizeof (struct nredir));
+ n2->type = NREDIR;
+ n2->nredir.n = n1;
+ n1 = n2;
+ }
+ n1->nredir.redirect = redir;
+ }
+
+ return n1;
+}
+
+
+static union node *
+simplecmd(union node **rpp, union node *redir)
+{
+ union node *args, **app;
+ union node **orig_rpp = rpp;
+ union node *n = NULL;
+ int special;
+ int savecheckkwd;
+
+ /* If we don't have any redirections already, then we must reset */
+ /* rpp to be the address of the local redir variable. */
+ if (redir == NULL)
+ rpp = &redir;
+
+ args = NULL;
+ app = &args;
+ /*
+ * We save the incoming value, because we need this for shell
+ * functions. There can not be a redirect or an argument between
+ * the function name and the open parenthesis.
+ */
+ orig_rpp = rpp;
+
+ savecheckkwd = CHKALIAS;
+
+ for (;;) {
+ checkkwd = savecheckkwd;
+ if (readtoken() == TWORD) {
+ n = makename();
+ *app = n;
+ app = &n->narg.next;
+ if (savecheckkwd != 0 && !isassignment(wordtext))
+ savecheckkwd = 0;
+ } else if (lasttoken == TREDIR) {
+ *rpp = n = redirnode;
+ rpp = &n->nfile.next;
+ parsefname(); /* read name of redirection file */
+ } else if (lasttoken == TLP && app == &args->narg.next
+ && rpp == orig_rpp) {
+ /* We have a function */
+ consumetoken(TRP);
+ funclinno = plinno;
+ /*
+ * - Require plain text.
+ * - Functions with '/' cannot be called.
+ * - Reject name=().
+ * - Reject ksh extended glob patterns.
+ */
+ if (!noexpand(n->narg.text) || quoteflag ||
+ strchr(n->narg.text, '/') ||
+ strchr("!%*+-=?@}~",
+ n->narg.text[strlen(n->narg.text) - 1]))
+ synerror("Bad function name");
+ rmescapes(n->narg.text);
+ if (find_builtin(n->narg.text, &special) >= 0 &&
+ special)
+ synerror("Cannot override a special builtin with a function");
+ n->type = NDEFUN;
+ n->narg.next = command();
+ funclinno = 0;
+ return n;
+ } else {
+ tokpushback++;
+ break;
+ }
+ }
+ *app = NULL;
+ *rpp = NULL;
+ n = (union node *)stalloc(sizeof (struct ncmd));
+ n->type = NCMD;
+ n->ncmd.args = args;
+ n->ncmd.redirect = redir;
+ return n;
+}
+
+static union node *
+makename(void)
+{
+ union node *n;
+
+ n = (union node *)stalloc(sizeof (struct narg));
+ n->type = NARG;
+ n->narg.next = NULL;
+ n->narg.text = wordtext;
+ n->narg.backquote = backquotelist;
+ return n;
+}
+
+static union node *
+makebinary(int type, union node *n1, union node *n2)
+{
+ union node *n;
+
+ n = (union node *)stalloc(sizeof (struct nbinary));
+ n->type = type;
+ n->nbinary.ch1 = n1;
+ n->nbinary.ch2 = n2;
+ return (n);
+}
+
+void
+forcealias(void)
+{
+ checkkwd |= CHKALIAS;
+}
+
+void
+fixredir(union node *n, const char *text, int err)
+{
+ TRACE(("Fix redir %s %d\n", text, err));
+ if (!err)
+ n->ndup.vname = NULL;
+
+ if (is_digit(text[0]) && text[1] == '\0')
+ n->ndup.dupfd = digit_val(text[0]);
+ else if (text[0] == '-' && text[1] == '\0')
+ n->ndup.dupfd = -1;
+ else {
+
+ if (err)
+ synerror("Bad fd number");
+ else
+ n->ndup.vname = makename();
+ }
+}
+
+
+static void
+parsefname(void)
+{
+ union node *n = redirnode;
+
+ consumetoken(TWORD);
+ if (n->type == NHERE) {
+ struct heredoc *here = heredoc;
+ struct heredoc *p;
+
+ if (quoteflag == 0)
+ n->type = NXHERE;
+ TRACE(("Here document %d\n", n->type));
+ if (here->striptabs) {
+ while (*wordtext == '\t')
+ wordtext++;
+ }
+ if (! noexpand(wordtext))
+ synerror("Illegal eof marker for << redirection");
+ rmescapes(wordtext);
+ here->eofmark = wordtext;
+ here->next = NULL;
+ if (heredoclist == NULL)
+ heredoclist = here;
+ else {
+ for (p = heredoclist ; p->next ; p = p->next);
+ p->next = here;
+ }
+ } else if (n->type == NTOFD || n->type == NFROMFD) {
+ fixredir(n, wordtext, 0);
+ } else {
+ n->nfile.fname = makename();
+ }
+}
+
+
+/*
+ * Input any here documents.
+ */
+
+static void
+parseheredoc(void)
+{
+ struct heredoc *here;
+ union node *n;
+
+ while (heredoclist) {
+ here = heredoclist;
+ heredoclist = here->next;
+ if (needprompt) {
+ setprompt(2);
+ needprompt = 0;
+ }
+ readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
+ here->eofmark, here->striptabs);
+ n = makename();
+ here->here->nhere.doc = n;
+ }
+}
+
+static int
+peektoken(void)
+{
+ int t;
+
+ t = readtoken();
+ tokpushback++;
+ return (t);
+}
+
+static int
+readtoken(void)
+{
+ int t;
+ struct alias *ap;
+#ifdef DEBUG
+ int alreadyseen = tokpushback;
+#endif
+
+ top:
+ t = xxreadtoken();
+
+ /*
+ * eat newlines
+ */
+ if (checkkwd & CHKNL) {
+ while (t == TNL) {
+ parseheredoc();
+ t = xxreadtoken();
+ }
+ }
+
+ /*
+ * check for keywords and aliases
+ */
+ if (t == TWORD && !quoteflag)
+ {
+ const char * const *pp;
+
+ if (checkkwd & CHKKWD)
+ for (pp = parsekwd; *pp; pp++) {
+ if (**pp == *wordtext && equal(*pp, wordtext))
+ {
+ lasttoken = t = pp - parsekwd + KWDOFFSET;
+ TRACE(("keyword %s recognized\n", tokname[t]));
+ goto out;
+ }
+ }
+ if (checkkwd & CHKALIAS &&
+ (ap = lookupalias(wordtext, 1)) != NULL) {
+ pushstring(ap->val, strlen(ap->val), ap);
+ goto top;
+ }
+ }
+out:
+ if (t != TNOT)
+ checkkwd = 0;
+
+#ifdef DEBUG
+ if (!alreadyseen)
+ TRACE(("token %s %s\n", tokname[t], t == TWORD ? wordtext : ""));
+ else
+ TRACE(("reread token %s %s\n", tokname[t], t == TWORD ? wordtext : ""));
+#endif
+ return (t);
+}
+
+
+/*
+ * Read the next input token.
+ * If the token is a word, we set backquotelist to the list of cmds in
+ * backquotes. We set quoteflag to true if any part of the word was
+ * quoted.
+ * If the token is TREDIR, then we set redirnode to a structure containing
+ * the redirection.
+ * In all cases, the variable startlinno is set to the number of the line
+ * on which the token starts.
+ *
+ * [Change comment: here documents and internal procedures]
+ * [Readtoken shouldn't have any arguments. Perhaps we should make the
+ * word parsing code into a separate routine. In this case, readtoken
+ * doesn't need to have any internal procedures, but parseword does.
+ * We could also make parseoperator in essence the main routine, and
+ * have parseword (readtoken1?) handle both words and redirection.]
+ */
+
+#define RETURN(token) return lasttoken = token
+
+static int
+xxreadtoken(void)
+{
+ int c;
+
+ if (tokpushback) {
+ tokpushback = 0;
+ return lasttoken;
+ }
+ if (needprompt) {
+ setprompt(2);
+ needprompt = 0;
+ }
+ startlinno = plinno;
+ for (;;) { /* until token or start of word found */
+ c = pgetc_macro();
+ switch (c) {
+ case ' ': case '\t':
+ continue;
+ case '#':
+ while ((c = pgetc()) != '\n' && c != PEOF);
+ pungetc();
+ continue;
+ case '\\':
+ if (pgetc() == '\n') {
+ startlinno = ++plinno;
+ if (doprompt)
+ setprompt(2);
+ else
+ setprompt(0);
+ continue;
+ }
+ pungetc();
+ /* FALLTHROUGH */
+ default:
+ return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
+ case '\n':
+ plinno++;
+ needprompt = doprompt;
+ RETURN(TNL);
+ case PEOF:
+ RETURN(TEOF);
+ case '&':
+ if (pgetc_linecont() == '&')
+ RETURN(TAND);
+ pungetc();
+ RETURN(TBACKGND);
+ case '|':
+ if (pgetc_linecont() == '|')
+ RETURN(TOR);
+ pungetc();
+ RETURN(TPIPE);
+ case ';':
+ c = pgetc_linecont();
+ if (c == ';')
+ RETURN(TENDCASE);
+ else if (c == '&')
+ RETURN(TFALLTHRU);
+ pungetc();
+ RETURN(TSEMI);
+ case '(':
+ RETURN(TLP);
+ case ')':
+ RETURN(TRP);
+ }
+ }
+#undef RETURN
+}
+
+
+#define MAXNEST_static 8
+struct tokenstate
+{
+ const char *syntax; /* *SYNTAX */
+ int parenlevel; /* levels of parentheses in arithmetic */
+ enum tokenstate_category
+ {
+ TSTATE_TOP,
+ TSTATE_VAR_OLD, /* ${var+-=?}, inherits dquotes */
+ TSTATE_VAR_NEW, /* other ${var...}, own dquote state */
+ TSTATE_ARITH
+ } category;
+};
+
+
+/*
+ * Check to see whether we are at the end of the here document. When this
+ * is called, c is set to the first character of the next input line. If
+ * we are at the end of the here document, this routine sets the c to PEOF.
+ * The new value of c is returned.
+ */
+
+static int
+checkend(int c, const char *eofmark, int striptabs)
+{
+ if (striptabs) {
+ while (c == '\t')
+ c = pgetc();
+ }
+ if (c == *eofmark) {
+ int c2;
+ const char *q;
+
+ for (q = eofmark + 1; c2 = pgetc(), *q != '\0' && c2 == *q; q++)
+ ;
+ if ((c2 == PEOF || c2 == '\n') && *q == '\0') {
+ c = PEOF;
+ if (c2 == '\n') {
+ plinno++;
+ needprompt = doprompt;
+ }
+ } else {
+ pungetc();
+ pushstring(eofmark + 1, q - (eofmark + 1), NULL);
+ }
+ } else if (c == '\n' && *eofmark == '\0') {
+ c = PEOF;
+ plinno++;
+ needprompt = doprompt;
+ }
+ return (c);
+}
+
+
+/*
+ * Parse a redirection operator. The variable "out" points to a string
+ * specifying the fd to be redirected. The variable "c" contains the
+ * first character of the redirection operator.
+ */
+
+static void
+parseredir(char *out, int c)
+{
+ char fd = *out;
+ union node *np;
+
+ np = (union node *)stalloc(sizeof (struct nfile));
+ if (c == '>') {
+ np->nfile.fd = 1;
+ c = pgetc_linecont();
+ if (c == '>')
+ np->type = NAPPEND;
+ else if (c == '&')
+ np->type = NTOFD;
+ else if (c == '|')
+ np->type = NCLOBBER;
+ else {
+ np->type = NTO;
+ pungetc();
+ }
+ } else { /* c == '<' */
+ np->nfile.fd = 0;
+ c = pgetc_linecont();
+ if (c == '<') {
+ if (sizeof (struct nfile) != sizeof (struct nhere)) {
+ np = (union node *)stalloc(sizeof (struct nhere));
+ np->nfile.fd = 0;
+ }
+ np->type = NHERE;
+ heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
+ heredoc->here = np;
+ if ((c = pgetc_linecont()) == '-') {
+ heredoc->striptabs = 1;
+ } else {
+ heredoc->striptabs = 0;
+ pungetc();
+ }
+ } else if (c == '&')
+ np->type = NFROMFD;
+ else if (c == '>')
+ np->type = NFROMTO;
+ else {
+ np->type = NFROM;
+ pungetc();
+ }
+ }
+ if (fd != '\0')
+ np->nfile.fd = digit_val(fd);
+ redirnode = np;
+}
+
+/*
+ * Called to parse command substitutions.
+ */
+
+static char *
+parsebackq(char *out, struct nodelist **pbqlist,
+ int oldstyle, int dblquote, int quoted)
+{
+ struct nodelist **nlpp;
+ union node *n;
+ char *volatile str;
+ struct jmploc jmploc;
+ struct jmploc *const savehandler = handler;
+ size_t savelen;
+ int saveprompt;
+ const int bq_startlinno = plinno;
+ char *volatile ostr = NULL;
+ struct parsefile *const savetopfile = getcurrentfile();
+ struct heredoc *const saveheredoclist = heredoclist;
+ struct heredoc *here;
+
+ str = NULL;
+ if (setjmp(jmploc.loc)) {
+ popfilesupto(savetopfile);
+ if (str)
+ ckfree(str);
+ if (ostr)
+ ckfree(ostr);
+ heredoclist = saveheredoclist;
+ handler = savehandler;
+ if (exception == EXERROR) {
+ startlinno = bq_startlinno;
+ synerror("Error in command substitution");
+ }
+ longjmp(handler->loc, 1);
+ }
+ INTOFF;
+ savelen = out - stackblock();
+ if (savelen > 0) {
+ str = ckmalloc(savelen);
+ memcpy(str, stackblock(), savelen);
+ }
+ handler = &jmploc;
+ heredoclist = NULL;
+ INTON;
+ if (oldstyle) {
+ /* We must read until the closing backquote, giving special
+ treatment to some slashes, and then push the string and
+ reread it as input, interpreting it normally. */
+ char *oout;
+ int c;
+ int olen;
+
+
+ STARTSTACKSTR(oout);
+ for (;;) {
+ if (needprompt) {
+ setprompt(2);
+ needprompt = 0;
+ }
+ CHECKSTRSPACE(2, oout);
+ c = pgetc_linecont();
+ if (c == '`')
+ break;
+ switch (c) {
+ case '\\':
+ c = pgetc();
+ if (c != '\\' && c != '`' && c != '$'
+ && (!dblquote || c != '"'))
+ USTPUTC('\\', oout);
+ break;
+
+ case '\n':
+ plinno++;
+ needprompt = doprompt;
+ break;
+
+ case PEOF:
+ startlinno = plinno;
+ synerror("EOF in backquote substitution");
+ break;
+
+ default:
+ break;
+ }
+ USTPUTC(c, oout);
+ }
+ USTPUTC('\0', oout);
+ olen = oout - stackblock();
+ INTOFF;
+ ostr = ckmalloc(olen);
+ memcpy(ostr, stackblock(), olen);
+ setinputstring(ostr, 1);
+ INTON;
+ }
+ nlpp = pbqlist;
+ while (*nlpp)
+ nlpp = &(*nlpp)->next;
+ *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
+ (*nlpp)->next = NULL;
+
+ if (oldstyle) {
+ saveprompt = doprompt;
+ doprompt = 0;
+ }
+
+ n = list(0);
+
+ if (oldstyle) {
+ if (peektoken() != TEOF)
+ synexpect(-1);
+ doprompt = saveprompt;
+ } else
+ consumetoken(TRP);
+
+ (*nlpp)->n = n;
+ if (oldstyle) {
+ /*
+ * Start reading from old file again, ignoring any pushed back
+ * tokens left from the backquote parsing
+ */
+ popfile();
+ tokpushback = 0;
+ }
+ STARTSTACKSTR(out);
+ CHECKSTRSPACE(savelen + 1, out);
+ INTOFF;
+ if (str) {
+ memcpy(out, str, savelen);
+ STADJUST(savelen, out);
+ ckfree(str);
+ str = NULL;
+ }
+ if (ostr) {
+ ckfree(ostr);
+ ostr = NULL;
+ }
+ here = saveheredoclist;
+ if (here != NULL) {
+ while (here->next != NULL)
+ here = here->next;
+ here->next = heredoclist;
+ heredoclist = saveheredoclist;
+ }
+ handler = savehandler;
+ INTON;
+ if (quoted)
+ USTPUTC(CTLBACKQ | CTLQUOTE, out);
+ else
+ USTPUTC(CTLBACKQ, out);
+ return out;
+}
+
+
+/*
+ * Called to parse a backslash escape sequence inside $'...'.
+ * The backslash has already been read.
+ */
+static char *
+readcstyleesc(char *out)
+{
+ int c, vc, i, n;
+ unsigned int v;
+
+ c = pgetc();
+ switch (c) {
+ case '\0':
+ synerror("Unterminated quoted string");
+ case '\n':
+ plinno++;
+ if (doprompt)
+ setprompt(2);
+ else
+ setprompt(0);
+ return out;
+ case '\\':
+ case '\'':
+ case '"':
+ v = c;
+ break;
+ case 'a': v = '\a'; break;
+ case 'b': v = '\b'; break;
+ case 'e': v = '\033'; break;
+ case 'f': v = '\f'; break;
+ case 'n': v = '\n'; break;
+ case 'r': v = '\r'; break;
+ case 't': v = '\t'; break;
+ case 'v': v = '\v'; break;
+ case 'x':
+ v = 0;
+ for (;;) {
+ c = pgetc();
+ if (c >= '0' && c <= '9')
+ v = (v << 4) + c - '0';
+ else if (c >= 'A' && c <= 'F')
+ v = (v << 4) + c - 'A' + 10;
+ else if (c >= 'a' && c <= 'f')
+ v = (v << 4) + c - 'a' + 10;
+ else
+ break;
+ }
+ pungetc();
+ break;
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ v = c - '0';
+ c = pgetc();
+ if (c >= '0' && c <= '7') {
+ v <<= 3;
+ v += c - '0';
+ c = pgetc();
+ if (c >= '0' && c <= '7') {
+ v <<= 3;
+ v += c - '0';
+ } else
+ pungetc();
+ } else
+ pungetc();
+ break;
+ case 'c':
+ c = pgetc();
+ if (c < 0x3f || c > 0x7a || c == 0x60)
+ synerror("Bad escape sequence");
+ if (c == '\\' && pgetc() != '\\')
+ synerror("Bad escape sequence");
+ if (c == '?')
+ v = 127;
+ else
+ v = c & 0x1f;
+ break;
+ case 'u':
+ case 'U':
+ n = c == 'U' ? 8 : 4;
+ v = 0;
+ for (i = 0; i < n; i++) {
+ c = pgetc();
+ if (c >= '0' && c <= '9')
+ v = (v << 4) + c - '0';
+ else if (c >= 'A' && c <= 'F')
+ v = (v << 4) + c - 'A' + 10;
+ else if (c >= 'a' && c <= 'f')
+ v = (v << 4) + c - 'a' + 10;
+ else
+ synerror("Bad escape sequence");
+ }
+ if (v == 0 || (v >= 0xd800 && v <= 0xdfff))
+ synerror("Bad escape sequence");
+ /* We really need iconv here. */
+ if (initial_localeisutf8 && v > 127) {
+ CHECKSTRSPACE(4, out);
+ /*
+ * We cannot use wctomb() as the locale may have
+ * changed.
+ */
+ if (v <= 0x7ff) {
+ USTPUTC(0xc0 | v >> 6, out);
+ USTPUTC(0x80 | (v & 0x3f), out);
+ return out;
+ } else if (v <= 0xffff) {
+ USTPUTC(0xe0 | v >> 12, out);
+ USTPUTC(0x80 | ((v >> 6) & 0x3f), out);
+ USTPUTC(0x80 | (v & 0x3f), out);
+ return out;
+ } else if (v <= 0x10ffff) {
+ USTPUTC(0xf0 | v >> 18, out);
+ USTPUTC(0x80 | ((v >> 12) & 0x3f), out);
+ USTPUTC(0x80 | ((v >> 6) & 0x3f), out);
+ USTPUTC(0x80 | (v & 0x3f), out);
+ return out;
+ }
+ }
+ if (v > 127)
+ v = '?';
+ break;
+ default:
+ synerror("Bad escape sequence");
+ }
+ vc = (char)v;
+ /*
+ * We can't handle NUL bytes.
+ * POSIX says we should skip till the closing quote.
+ */
+ if (vc == '\0') {
+ while ((c = pgetc()) != '\'') {
+ if (c == '\\')
+ c = pgetc();
+ if (c == PEOF)
+ synerror("Unterminated quoted string");
+ if (c == '\n') {
+ plinno++;
+ if (doprompt)
+ setprompt(2);
+ else
+ setprompt(0);
+ }
+ }
+ pungetc();
+ return out;
+ }
+ if (SQSYNTAX[vc] == CCTL)
+ USTPUTC(CTLESC, out);
+ USTPUTC(vc, out);
+ return out;
+}
+
+
+/*
+ * If eofmark is NULL, read a word or a redirection symbol. If eofmark
+ * is not NULL, read a here document. In the latter case, eofmark is the
+ * word which marks the end of the document and striptabs is true if
+ * leading tabs should be stripped from the document. The argument firstc
+ * is the first character of the input token or document.
+ *
+ * Because C does not have internal subroutines, I have simulated them
+ * using goto's to implement the subroutine linkage. The following macros
+ * will run code that appears at the end of readtoken1.
+ */
+
+#define PARSESUB() {goto parsesub; parsesub_return:;}
+#define PARSEARITH() {goto parsearith; parsearith_return:;}
+
+static int
+readtoken1(int firstc, char const *initialsyntax, const char *eofmark,
+ int striptabs)
+{
+ int c = firstc;
+ char *out;
+ int len;
+ struct nodelist *bqlist;
+ int quotef;
+ int newvarnest;
+ int level;
+ int synentry;
+ struct tokenstate state_static[MAXNEST_static];
+ int maxnest = MAXNEST_static;
+ struct tokenstate *state = state_static;
+ int sqiscstyle = 0;
+
+ startlinno = plinno;
+ quotef = 0;
+ bqlist = NULL;
+ newvarnest = 0;
+ level = 0;
+ state[level].syntax = initialsyntax;
+ state[level].parenlevel = 0;
+ state[level].category = TSTATE_TOP;
+
+ STARTSTACKSTR(out);
+ loop: { /* for each line, until end of word */
+ if (eofmark && eofmark != NOEOFMARK)
+ /* set c to PEOF if at end of here document */
+ c = checkend(c, eofmark, striptabs);
+ for (;;) { /* until end of line or end of word */
+ CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
+
+ synentry = state[level].syntax[c];
+
+ switch(synentry) {
+ case CNL: /* '\n' */
+ if (state[level].syntax == BASESYNTAX)
+ goto endword; /* exit outer loop */
+ USTPUTC(c, out);
+ plinno++;
+ if (doprompt)
+ setprompt(2);
+ else
+ setprompt(0);
+ c = pgetc();
+ goto loop; /* continue outer loop */
+ case CSBACK:
+ if (sqiscstyle) {
+ out = readcstyleesc(out);
+ break;
+ }
+ /* FALLTHROUGH */
+ case CWORD:
+ USTPUTC(c, out);
+ break;
+ case CCTL:
+ if (eofmark == NULL || initialsyntax != SQSYNTAX)
+ USTPUTC(CTLESC, out);
+ USTPUTC(c, out);
+ break;
+ case CBACK: /* backslash */
+ c = pgetc();
+ if (c == PEOF) {
+ USTPUTC('\\', out);
+ pungetc();
+ } else if (c == '\n') {
+ plinno++;
+ if (doprompt)
+ setprompt(2);
+ else
+ setprompt(0);
+ } else {
+ if (state[level].syntax == DQSYNTAX &&
+ c != '\\' && c != '`' && c != '$' &&
+ (c != '"' || (eofmark != NULL &&
+ newvarnest == 0)) &&
+ (c != '}' || state[level].category != TSTATE_VAR_OLD))
+ USTPUTC('\\', out);
+ if ((eofmark == NULL ||
+ newvarnest > 0) &&
+ state[level].syntax == BASESYNTAX)
+ USTPUTC(CTLQUOTEMARK, out);
+ if (SQSYNTAX[c] == CCTL)
+ USTPUTC(CTLESC, out);
+ USTPUTC(c, out);
+ if ((eofmark == NULL ||
+ newvarnest > 0) &&
+ state[level].syntax == BASESYNTAX &&
+ state[level].category == TSTATE_VAR_OLD)
+ USTPUTC(CTLQUOTEEND, out);
+ quotef++;
+ }
+ break;
+ case CSQUOTE:
+ USTPUTC(CTLQUOTEMARK, out);
+ state[level].syntax = SQSYNTAX;
+ sqiscstyle = 0;
+ break;
+ case CDQUOTE:
+ USTPUTC(CTLQUOTEMARK, out);
+ state[level].syntax = DQSYNTAX;
+ break;
+ case CENDQUOTE:
+ if (eofmark != NULL && newvarnest == 0)
+ USTPUTC(c, out);
+ else {
+ if (state[level].category == TSTATE_VAR_OLD)
+ USTPUTC(CTLQUOTEEND, out);
+ state[level].syntax = BASESYNTAX;
+ quotef++;
+ }
+ break;
+ case CVAR: /* '$' */
+ PARSESUB(); /* parse substitution */
+ break;
+ case CENDVAR: /* '}' */
+ if (level > 0 &&
+ ((state[level].category == TSTATE_VAR_OLD &&
+ state[level].syntax ==
+ state[level - 1].syntax) ||
+ (state[level].category == TSTATE_VAR_NEW &&
+ state[level].syntax == BASESYNTAX))) {
+ if (state[level].category == TSTATE_VAR_NEW)
+ newvarnest--;
+ level--;
+ USTPUTC(CTLENDVAR, out);
+ } else {
+ USTPUTC(c, out);
+ }
+ break;
+ case CLP: /* '(' in arithmetic */
+ state[level].parenlevel++;
+ USTPUTC(c, out);
+ break;
+ case CRP: /* ')' in arithmetic */
+ if (state[level].parenlevel > 0) {
+ USTPUTC(c, out);
+ --state[level].parenlevel;
+ } else {
+ if (pgetc_linecont() == ')') {
+ if (level > 0 &&
+ state[level].category == TSTATE_ARITH) {
+ level--;
+ USTPUTC(CTLENDARI, out);
+ } else
+ USTPUTC(')', out);
+ } else {
+ /*
+ * unbalanced parens
+ * (don't 2nd guess - no error)
+ */
+ pungetc();
+ USTPUTC(')', out);
+ }
+ }
+ break;
+ case CBQUOTE: /* '`' */
+ out = parsebackq(out, &bqlist, 1,
+ state[level].syntax == DQSYNTAX &&
+ (eofmark == NULL || newvarnest > 0),
+ state[level].syntax == DQSYNTAX || state[level].syntax == ARISYNTAX);
+ break;
+ case CEOF:
+ goto endword; /* exit outer loop */
+ case CIGN:
+ break;
+ default:
+ if (level == 0)
+ goto endword; /* exit outer loop */
+ USTPUTC(c, out);
+ }
+ c = pgetc_macro();
+ }
+ }
+endword:
+ if (state[level].syntax == ARISYNTAX)
+ synerror("Missing '))'");
+ if (state[level].syntax != BASESYNTAX && eofmark == NULL)
+ synerror("Unterminated quoted string");
+ if (state[level].category == TSTATE_VAR_OLD ||
+ state[level].category == TSTATE_VAR_NEW) {
+ startlinno = plinno;
+ synerror("Missing '}'");
+ }
+ if (state != state_static)
+ parser_temp_free_upto(state);
+ USTPUTC('\0', out);
+ len = out - stackblock();
+ out = stackblock();
+ if (eofmark == NULL) {
+ if ((c == '>' || c == '<')
+ && quotef == 0
+ && len <= 2
+ && (*out == '\0' || is_digit(*out))) {
+ parseredir(out, c);
+ return lasttoken = TREDIR;
+ } else {
+ pungetc();
+ }
+ }
+ quoteflag = quotef;
+ backquotelist = bqlist;
+ grabstackblock(len);
+ wordtext = out;
+ return lasttoken = TWORD;
+/* end of readtoken routine */
+
+
+/*
+ * Parse a substitution. At this point, we have read the dollar sign
+ * and nothing else.
+ */
+
+parsesub: {
+ int subtype;
+ int typeloc;
+ int flags;
+ char *p;
+ static const char types[] = "}-+?=";
+ int linno;
+ int length;
+ int c1;
+
+ c = pgetc_linecont();
+ if (c == '(') { /* $(command) or $((arith)) */
+ if (pgetc_linecont() == '(') {
+ PARSEARITH();
+ } else {
+ pungetc();
+ out = parsebackq(out, &bqlist, 0,
+ state[level].syntax == DQSYNTAX &&
+ (eofmark == NULL || newvarnest > 0),
+ state[level].syntax == DQSYNTAX ||
+ state[level].syntax == ARISYNTAX);
+ }
+ } else if (c == '{' || is_name(c) || is_special(c)) {
+ USTPUTC(CTLVAR, out);
+ typeloc = out - stackblock();
+ USTPUTC(VSNORMAL, out);
+ subtype = VSNORMAL;
+ flags = 0;
+ if (c == '{') {
+ c = pgetc_linecont();
+ subtype = 0;
+ }
+varname:
+ if (!is_eof(c) && is_name(c)) {
+ length = 0;
+ do {
+ STPUTC(c, out);
+ c = pgetc_linecont();
+ length++;
+ } while (!is_eof(c) && is_in_name(c));
+ if (length == 6 &&
+ strncmp(out - length, "LINENO", length) == 0) {
+ /* Replace the variable name with the
+ * current line number. */
+ STADJUST(-6, out);
+ CHECKSTRSPACE(11, out);
+ linno = plinno;
+ if (funclinno != 0)
+ linno -= funclinno - 1;
+ length = snprintf(out, 11, "%d", linno);
+ if (length > 10)
+ length = 10;
+ out += length;
+ flags |= VSLINENO;
+ }
+ } else if (is_digit(c)) {
+ if (subtype != VSNORMAL) {
+ do {
+ STPUTC(c, out);
+ c = pgetc_linecont();
+ } while (is_digit(c));
+ } else {
+ USTPUTC(c, out);
+ c = pgetc_linecont();
+ }
+ } else if (is_special(c)) {
+ c1 = c;
+ c = pgetc_linecont();
+ if (subtype == 0 && c1 == '#') {
+ subtype = VSLENGTH;
+ if (strchr(types, c) == NULL && c != ':' &&
+ c != '#' && c != '%')
+ goto varname;
+ c1 = c;
+ c = pgetc_linecont();
+ if (c1 != '}' && c == '}') {
+ pungetc();
+ c = c1;
+ goto varname;
+ }
+ pungetc();
+ c = c1;
+ c1 = '#';
+ subtype = 0;
+ }
+ USTPUTC(c1, out);
+ } else {
+ subtype = VSERROR;
+ if (c == '}')
+ pungetc();
+ else if (c == '\n' || c == PEOF)
+ synerror("Unexpected end of line in substitution");
+ else if (BASESYNTAX[c] != CCTL)
+ USTPUTC(c, out);
+ }
+ if (subtype == 0) {
+ switch (c) {
+ case ':':
+ flags |= VSNUL;
+ c = pgetc_linecont();
+ /*FALLTHROUGH*/
+ default:
+ p = strchr(types, c);
+ if (p == NULL) {
+ if (c == '\n' || c == PEOF)
+ synerror("Unexpected end of line in substitution");
+ if (flags == VSNUL)
+ STPUTC(':', out);
+ if (BASESYNTAX[c] != CCTL)
+ STPUTC(c, out);
+ subtype = VSERROR;
+ } else
+ subtype = p - types + VSNORMAL;
+ break;
+ case '%':
+ case '#':
+ {
+ int cc = c;
+ subtype = c == '#' ? VSTRIMLEFT :
+ VSTRIMRIGHT;
+ c = pgetc_linecont();
+ if (c == cc)
+ subtype++;
+ else
+ pungetc();
+ break;
+ }
+ }
+ } else if (subtype != VSERROR) {
+ if (subtype == VSLENGTH && c != '}')
+ subtype = VSERROR;
+ pungetc();
+ }
+ STPUTC('=', out);
+ if (state[level].syntax == DQSYNTAX ||
+ state[level].syntax == ARISYNTAX)
+ flags |= VSQUOTE;
+ *(stackblock() + typeloc) = subtype | flags;
+ if (subtype != VSNORMAL) {
+ if (level + 1 >= maxnest) {
+ maxnest *= 2;
+ if (state == state_static) {
+ state = parser_temp_alloc(
+ maxnest * sizeof(*state));
+ memcpy(state, state_static,
+ MAXNEST_static * sizeof(*state));
+ } else
+ state = parser_temp_realloc(state,
+ maxnest * sizeof(*state));
+ }
+ level++;
+ state[level].parenlevel = 0;
+ if (subtype == VSMINUS || subtype == VSPLUS ||
+ subtype == VSQUESTION || subtype == VSASSIGN) {
+ /*
+ * For operators that were in the Bourne shell,
+ * inherit the double-quote state.
+ */
+ state[level].syntax = state[level - 1].syntax;
+ state[level].category = TSTATE_VAR_OLD;
+ } else {
+ /*
+ * The other operators take a pattern,
+ * so go to BASESYNTAX.
+ * Also, ' and " are now special, even
+ * in here documents.
+ */
+ state[level].syntax = BASESYNTAX;
+ state[level].category = TSTATE_VAR_NEW;
+ newvarnest++;
+ }
+ }
+ } else if (c == '\'' && state[level].syntax == BASESYNTAX) {
+ /* $'cstylequotes' */
+ USTPUTC(CTLQUOTEMARK, out);
+ state[level].syntax = SQSYNTAX;
+ sqiscstyle = 1;
+ } else {
+ USTPUTC('$', out);
+ pungetc();
+ }
+ goto parsesub_return;
+}
+
+
+/*
+ * Parse an arithmetic expansion (indicate start of one and set state)
+ */
+parsearith: {
+
+ if (level + 1 >= maxnest) {
+ maxnest *= 2;
+ if (state == state_static) {
+ state = parser_temp_alloc(
+ maxnest * sizeof(*state));
+ memcpy(state, state_static,
+ MAXNEST_static * sizeof(*state));
+ } else
+ state = parser_temp_realloc(state,
+ maxnest * sizeof(*state));
+ }
+ level++;
+ state[level].syntax = ARISYNTAX;
+ state[level].parenlevel = 0;
+ state[level].category = TSTATE_ARITH;
+ USTPUTC(CTLARI, out);
+ if (state[level - 1].syntax == DQSYNTAX)
+ USTPUTC('"',out);
+ else
+ USTPUTC(' ',out);
+ goto parsearith_return;
+}
+
+} /* end of readtoken */
+
+
+/*
+ * Returns true if the text contains nothing to expand (no dollar signs
+ * or backquotes).
+ */
+
+static int
+noexpand(char *text)
+{
+ char *p;
+ char c;
+
+ p = text;
+ while ((c = *p++) != '\0') {
+ if ( c == CTLQUOTEMARK)
+ continue;
+ if (c == CTLESC)
+ p++;
+ else if (BASESYNTAX[(int)c] == CCTL)
+ return 0;
+ }
+ return 1;
+}
+
+
+/*
+ * Return true if the argument is a legal variable name (a letter or
+ * underscore followed by zero or more letters, underscores, and digits).
+ */
+
+int
+goodname(const char *name)
+{
+ const char *p;
+
+ p = name;
+ if (! is_name(*p))
+ return 0;
+ while (*++p) {
+ if (! is_in_name(*p))
+ return 0;
+ }
+ return 1;
+}
+
+
+int
+isassignment(const char *p)
+{
+ if (!is_name(*p))
+ return 0;
+ p++;
+ for (;;) {
+ if (*p == '=')
+ return 1;
+ else if (!is_in_name(*p))
+ return 0;
+ p++;
+ }
+}
+
+
+static void
+consumetoken(int token)
+{
+ if (readtoken() != token)
+ synexpect(token);
+}
+
+
+/*
+ * Called when an unexpected token is read during the parse. The argument
+ * is the token that is expected, or -1 if more than one type of token can
+ * occur at this point.
+ */
+
+static void
+synexpect(int token)
+{
+ char msg[64];
+
+ if (token >= 0) {
+ fmtstr(msg, 64, "%s unexpected (expecting %s)",
+ tokname[lasttoken], tokname[token]);
+ } else {
+ fmtstr(msg, 64, "%s unexpected", tokname[lasttoken]);
+ }
+ synerror(msg);
+}
+
+
+static void
+synerror(const char *msg)
+{
+ if (commandname)
+ outfmt(out2, "%s: %d: ", commandname, startlinno);
+ else if (arg0)
+ outfmt(out2, "%s: ", arg0);
+ outfmt(out2, "Syntax error: %s\n", msg);
+ error((char *)NULL);
+}
+
+static void
+setprompt(int which)
+{
+ whichprompt = which;
+ if (which == 0)
+ return;
+
+#ifndef NO_HISTORY
+ if (!el)
+#endif
+ {
+ out2str(getprompt(NULL));
+ flushout(out2);
+ }
+}
+
+static int
+pgetc_linecont(void)
+{
+ int c;
+
+ while ((c = pgetc_macro()) == '\\') {
+ c = pgetc();
+ if (c == '\n') {
+ plinno++;
+ if (doprompt)
+ setprompt(2);
+ else
+ setprompt(0);
+ } else {
+ pungetc();
+ /* Allow the backslash to be pushed back. */
+ pushstring("\\", 1, NULL);
+ return (pgetc());
+ }
+ }
+ return (c);
+}
+
+/*
+ * called by editline -- any expansions to the prompt
+ * should be added here.
+ */
+char *
+getprompt(void *unused __unused)
+{
+ static char ps[PROMPTLEN];
+ const char *fmt;
+ const char *pwd;
+ int i, trim;
+ static char internal_error[] = "??";
+
+ /*
+ * Select prompt format.
+ */
+ switch (whichprompt) {
+ case 0:
+ fmt = "";
+ break;
+ case 1:
+ fmt = ps1val();
+ break;
+ case 2:
+ fmt = ps2val();
+ break;
+ default:
+ return internal_error;
+ }
+
+ /*
+ * Format prompt string.
+ */
+ for (i = 0; (i < PROMPTLEN - 1) && (*fmt != '\0'); i++, fmt++)
+ if (*fmt == '\\')
+ switch (*++fmt) {
+
+ /*
+ * Hostname.
+ *
+ * \h specifies just the local hostname,
+ * \H specifies fully-qualified hostname.
+ */
+ case 'h':
+ case 'H':
+ ps[i] = '\0';
+ gethostname(&ps[i], PROMPTLEN - i - 1);
+ ps[PROMPTLEN - 1] = '\0';
+ /* Skip to end of hostname. */
+ trim = (*fmt == 'h') ? '.' : '\0';
+ while ((ps[i] != '\0') && (ps[i] != trim))
+ i++;
+ --i;
+ break;
+
+ /*
+ * Working directory.
+ *
+ * \W specifies just the final component,
+ * \w specifies the entire path.
+ */
+ case 'W':
+ case 'w':
+ pwd = lookupvar("PWD");
+ if (pwd == NULL || *pwd == '\0')
+ pwd = "?";
+ if (*fmt == 'W' &&
+ *pwd == '/' && pwd[1] != '\0')
+ strlcpy(&ps[i], strrchr(pwd, '/') + 1,
+ PROMPTLEN - i);
+ else
+ strlcpy(&ps[i], pwd, PROMPTLEN - i);
+ /* Skip to end of path. */
+ while (ps[i + 1] != '\0')
+ i++;
+ break;
+
+ /*
+ * Superuser status.
+ *
+ * '$' for normal users, '#' for root.
+ */
+ case '$':
+ ps[i] = (geteuid() != 0) ? '$' : '#';
+ break;
+
+ /*
+ * A literal \.
+ */
+ case '\\':
+ ps[i] = '\\';
+ break;
+
+ /*
+ * Emit unrecognized formats verbatim.
+ */
+ default:
+ ps[i] = '\\';
+ if (i < PROMPTLEN - 2)
+ ps[++i] = *fmt;
+ break;
+ }
+ else
+ ps[i] = *fmt;
+ ps[i] = '\0';
+ return (ps);
+}
+
+
+const char *
+expandstr(const char *ps)
+{
+ union node n;
+ struct jmploc jmploc;
+ struct jmploc *const savehandler = handler;
+ const int saveprompt = doprompt;
+ struct parsefile *const savetopfile = getcurrentfile();
+ struct parser_temp *const saveparser_temp = parser_temp;
+ const char *result = NULL;
+
+ if (!setjmp(jmploc.loc)) {
+ handler = &jmploc;
+ parser_temp = NULL;
+ setinputstring(ps, 1);
+ doprompt = 0;
+ readtoken1(pgetc(), DQSYNTAX, NOEOFMARK, 0);
+ if (backquotelist != NULL)
+ error("Command substitution not allowed here");
+
+ n.narg.type = NARG;
+ n.narg.next = NULL;
+ n.narg.text = wordtext;
+ n.narg.backquote = backquotelist;
+
+ expandarg(&n, NULL, 0);
+ result = stackblock();
+ INTOFF;
+ }
+ handler = savehandler;
+ doprompt = saveprompt;
+ popfilesupto(savetopfile);
+ if (parser_temp != saveparser_temp) {
+ parser_temp_free_all();
+ parser_temp = saveparser_temp;
+ }
+ if (result != NULL) {
+ INTON;
+ } else if (exception == EXINT)
+ raise(SIGINT);
+ return result;
+}
diff --git a/shell_cmds/sh/parser.h b/shell_cmds/sh/parser.h
new file mode 100644
index 0000000..210726b
--- /dev/null
+++ b/shell_cmds/sh/parser.h
@@ -0,0 +1,87 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)parser.h 8.3 (Berkeley) 5/4/95
+ * $FreeBSD: head/bin/sh/parser.h 326025 2017-11-20 19:49:47Z pfg $
+ */
+
+/* control characters in argument strings */
+#define CTLESC '\300'
+#define CTLVAR '\301'
+#define CTLENDVAR '\371'
+#define CTLBACKQ '\372'
+#define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
+/* CTLBACKQ | CTLQUOTE == '\373' */
+#define CTLARI '\374'
+#define CTLENDARI '\375'
+#define CTLQUOTEMARK '\376'
+#define CTLQUOTEEND '\377' /* only for ${v+-...} */
+
+/* variable substitution byte (follows CTLVAR) */
+#define VSTYPE 0x0f /* type of variable substitution */
+#define VSNUL 0x10 /* colon--treat the empty string as unset */
+#define VSLINENO 0x20 /* expansion of $LINENO, the line number \
+ follows immediately */
+#define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
+
+/* values of VSTYPE field */
+#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
+#define VSMINUS 0x2 /* ${var-text} */
+#define VSPLUS 0x3 /* ${var+text} */
+#define VSQUESTION 0x4 /* ${var?message} */
+#define VSASSIGN 0x5 /* ${var=text} */
+#define VSTRIMLEFT 0x6 /* ${var#pattern} */
+#define VSTRIMLEFTMAX 0x7 /* ${var##pattern} */
+#define VSTRIMRIGHT 0x8 /* ${var%pattern} */
+#define VSTRIMRIGHTMAX 0x9 /* ${var%%pattern} */
+#define VSLENGTH 0xa /* ${#var} */
+#define VSERROR 0xb /* Syntax error, issue when expanded */
+
+
+/*
+ * NEOF is returned by parsecmd when it encounters an end of file. It
+ * must be distinct from NULL.
+ */
+#define NEOF ((union node *)-1)
+extern int whichprompt; /* 1 == PS1, 2 == PS2 */
+extern const char *const parsekwd[];
+
+
+union node *parsecmd(int);
+union node *parsewordexp(void);
+void forcealias(void);
+void fixredir(union node *, const char *, int);
+int goodname(const char *);
+int isassignment(const char *);
+char *getprompt(void *);
+const char *expandstr(const char *);
diff --git a/shell_cmds/sh/redir.c b/shell_cmds/sh/redir.c
new file mode 100644
index 0000000..8f415a6
--- /dev/null
+++ b/shell_cmds/sh/redir.c
@@ -0,0 +1,365 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)redir.c 8.2 (Berkeley) 5/4/95";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/bin/sh/redir.c 326025 2017-11-20 19:49:47Z pfg $");
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+/*
+ * Code for dealing with input/output redirection.
+ */
+
+#include "shell.h"
+#include "nodes.h"
+#include "jobs.h"
+#include "expand.h"
+#include "redir.h"
+#include "output.h"
+#include "memalloc.h"
+#include "error.h"
+#include "options.h"
+
+
+#define EMPTY -2 /* marks an unused slot in redirtab */
+#define CLOSED -1 /* fd was not open before redir */
+
+
+struct redirtab {
+ struct redirtab *next;
+ int renamed[10];
+ int fd0_redirected;
+ unsigned int empty_redirs;
+};
+
+
+static struct redirtab *redirlist;
+
+/*
+ * We keep track of whether or not fd0 has been redirected. This is for
+ * background commands, where we want to redirect fd0 to /dev/null only
+ * if it hasn't already been redirected.
+*/
+static int fd0_redirected = 0;
+
+/* Number of redirtabs that have not been allocated. */
+static unsigned int empty_redirs = 0;
+
+static void openredirect(union node *, char[10 ]);
+static int openhere(union node *);
+
+
+/*
+ * Process a list of redirection commands. If the REDIR_PUSH flag is set,
+ * old file descriptors are stashed away so that the redirection can be
+ * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
+ * standard output, and the standard error if it becomes a duplicate of
+ * stdout, is saved in memory.
+*
+ * We suppress interrupts so that we won't leave open file
+ * descriptors around. Because the signal handler remains
+ * installed and we do not use system call restart, interrupts
+ * will still abort blocking opens such as fifos (they will fail
+ * with EINTR). There is, however, a race condition if an interrupt
+ * arrives after INTOFF and before open blocks.
+ */
+
+void
+redirect(union node *redir, int flags)
+{
+ union node *n;
+ struct redirtab *sv = NULL;
+ int i;
+ int fd;
+ char memory[10]; /* file descriptors to write to memory */
+
+ INTOFF;
+ for (i = 10 ; --i >= 0 ; )
+ memory[i] = 0;
+ memory[1] = flags & REDIR_BACKQ;
+ if (flags & REDIR_PUSH) {
+ empty_redirs++;
+ if (redir != NULL) {
+ sv = ckmalloc(sizeof (struct redirtab));
+ for (i = 0 ; i < 10 ; i++)
+ sv->renamed[i] = EMPTY;
+ sv->fd0_redirected = fd0_redirected;
+ sv->empty_redirs = empty_redirs - 1;
+ sv->next = redirlist;
+ redirlist = sv;
+ empty_redirs = 0;
+ }
+ }
+ for (n = redir ; n ; n = n->nfile.next) {
+ fd = n->nfile.fd;
+ if (fd == 0)
+ fd0_redirected = 1;
+ if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
+ n->ndup.dupfd == fd)
+ continue; /* redirect from/to same file descriptor */
+
+ if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) {
+ INTOFF;
+ if ((i = fcntl(fd, F_DUPFD_CLOEXEC, 10)) == -1) {
+ switch (errno) {
+ case EBADF:
+ i = CLOSED;
+ break;
+ default:
+ INTON;
+ error("%d: %s", fd, strerror(errno));
+ break;
+ }
+ }
+ sv->renamed[fd] = i;
+ INTON;
+ }
+ openredirect(n, memory);
+ INTON;
+ INTOFF;
+ }
+ if (memory[1])
+ out1 = &memout;
+ if (memory[2])
+ out2 = &memout;
+ INTON;
+}
+
+
+static void
+openredirect(union node *redir, char memory[10])
+{
+ struct stat sb;
+ int fd = redir->nfile.fd;
+ const char *fname;
+ int f;
+ int e;
+
+ memory[fd] = 0;
+ switch (redir->nfile.type) {
+ case NFROM:
+ fname = redir->nfile.expfname;
+ if ((f = open(fname, O_RDONLY)) < 0)
+ error("cannot open %s: %s", fname, strerror(errno));
+ break;
+ case NFROMTO:
+ fname = redir->nfile.expfname;
+ if ((f = open(fname, O_RDWR|O_CREAT, 0666)) < 0)
+ error("cannot create %s: %s", fname, strerror(errno));
+ break;
+ case NTO:
+ if (Cflag) {
+ fname = redir->nfile.expfname;
+ if (stat(fname, &sb) == -1) {
+ if ((f = open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666)) < 0)
+ error("cannot create %s: %s", fname, strerror(errno));
+ } else if (!S_ISREG(sb.st_mode)) {
+ if ((f = open(fname, O_WRONLY, 0666)) < 0)
+ error("cannot create %s: %s", fname, strerror(errno));
+ if (fstat(f, &sb) != -1 && S_ISREG(sb.st_mode)) {
+ close(f);
+ error("cannot create %s: %s", fname,
+ strerror(EEXIST));
+ }
+ } else
+ error("cannot create %s: %s", fname,
+ strerror(EEXIST));
+ break;
+ }
+ /* FALLTHROUGH */
+ case NCLOBBER:
+ fname = redir->nfile.expfname;
+ if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
+ error("cannot create %s: %s", fname, strerror(errno));
+ break;
+ case NAPPEND:
+ fname = redir->nfile.expfname;
+ if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
+ error("cannot create %s: %s", fname, strerror(errno));
+ break;
+ case NTOFD:
+ case NFROMFD:
+ if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
+ if (memory[redir->ndup.dupfd])
+ memory[fd] = 1;
+ else {
+ if (dup2(redir->ndup.dupfd, fd) < 0)
+ error("%d: %s", redir->ndup.dupfd,
+ strerror(errno));
+ }
+ } else {
+ close(fd);
+ }
+ return;
+ case NHERE:
+ case NXHERE:
+ f = openhere(redir);
+ break;
+ default:
+ abort();
+ }
+ if (f != fd) {
+ if (dup2(f, fd) == -1) {
+ e = errno;
+ close(f);
+ error("%d: %s", fd, strerror(e));
+ }
+ close(f);
+ }
+}
+
+
+/*
+ * Handle here documents. Normally we fork off a process to write the
+ * data to a pipe. If the document is short, we can stuff the data in
+ * the pipe without forking.
+ */
+
+static int
+openhere(union node *redir)
+{
+ const char *p;
+ int pip[2];
+ size_t len = 0;
+ int flags;
+ ssize_t written = 0;
+
+ if (pipe(pip) < 0)
+ error("Pipe call failed: %s", strerror(errno));
+
+ if (redir->type == NXHERE)
+ p = redir->nhere.expdoc;
+ else
+ p = redir->nhere.doc->narg.text;
+ len = strlen(p);
+ if (len == 0)
+ goto out;
+ flags = fcntl(pip[1], F_GETFL, 0);
+ if (flags != -1 && fcntl(pip[1], F_SETFL, flags | O_NONBLOCK) != -1) {
+ written = write(pip[1], p, len);
+ if (written < 0)
+ written = 0;
+ if ((size_t)written == len)
+ goto out;
+ fcntl(pip[1], F_SETFL, flags);
+ }
+
+ if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
+ close(pip[0]);
+ signal(SIGINT, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+ signal(SIGHUP, SIG_IGN);
+ signal(SIGTSTP, SIG_IGN);
+ signal(SIGPIPE, SIG_DFL);
+ xwrite(pip[1], p + written, len - written);
+ _exit(0);
+ }
+out:
+ close(pip[1]);
+ return pip[0];
+}
+
+
+
+/*
+ * Undo the effects of the last redirection.
+ */
+
+void
+popredir(void)
+{
+ struct redirtab *rp = redirlist;
+ int i;
+
+ INTOFF;
+ if (empty_redirs > 0) {
+ empty_redirs--;
+ INTON;
+ return;
+ }
+ for (i = 0 ; i < 10 ; i++) {
+ if (rp->renamed[i] != EMPTY) {
+ if (rp->renamed[i] >= 0) {
+ dup2(rp->renamed[i], i);
+ close(rp->renamed[i]);
+ } else {
+ close(i);
+ }
+ }
+ }
+ fd0_redirected = rp->fd0_redirected;
+ empty_redirs = rp->empty_redirs;
+ redirlist = rp->next;
+ ckfree(rp);
+ INTON;
+}
+
+/* Return true if fd 0 has already been redirected at least once. */
+int
+fd0_redirected_p(void)
+{
+ return fd0_redirected != 0;
+}
+
+/*
+ * Discard all saved file descriptors.
+ */
+
+void
+clearredir(void)
+{
+ struct redirtab *rp;
+ int i;
+
+ for (rp = redirlist ; rp ; rp = rp->next) {
+ for (i = 0 ; i < 10 ; i++) {
+ if (rp->renamed[i] >= 0) {
+ close(rp->renamed[i]);
+ }
+ rp->renamed[i] = EMPTY;
+ }
+ }
+}
diff --git a/shell_cmds/sh/redir.h b/shell_cmds/sh/redir.h
new file mode 100644
index 0000000..74d17b1
--- /dev/null
+++ b/shell_cmds/sh/redir.h
@@ -0,0 +1,47 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)redir.h 8.2 (Berkeley) 5/4/95
+ * $FreeBSD: head/bin/sh/redir.h 326025 2017-11-20 19:49:47Z pfg $
+ */
+
+/* flags passed to redirect */
+#define REDIR_PUSH 01 /* save previous values of file descriptors */
+#define REDIR_BACKQ 02 /* save the command output in memory */
+
+union node;
+void redirect(union node *, int);
+void popredir(void);
+int fd0_redirected_p(void);
+void clearredir(void);
+
diff --git a/shell_cmds/sh/sh.1 b/shell_cmds/sh/sh.1
new file mode 100644
index 0000000..5c2e87d
--- /dev/null
+++ b/shell_cmds/sh/sh.1
@@ -0,0 +1,2879 @@
+.\"-
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Kenneth Almquist.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" from: @(#)sh.1 8.6 (Berkeley) 5/4/95
+.\" $FreeBSD: head/bin/sh/sh.1 327121 2017-12-23 22:58:19Z jilles $
+.\"
+.Dd October 8, 2016
+.Dt SH 1
+.Os
+.Sh NAME
+.Nm sh
+.Nd command interpreter (shell)
+.Sh SYNOPSIS
+.Nm
+.Op Fl /+abCEefhIimnPpTuVvx
+.Op Fl /+o Ar longname
+.Oo
+.Ar script
+.Op Ar arg ...
+.Oc
+.Nm
+.Op Fl /+abCEefhIimnPpTuVvx
+.Op Fl /+o Ar longname
+.Fl c Ar string
+.Oo
+.Ar name
+.Op Ar arg ...
+.Oc
+.Nm
+.Op Fl /+abCEefhIimnPpTuVvx
+.Op Fl /+o Ar longname
+.Fl s
+.Op Ar arg ...
+.Sh DESCRIPTION
+The
+.Nm
+utility is the standard command interpreter for the system.
+The current version of
+.Nm
+is close to the
+.St -p1003.1
+specification for the shell.
+It only supports features
+designated by
+.Tn POSIX ,
+plus a few Berkeley extensions.
+This man page is not intended to be a tutorial nor a complete
+specification of the shell.
+.Ss Overview
+The shell is a command that reads lines from
+either a file or the terminal, interprets them, and
+generally executes other commands.
+It is the program that is started when a user logs into the system,
+although a user can select a different shell with the
+.Xr chsh 1
+command.
+The shell
+implements a language that has flow control constructs,
+a macro facility that provides a variety of features in
+addition to data storage, along with built-in history and line
+editing capabilities.
+It incorporates many features to
+aid interactive use and has the advantage that the interpretative
+language is common to both interactive and non-interactive
+use (shell scripts).
+That is, commands can be typed directly
+to the running shell or can be put into a file,
+which can be executed directly by the shell.
+.Ss Invocation
+.\"
+.\" XXX This next sentence is incredibly confusing.
+.\"
+If no arguments are present and if the standard input of the shell
+is connected to a terminal
+(or if the
+.Fl i
+option is set),
+the shell is considered an interactive shell.
+An interactive shell
+generally prompts before each command and handles programming
+and command errors differently (as described below).
+When first starting, the shell inspects argument 0, and
+if it begins with a dash
+.Pq Ql - ,
+the shell is also considered a login shell.
+This is normally done automatically by the system
+when the user first logs in.
+A login shell first reads commands
+from the files
+.Pa /etc/profile
+and then
+.Pa .profile
+in a user's home directory,
+if they exist.
+If the environment variable
+.Ev ENV
+is set on entry to a shell, or is set in the
+.Pa .profile
+of a login shell, the shell then subjects its value to parameter expansion
+and arithmetic expansion and reads commands from the named file.
+Therefore, a user should place commands that are to be executed only
+at login time in the
+.Pa .profile
+file, and commands that are executed for every shell inside the
+.Ev ENV
+file.
+The user can set the
+.Ev ENV
+variable to some file by placing the following line in the file
+.Pa .profile
+in the home directory,
+substituting for
+.Pa .shrc
+the filename desired:
+.Pp
+.Dl "ENV=$HOME/.shrc; export ENV"
+.Pp
+The first non-option argument specified on the command line
+will be treated as the
+name of a file from which to read commands (a shell script), and
+the remaining arguments are set as the positional parameters
+of the shell
+.Li ( $1 , $2 ,
+etc.).
+Otherwise, the shell reads commands
+from its standard input.
+.Pp
+Unlike older versions of
+.Nm
+the
+.Ev ENV
+script is only sourced on invocation of interactive shells.
+This
+closes a well-known, and sometimes easily exploitable security
+hole related to poorly thought out
+.Ev ENV
+scripts.
+.Ss Argument List Processing
+All of the single letter options to
+.Nm
+have a corresponding long name,
+with the exception of
+.Fl c
+and
+.Fl /+o .
+These long names are provided next to the single letter options
+in the descriptions below.
+The long name for an option may be specified as an argument to the
+.Fl /+o
+option of
+.Nm .
+Once the shell is running,
+the long name for an option may be specified as an argument to the
+.Fl /+o
+option of the
+.Ic set
+built-in command
+(described later in the section called
+.Sx Built-in Commands ) .
+Introducing an option with a dash
+.Pq Ql -
+enables the option,
+while using a plus
+.Pq Ql +
+disables the option.
+A
+.Dq Li --
+or plain
+.Ql -
+will stop option processing and will force the remaining
+words on the command line to be treated as arguments.
+The
+.Fl /+o
+and
+.Fl c
+options do not have long names.
+They take arguments and are described after the single letter options.
+.Bl -tag -width indent
+.It Fl a Li allexport
+Flag variables for export when assignments are made to them.
+.It Fl b Li notify
+Enable asynchronous notification of background job
+completion.
+(UNIMPLEMENTED)
+.It Fl C Li noclobber
+Do not overwrite existing files with
+.Ql > .
+.It Fl E Li emacs
+Enable the built-in
+.Xr emacs 1
+command line editor (disables the
+.Fl V
+option if it has been set;
+set automatically when interactive on terminals).
+.It Fl e Li errexit
+Exit immediately if any untested command fails in non-interactive mode.
+The exit status of a command is considered to be
+explicitly tested if the command is part of the list used to control
+an
+.Ic if , elif , while ,
+or
+.Ic until ;
+if the command is the left
+hand operand of an
+.Dq Li &&
+or
+.Dq Li ||
+operator; or if the command is a pipeline preceded by the
+.Ic !\&
+keyword.
+If a shell function is executed and its exit status is explicitly
+tested, all commands of the function are considered to be tested as
+well.
+.Pp
+It is recommended to check for failures explicitly
+instead of relying on
+.Fl e
+because it tends to behave in unexpected ways,
+particularly in larger scripts.
+.It Fl f Li noglob
+Disable pathname expansion.
+.It Fl h Li trackall
+A do-nothing option for
+.Tn POSIX
+compliance.
+.It Fl I Li ignoreeof
+Ignore
+.Dv EOF Ap s
+from input when in interactive mode.
+.It Fl i Li interactive
+Force the shell to behave interactively.
+.It Fl m Li monitor
+Turn on job control (set automatically when interactive).
+A new process group is created for each pipeline (called a job).
+It is possible to suspend jobs or to have them run in the foreground or
+in the background.
+In a non-interactive shell,
+this option can be set even if no terminal is available
+and is useful to place processes in separate process groups.
+.It Fl n Li noexec
+If not interactive, read commands but do not
+execute them.
+This is useful for checking the
+syntax of shell scripts.
+.It Fl P Li physical
+Change the default for the
+.Ic cd
+and
+.Ic pwd
+commands from
+.Fl L
+(logical directory layout)
+to
+.Fl P
+(physical directory layout).
+.It Fl p Li privileged
+Turn on privileged mode.
+This mode is enabled on startup
+if either the effective user or group ID is not equal to the
+real user or group ID.
+Turning this mode off sets the
+effective user and group IDs to the real user and group IDs.
+When this mode is enabled for interactive shells, the file
+.Pa /etc/suid_profile
+is sourced instead of
+.Pa ~/.profile
+after
+.Pa /etc/profile
+is sourced, and the contents of the
+.Ev ENV
+variable are ignored.
+.It Fl s Li stdin
+Read commands from standard input (set automatically
+if no file arguments are present).
+This option has
+no effect when set after the shell has already started
+running (i.e., when set with the
+.Ic set
+command).
+.It Fl T Li trapsasync
+When waiting for a child, execute traps immediately.
+If this option is not set,
+traps are executed after the child exits,
+as specified in
+.St -p1003.2 .
+This nonstandard option is useful for putting guarding shells around
+children that block signals.
+The surrounding shell may kill the child
+or it may just return control to the tty and leave the child alone,
+like this:
+.Bd -literal -offset indent
+sh -T -c "trap 'exit 1' 2 ; some-blocking-program"
+.Ed
+.It Fl u Li nounset
+Write a message to standard error when attempting
+to expand a variable, a positional parameter or
+the special parameter
+.Va \&!
+that is not set, and if the
+shell is not interactive, exit immediately.
+.It Fl V Li vi
+Enable the built-in
+.Xr vi 1
+command line editor (disables
+.Fl E
+if it has been set).
+.It Fl v Li verbose
+The shell writes its input to standard error
+as it is read.
+Useful for debugging.
+.It Fl x Li xtrace
+Write each command
+(preceded by the value of the
+.Va PS4
+variable subjected to parameter expansion and arithmetic expansion)
+to standard error before it is executed.
+Useful for debugging.
+.It Li nolog
+Another do-nothing option for
+.Tn POSIX
+compliance.
+It only has a long name.
+.El
+.Pp
+The
+.Fl c
+option causes the commands to be read from the
+.Ar string
+operand instead of from the standard input.
+Keep in mind that this option only accepts a single string as its
+argument, hence multi-word strings must be quoted.
+.Pp
+The
+.Fl /+o
+option takes as its only argument the long name of an option
+to be enabled or disabled.
+For example, the following two invocations of
+.Nm
+both enable the built-in
+.Xr emacs 1
+command line editor:
+.Bd -literal -offset indent
+set -E
+set -o emacs
+.Ed
+.Pp
+If used without an argument, the
+.Fl o
+option displays the current option settings in a human-readable format.
+If
+.Cm +o
+is used without an argument, the current option settings are output
+in a format suitable for re-input into the shell.
+.Ss Lexical Structure
+The shell reads input in terms of lines from a file and breaks
+it up into words at whitespace (blanks and tabs), and at
+certain sequences of
+characters called
+.Dq operators ,
+which are special to the shell.
+There are two types of operators: control operators and
+redirection operators (their meaning is discussed later).
+The following is a list of valid operators:
+.Bl -tag -width indent
+.It Control operators:
+.Bl -column "XXX" "XXX" "XXX" "XXX" "XXX" -offset center -compact
+.It Li & Ta Li && Ta Li \&( Ta Li \&) Ta Li \en
+.It Li ;; Ta Li ;& Ta Li \&; Ta Li \&| Ta Li ||
+.El
+.It Redirection operators:
+.Bl -column "XXX" "XXX" "XXX" "XXX" "XXX" -offset center -compact
+.It Li < Ta Li > Ta Li << Ta Li >> Ta Li <>
+.It Li <& Ta Li >& Ta Li <<- Ta Li >| Ta \&
+.El
+.El
+.Pp
+The character
+.Ql #
+introduces a comment if used at the beginning of a word.
+The word starting with
+.Ql #
+and the rest of the line are ignored.
+.Pp
+.Tn ASCII
+.Dv NUL
+characters (character code 0) are not allowed in shell input.
+.Ss Quoting
+Quoting is used to remove the special meaning of certain characters
+or words to the shell, such as operators, whitespace, keywords,
+or alias names.
+.Pp
+There are four types of quoting: matched single quotes,
+dollar-single quotes,
+matched double quotes, and backslash.
+.Bl -tag -width indent
+.It Single Quotes
+Enclosing characters in single quotes preserves the literal
+meaning of all the characters (except single quotes, making
+it impossible to put single-quotes in a single-quoted string).
+.It Dollar-Single Quotes
+Enclosing characters between
+.Li $'
+and
+.Li '
+preserves the literal meaning of all characters
+except backslashes and single quotes.
+A backslash introduces a C-style escape sequence:
+.Bl -tag -width xUnnnnnnnn
+.It \ea
+Alert (ring the terminal bell)
+.It \eb
+Backspace
+.It \ec Ns Ar c
+The control character denoted by
+.Li ^ Ns Ar c
+in
+.Xr stty 1 .
+If
+.Ar c
+is a backslash, it must be doubled.
+.It \ee
+The ESC character
+.Tn ( ASCII
+0x1b)
+.It \ef
+Formfeed
+.It \en
+Newline
+.It \er
+Carriage return
+.It \et
+Horizontal tab
+.It \ev
+Vertical tab
+.It \e\e
+Literal backslash
+.It \e\&'
+Literal single-quote
+.It \e\&"
+Literal double-quote
+.It \e Ns Ar nnn
+The byte whose octal value is
+.Ar nnn
+(one to three digits)
+.It \ex Ns Ar nn
+The byte whose hexadecimal value is
+.Ar nn
+(one or more digits only the last two of which are used)
+.It \eu Ns Ar nnnn
+The Unicode code point
+.Ar nnnn
+(four hexadecimal digits)
+.It \eU Ns Ar nnnnnnnn
+The Unicode code point
+.Ar nnnnnnnn
+(eight hexadecimal digits)
+.El
+.Pp
+The sequences for Unicode code points are currently only useful with
+UTF-8 locales.
+They reject code point 0 and UTF-16 surrogates.
+.Pp
+If an escape sequence would produce a byte with value 0,
+that byte and the rest of the string until the matching single-quote
+are ignored.
+.Pp
+Any other string starting with a backslash is an error.
+.It Double Quotes
+Enclosing characters within double quotes preserves the literal
+meaning of all characters except dollar sign
+.Pq Ql $ ,
+backquote
+.Pq Ql ` ,
+and backslash
+.Pq Ql \e .
+The backslash inside double quotes is historically weird.
+It remains literal unless it precedes the following characters,
+which it serves to quote:
+.Pp
+.Bl -column "XXX" "XXX" "XXX" "XXX" "XXX" -offset center -compact
+.It Li $ Ta Li ` Ta Li \&" Ta Li \e Ta Li \en
+.El
+.It Backslash
+A backslash preserves the literal meaning of the following
+character, with the exception of the newline character
+.Pq Ql \en .
+A backslash preceding a newline is treated as a line continuation.
+.El
+.Ss Keywords
+Keywords or reserved words are words that have special meaning to the
+shell and are recognized at the beginning of a line and
+after a control operator.
+The following are keywords:
+.Bl -column "doneXX" "elifXX" "elseXX" "untilXX" "whileX" -offset center
+.It Li \&! Ta { Ta } Ta Ic case Ta Ic do
+.It Ic done Ta Ic elif Ta Ic else Ta Ic esac Ta Ic fi
+.It Ic for Ta Ic if Ta Ic then Ta Ic until Ta Ic while
+.El
+.Ss Aliases
+An alias is a name and corresponding value set using the
+.Ic alias
+built-in command.
+Wherever the command word of a simple command may occur,
+and after checking for keywords if a keyword may occur, the shell
+checks the word to see if it matches an alias.
+If it does, it replaces it in the input stream with its value.
+For example, if there is an alias called
+.Dq Li lf
+with the value
+.Dq Li "ls -F" ,
+then the input
+.Pp
+.Dl "lf foobar"
+.Pp
+would become
+.Pp
+.Dl "ls -F foobar"
+.Pp
+Aliases are also recognized after an alias
+whose value ends with a space or tab.
+For example, if there is also an alias called
+.Dq Li nohup
+with the value
+.Dq Li "nohup " ,
+then the input
+.Pp
+.Dl "nohup lf foobar"
+.Pp
+would become
+.Pp
+.Dl "nohup ls -F foobar"
+.Pp
+Aliases provide a convenient way for naive users to
+create shorthands for commands without having to learn how
+to create functions with arguments.
+Using aliases in scripts is discouraged
+because the command that defines them must be executed
+before the code that uses them is parsed.
+This is fragile and not portable.
+.Pp
+An alias name may be escaped in a command line, so that it is not
+replaced by its alias value, by using quoting characters within or
+adjacent to the alias name.
+This is most often done by prefixing
+an alias name with a backslash to execute a function, built-in, or
+normal program with the same name.
+See the
+.Sx Quoting
+subsection.
+.Ss Commands
+The shell interprets the words it reads according to a
+language, the specification of which is outside the scope
+of this man page (refer to the BNF in the
+.St -p1003.2
+document).
+Essentially though, a line is read and if
+the first word of the line (or after a control operator)
+is not a keyword, then the shell has recognized a
+simple command.
+Otherwise, a complex command or some
+other special construct may have been recognized.
+.Ss Simple Commands
+If a simple command has been recognized, the shell performs
+the following actions:
+.Bl -enum
+.It
+Leading words of the form
+.Dq Li name=value
+are stripped off and assigned to the environment of
+the simple command
+(they do not affect expansions).
+Redirection operators and
+their arguments (as described below) are stripped
+off and saved for processing.
+.It
+The remaining words are expanded as described in
+the section called
+.Sx Word Expansions ,
+and the first remaining word is considered the command
+name and the command is located.
+The remaining
+words are considered the arguments of the command.
+If no command name resulted, then the
+.Dq Li name=value
+variable assignments recognized in 1) affect the
+current shell.
+.It
+Redirections are performed as described in
+the next section.
+.El
+.Ss Redirections
+Redirections are used to change where a command reads its input
+or sends its output.
+In general, redirections open, close, or
+duplicate an existing reference to a file.
+The overall format
+used for redirection is:
+.Pp
+.D1 Oo Ar n Oc Ar redir-op file
+.Pp
+The
+.Ar redir-op
+is one of the redirection operators mentioned
+previously.
+The following gives some examples of how these
+operators can be used.
+Note that stdin and stdout are commonly used abbreviations
+for standard input and standard output respectively.
+.Bl -tag -width "1234567890XX" -offset indent
+.It Oo Ar n Oc Ns Li > Ar file
+redirect stdout (or file descriptor
+.Ar n )
+to
+.Ar file
+.It Oo Ar n Oc Ns Li >| Ar file
+same as above, but override the
+.Fl C
+option
+.It Oo Ar n Oc Ns Li >> Ar file
+append stdout (or file descriptor
+.Ar n )
+to
+.Ar file
+.It Oo Ar n Oc Ns Li < Ar file
+redirect stdin (or file descriptor
+.Ar n )
+from
+.Ar file
+.It Oo Ar n Oc Ns Li <> Ar file
+redirect stdin (or file descriptor
+.Ar n )
+to and from
+.Ar file
+.It Oo Ar n1 Oc Ns Li <& Ns Ar n2
+duplicate stdin (or file descriptor
+.Ar n1 )
+from file descriptor
+.Ar n2
+.It Oo Ar n Oc Ns Li <&-
+close stdin (or file descriptor
+.Ar n )
+.It Oo Ar n1 Oc Ns Li >& Ns Ar n2
+duplicate stdout (or file descriptor
+.Ar n1 )
+to file descriptor
+.Ar n2
+.It Oo Ar n Oc Ns Li >&-
+close stdout (or file descriptor
+.Ar n )
+.El
+.Pp
+The following redirection is often called a
+.Dq here-document .
+.Bd -unfilled -offset indent
+.Oo Ar n Oc Ns Li << Ar delimiter
+.Ar here-doc-text
+.Ar ...
+.Ar delimiter
+.Ed
+.Pp
+All the text on successive lines up to the delimiter is
+saved away and made available to the command on standard
+input, or file descriptor
+.Ar n
+if it is specified.
+If the
+.Ar delimiter
+as specified on the initial line is quoted, then the
+.Ar here-doc-text
+is treated literally, otherwise the text is subjected to
+parameter expansion, command substitution, and arithmetic
+expansion (as described in the section on
+.Sx Word Expansions ) .
+If the operator is
+.Dq Li <<-
+instead of
+.Dq Li << ,
+then leading tabs
+in the
+.Ar here-doc-text
+are stripped.
+.Ss Search and Execution
+There are three types of commands: shell functions,
+built-in commands, and normal programs.
+The command is searched for (by name) in that order.
+The three types of commands are all executed in a different way.
+.Pp
+When a shell function is executed, all of the shell positional
+parameters (except
+.Li $0 ,
+which remains unchanged) are
+set to the arguments of the shell function.
+The variables which are explicitly placed in the environment of
+the command (by placing assignments to them before the
+function name) are made local to the function and are set
+to the values given.
+Then the command given in the function definition is executed.
+The positional parameters are restored to their original values
+when the command completes.
+This all occurs within the current shell.
+.Pp
+Shell built-in commands are executed internally to the shell, without
+spawning a new process.
+There are two kinds of built-in commands: regular and special.
+Assignments before special builtins persist after they finish
+executing and assignment errors, redirection errors and certain
+operand errors cause a script to be aborted.
+Special builtins cannot be overridden with a function.
+Both regular and special builtins can affect the shell in ways
+normal programs cannot.
+.Pp
+Otherwise, if the command name does not match a function
+or built-in command, the command is searched for as a normal
+program in the file system (as described in the next section).
+When a normal program is executed, the shell runs the program,
+passing the arguments and the environment to the program.
+If the program is not a normal executable file
+(i.e., if it does not begin with the
+.Dq "magic number"
+whose
+.Tn ASCII
+representation is
+.Dq Li #! ,
+resulting in an
+.Er ENOEXEC
+return value from
+.Xr execve 2 )
+but appears to be a text file,
+the shell will run a new instance of
+.Nm
+to interpret it.
+.Pp
+Note that previous versions of this document
+and the source code itself misleadingly and sporadically
+refer to a shell script without a magic number
+as a
+.Dq "shell procedure" .
+.Ss Path Search
+When locating a command, the shell first looks to see if
+it has a shell function by that name.
+Then it looks for a
+built-in command by that name.
+If a built-in command is not found,
+one of two things happen:
+.Bl -enum
+.It
+Command names containing a slash are simply executed without
+performing any searches.
+.It
+The shell searches each entry in the
+.Va PATH
+variable
+in turn for the command.
+The value of the
+.Va PATH
+variable should be a series of
+entries separated by colons.
+Each entry consists of a
+directory name.
+The current directory
+may be indicated implicitly by an empty directory name,
+or explicitly by a single period.
+.El
+.Ss Command Exit Status
+Each command has an exit status that can influence the behavior
+of other shell commands.
+The paradigm is that a command exits
+with zero for normal or success, and non-zero for failure,
+error, or a false indication.
+The man page for each command
+should indicate the various exit codes and what they mean.
+Additionally, the built-in commands return exit codes, as does
+an executed shell function.
+.Pp
+If a command is terminated by a signal, its exit status is greater than 128.
+The signal name can be found by passing the exit status to
+.Li kill -l .
+.Pp
+If there is no command word,
+the exit status is the exit status of the last command substitution executed,
+or zero if the command does not contain any command substitutions.
+.Ss Complex Commands
+Complex commands are combinations of simple commands
+with control operators or keywords, together creating a larger complex
+command.
+More generally, a command is one of the following:
+.Bl -item -offset indent
+.It
+simple command
+.It
+pipeline
+.It
+list or compound-list
+.It
+compound command
+.It
+function definition
+.El
+.Pp
+Unless otherwise stated, the exit status of a command is
+that of the last simple command executed by the command,
+or zero if no simple command was executed.
+.Ss Pipelines
+A pipeline is a sequence of one or more commands separated
+by the control operator
+.Ql \&| .
+The standard output of all but
+the last command is connected to the standard input
+of the next command.
+The standard output of the last
+command is inherited from the shell, as usual.
+.Pp
+The format for a pipeline is:
+.Pp
+.D1 Oo Li \&! Oc Ar command1 Op Li \&| Ar command2 ...
+.Pp
+The standard output of
+.Ar command1
+is connected to the standard input of
+.Ar command2 .
+The standard input, standard output, or
+both of a command is considered to be assigned by the
+pipeline before any redirection specified by redirection
+operators that are part of the command.
+.Pp
+Note that unlike some other shells,
+.Nm
+executes each process in a pipeline with more than one command
+in a subshell environment and as a child of the
+.Nm
+process.
+.Pp
+If the pipeline is not in the background (discussed later),
+the shell waits for all commands to complete.
+.Pp
+If the keyword
+.Ic !\&
+does not precede the pipeline, the
+exit status is the exit status of the last command specified
+in the pipeline.
+Otherwise, the exit status is the logical
+NOT of the exit status of the last command.
+That is, if
+the last command returns zero, the exit status is 1; if
+the last command returns greater than zero, the exit status
+is zero.
+.Pp
+Because pipeline assignment of standard input or standard
+output or both takes place before redirection, it can be
+modified by redirection.
+For example:
+.Pp
+.Dl "command1 2>&1 | command2"
+.Pp
+sends both the standard output and standard error of
+.Ar command1
+to the standard input of
+.Ar command2 .
+.Pp
+A
+.Ql \&;
+or newline terminator causes the preceding
+AND-OR-list
+(described below in the section called
+.Sx Short-Circuit List Operators )
+to be executed sequentially;
+an
+.Ql &
+causes asynchronous execution of the preceding AND-OR-list.
+.Ss Background Commands (&)
+If a command is terminated by the control operator ampersand
+.Pq Ql & ,
+the shell executes the command in a subshell environment (see
+.Sx Grouping Commands Together
+below) and asynchronously;
+the shell does not wait for the command to finish
+before executing the next command.
+.Pp
+The format for running a command in background is:
+.Pp
+.D1 Ar command1 Li & Op Ar command2 Li & Ar ...
+.Pp
+If the shell is not interactive, the standard input of an
+asynchronous command is set to
+.Pa /dev/null .
+.Pp
+The exit status is zero.
+.Ss Lists (Generally Speaking)
+A list is a sequence of zero or more commands separated by
+newlines, semicolons, or ampersands,
+and optionally terminated by one of these three characters.
+The commands in a
+list are executed in the order they are written.
+If command is followed by an ampersand, the shell starts the
+command and immediately proceeds onto the next command;
+otherwise it waits for the command to terminate before
+proceeding to the next one.
+.Ss Short-Circuit List Operators
+.Dq Li &&
+and
+.Dq Li ||
+are AND-OR list operators.
+.Dq Li &&
+executes the first command, and then executes the second command
+if the exit status of the first command is zero.
+.Dq Li ||
+is similar, but executes the second command if the exit
+status of the first command is nonzero.
+.Dq Li &&
+and
+.Dq Li ||
+both have the same priority.
+.Ss Flow-Control Constructs (if, while, for, case)
+The syntax of the
+.Ic if
+command is:
+.Bd -unfilled -offset indent -compact
+.Ic if Ar list
+.Ic then Ar list
+.Oo Ic elif Ar list
+.Ic then Ar list Oc Ar ...
+.Op Ic else Ar list
+.Ic fi
+.Ed
+.Pp
+The exit status is that of selected
+.Ic then
+or
+.Ic else
+list,
+or zero if no list was selected.
+.Pp
+The syntax of the
+.Ic while
+command is:
+.Bd -unfilled -offset indent -compact
+.Ic while Ar list
+.Ic do Ar list
+.Ic done
+.Ed
+.Pp
+The two lists are executed repeatedly while the exit status of the
+first list is zero.
+The
+.Ic until
+command is similar, but has the word
+.Ic until
+in place of
+.Ic while ,
+which causes it to
+repeat until the exit status of the first list is zero.
+.Pp
+The exit status is that of the last execution of the second list,
+or zero if it was never executed.
+.Pp
+The syntax of the
+.Ic for
+command is:
+.Bd -unfilled -offset indent -compact
+.Ic for Ar variable Op Ic in Ar word ...
+.Ic do Ar list
+.Ic done
+.Ed
+.Pp
+If
+.Ic in
+and the following words are omitted,
+.Ic in Li \&"$@\&"
+is used instead.
+The words are expanded, and then the list is executed
+repeatedly with the variable set to each word in turn.
+The
+.Ic do
+and
+.Ic done
+commands may be replaced with
+.Ql {
+and
+.Ql } .
+.Pp
+The syntax of the
+.Ic break
+and
+.Ic continue
+commands is:
+.D1 Ic break Op Ar num
+.D1 Ic continue Op Ar num
+.Pp
+The
+.Ic break
+command terminates the
+.Ar num
+innermost
+.Ic for
+or
+.Ic while
+loops.
+The
+.Ic continue
+command continues with the next iteration of the innermost loop.
+These are implemented as special built-in commands.
+.Pp
+The syntax of the
+.Ic case
+command is:
+.Bd -unfilled -offset indent -compact
+.Ic case Ar word Ic in
+.Ar pattern ) Ar list Li ;;
+.Ar ...
+.Ic esac
+.Ed
+.Pp
+The pattern can actually be one or more patterns
+(see
+.Sx Shell Patterns
+described later),
+separated by
+.Ql \&|
+characters.
+Tilde expansion, parameter expansion, command substitution,
+arithmetic expansion and quote removal are applied to the word.
+Then, each pattern is expanded in turn using tilde expansion,
+parameter expansion, command substitution and arithmetic expansion and
+the expanded form of the word is checked against it.
+If a match is found, the corresponding list is executed.
+If the selected list is terminated by the control operator
+.Ql ;&
+instead of
+.Ql ;; ,
+execution continues with the next list,
+continuing until a list terminated with
+.Ql ;;
+or the end of the
+.Ic case
+command.
+.Ss Grouping Commands Together
+Commands may be grouped by writing either
+.Pp
+.D1 Li \&( Ns Ar list Ns Li \%)
+.Pp
+or
+.Pp
+.D1 Li { Ar list Ns Li \&; }
+.Pp
+The first form executes the commands in a subshell environment.
+A subshell environment has its own copy of:
+.Bl -enum
+.It
+The current working directory as set by
+.Ic cd .
+.It
+The file creation mask as set by
+.Ic umask .
+.It
+Resource limits as set by
+.Ic ulimit .
+.It
+References to open files.
+.It
+Traps as set by
+.Ic trap .
+.It
+Known jobs.
+.It
+Positional parameters and variables.
+.It
+Shell options.
+.It
+Shell functions.
+.It
+Shell aliases.
+.El
+.Pp
+These are copied from the parent shell environment,
+except that trapped (but not ignored) signals are reset to the default action
+and known jobs are cleared.
+Any changes do not affect the parent shell environment.
+.Pp
+A subshell environment may be implemented as a child process or differently.
+If job control is enabled in an interactive shell,
+commands grouped in parentheses can be suspended and continued as a unit.
+.Pp
+For compatibility with other shells,
+two open parentheses in sequence should be separated by whitespace.
+.Pp
+The second form never forks another shell,
+so it is slightly more efficient.
+Grouping commands together this way allows the user to
+redirect their output as though they were one program:
+.Bd -literal -offset indent
+{ echo -n "hello"; echo " world"; } > greeting
+.Ed
+.Ss Functions
+The syntax of a function definition is
+.Pp
+.D1 Ar name Li \&( \&) Ar command
+.Pp
+A function definition is an executable statement; when
+executed it installs a function named
+.Ar name
+and returns an
+exit status of zero.
+The
+.Ar command
+is normally a list
+enclosed between
+.Ql {
+and
+.Ql } .
+.Pp
+Variables may be declared to be local to a function by
+using the
+.Ic local
+command.
+This should appear as the first statement of a function,
+and the syntax is:
+.Pp
+.D1 Ic local Oo Ar variable ... Oc Op Fl
+.Pp
+The
+.Ic local
+command is implemented as a built-in command.
+The exit status is zero
+unless the command is not in a function or a variable name is invalid.
+.Pp
+When a variable is made local, it inherits the initial
+value and exported and readonly flags from the variable
+with the same name in the surrounding scope, if there is
+one.
+Otherwise, the variable is initially unset.
+The shell
+uses dynamic scoping, so that if the variable
+.Va x
+is made local to function
+.Em f ,
+which then calls function
+.Em g ,
+references to the variable
+.Va x
+made inside
+.Em g
+will refer to the variable
+.Va x
+declared inside
+.Em f ,
+not to the global variable named
+.Va x .
+.Pp
+The only special parameter that can be made local is
+.Ql - .
+Making
+.Ql -
+local causes any shell options
+(including those that only have long names)
+that are
+changed via the
+.Ic set
+command inside the function to be
+restored to their original values when the function
+returns.
+.Pp
+The syntax of the
+.Ic return
+command is
+.Pp
+.D1 Ic return Op Ar exitstatus
+.Pp
+It terminates the current executional scope, returning from the closest
+nested function or sourced script;
+if no function or sourced script is being executed,
+it exits the shell instance.
+The
+.Ic return
+command is implemented as a special built-in command.
+.Ss Variables and Parameters
+The shell maintains a set of parameters.
+A parameter
+denoted by a name
+(consisting solely
+of alphabetics, numerics, and underscores,
+and starting with an alphabetic or an underscore)
+is called a variable.
+When starting up,
+the shell turns all environment variables with valid names into shell
+variables.
+New variables can be set using the form
+.Pp
+.D1 Ar name Ns = Ns Ar value
+.Pp
+A parameter can also be denoted by a number
+or a special character as explained below.
+.Pp
+Assignments are expanded differently from other words:
+tilde expansion is also performed after the equals sign and after any colon
+and usernames are also terminated by colons,
+and field splitting and pathname expansion are not performed.
+.Pp
+This special expansion applies not only to assignments that form a simple
+command by themselves or precede a command word,
+but also to words passed to the
+.Ic export ,
+.Ic local
+or
+.Ic readonly
+built-in commands that have this form.
+For this, the builtin's name must be literal
+(not the result of an expansion)
+and may optionally be preceded by one or more literal instances of
+.Ic command
+without options.
+.Ss Positional Parameters
+A positional parameter is a parameter denoted by a number greater than zero.
+The shell sets these initially to the values of its command line
+arguments that follow the name of the shell script.
+The
+.Ic set
+built-in command can also be used to set or reset them.
+.Ss Special Parameters
+Special parameters are parameters denoted by a single special character
+or the digit zero.
+They are shown in the following list, exactly as they would appear in input
+typed by the user or in the source of a shell script.
+.Bl -hang
+.It Li $*
+Expands to the positional parameters, starting from one.
+When
+the expansion occurs within a double-quoted string
+it expands to a single field with the value of each parameter
+separated by the first character of the
+.Va IFS
+variable,
+or by a space if
+.Va IFS
+is unset.
+.It Li $@
+Expands to the positional parameters, starting from one.
+When
+the expansion occurs within double-quotes, each positional
+parameter expands as a separate argument.
+If there are no positional parameters, the
+expansion of
+.Li @
+generates zero arguments, even when
+.Li @
+is double-quoted.
+What this basically means, for example, is
+if
+.Li $1
+is
+.Dq Li abc
+and
+.Li $2
+is
+.Dq Li "def ghi" ,
+then
+.Li \&"$@\&"
+expands to
+the two arguments:
+.Bd -literal -offset indent
+"abc" "def ghi"
+.Ed
+.It Li $#
+Expands to the number of positional parameters.
+.It Li $?
+Expands to the exit status of the most recent pipeline.
+.It Li $-
+(hyphen) Expands to the current option flags (the single-letter
+option names concatenated into a string) as specified on
+invocation, by the
+.Ic set
+built-in command, or implicitly
+by the shell.
+.It Li $$
+Expands to the process ID of the invoked shell.
+A subshell
+retains the same value of
+.Va $
+as its parent.
+.It Li $!
+Expands to the process ID of the most recent background
+command executed from the current shell.
+For a
+pipeline, the process ID is that of the last command in the
+pipeline.
+If this parameter is referenced, the shell will remember
+the process ID and its exit status until the
+.Ic wait
+built-in command reports completion of the process.
+.It Li $0
+(zero) Expands to the name of the shell script if passed on the command line,
+the
+.Ar name
+operand if given (with
+.Fl c )
+or otherwise argument 0 passed to the shell.
+.El
+.Ss Special Variables
+The following variables are set by the shell or
+have special meaning to it:
+.Bl -tag -width ".Va HISTSIZE"
+.It Va CDPATH
+The search path used with the
+.Ic cd
+built-in.
+.It Va EDITOR
+The fallback editor used with the
+.Ic fc
+built-in.
+If not set, the default editor is
+.Xr ed 1 .
+.It Va FCEDIT
+The default editor used with the
+.Ic fc
+built-in.
+.It Va HISTSIZE
+The number of previous commands that are accessible.
+.It Va HOME
+The user's home directory,
+used in tilde expansion and as a default directory for the
+.Ic cd
+built-in.
+.It Va IFS
+Input Field Separators.
+This is initialized at startup to
+.Aq space ,
+.Aq tab ,
+and
+.Aq newline
+in that order.
+This value also applies if
+.Va IFS
+is unset, but not if it is set to the empty string.
+See the
+.Sx White Space Splitting
+section for more details.
+.It Va LINENO
+The current line number in the script or function.
+.It Va MAIL
+The name of a mail file, that will be checked for the arrival of new
+mail.
+Overridden by
+.Va MAILPATH .
+.It Va MAILPATH
+A colon
+.Pq Ql \&:
+separated list of file names, for the shell to check for incoming
+mail.
+This variable overrides the
+.Va MAIL
+setting.
+There is a maximum of 10 mailboxes that can be monitored at once.
+.It Va OPTIND
+The index of the next argument to be processed by
+.Ic getopts .
+This is initialized to 1 at startup.
+.It Va PATH
+The default search path for executables.
+See the
+.Sx Path Search
+section for details.
+.It Va PPID
+The parent process ID of the invoked shell.
+This is set at startup
+unless this variable is in the environment.
+A later change of parent process ID is not reflected.
+A subshell retains the same value of
+.Va PPID .
+.It Va PS1
+The primary prompt string, which defaults to
+.Dq Li "$ " ,
+unless you are the superuser, in which case it defaults to
+.Dq Li "# " .
+.Va PS1
+may include any of the following formatting sequences,
+which are replaced by the given information:
+.Bl -tag -width indent
+.It Li \eH
+This system's fully-qualified hostname (FQDN).
+.It Li \eh
+This system's hostname.
+.It Li \eW
+The final component of the current working directory.
+.It Li \ew
+The entire path of the current working directory.
+.It Li \e$
+Superuser status.
+.Dq Li "$ "
+for normal users and
+.Dq Li "# "
+for superusers.
+.It Li \e\e
+A literal backslash.
+.El
+.It Va PS2
+The secondary prompt string, which defaults to
+.Dq Li "> " .
+.Va PS2
+may include any of the formatting sequences from
+.Va PS1 .
+.It Va PS4
+The prefix for the trace output (if
+.Fl x
+is active).
+The default is
+.Dq Li "+ " .
+.El
+.Ss Word Expansions
+This clause describes the various expansions that are
+performed on words.
+Not all expansions are performed on
+every word, as explained later.
+.Pp
+Tilde expansions, parameter expansions, command substitutions,
+arithmetic expansions, and quote removals that occur within
+a single word expand to a single field.
+It is only field
+splitting or pathname expansion that can create multiple
+fields from a single word.
+The single exception to this rule is
+the expansion of the special parameter
+.Va @
+within double-quotes,
+as was described above.
+.Pp
+The order of word expansion is:
+.Bl -enum
+.It
+Tilde Expansion, Parameter Expansion, Command Substitution,
+Arithmetic Expansion (these all occur at the same time).
+.It
+Field Splitting is performed on fields generated by step (1)
+unless the
+.Va IFS
+variable is null.
+.It
+Pathname Expansion (unless the
+.Fl f
+option is in effect).
+.It
+Quote Removal.
+.El
+.Pp
+The
+.Ql $
+character is used to introduce parameter expansion, command
+substitution, or arithmetic expansion.
+.Ss Tilde Expansion (substituting a user's home directory)
+A word beginning with an unquoted tilde character
+.Pq Ql ~
+is
+subjected to tilde expansion.
+All the characters up to a slash
+.Pq Ql /
+or the end of the word are treated as a username
+and are replaced with the user's home directory.
+If the
+username is missing (as in
+.Pa ~/foobar ) ,
+the tilde is replaced with the value of the
+.Va HOME
+variable (the current user's home directory).
+.Ss Parameter Expansion
+The format for parameter expansion is as follows:
+.Pp
+.D1 Li ${ Ns Ar expression Ns Li }
+.Pp
+where
+.Ar expression
+consists of all characters until the matching
+.Ql } .
+Any
+.Ql }
+escaped by a backslash or within a single-quoted or double-quoted
+string, and characters in
+embedded arithmetic expansions, command substitutions, and variable
+expansions, are not examined in determining the matching
+.Ql } .
+If the variants with
+.Ql + ,
+.Ql - ,
+.Ql =
+or
+.Ql ?\&
+occur within a double-quoted string,
+as an extension there may be unquoted parts
+(via double-quotes inside the expansion);
+.Ql }
+within such parts are also not examined in determining the matching
+.Ql } .
+.Pp
+The simplest form for parameter expansion is:
+.Pp
+.D1 Li ${ Ns Ar parameter Ns Li }
+.Pp
+The value, if any, of
+.Ar parameter
+is substituted.
+.Pp
+The parameter name or symbol can be enclosed in braces, which are
+optional except for positional parameters with more than one digit or
+when parameter is followed by a character that could be interpreted as
+part of the name.
+If a parameter expansion occurs inside double-quotes:
+.Bl -enum
+.It
+Field splitting is not performed on the results of the
+expansion, with the exception of the special parameter
+.Va @ .
+.It
+Pathname expansion is not performed on the results of the
+expansion.
+.El
+.Pp
+In addition, a parameter expansion can be modified by using one of the
+following formats.
+.Bl -tag -width indent
+.It Li ${ Ns Ar parameter Ns Li :- Ns Ar word Ns Li }
+Use Default Values.
+If
+.Ar parameter
+is unset or null, the expansion of
+.Ar word
+is substituted; otherwise, the value of
+.Ar parameter
+is substituted.
+.It Li ${ Ns Ar parameter Ns Li := Ns Ar word Ns Li }
+Assign Default Values.
+If
+.Ar parameter
+is unset or null, the expansion of
+.Ar word
+is assigned to
+.Ar parameter .
+In all cases, the
+final value of
+.Ar parameter
+is substituted.
+Quoting inside
+.Ar word
+does not prevent field splitting or pathname expansion.
+Only variables, not positional
+parameters or special parameters, can be
+assigned in this way.
+.It Li ${ Ns Ar parameter Ns Li :? Ns Oo Ar word Oc Ns Li }
+Indicate Error if Null or Unset.
+If
+.Ar parameter
+is unset or null, the expansion of
+.Ar word
+(or a message indicating it is unset if
+.Ar word
+is omitted) is written to standard
+error and the shell exits with a nonzero
+exit status.
+Otherwise, the value of
+.Ar parameter
+is substituted.
+An
+interactive shell need not exit.
+.It Li ${ Ns Ar parameter Ns Li :+ Ns Ar word Ns Li }
+Use Alternate Value.
+If
+.Ar parameter
+is unset or null, null is substituted;
+otherwise, the expansion of
+.Ar word
+is substituted.
+.El
+.Pp
+In the parameter expansions shown previously, use of the colon in the
+format results in a test for a parameter that is unset or null; omission
+of the colon results in a test for a parameter that is only unset.
+.Pp
+The
+.Ar word
+inherits the type of quoting
+(unquoted, double-quoted or here-document)
+from the surroundings,
+with the exception that a backslash that quotes a closing brace is removed
+during quote removal.
+.Bl -tag -width indent
+.It Li ${# Ns Ar parameter Ns Li }
+String Length.
+The length in characters of
+the value of
+.Ar parameter .
+.El
+.Pp
+The following four varieties of parameter expansion provide for substring
+processing.
+In each case, pattern matching notation
+(see
+.Sx Shell Patterns ) ,
+rather than regular expression notation,
+is used to evaluate the patterns.
+If parameter is one of the special parameters
+.Va *
+or
+.Va @ ,
+the result of the expansion is unspecified.
+Enclosing the full parameter expansion string in double-quotes does not
+cause the following four varieties of pattern characters to be quoted,
+whereas quoting characters within the braces has this effect.
+.Bl -tag -width indent
+.It Li ${ Ns Ar parameter Ns Li % Ns Ar word Ns Li }
+Remove Smallest Suffix Pattern.
+The
+.Ar word
+is expanded to produce a pattern.
+The
+parameter expansion then results in
+.Ar parameter ,
+with the smallest portion of the
+suffix matched by the pattern deleted.
+.It Li ${ Ns Ar parameter Ns Li %% Ns Ar word Ns Li }
+Remove Largest Suffix Pattern.
+The
+.Ar word
+is expanded to produce a pattern.
+The
+parameter expansion then results in
+.Ar parameter ,
+with the largest portion of the
+suffix matched by the pattern deleted.
+.It Li ${ Ns Ar parameter Ns Li # Ns Ar word Ns Li }
+Remove Smallest Prefix Pattern.
+The
+.Ar word
+is expanded to produce a pattern.
+The
+parameter expansion then results in
+.Ar parameter ,
+with the smallest portion of the
+prefix matched by the pattern deleted.
+.It Li ${ Ns Ar parameter Ns Li ## Ns Ar word Ns Li }
+Remove Largest Prefix Pattern.
+The
+.Ar word
+is expanded to produce a pattern.
+The
+parameter expansion then results in
+.Ar parameter ,
+with the largest portion of the
+prefix matched by the pattern deleted.
+.El
+.Ss Command Substitution
+Command substitution allows the output of a command to be substituted in
+place of the command name itself.
+Command substitution occurs when
+the command is enclosed as follows:
+.Pp
+.D1 Li $( Ns Ar command Ns Li )\&
+.Pp
+or the backquoted version:
+.Pp
+.D1 Li ` Ns Ar command Ns Li `
+.Pp
+The shell expands the command substitution by executing command
+and replacing the command substitution
+with the standard output of the command,
+removing sequences of one or more newlines at the end of the substitution.
+Embedded newlines before the end of the output are not removed;
+however, during field splitting, they may be translated into spaces
+depending on the value of
+.Va IFS
+and the quoting that is in effect.
+The command is executed in a subshell environment,
+except that the built-in commands
+.Ic jobid ,
+.Ic jobs ,
+and
+.Ic trap
+return information about the parent shell environment
+and
+.Ic times
+returns information about the same process
+if they are the only command in a command substitution.
+.Pp
+If a command substitution of the
+.Li $(
+form begins with a subshell,
+the
+.Li $(
+and
+.Li (\&
+must be separated by whitespace
+to avoid ambiguity with arithmetic expansion.
+.Ss Arithmetic Expansion
+Arithmetic expansion provides a mechanism for evaluating an arithmetic
+expression and substituting its value.
+The format for arithmetic expansion is as follows:
+.Pp
+.D1 Li $(( Ns Ar expression Ns Li ))
+.Pp
+The
+.Ar expression
+is treated as if it were in double-quotes, except
+that a double-quote inside the expression is not treated specially.
+The
+shell expands all tokens in the
+.Ar expression
+for parameter expansion,
+command substitution,
+arithmetic expansion
+and quote removal.
+.Pp
+The allowed expressions are a subset of C expressions,
+summarized below.
+.Bl -tag -width "Variables" -offset indent
+.It Values
+All values are of type
+.Ft intmax_t .
+.It Constants
+Decimal, octal (starting with
+.Li 0 )
+and hexadecimal (starting with
+.Li 0x )
+integer constants.
+.It Variables
+Shell variables can be read and written
+and contain integer constants.
+.It Unary operators
+.Li "! ~ + -"
+.It Binary operators
+.Li "* / % + - << >> < <= > >= == != & ^ | && ||"
+.It Assignment operators
+.Li "= += -= *= /= %= <<= >>= &= ^= |="
+.It Conditional operator
+.Li "? :"
+.El
+.Pp
+The result of the expression is substituted in decimal.
+.Ss White Space Splitting (Field Splitting)
+In certain contexts,
+after parameter expansion, command substitution, and
+arithmetic expansion the shell scans the results of
+expansions and substitutions that did not occur in double-quotes for
+field splitting and multiple fields can result.
+.Pp
+Characters in
+.Va IFS
+that are whitespace
+.Po
+.Aq space ,
+.Aq tab ,
+and
+.Aq newline
+.Pc
+are treated differently from other characters in
+.Va IFS .
+.Pp
+Whitespace in
+.Va IFS
+at the beginning or end of a word is discarded.
+.Pp
+Subsequently, a field is delimited by either
+.Bl -enum
+.It
+a non-whitespace character in
+.Va IFS
+with any whitespace in
+.Va IFS
+surrounding it, or
+.It
+one or more whitespace characters in
+.Va IFS .
+.El
+.Pp
+If a word ends with a non-whitespace character in
+.Va IFS ,
+there is no empty field after this character.
+.Pp
+If no field is delimited, the word is discarded.
+In particular, if a word consists solely of an unquoted substitution
+and the result of the substitution is null,
+it is removed by field splitting even if
+.Va IFS
+is null.
+.Ss Pathname Expansion (File Name Generation)
+Unless the
+.Fl f
+option is set,
+file name generation is performed
+after word splitting is complete.
+Each word is
+viewed as a series of patterns, separated by slashes.
+The
+process of expansion replaces the word with the names of
+all existing files whose names can be formed by replacing
+each pattern with a string that matches the specified pattern.
+There are two restrictions on this: first, a pattern cannot match
+a string containing a slash, and second,
+a pattern cannot match a string starting with a period
+unless the first character of the pattern is a period.
+The next section describes the patterns used for
+Pathname Expansion,
+the four varieties of parameter expansion for substring processing and the
+.Ic case
+command.
+.Ss Shell Patterns
+A pattern consists of normal characters, which match themselves,
+and meta-characters.
+The meta-characters are
+.Ql * ,
+.Ql \&? ,
+and
+.Ql \&[ .
+These characters lose their special meanings if they are quoted.
+When command or variable substitution is performed and the dollar sign
+or back quotes are not double-quoted, the value of the
+variable or the output of the command is scanned for these
+characters and they are turned into meta-characters.
+.Pp
+An asterisk
+.Pq Ql *
+matches any string of characters.
+A question mark
+.Pq Ql \&?
+matches any single character.
+A left bracket
+.Pq Ql \&[
+introduces a character class.
+The end of the character class is indicated by a
+.Ql \&] ;
+if the
+.Ql \&]
+is missing then the
+.Ql \&[
+matches a
+.Ql \&[
+rather than introducing a character class.
+A character class matches any of the characters between the square brackets.
+A locale-dependent range of characters may be specified using a minus sign.
+A named class of characters (see
+.Xr wctype 3 )
+may be specified by surrounding the name with
+.Ql \&[:
+and
+.Ql :\&] .
+For example,
+.Ql \&[\&[:alpha:\&]\&]
+is a shell pattern that matches a single letter.
+The character class may be complemented by making an exclamation point
+.Pq Ql !\&
+the first character of the character class.
+A caret
+.Pq Ql ^
+has the same effect but is non-standard.
+.Pp
+To include a
+.Ql \&]
+in a character class, make it the first character listed
+(after the
+.Ql \&!
+or
+.Ql ^ ,
+if any).
+To include a
+.Ql - ,
+make it the first or last character listed.
+.Ss Built-in Commands
+This section lists the built-in commands.
+.Bl -tag -width indent
+.It Ic \&:
+A null command that returns a 0 (true) exit value.
+.It Ic \&. Ar file
+The commands in the specified file are read and executed by the shell.
+The
+.Ic return
+command may be used to return to the
+.Ic \&.
+command's caller.
+If
+.Ar file
+contains any
+.Ql /
+characters, it is used as is.
+Otherwise, the shell searches the
+.Va PATH
+for the file.
+If it is not found in the
+.Va PATH ,
+it is sought in the current working directory.
+.It Ic \&[
+A built-in equivalent of
+.Xr test 1 .
+.It Ic alias Oo Ar name Ns Oo = Ns Ar string Oc ... Oc
+If
+.Ar name Ns = Ns Ar string
+is specified, the shell defines the alias
+.Ar name
+with value
+.Ar string .
+If just
+.Ar name
+is specified, the value of the alias
+.Ar name
+is printed.
+With no arguments, the
+.Ic alias
+built-in command prints the names and values of all defined aliases
+(see
+.Ic unalias ) .
+Alias values are written with appropriate quoting so that they are
+suitable for re-input to the shell.
+Also see the
+.Sx Aliases
+subsection.
+.It Ic bg Op Ar job ...
+Continue the specified jobs
+(or the current job if no jobs are given)
+in the background.
+.It Ic bind Oo Fl aeklrsv Oc Oo Ar key Oo Ar command Oc Oc
+List or alter key bindings for the line editor.
+This command is documented in
+.Xr editrc 5 .
+.It Ic break Op Ar num
+See the
+.Sx Flow-Control Constructs
+subsection.
+.It Ic builtin Ar cmd Op Ar arg ...
+Execute the specified built-in command,
+.Ar cmd .
+This is useful when the user wishes to override a shell function
+with the same name as a built-in command.
+.It Ic cd Oo Fl L | P Oc Oo Fl e Oc Op Ar directory
+.It Ic cd Fl
+Switch to the specified
+.Ar directory ,
+to the directory specified in the
+.Va HOME
+environment variable if no
+.Ar directory
+is specified or
+to the directory specified in the
+.Va OLDPWD
+environment variable if
+.Ar directory
+is
+.Fl .
+If
+.Ar directory
+does not begin with
+.Pa / , \&. ,
+or
+.Pa .. ,
+then the directories listed in the
+.Va CDPATH
+variable will be
+searched for the specified
+.Ar directory .
+If
+.Va CDPATH
+is unset, the current directory is searched.
+The format of
+.Va CDPATH
+is the same as that of
+.Va PATH .
+In an interactive shell,
+the
+.Ic cd
+command will print out the name of the directory
+that it actually switched to
+if the
+.Va CDPATH
+mechanism was used or if
+.Ar directory
+was
+.Fl .
+.Pp
+If the
+.Fl P
+option is specified,
+.Pa ..
+is handled physically and symbolic links are resolved before
+.Pa ..
+components are processed.
+If the
+.Fl L
+option is specified,
+.Pa ..
+is handled logically.
+This is the default.
+.Pp
+The
+.Fl e
+option causes
+.Ic cd
+to return exit status 1 if the full pathname of the new directory
+cannot be determined reliably or at all.
+Normally this is not considered an error,
+although a warning is printed.
+.Pp
+If changing the directory fails, the exit status is greater than 1.
+If the directory is changed, the exit status is 0, or also 1 if
+.Fl e
+was given.
+.It Ic chdir
+A synonym for the
+.Ic cd
+built-in command.
+.It Ic command Oo Fl p Oc Op Ar utility Op Ar argument ...
+.It Ic command Oo Fl p Oc Fl v Ar utility
+.It Ic command Oo Fl p Oc Fl V Ar utility
+The first form of invocation executes the specified
+.Ar utility ,
+ignoring shell functions in the search.
+If
+.Ar utility
+is a special builtin,
+it is executed as if it were a regular builtin.
+.Pp
+If the
+.Fl p
+option is specified, the command search is performed using a
+default value of
+.Va PATH
+that is guaranteed to find all of the standard utilities.
+.Pp
+If the
+.Fl v
+option is specified,
+.Ar utility
+is not executed but a description of its interpretation by the shell is
+printed.
+For ordinary commands the output is the path name; for shell built-in
+commands, shell functions and keywords only the name is written.
+Aliases are printed as
+.Dq Ic alias Ar name Ns = Ns Ar value .
+.Pp
+The
+.Fl V
+option is identical to
+.Fl v
+except for the output.
+It prints
+.Dq Ar utility Ic is Ar description
+where
+.Ar description
+is either
+the path name to
+.Ar utility ,
+a special shell builtin,
+a shell builtin,
+a shell function,
+a shell keyword
+or
+an alias for
+.Ar value .
+.It Ic continue Op Ar num
+See the
+.Sx Flow-Control Constructs
+subsection.
+.It Ic echo Oo Fl e | n Oc Op Ar string ...
+Print a space-separated list of the arguments to the standard output
+and append a newline character.
+.Bl -tag -width indent
+.It Fl n
+Suppress the output of the trailing newline.
+.It Fl e
+Process C-style backslash escape sequences.
+The
+.Ic echo
+command understands the following character escapes:
+.Bl -tag -width indent
+.It \ea
+Alert (ring the terminal bell)
+.It \eb
+Backspace
+.It \ec
+Suppress the trailing newline (this has the side-effect of truncating the
+line if it is not the last character)
+.It \ee
+The ESC character
+.Tn ( ASCII
+0x1b)
+.It \ef
+Formfeed
+.It \en
+Newline
+.It \er
+Carriage return
+.It \et
+Horizontal tab
+.It \ev
+Vertical tab
+.It \e\e
+Literal backslash
+.It \e0nnn
+(Zero) The character whose octal value is
+.Ar nnn
+.El
+.Pp
+If
+.Ar string
+is not enclosed in quotes then the backslash itself must be escaped
+with a backslash to protect it from the shell.
+For example
+.Bd -literal -offset indent
+$ echo -e "a\evb"
+a
+ b
+$ echo -e a\e\evb
+a
+ b
+$ echo -e "a\e\eb"
+a\eb
+$ echo -e a\e\e\e\eb
+a\eb
+.Ed
+.El
+.Pp
+Only one of the
+.Fl e
+and
+.Fl n
+options may be specified.
+.It Ic eval Ar string ...
+Concatenate all the arguments with spaces.
+Then re-parse and execute the command.
+.It Ic exec Op Ar command Op arg ...
+Unless
+.Ar command
+is omitted,
+the shell process is replaced with the specified program
+(which must be a real program, not a shell built-in command or function).
+Any redirections on the
+.Ic exec
+command are marked as permanent,
+so that they are not undone when the
+.Ic exec
+command finishes.
+.It Ic exit Op Ar exitstatus
+Terminate the shell process.
+If
+.Ar exitstatus
+is given
+it is used as the exit status of the shell.
+Otherwise, if the shell is executing an
+.Cm EXIT
+trap, the exit status of the last command before the trap is used;
+if the shell is executing a trap for a signal,
+the shell exits by resending the signal to itself.
+Otherwise, the exit status of the preceding command is used.
+The exit status should be an integer between 0 and 255.
+.It Ic export Ar name ...
+.It Ic export Op Fl p
+The specified names are exported so that they will
+appear in the environment of subsequent commands.
+The only way to un-export a variable is to
+.Ic unset
+it.
+The shell allows the value of a variable to be set
+at the same time as it is exported by writing
+.Pp
+.D1 Ic export Ar name Ns = Ns Ar value
+.Pp
+With no arguments the
+.Ic export
+command lists the names
+of all exported variables.
+If the
+.Fl p
+option is specified, the exported variables are printed as
+.Dq Ic export Ar name Ns = Ns Ar value
+lines, suitable for re-input to the shell.
+.It Ic false
+A null command that returns a non-zero (false) exit value.
+.It Ic fc Oo Fl e Ar editor Oc Op Ar first Op Ar last
+.It Ic fc Fl l Oo Fl nr Oc Op Ar first Op Ar last
+.It Ic fc Fl s Oo Ar old Ns = Ns Ar new Oc Op Ar first
+The
+.Ic fc
+built-in command lists, or edits and re-executes,
+commands previously entered to an interactive shell.
+.Bl -tag -width indent
+.It Fl e Ar editor
+Use the editor named by
+.Ar editor
+to edit the commands.
+The
+.Ar editor
+string is a command name,
+subject to search via the
+.Va PATH
+variable.
+The value in the
+.Va FCEDIT
+variable is used as a default when
+.Fl e
+is not specified.
+If
+.Va FCEDIT
+is null or unset, the value of the
+.Va EDITOR
+variable is used.
+If
+.Va EDITOR
+is null or unset,
+.Xr ed 1
+is used as the editor.
+.It Fl l No (ell)
+List the commands rather than invoking
+an editor on them.
+The commands are written in the
+sequence indicated by the
+.Ar first
+and
+.Ar last
+operands, as affected by
+.Fl r ,
+with each command preceded by the command number.
+.It Fl n
+Suppress command numbers when listing with
+.Fl l .
+.It Fl r
+Reverse the order of the commands listed
+(with
+.Fl l )
+or edited
+(with neither
+.Fl l
+nor
+.Fl s ) .
+.It Fl s
+Re-execute the command without invoking an editor.
+.It Ar first
+.It Ar last
+Select the commands to list or edit.
+The number of previous commands that can be accessed
+are determined by the value of the
+.Va HISTSIZE
+variable.
+The value of
+.Ar first
+or
+.Ar last
+or both are one of the following:
+.Bl -tag -width indent
+.It Oo Cm + Oc Ns Ar num
+A positive number representing a command number;
+command numbers can be displayed with the
+.Fl l
+option.
+.It Fl Ar num
+A negative decimal number representing the
+command that was executed
+.Ar num
+of
+commands previously.
+For example, \-1 is the immediately previous command.
+.It Ar string
+A string indicating the most recently entered command
+that begins with that string.
+If the
+.Ar old Ns = Ns Ar new
+operand is not also specified with
+.Fl s ,
+the string form of the first operand cannot contain an embedded equal sign.
+.El
+.El
+.Pp
+The following variables affect the execution of
+.Ic fc :
+.Bl -tag -width ".Va HISTSIZE"
+.It Va FCEDIT
+Name of the editor to use for history editing.
+.It Va HISTSIZE
+The number of previous commands that are accessible.
+.El
+.It Ic fg Op Ar job
+Move the specified
+.Ar job
+or the current job to the foreground.
+.It Ic getopts Ar optstring var
+The
+.Tn POSIX
+.Ic getopts
+command.
+The
+.Ic getopts
+command deprecates the older
+.Xr getopt 1
+command.
+The first argument should be a series of letters, each possibly
+followed by a colon which indicates that the option takes an argument.
+The specified variable is set to the parsed option.
+The index of
+the next argument is placed into the shell variable
+.Va OPTIND .
+If an option takes an argument, it is placed into the shell variable
+.Va OPTARG .
+If an invalid option is encountered,
+.Ar var
+is set to
+.Ql \&? .
+It returns a false value (1) when it encounters the end of the options.
+A new set of arguments may be parsed by assigning
+.Li OPTIND=1 .
+.It Ic hash Oo Fl rv Oc Op Ar command ...
+The shell maintains a hash table which remembers the locations of commands.
+With no arguments whatsoever, the
+.Ic hash
+command prints out the contents of this table.
+.Pp
+With arguments, the
+.Ic hash
+command removes each specified
+.Ar command
+from the hash table (unless they are functions) and then locates it.
+With the
+.Fl v
+option,
+.Ic hash
+prints the locations of the commands as it finds them.
+The
+.Fl r
+option causes the
+.Ic hash
+command to delete all the entries in the hash table except for functions.
+.It Ic jobid Op Ar job
+Print the process IDs of the processes in the specified
+.Ar job .
+If the
+.Ar job
+argument is omitted, use the current job.
+.It Ic jobs Oo Fl lps Oc Op Ar job ...
+Print information about the specified jobs, or all jobs if no
+.Ar job
+argument is given.
+The information printed includes job ID, status and command name.
+.Pp
+If the
+.Fl l
+option is specified, the PID of each job is also printed.
+If the
+.Fl p
+option is specified, only the process IDs for the process group leaders
+are printed, one per line.
+If the
+.Fl s
+option is specified, only the PIDs of the job commands are printed, one per
+line.
+.It Ic kill
+A built-in equivalent of
+.Xr kill 1
+that additionally supports sending signals to jobs.
+.It Ic local Oo Ar variable ... Oc Op Fl
+See the
+.Sx Functions
+subsection.
+.It Ic printf
+A built-in equivalent of
+.Xr printf 1 .
+.It Ic pwd Op Fl L | P
+Print the path of the current directory.
+The built-in command may
+differ from the program of the same name because the
+built-in command remembers what the current directory
+is rather than recomputing it each time.
+This makes
+it faster.
+However, if the current directory is
+renamed,
+the built-in version of
+.Xr pwd 1
+will continue to print the old name for the directory.
+.Pp
+If the
+.Fl P
+option is specified, symbolic links are resolved.
+If the
+.Fl L
+option is specified, the shell's notion of the current directory
+is printed (symbolic links are not resolved).
+This is the default.
+.It Ic read Oo Fl p Ar prompt Oc Oo
+.Fl t Ar timeout Oc Oo Fl er Oc Ar variable ...
+The
+.Ar prompt
+is printed if the
+.Fl p
+option is specified
+and the standard input is a terminal.
+Then a line is
+read from the standard input.
+The trailing newline
+is deleted from the line and the line is split as
+described in the section on
+.Sx White Space Splitting (Field Splitting)
+above, and
+the pieces are assigned to the variables in order.
+If there are more pieces than variables, the remaining
+pieces (along with the characters in
+.Va IFS
+that separated them)
+are assigned to the last variable.
+If there are more variables than pieces, the remaining
+variables are assigned the null string.
+.Pp
+Backslashes are treated specially, unless the
+.Fl r
+option is
+specified.
+If a backslash is followed by
+a newline, the backslash and the newline will be
+deleted.
+If a backslash is followed by any other
+character, the backslash will be deleted and the following
+character will be treated as though it were not in
+.Va IFS ,
+even if it is.
+.Pp
+If the
+.Fl t
+option is specified and the
+.Ar timeout
+elapses before a complete line of input is supplied,
+the
+.Ic read
+command will return an exit status as if terminated by
+.Dv SIGALRM
+without assigning any values.
+The
+.Ar timeout
+value may optionally be followed by one of
+.Ql s ,
+.Ql m
+or
+.Ql h
+to explicitly specify seconds, minutes or hours.
+If none is supplied,
+.Ql s
+is assumed.
+.Pp
+The
+.Fl e
+option exists only for backward compatibility with older scripts.
+.Pp
+The exit status is 0 on success, 1 on end of file,
+between 2 and 128 if an error occurs
+and greater than 128 if a trapped signal interrupts
+.Ic read .
+.It Ic readonly Oo Fl p Oc Op Ar name ...
+Each specified
+.Ar name
+is marked as read only,
+so that it cannot be subsequently modified or unset.
+The shell allows the value of a variable to be set
+at the same time as it is marked read only
+by using the following form:
+.Pp
+.D1 Ic readonly Ar name Ns = Ns Ar value
+.Pp
+With no arguments the
+.Ic readonly
+command lists the names of all read only variables.
+If the
+.Fl p
+option is specified, the read-only variables are printed as
+.Dq Ic readonly Ar name Ns = Ns Ar value
+lines, suitable for re-input to the shell.
+.It Ic return Op Ar exitstatus
+See the
+.Sx Functions
+subsection.
+.It Ic set Oo Fl /+abCEefIimnpTuVvx Oc Oo Fl /+o Ar longname Oc Oo
+.Fl c Ar string Oc Op Fl - Ar arg ...
+The
+.Ic set
+command performs three different functions:
+.Bl -item
+.It
+With no arguments, it lists the values of all shell variables.
+.It
+If options are given,
+either in short form or using the long
+.Dq Fl /+o Ar longname
+form,
+it sets or clears the specified options as described in the section called
+.Sx Argument List Processing .
+.It
+If the
+.Dq Fl -
+option is specified,
+.Ic set
+will replace the shell's positional parameters with the subsequent
+arguments.
+If no arguments follow the
+.Dq Fl -
+option,
+all the positional parameters will be cleared,
+which is equivalent to executing the command
+.Dq Li "shift $#" .
+The
+.Dq Fl -
+flag may be omitted when specifying arguments to be used
+as positional replacement parameters.
+This is not recommended,
+because the first argument may begin with a dash
+.Pq Ql -
+or a plus
+.Pq Ql + ,
+which the
+.Ic set
+command will interpret as a request to enable or disable options.
+.El
+.It Ic setvar Ar variable value
+Assigns the specified
+.Ar value
+to the specified
+.Ar variable .
+The
+.Ic setvar
+command is intended to be used in functions that
+assign values to variables whose names are passed as parameters.
+In general it is better to write
+.Dq Ar variable Ns = Ns Ar value
+rather than using
+.Ic setvar .
+.It Ic shift Op Ar n
+Shift the positional parameters
+.Ar n
+times, or once if
+.Ar n
+is not specified.
+A shift sets the value of
+.Li $1
+to the value of
+.Li $2 ,
+the value of
+.Li $2
+to the value of
+.Li $3 ,
+and so on,
+decreasing the value of
+.Li $#
+by one.
+For portability, shifting if there are zero positional parameters
+should be avoided, since the shell may abort.
+.It Ic test
+A built-in equivalent of
+.Xr test 1 .
+.It Ic times
+Print the amount of time spent executing the shell process and its children.
+The first output line shows the user and system times for the shell process
+itself, the second one contains the user and system times for the
+children.
+.It Ic trap Oo Ar action Oc Ar signal ...
+.It Ic trap Fl l
+Cause the shell to parse and execute
+.Ar action
+when any specified
+.Ar signal
+is received.
+The signals are specified by name or number.
+In addition, the pseudo-signal
+.Cm EXIT
+may be used to specify an
+.Ar action
+that is performed when the shell terminates.
+The
+.Ar action
+may be an empty string or a dash
+.Pq Ql - ;
+the former causes the specified signal to be ignored
+and the latter causes the default action to be taken.
+Omitting the
+.Ar action
+and using only signal numbers is another way to request the default action.
+In a subshell or utility environment,
+the shell resets trapped (but not ignored) signals to the default action.
+The
+.Ic trap
+command has no effect on signals that were ignored on entry to the shell.
+.Pp
+Option
+.Fl l
+causes the
+.Ic trap
+command to display a list of valid signal names.
+.It Ic true
+A null command that returns a 0 (true) exit value.
+.It Ic type Op Ar name ...
+Interpret each
+.Ar name
+as a command and print the resolution of the command search.
+Possible resolutions are:
+shell keyword, alias, special shell builtin, shell builtin, command,
+tracked alias
+and not found.
+For aliases the alias expansion is printed;
+for commands and tracked aliases
+the complete pathname of the command is printed.
+.It Ic ulimit Oo Fl HSabcdfklmnopstuvw Oc Op Ar limit
+Set or display resource limits (see
+.Xr getrlimit 2 ) .
+If
+.Ar limit
+is specified, the named resource will be set;
+otherwise the current resource value will be displayed.
+.Pp
+If
+.Fl H
+is specified, the hard limits will be set or displayed.
+While everybody is allowed to reduce a hard limit,
+only the superuser can increase it.
+The
+.Fl S
+option
+specifies the soft limits instead.
+When displaying limits,
+only one of
+.Fl S
+or
+.Fl H
+can be given.
+The default is to display the soft limits,
+and to set both the hard and the soft limits.
+.Pp
+Option
+.Fl a
+causes the
+.Ic ulimit
+command to display all resources.
+The parameter
+.Ar limit
+is not acceptable in this mode.
+.Pp
+The remaining options specify which resource value is to be
+displayed or modified.
+They are mutually exclusive.
+.Bl -tag -width indent
+.It Fl b Ar sbsize
+The maximum size of socket buffer usage, in bytes.
+.It Fl c Ar coredumpsize
+The maximal size of core dump files, in 512-byte blocks.
+.It Fl d Ar datasize
+The maximal size of the data segment of a process, in kilobytes.
+.It Fl f Ar filesize
+The maximal size of a file, in 512-byte blocks.
+.It Fl k Ar kqueues
+The maximal number of kqueues
+(see
+.Xr kqueue 2 )
+for this user ID.
+.It Fl l Ar lockedmem
+The maximal size of memory that can be locked by a process, in
+kilobytes.
+.It Fl m Ar memoryuse
+The maximal resident set size of a process, in kilobytes.
+.It Fl n Ar nofiles
+The maximal number of descriptors that could be opened by a process.
+.It Fl o Ar umtxp
+The maximal number of process-shared locks
+(see
+.Xr pthread 3 )
+for this user ID.
+.It Fl p Ar pseudoterminals
+The maximal number of pseudo-terminals for this user ID.
+.It Fl s Ar stacksize
+The maximal size of the stack segment, in kilobytes.
+.It Fl t Ar time
+The maximal amount of CPU time to be used by each process, in seconds.
+.It Fl u Ar userproc
+The maximal number of simultaneous processes for this user ID.
+.It Fl v Ar virtualmem
+The maximal virtual size of a process, in kilobytes.
+.It Fl w Ar swapuse
+The maximum amount of swap space reserved or used for this user ID,
+in kilobytes.
+.El
+.It Ic umask Oo Fl S Oc Op Ar mask
+Set the file creation mask (see
+.Xr umask 2 )
+to the octal or symbolic (see
+.Xr chmod 1 )
+value specified by
+.Ar mask .
+If the argument is omitted, the current mask value is printed.
+If the
+.Fl S
+option is specified, the output is symbolic, otherwise the output is octal.
+.It Ic unalias Oo Fl a Oc Op Ar name ...
+The specified alias names are removed.
+If
+.Fl a
+is specified, all aliases are removed.
+.It Ic unset Oo Fl fv Oc Ar name ...
+The specified variables or functions are unset and unexported.
+If the
+.Fl v
+option is specified or no options are given, the
+.Ar name
+arguments are treated as variable names.
+If the
+.Fl f
+option is specified, the
+.Ar name
+arguments are treated as function names.
+.It Ic wait Op Ar job ...
+Wait for each specified
+.Ar job
+to complete and return the exit status of the last process in the
+last specified
+.Ar job .
+If any
+.Ar job
+specified is unknown to the shell, it is treated as if it
+were a known job that exited with exit status 127.
+If no operands are given, wait for all jobs to complete
+and return an exit status of zero.
+.El
+.Ss Command Line Editing
+When
+.Nm
+is being used interactively from a terminal, the current command
+and the command history
+(see
+.Ic fc
+in
+.Sx Built-in Commands )
+can be edited using
+.Nm vi Ns -mode
+command line editing.
+This mode uses commands similar
+to a subset of those described in the
+.Xr vi 1
+man page.
+The command
+.Dq Li "set -o vi"
+(or
+.Dq Li "set -V" )
+enables
+.Nm vi Ns -mode
+editing and places
+.Nm
+into
+.Nm vi
+insert mode.
+With
+.Nm vi Ns -mode
+enabled,
+.Nm
+can be switched between insert mode and command mode by typing
+.Aq ESC .
+Hitting
+.Aq return
+while in command mode will pass the line to the shell.
+.Pp
+Similarly, the
+.Dq Li "set -o emacs"
+(or
+.Dq Li "set -E" )
+command can be used to enable a subset of
+.Nm emacs Ns -style
+command line editing features.
+.Sh ENVIRONMENT
+The following environment variables affect the execution of
+.Nm :
+.Bl -tag -width ".Ev LANGXXXXXX"
+.It Ev ENV
+Initialization file for interactive shells.
+.It Ev LANG , Ev LC_*
+Locale settings.
+These are inherited by children of the shell,
+and is used in a limited manner by the shell itself.
+.It Ev OLDPWD
+The previous current directory.
+This is used and updated by
+.Ic cd .
+.It Ev PWD
+An absolute pathname for the current directory,
+possibly containing symbolic links.
+This is used and updated by the shell.
+.It Ev TERM
+The default terminal setting for the shell.
+This is inherited by children of the shell, and is used in the history
+editing modes.
+.El
+.Pp
+Additionally, environment variables are turned into shell variables
+at startup,
+which may affect the shell as described under
+.Sx Special Variables .
+.Sh FILES
+.Bl -tag -width "/etc/suid_profileXX" -compact
+.It Pa ~/.profile
+User's login profile.
+.It Pa /etc/profile
+System login profile.
+.It Pa /etc/shells
+Shell database.
+.It Pa /etc/suid_profile
+Privileged shell profile.
+.El
+.Sh EXIT STATUS
+Errors that are detected by the shell, such as a syntax error, will
+cause the shell to exit with a non-zero exit status.
+If the shell is not an interactive shell, the execution of the shell
+file will be aborted.
+Otherwise the shell will return the exit status of the last command
+executed, or if the
+.Ic exit
+builtin is used with a numeric argument, it
+will return the argument.
+.Sh SEE ALSO
+.Xr builtin 1 ,
+.Xr chsh 1 ,
+.Xr echo 1 ,
+.Xr ed 1 ,
+.Xr emacs 1 ,
+.Xr kill 1 ,
+.Xr printf 1 ,
+.Xr pwd 1 ,
+.Xr test 1 ,
+.Xr vi 1 ,
+.Xr execve 2 ,
+.Xr getrlimit 2 ,
+.Xr umask 2 ,
+.Xr wctype 3 ,
+.Xr editrc 5 ,
+.Xr shells 5
+.Sh HISTORY
+A
+.Nm
+command, the Thompson shell, appeared in
+.At v1 .
+It was superseded in
+.At v7
+by the Bourne shell, which inherited the name
+.Nm .
+.Pp
+This version of
+.Nm
+was rewritten in 1989 under the
+.Bx
+license after the Bourne shell from
+.At V.4 .
+.Sh AUTHORS
+This version of
+.Nm
+was originally written by
+.An Kenneth Almquist .
+.Sh BUGS
+The
+.Nm
+utility does not recognize multibyte characters other than UTF-8.
+Splitting using
+.Va IFS
+does not recognize multibyte characters.
diff --git a/shell_cmds/sh/sh.plist.part b/shell_cmds/sh/sh.plist.part
new file mode 100644
index 0000000..f023fca
--- /dev/null
+++ b/shell_cmds/sh/sh.plist.part
@@ -0,0 +1,23 @@
+ <dict>
+ <key>OpenSourceProject</key>
+ <string>sh</string>
+ <key>OpenSourceVersion</key>
+ <string>2016-10-08</string>
+ <key>OpenSourceWebsiteURL</key>
+ <string>http://svnweb.freebsd.org/base/head/bin/sh/</string>
+ <key>OpenSourceSCM</key>
+ <string>svn co http://svn.freebsd.org/base/head/bin/sh/</string>
+ <key>OpenSourceImportDate</key>
+ <string>2016-10-27</string>
+ <key>OpenSourceModifications</key>
+ <array>
+ <string>exec.c: eaccess</string>
+ <string>input.c: remove multiple definition</string>
+ <string>input.c: strchrnul</string>
+ <string>miscbltin.c: warning fix</string>
+ <string>mknodes.c: __printf0like</string>
+ <string>trap.c: sys_nsig</string>
+ </array>
+ <key>OpenSourceLicense</key>
+ <string>bsd</string>
+ </dict>
diff --git a/shell_cmds/sh/shell.h b/shell_cmds/sh/shell.h
new file mode 100644
index 0000000..1c7a766
--- /dev/null
+++ b/shell_cmds/sh/shell.h
@@ -0,0 +1,79 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)shell.h 8.2 (Berkeley) 5/4/95
+ * $FreeBSD: head/bin/sh/shell.h 326025 2017-11-20 19:49:47Z pfg $
+ */
+
+#ifndef SHELL_H_
+#define SHELL_H_
+
+#include <inttypes.h>
+
+/*
+ * The follow should be set to reflect the type of system you have:
+ * JOBS -> 1 if you have Berkeley job control, 0 otherwise.
+ * define DEBUG=1 to compile in debugging (set global "debug" to turn on)
+ * define DEBUG=2 to compile in and turn on debugging.
+ *
+ * When debugging is on, debugging info will be written to ./trace and
+ * a quit signal will generate a core dump.
+ */
+
+
+#define JOBS 1
+/* #define DEBUG 1 */
+
+/*
+ * Type of used arithmetics. SUSv3 requires us to have at least signed long.
+ */
+typedef intmax_t arith_t;
+#define ARITH_FORMAT_STR "%" PRIdMAX
+#define atoarith_t(arg) strtoimax(arg, NULL, 0)
+#define strtoarith_t(nptr, endptr, base) strtoimax(nptr, endptr, base)
+#define ARITH_MIN INTMAX_MIN
+#define ARITH_MAX INTMAX_MAX
+
+typedef void *pointer;
+
+#include <sys/cdefs.h>
+
+extern char nullstr[1]; /* null string */
+
+#ifdef DEBUG
+#define TRACE(param) sh_trace param
+#else
+#define TRACE(param)
+#endif
+
+#endif /* !SHELL_H_ */
diff --git a/shell_cmds/sh/show.c b/shell_cmds/sh/show.c
new file mode 100644
index 0000000..9b55708
--- /dev/null
+++ b/shell_cmds/sh/show.c
@@ -0,0 +1,410 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)show.c 8.3 (Berkeley) 5/4/95";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/bin/sh/show.c 326025 2017-11-20 19:49:47Z pfg $");
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <errno.h>
+
+#include "shell.h"
+#include "parser.h"
+#include "nodes.h"
+#include "mystring.h"
+#include "show.h"
+
+
+#ifdef DEBUG
+static void shtree(union node *, int, char *, FILE*);
+static void shcmd(union node *, FILE *);
+static void sharg(union node *, FILE *);
+static void indent(int, char *, FILE *);
+static void trstring(char *);
+
+
+void
+showtree(union node *n)
+{
+ trputs("showtree called\n");
+ shtree(n, 1, NULL, stdout);
+}
+
+
+static void
+shtree(union node *n, int ind, char *pfx, FILE *fp)
+{
+ struct nodelist *lp;
+ char *s;
+
+ if (n == NULL)
+ return;
+
+ indent(ind, pfx, fp);
+ switch(n->type) {
+ case NSEMI:
+ s = "; ";
+ goto binop;
+ case NAND:
+ s = " && ";
+ goto binop;
+ case NOR:
+ s = " || ";
+binop:
+ shtree(n->nbinary.ch1, ind, NULL, fp);
+ /* if (ind < 0) */
+ fputs(s, fp);
+ shtree(n->nbinary.ch2, ind, NULL, fp);
+ break;
+ case NCMD:
+ shcmd(n, fp);
+ if (ind >= 0)
+ putc('\n', fp);
+ break;
+ case NPIPE:
+ for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
+ shcmd(lp->n, fp);
+ if (lp->next)
+ fputs(" | ", fp);
+ }
+ if (n->npipe.backgnd)
+ fputs(" &", fp);
+ if (ind >= 0)
+ putc('\n', fp);
+ break;
+ default:
+ fprintf(fp, "<node type %d>", n->type);
+ if (ind >= 0)
+ putc('\n', fp);
+ break;
+ }
+}
+
+
+
+static void
+shcmd(union node *cmd, FILE *fp)
+{
+ union node *np;
+ int first;
+ char *s;
+ int dftfd;
+
+ first = 1;
+ for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
+ if (! first)
+ putchar(' ');
+ sharg(np, fp);
+ first = 0;
+ }
+ for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
+ if (! first)
+ putchar(' ');
+ switch (np->nfile.type) {
+ case NTO: s = ">"; dftfd = 1; break;
+ case NAPPEND: s = ">>"; dftfd = 1; break;
+ case NTOFD: s = ">&"; dftfd = 1; break;
+ case NCLOBBER: s = ">|"; dftfd = 1; break;
+ case NFROM: s = "<"; dftfd = 0; break;
+ case NFROMTO: s = "<>"; dftfd = 0; break;
+ case NFROMFD: s = "<&"; dftfd = 0; break;
+ case NHERE: s = "<<"; dftfd = 0; break;
+ case NXHERE: s = "<<"; dftfd = 0; break;
+ default: s = "*error*"; dftfd = 0; break;
+ }
+ if (np->nfile.fd != dftfd)
+ fprintf(fp, "%d", np->nfile.fd);
+ fputs(s, fp);
+ if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
+ if (np->ndup.dupfd >= 0)
+ fprintf(fp, "%d", np->ndup.dupfd);
+ else
+ fprintf(fp, "-");
+ } else if (np->nfile.type == NHERE) {
+ fprintf(fp, "HERE");
+ } else if (np->nfile.type == NXHERE) {
+ fprintf(fp, "XHERE");
+ } else {
+ sharg(np->nfile.fname, fp);
+ }
+ first = 0;
+ }
+}
+
+
+
+static void
+sharg(union node *arg, FILE *fp)
+{
+ char *p;
+ struct nodelist *bqlist;
+ int subtype;
+
+ if (arg->type != NARG) {
+ printf("<node type %d>\n", arg->type);
+ fflush(stdout);
+ abort();
+ }
+ bqlist = arg->narg.backquote;
+ for (p = arg->narg.text ; *p ; p++) {
+ switch (*p) {
+ case CTLESC:
+ putc(*++p, fp);
+ break;
+ case CTLVAR:
+ putc('$', fp);
+ putc('{', fp);
+ subtype = *++p;
+ if (subtype == VSLENGTH)
+ putc('#', fp);
+
+ while (*p != '=')
+ putc(*p++, fp);
+
+ if (subtype & VSNUL)
+ putc(':', fp);
+
+ switch (subtype & VSTYPE) {
+ case VSNORMAL:
+ putc('}', fp);
+ break;
+ case VSMINUS:
+ putc('-', fp);
+ break;
+ case VSPLUS:
+ putc('+', fp);
+ break;
+ case VSQUESTION:
+ putc('?', fp);
+ break;
+ case VSASSIGN:
+ putc('=', fp);
+ break;
+ case VSTRIMLEFT:
+ putc('#', fp);
+ break;
+ case VSTRIMLEFTMAX:
+ putc('#', fp);
+ putc('#', fp);
+ break;
+ case VSTRIMRIGHT:
+ putc('%', fp);
+ break;
+ case VSTRIMRIGHTMAX:
+ putc('%', fp);
+ putc('%', fp);
+ break;
+ case VSLENGTH:
+ break;
+ default:
+ printf("<subtype %d>", subtype);
+ }
+ break;
+ case CTLENDVAR:
+ putc('}', fp);
+ break;
+ case CTLBACKQ:
+ case CTLBACKQ|CTLQUOTE:
+ putc('$', fp);
+ putc('(', fp);
+ shtree(bqlist->n, -1, NULL, fp);
+ putc(')', fp);
+ break;
+ default:
+ putc(*p, fp);
+ break;
+ }
+ }
+}
+
+
+static void
+indent(int amount, char *pfx, FILE *fp)
+{
+ int i;
+
+ for (i = 0 ; i < amount ; i++) {
+ if (pfx && i == amount - 1)
+ fputs(pfx, fp);
+ putc('\t', fp);
+ }
+}
+
+
+/*
+ * Debugging stuff.
+ */
+
+
+FILE *tracefile;
+
+#if DEBUG >= 2
+int debug = 1;
+#else
+int debug = 0;
+#endif
+
+
+void
+trputc(int c)
+{
+ if (tracefile == NULL)
+ return;
+ putc(c, tracefile);
+ if (c == '\n')
+ fflush(tracefile);
+}
+
+
+void
+sh_trace(const char *fmt, ...)
+{
+ va_list va;
+ va_start(va, fmt);
+ if (tracefile != NULL) {
+ (void) vfprintf(tracefile, fmt, va);
+ if (strchr(fmt, '\n'))
+ (void) fflush(tracefile);
+ }
+ va_end(va);
+}
+
+
+void
+trputs(const char *s)
+{
+ if (tracefile == NULL)
+ return;
+ fputs(s, tracefile);
+ if (strchr(s, '\n'))
+ fflush(tracefile);
+}
+
+
+static void
+trstring(char *s)
+{
+ char *p;
+ char c;
+
+ if (tracefile == NULL)
+ return;
+ putc('"', tracefile);
+ for (p = s ; *p ; p++) {
+ switch (*p) {
+ case '\n': c = 'n'; goto backslash;
+ case '\t': c = 't'; goto backslash;
+ case '\r': c = 'r'; goto backslash;
+ case '"': c = '"'; goto backslash;
+ case '\\': c = '\\'; goto backslash;
+ case CTLESC: c = 'e'; goto backslash;
+ case CTLVAR: c = 'v'; goto backslash;
+ case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
+ case CTLBACKQ: c = 'q'; goto backslash;
+ case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
+backslash: putc('\\', tracefile);
+ putc(c, tracefile);
+ break;
+ default:
+ if (*p >= ' ' && *p <= '~')
+ putc(*p, tracefile);
+ else {
+ putc('\\', tracefile);
+ putc(*p >> 6 & 03, tracefile);
+ putc(*p >> 3 & 07, tracefile);
+ putc(*p & 07, tracefile);
+ }
+ break;
+ }
+ }
+ putc('"', tracefile);
+}
+
+
+void
+trargs(char **ap)
+{
+ if (tracefile == NULL)
+ return;
+ while (*ap) {
+ trstring(*ap++);
+ if (*ap)
+ putc(' ', tracefile);
+ else
+ putc('\n', tracefile);
+ }
+ fflush(tracefile);
+}
+
+
+void
+opentrace(void)
+{
+ char s[100];
+ int flags;
+
+ if (!debug)
+ return;
+#ifdef not_this_way
+ {
+ char *p;
+ if ((p = getenv("HOME")) == NULL) {
+ if (geteuid() == 0)
+ p = "/";
+ else
+ p = "/tmp";
+ }
+ strcpy(s, p);
+ strcat(s, "/trace");
+ }
+#else
+ strcpy(s, "./trace");
+#endif /* not_this_way */
+ if ((tracefile = fopen(s, "a")) == NULL) {
+ fprintf(stderr, "Can't open %s: %s\n", s, strerror(errno));
+ return;
+ }
+ if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
+ fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
+ fputs("\nTracing started.\n", tracefile);
+ fflush(tracefile);
+}
+#endif /* DEBUG */
diff --git a/shell_cmds/sh/show.h b/shell_cmds/sh/show.h
new file mode 100644
index 0000000..fc5ef76
--- /dev/null
+++ b/shell_cmds/sh/show.h
@@ -0,0 +1,42 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1995
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)show.h 1.1 (Berkeley) 5/4/95
+ * $FreeBSD: head/bin/sh/show.h 326025 2017-11-20 19:49:47Z pfg $
+ */
+
+void showtree(union node *);
+#ifdef DEBUG
+void sh_trace(const char *, ...) __printflike(1, 2);
+void trargs(char **);
+void trputc(int);
+void trputs(const char *);
+void opentrace(void);
+#endif
diff --git a/shell_cmds/sh/tests/Makefile b/shell_cmds/sh/tests/Makefile
new file mode 100644
index 0000000..b7d7b7d
--- /dev/null
+++ b/shell_cmds/sh/tests/Makefile
@@ -0,0 +1,14 @@
+# $FreeBSD: head/bin/sh/tests/Makefile 322438 2017-08-12 19:17:48Z jilles $
+
+.include <bsd.own.mk>
+
+TESTS_SUBDIRS+= builtins
+TESTS_SUBDIRS+= errors
+TESTS_SUBDIRS+= execution
+TESTS_SUBDIRS+= expansion
+TESTS_SUBDIRS+= invocation
+TESTS_SUBDIRS+= parameters
+TESTS_SUBDIRS+= parser
+TESTS_SUBDIRS+= set-e
+
+.include <bsd.test.mk>
diff --git a/shell_cmds/sh/tests/Makefile.depend b/shell_cmds/sh/tests/Makefile.depend
new file mode 100644
index 0000000..9ff4aed
--- /dev/null
+++ b/shell_cmds/sh/tests/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD: head/bin/sh/tests/Makefile.depend 296587 2016-03-09 22:46:01Z bdrewery $
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/shell_cmds/sh/tests/builtins/Makefile b/shell_cmds/sh/tests/builtins/Makefile
new file mode 100644
index 0000000..98c3841
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/Makefile
@@ -0,0 +1,185 @@
+# $FreeBSD: head/bin/sh/tests/builtins/Makefile 320340 2017-06-25 21:53:08Z jilles $
+
+PACKAGE= tests
+
+.include <src.opts.mk>
+
+TESTSDIR= ${TESTSBASE}/bin/sh/${.CURDIR:T}
+
+.PATH: ${.CURDIR:H}
+ATF_TESTS_SH= functional_test
+
+${PACKAGE}FILES+= alias.0 alias.0.stdout
+${PACKAGE}FILES+= alias.1 alias.1.stderr
+${PACKAGE}FILES+= alias3.0 alias3.0.stdout
+${PACKAGE}FILES+= alias4.0
+${PACKAGE}FILES+= break1.0
+${PACKAGE}FILES+= break2.0 break2.0.stdout
+${PACKAGE}FILES+= break3.0
+${PACKAGE}FILES+= break4.4
+${PACKAGE}FILES+= break5.4
+${PACKAGE}FILES+= break6.0
+${PACKAGE}FILES+= builtin1.0
+${PACKAGE}FILES+= case1.0
+${PACKAGE}FILES+= case2.0
+${PACKAGE}FILES+= case3.0
+${PACKAGE}FILES+= case4.0
+${PACKAGE}FILES+= case5.0
+${PACKAGE}FILES+= case6.0
+${PACKAGE}FILES+= case7.0
+${PACKAGE}FILES+= case8.0
+${PACKAGE}FILES+= case9.0
+${PACKAGE}FILES+= case10.0
+${PACKAGE}FILES+= case11.0
+${PACKAGE}FILES+= case12.0
+${PACKAGE}FILES+= case13.0
+${PACKAGE}FILES+= case14.0
+${PACKAGE}FILES+= case15.0
+${PACKAGE}FILES+= case16.0
+${PACKAGE}FILES+= case17.0
+${PACKAGE}FILES+= case18.0
+${PACKAGE}FILES+= case19.0
+${PACKAGE}FILES+= case20.0
+${PACKAGE}FILES+= case21.0
+${PACKAGE}FILES+= case22.0
+${PACKAGE}FILES+= cd1.0
+${PACKAGE}FILES+= cd2.0
+${PACKAGE}FILES+= cd3.0
+${PACKAGE}FILES+= cd4.0
+${PACKAGE}FILES+= cd5.0
+${PACKAGE}FILES+= cd6.0
+${PACKAGE}FILES+= cd7.0
+${PACKAGE}FILES+= cd8.0
+${PACKAGE}FILES+= cd9.0 cd9.0.stdout
+${PACKAGE}FILES+= cd10.0
+${PACKAGE}FILES+= command1.0
+${PACKAGE}FILES+= command2.0
+${PACKAGE}FILES+= command3.0
+${PACKAGE}FILES+= command3.0.stdout
+${PACKAGE}FILES+= command4.0
+${PACKAGE}FILES+= command5.0
+${PACKAGE}FILES+= command5.0.stdout
+${PACKAGE}FILES+= command6.0
+${PACKAGE}FILES+= command6.0.stdout
+${PACKAGE}FILES+= command7.0
+${PACKAGE}FILES+= command8.0
+${PACKAGE}FILES+= command9.0
+${PACKAGE}FILES+= command10.0
+${PACKAGE}FILES+= command11.0
+${PACKAGE}FILES+= command12.0
+${PACKAGE}FILES+= dot1.0
+${PACKAGE}FILES+= dot2.0
+${PACKAGE}FILES+= dot3.0
+${PACKAGE}FILES+= dot4.0
+${PACKAGE}FILES+= echo1.0
+${PACKAGE}FILES+= echo2.0
+${PACKAGE}FILES+= echo3.0
+${PACKAGE}FILES+= eval1.0
+${PACKAGE}FILES+= eval2.0
+${PACKAGE}FILES+= eval3.0
+${PACKAGE}FILES+= eval4.0
+${PACKAGE}FILES+= eval5.0
+${PACKAGE}FILES+= eval6.0
+${PACKAGE}FILES+= eval7.0
+${PACKAGE}FILES+= eval8.7
+${PACKAGE}FILES+= exec1.0
+${PACKAGE}FILES+= exec2.0
+${PACKAGE}FILES+= exit1.0
+${PACKAGE}FILES+= exit2.8
+${PACKAGE}FILES+= exit3.0
+${PACKAGE}FILES+= export1.0
+${PACKAGE}FILES+= fc1.0
+${PACKAGE}FILES+= fc2.0
+${PACKAGE}FILES+= for1.0
+${PACKAGE}FILES+= for2.0
+${PACKAGE}FILES+= for3.0
+${PACKAGE}FILES+= getopts1.0 getopts1.0.stdout
+${PACKAGE}FILES+= getopts2.0 getopts2.0.stdout
+${PACKAGE}FILES+= getopts3.0
+${PACKAGE}FILES+= getopts4.0
+${PACKAGE}FILES+= getopts5.0
+${PACKAGE}FILES+= getopts6.0
+${PACKAGE}FILES+= getopts7.0
+${PACKAGE}FILES+= getopts8.0 getopts8.0.stdout
+${PACKAGE}FILES+= getopts9.0 getopts9.0.stdout
+${PACKAGE}FILES+= getopts10.0
+${PACKAGE}FILES+= hash1.0 hash1.0.stdout
+${PACKAGE}FILES+= hash2.0 hash2.0.stdout
+${PACKAGE}FILES+= hash3.0 hash3.0.stdout
+${PACKAGE}FILES+= hash4.0
+${PACKAGE}FILES+= jobid1.0
+${PACKAGE}FILES+= jobid2.0
+${PACKAGE}FILES+= kill1.0 kill2.0
+${PACKAGE}FILES+= lineno.0 lineno.0.stdout
+${PACKAGE}FILES+= lineno2.0
+${PACKAGE}FILES+= lineno3.0 lineno3.0.stdout
+${PACKAGE}FILES+= local1.0
+${PACKAGE}FILES+= local2.0
+${PACKAGE}FILES+= local3.0
+${PACKAGE}FILES+= local4.0
+${PACKAGE}FILES+= local5.0
+${PACKAGE}FILES+= local6.0
+${PACKAGE}FILES+= local7.0
+.if ${MK_NLS} != "no"
+${PACKAGE}FILES+= locale1.0
+.endif
+${PACKAGE}FILES+= locale2.0
+${PACKAGE}FILES+= printf1.0
+${PACKAGE}FILES+= printf2.0
+${PACKAGE}FILES+= printf3.0
+${PACKAGE}FILES+= printf4.0
+${PACKAGE}FILES+= read1.0 read1.0.stdout
+${PACKAGE}FILES+= read2.0
+${PACKAGE}FILES+= read3.0 read3.0.stdout
+${PACKAGE}FILES+= read4.0 read4.0.stdout
+${PACKAGE}FILES+= read5.0
+${PACKAGE}FILES+= read6.0
+${PACKAGE}FILES+= read7.0
+${PACKAGE}FILES+= read8.0
+${PACKAGE}FILES+= read9.0
+${PACKAGE}FILES+= return1.0
+${PACKAGE}FILES+= return2.1
+${PACKAGE}FILES+= return3.1
+${PACKAGE}FILES+= return4.0
+${PACKAGE}FILES+= return5.0
+${PACKAGE}FILES+= return6.4
+${PACKAGE}FILES+= return7.4
+${PACKAGE}FILES+= return8.0
+${PACKAGE}FILES+= set1.0
+${PACKAGE}FILES+= set2.0
+${PACKAGE}FILES+= set3.0
+${PACKAGE}FILES+= trap1.0
+${PACKAGE}FILES+= trap10.0
+${PACKAGE}FILES+= trap11.0
+${PACKAGE}FILES+= trap12.0
+${PACKAGE}FILES+= trap13.0
+${PACKAGE}FILES+= trap14.0
+${PACKAGE}FILES+= trap15.0
+${PACKAGE}FILES+= trap16.0
+${PACKAGE}FILES+= trap17.0
+${PACKAGE}FILES+= trap2.0
+${PACKAGE}FILES+= trap3.0
+${PACKAGE}FILES+= trap4.0
+${PACKAGE}FILES+= trap5.0
+${PACKAGE}FILES+= trap6.0
+${PACKAGE}FILES+= trap7.0
+${PACKAGE}FILES+= trap8.0
+${PACKAGE}FILES+= trap9.0
+${PACKAGE}FILES+= type1.0 type1.0.stderr
+${PACKAGE}FILES+= type2.0
+${PACKAGE}FILES+= type3.0
+${PACKAGE}FILES+= unalias.0
+${PACKAGE}FILES+= var-assign.0
+${PACKAGE}FILES+= var-assign2.0
+${PACKAGE}FILES+= wait1.0
+${PACKAGE}FILES+= wait2.0
+${PACKAGE}FILES+= wait3.0
+${PACKAGE}FILES+= wait4.0
+${PACKAGE}FILES+= wait5.0
+${PACKAGE}FILES+= wait6.0
+${PACKAGE}FILES+= wait7.0
+${PACKAGE}FILES+= wait8.0
+${PACKAGE}FILES+= wait9.127
+${PACKAGE}FILES+= wait10.0
+
+.include <bsd.test.mk>
diff --git a/shell_cmds/sh/tests/builtins/Makefile.depend b/shell_cmds/sh/tests/builtins/Makefile.depend
new file mode 100644
index 0000000..21c5642
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD: head/bin/sh/tests/builtins/Makefile.depend 296587 2016-03-09 22:46:01Z bdrewery $
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/shell_cmds/sh/tests/builtins/alias.0 b/shell_cmds/sh/tests/builtins/alias.0
new file mode 100644
index 0000000..067a890
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/alias.0
@@ -0,0 +1,9 @@
+# $FreeBSD: head/bin/sh/tests/builtins/alias.0 190285 2009-03-22 21:12:00Z stefanf $
+set -e
+
+unalias -a
+alias foo=bar
+alias bar=
+alias quux="1 2 3"
+alias
+alias foo
diff --git a/shell_cmds/sh/tests/builtins/alias.0.stdout b/shell_cmds/sh/tests/builtins/alias.0.stdout
new file mode 100644
index 0000000..52efaf0
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/alias.0.stdout
@@ -0,0 +1,4 @@
+bar=''
+foo=bar
+quux='1 2 3'
+foo=bar
diff --git a/shell_cmds/sh/tests/builtins/alias.1 b/shell_cmds/sh/tests/builtins/alias.1
new file mode 100644
index 0000000..22093dd
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/alias.1
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/builtins/alias.1 149781 2005-09-04 11:59:59Z stefanf $
+unalias -a
+alias foo
diff --git a/shell_cmds/sh/tests/builtins/alias.1.stderr b/shell_cmds/sh/tests/builtins/alias.1.stderr
new file mode 100644
index 0000000..c9f4011
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/alias.1.stderr
@@ -0,0 +1 @@
+alias: foo: not found
diff --git a/shell_cmds/sh/tests/builtins/alias3.0 b/shell_cmds/sh/tests/builtins/alias3.0
new file mode 100644
index 0000000..e2e215a
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/alias3.0
@@ -0,0 +1,12 @@
+# $FreeBSD: head/bin/sh/tests/builtins/alias3.0 242767 2012-11-08 13:36:19Z jilles $
+set -e
+
+unalias -a
+alias foo=bar
+alias bar=
+alias quux="1 2 3"
+alias foo=bar
+alias bar=
+alias quux="1 2 3"
+alias
+alias foo
diff --git a/shell_cmds/sh/tests/builtins/alias3.0.stdout b/shell_cmds/sh/tests/builtins/alias3.0.stdout
new file mode 100644
index 0000000..52efaf0
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/alias3.0.stdout
@@ -0,0 +1,4 @@
+bar=''
+foo=bar
+quux='1 2 3'
+foo=bar
diff --git a/shell_cmds/sh/tests/builtins/alias4.0 b/shell_cmds/sh/tests/builtins/alias4.0
new file mode 100644
index 0000000..d86559b
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/alias4.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/builtins/alias4.0 254849 2013-08-25 11:42:53Z jilles $
+
+unalias -a
+alias --
diff --git a/shell_cmds/sh/tests/builtins/break1.0 b/shell_cmds/sh/tests/builtins/break1.0
new file mode 100644
index 0000000..219cbf2
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/break1.0
@@ -0,0 +1,16 @@
+# $FreeBSD: head/bin/sh/tests/builtins/break1.0 211349 2010-08-15 21:06:53Z jilles $
+
+if [ "$1" != nested ]; then
+ while :; do
+ set -- nested
+ . "$0"
+ echo bad2
+ exit 2
+ done
+ exit 0
+fi
+# To trigger the bug, the following commands must be at the top level,
+# with newlines in between.
+break
+echo bad1
+exit 1
diff --git a/shell_cmds/sh/tests/builtins/break2.0 b/shell_cmds/sh/tests/builtins/break2.0
new file mode 100644
index 0000000..f836e31
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/break2.0
@@ -0,0 +1,12 @@
+# $FreeBSD: head/bin/sh/tests/builtins/break2.0 211467 2010-08-18 20:26:50Z jilles $
+
+# It is not immediately obvious that this should work, and someone probably
+# relies on it.
+
+while :; do
+ trap 'break' USR1
+ kill -USR1 $$
+ echo bad
+ exit 1
+done
+echo good
diff --git a/shell_cmds/sh/tests/builtins/break2.0.stdout b/shell_cmds/sh/tests/builtins/break2.0.stdout
new file mode 100644
index 0000000..12799cc
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/break2.0.stdout
@@ -0,0 +1 @@
+good
diff --git a/shell_cmds/sh/tests/builtins/break3.0 b/shell_cmds/sh/tests/builtins/break3.0
new file mode 100644
index 0000000..1a6985c
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/break3.0
@@ -0,0 +1,15 @@
+# $FreeBSD: head/bin/sh/tests/builtins/break3.0 211612 2010-08-22 11:07:46Z jilles $
+
+# We accept this and people might rely on it.
+# However, various other shells do not accept it.
+
+f() {
+ break
+ echo bad1
+}
+
+while :; do
+ f
+ echo bad2
+ exit 2
+done
diff --git a/shell_cmds/sh/tests/builtins/break4.4 b/shell_cmds/sh/tests/builtins/break4.4
new file mode 100644
index 0000000..3b1bb0c
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/break4.4
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/builtins/break4.4 251180 2013-05-31 14:45:25Z jilles $
+
+# Although this is not specified by POSIX, some configure scripts (gawk 4.1.0)
+# appear to depend on it.
+
+break
+exit 4
diff --git a/shell_cmds/sh/tests/builtins/break5.4 b/shell_cmds/sh/tests/builtins/break5.4
new file mode 100644
index 0000000..a29f317
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/break5.4
@@ -0,0 +1,12 @@
+# $FreeBSD: head/bin/sh/tests/builtins/break5.4 251180 2013-05-31 14:45:25Z jilles $
+
+# Although this is not specified by POSIX, some configure scripts (gawk 4.1.0)
+# appear to depend on it.
+# In some uncommitted code, the subshell environment corrupted the outer
+# shell environment's state.
+
+(for i in a b c; do
+ exit 3
+done)
+break
+exit 4
diff --git a/shell_cmds/sh/tests/builtins/break6.0 b/shell_cmds/sh/tests/builtins/break6.0
new file mode 100644
index 0000000..b5fc63b
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/break6.0
@@ -0,0 +1,8 @@
+# $FreeBSD: head/bin/sh/tests/builtins/break6.0 268927 2014-07-20 20:29:09Z jilles $
+# Per POSIX, this need only work if LONG_MAX > 4294967295.
+
+while :; do
+ break 4294967296
+ echo bad
+ exit 3
+done
diff --git a/shell_cmds/sh/tests/builtins/builtin1.0 b/shell_cmds/sh/tests/builtins/builtin1.0
new file mode 100644
index 0000000..dd77422
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/builtin1.0
@@ -0,0 +1,31 @@
+# $FreeBSD: head/bin/sh/tests/builtins/builtin1.0 201431 2010-01-03 15:01:38Z jilles $
+
+failures=0
+
+check() {
+ if ! eval "[ $* ]"; then
+ echo "Failed: $*"
+ : $((failures += 1))
+ fi
+}
+
+builtin : || echo "Bad return code at $LINENO"
+builtin true || echo "Bad return code at $LINENO"
+builtin ls 2>/dev/null && echo "Bad return code at $LINENO"
+check '"$(builtin pwd)" = "$(pwd)"'
+check '-z "$(builtin :)"'
+check '-z "$(builtin true)"'
+check '-z "$( (builtin nosuchtool) 2>/dev/null)"'
+check '-z "$(builtin nosuchtool 2>/dev/null)"'
+check '-z "$(builtin nosuchtool 2>/dev/null; :)"'
+check '-z "$( (builtin ls) 2>/dev/null)"'
+check '-z "$(builtin ls 2>/dev/null)"'
+check '-z "$(builtin ls 2>/dev/null; :)"'
+check '-n "$( (builtin nosuchtool) 2>&1)"'
+check '-n "$(builtin nosuchtool 2>&1)"'
+check '-n "$(builtin nosuchtool 2>&1; :)"'
+check '-n "$( (builtin ls) 2>&1)"'
+check '-n "$(builtin ls 2>&1)"'
+check '-n "$(builtin ls 2>&1; :)"'
+
+exit $((failures > 0))
diff --git a/shell_cmds/sh/tests/builtins/case1.0 b/shell_cmds/sh/tests/builtins/case1.0
new file mode 100644
index 0000000..b8e8d9b
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/case1.0
@@ -0,0 +1,13 @@
+#$FreeBSD: head/bin/sh/tests/builtins/case1.0 172440 2007-10-04 16:14:48Z stefanf $
+f()
+{
+ false
+ case $1 in
+ foo) true ;;
+ bar) false ;;
+ esac
+}
+
+f foo || exit 1
+f bar && exit 1
+f quux || exit 1
diff --git a/shell_cmds/sh/tests/builtins/case10.0 b/shell_cmds/sh/tests/builtins/case10.0
new file mode 100644
index 0000000..e8cd933
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/case10.0
@@ -0,0 +1,16 @@
+# $FreeBSD: head/bin/sh/tests/builtins/case10.0 223546 2011-06-25 20:37:43Z jilles $
+
+case ! in
+[\!!]) ;;
+*) echo Failed at $LINENO ;;
+esac
+
+case ! in
+['!'!]) ;;
+*) echo Failed at $LINENO ;;
+esac
+
+case ! in
+["!"!]) ;;
+*) echo Failed at $LINENO ;;
+esac
diff --git a/shell_cmds/sh/tests/builtins/case11.0 b/shell_cmds/sh/tests/builtins/case11.0
new file mode 100644
index 0000000..afcfa43
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/case11.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/builtins/case11.0 228007 2011-11-26 22:28:25Z jilles $
+
+false
+case x in
+*)
+esac
diff --git a/shell_cmds/sh/tests/builtins/case12.0 b/shell_cmds/sh/tests/builtins/case12.0
new file mode 100644
index 0000000..630bee5
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/case12.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/builtins/case12.0 228007 2011-11-26 22:28:25Z jilles $
+
+false
+case x in
+y)
+esac
diff --git a/shell_cmds/sh/tests/builtins/case13.0 b/shell_cmds/sh/tests/builtins/case13.0
new file mode 100644
index 0000000..669ce62
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/case13.0
@@ -0,0 +1,12 @@
+# $FreeBSD: head/bin/sh/tests/builtins/case13.0 228943 2011-12-28 23:51:17Z jilles $
+
+case ^ in
+[\^^]) ;;
+*) echo Failed at $LINENO ;;
+esac
+
+case s in
+[\^^]) echo Failed at $LINENO ;;
+[s\]]) ;;
+*) echo Failed at $LINENO ;;
+esac
diff --git a/shell_cmds/sh/tests/builtins/case14.0 b/shell_cmds/sh/tests/builtins/case14.0
new file mode 100644
index 0000000..f6a68cb
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/case14.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/builtins/case14.0 230154 2012-01-15 20:04:05Z jilles $
+
+case `false` in
+no) exit 3 ;;
+esac
diff --git a/shell_cmds/sh/tests/builtins/case15.0 b/shell_cmds/sh/tests/builtins/case15.0
new file mode 100644
index 0000000..083aaa6
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/case15.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/builtins/case15.0 230154 2012-01-15 20:04:05Z jilles $
+
+case x in
+`false`) exit 3 ;;
+esac
diff --git a/shell_cmds/sh/tests/builtins/case16.0 b/shell_cmds/sh/tests/builtins/case16.0
new file mode 100644
index 0000000..7031a92
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/case16.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/builtins/case16.0 230154 2012-01-15 20:04:05Z jilles $
+
+f() { return 42; }
+f
+case x in
+x) [ $? = 42 ] ;;
+esac
diff --git a/shell_cmds/sh/tests/builtins/case17.0 b/shell_cmds/sh/tests/builtins/case17.0
new file mode 100644
index 0000000..10d8d9c
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/case17.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/builtins/case17.0 230161 2012-01-15 21:39:38Z jilles $
+
+! case x in x) false ;& y) esac
diff --git a/shell_cmds/sh/tests/builtins/case18.0 b/shell_cmds/sh/tests/builtins/case18.0
new file mode 100644
index 0000000..b0e601f
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/case18.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/builtins/case18.0 230161 2012-01-15 21:39:38Z jilles $
+
+case x$(false) in
+x) ;&
+y) [ $? != 0 ] ;;
+z) false ;;
+esac
diff --git a/shell_cmds/sh/tests/builtins/case19.0 b/shell_cmds/sh/tests/builtins/case19.0
new file mode 100644
index 0000000..1a9b09a
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/case19.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/builtins/case19.0 230161 2012-01-15 21:39:38Z jilles $
+
+[ "`case x in
+x) false ;&
+y) ;&
+z) echo $? ;;
+esac`" != 0 ]
diff --git a/shell_cmds/sh/tests/builtins/case2.0 b/shell_cmds/sh/tests/builtins/case2.0
new file mode 100644
index 0000000..ae3f356
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/case2.0
@@ -0,0 +1,106 @@
+# Generated by ./test-fnmatch -s 1, do not edit.
+# $FreeBSD: head/bin/sh/tests/builtins/case2.0 207821 2010-05-09 16:15:40Z jilles $
+failures=
+failed() { printf '%s\n' "Failed: $1 '$2' '$3'"; failures=x$failures; }
+testmatch() { eval "case \$2 in ''$1) ;; *) failed testmatch \"\$@\";; esac"; }
+testnomatch() { eval "case \$2 in ''$1) failed testnomatch \"\$@\";; esac"; }
+testmatch '' ''
+testmatch 'a' 'a'
+testnomatch 'a' 'b'
+testnomatch 'a' 'A'
+testmatch '*' 'a'
+testmatch '*' 'aa'
+testmatch '*a' 'a'
+testnomatch '*a' 'b'
+testnomatch '*a*' 'b'
+testmatch '*a*b*' 'ab'
+testmatch '*a*b*' 'qaqbq'
+testmatch '*a*bb*' 'qaqbqbbq'
+testmatch '*a*bc*' 'qaqbqbcq'
+testmatch '*a*bb*' 'qaqbqbb'
+testmatch '*a*bc*' 'qaqbqbc'
+testmatch '*a*bb' 'qaqbqbb'
+testmatch '*a*bc' 'qaqbqbc'
+testnomatch '*a*bb' 'qaqbqbbq'
+testnomatch '*a*bc' 'qaqbqbcq'
+testnomatch '*a*a*a*a*a*a*a*a*a*a*' 'aaaaaaaaa'
+testmatch '*a*a*a*a*a*a*a*a*a*a*' 'aaaaaaaaaa'
+testmatch '*a*a*a*a*a*a*a*a*a*a*' 'aaaaaaaaaaa'
+testnomatch '.*.*.*.*.*.*.*.*.*.*' '.........'
+testmatch '.*.*.*.*.*.*.*.*.*.*' '..........'
+testmatch '.*.*.*.*.*.*.*.*.*.*' '...........'
+testnomatch '*?*?*?*?*?*?*?*?*?*?*' '123456789'
+testnomatch '??????????*' '123456789'
+testnomatch '*??????????' '123456789'
+testmatch '*?*?*?*?*?*?*?*?*?*?*' '1234567890'
+testmatch '??????????*' '1234567890'
+testmatch '*??????????' '1234567890'
+testmatch '*?*?*?*?*?*?*?*?*?*?*' '12345678901'
+testmatch '??????????*' '12345678901'
+testmatch '*??????????' '12345678901'
+testmatch '[x]' 'x'
+testmatch '[*]' '*'
+testmatch '[?]' '?'
+testmatch '[' '['
+testmatch '[[]' '['
+testnomatch '[[]' 'x'
+testnomatch '[*]' ''
+testnomatch '[*]' 'x'
+testnomatch '[?]' 'x'
+testmatch '*[*]*' 'foo*foo'
+testnomatch '*[*]*' 'foo'
+testmatch '[0-9]' '0'
+testmatch '[0-9]' '5'
+testmatch '[0-9]' '9'
+testnomatch '[0-9]' '/'
+testnomatch '[0-9]' ':'
+testnomatch '[0-9]' '*'
+testnomatch '[!0-9]' '0'
+testnomatch '[!0-9]' '5'
+testnomatch '[!0-9]' '9'
+testmatch '[!0-9]' '/'
+testmatch '[!0-9]' ':'
+testmatch '[!0-9]' '*'
+testmatch '*[0-9]' 'a0'
+testmatch '*[0-9]' 'a5'
+testmatch '*[0-9]' 'a9'
+testnomatch '*[0-9]' 'a/'
+testnomatch '*[0-9]' 'a:'
+testnomatch '*[0-9]' 'a*'
+testnomatch '*[!0-9]' 'a0'
+testnomatch '*[!0-9]' 'a5'
+testnomatch '*[!0-9]' 'a9'
+testmatch '*[!0-9]' 'a/'
+testmatch '*[!0-9]' 'a:'
+testmatch '*[!0-9]' 'a*'
+testmatch '*[0-9]' 'a00'
+testmatch '*[0-9]' 'a55'
+testmatch '*[0-9]' 'a99'
+testmatch '*[0-9]' 'a0a0'
+testmatch '*[0-9]' 'a5a5'
+testmatch '*[0-9]' 'a9a9'
+testmatch '\*' '*'
+testmatch '\?' '?'
+testmatch '\[x]' '[x]'
+testmatch '\[' '['
+testmatch '\\' '\'
+testmatch '*\**' 'foo*foo'
+testnomatch '*\**' 'foo'
+testmatch '*\\*' 'foo\foo'
+testnomatch '*\\*' 'foo'
+testmatch '\(' '('
+testmatch '\a' 'a'
+testnomatch '\*' 'a'
+testnomatch '\?' 'a'
+testnomatch '\*' '\*'
+testnomatch '\?' '\?'
+testnomatch '\[x]' '\[x]'
+testnomatch '\[x]' '\x'
+testnomatch '\[' '\['
+testnomatch '\(' '\('
+testnomatch '\a' '\a'
+testmatch '.*' '.'
+testmatch '.*' '..'
+testmatch '.*' '.a'
+testmatch 'a*' 'a.'
+[ -z "$failures" ]
diff --git a/shell_cmds/sh/tests/builtins/case20.0 b/shell_cmds/sh/tests/builtins/case20.0
new file mode 100644
index 0000000..bd91e5b
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/case20.0
@@ -0,0 +1,9 @@
+# $FreeBSD: head/bin/sh/tests/builtins/case20.0 287148 2015-08-25 21:55:15Z jilles $
+
+# Shells do not agree about what this pattern should match, but it is
+# certain that it must not crash and the missing close bracket must not
+# be simply ignored.
+
+case B in
+[[:alpha:]) echo bad ;;
+esac
diff --git a/shell_cmds/sh/tests/builtins/case21.0 b/shell_cmds/sh/tests/builtins/case21.0
new file mode 100644
index 0000000..7d865f0
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/case21.0
@@ -0,0 +1,10 @@
+# $FreeBSD: head/bin/sh/tests/builtins/case21.0 318258 2017-05-13 20:28:32Z jilles $
+
+case 5 in
+[0$((-9))]) ;;
+*) echo bad1 ;;
+esac
+
+case - in
+[0$((-9))]) echo bad2 ;;
+esac
diff --git a/shell_cmds/sh/tests/builtins/case22.0 b/shell_cmds/sh/tests/builtins/case22.0
new file mode 100644
index 0000000..a89c0bd
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/case22.0
@@ -0,0 +1,10 @@
+# $FreeBSD: head/bin/sh/tests/builtins/case22.0 318269 2017-05-14 13:14:19Z jilles $
+
+case 5 in
+[0"$((-9))"]) echo bad1 ;;
+esac
+
+case - in
+[0"$((-9))"]) ;;
+*) echo bad2 ;;
+esac
diff --git a/shell_cmds/sh/tests/builtins/case3.0 b/shell_cmds/sh/tests/builtins/case3.0
new file mode 100644
index 0000000..a2efd87
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/case3.0
@@ -0,0 +1,95 @@
+# Generated by ./test-fnmatch -s 2, do not edit.
+# $FreeBSD: head/bin/sh/tests/builtins/case3.0 207821 2010-05-09 16:15:40Z jilles $
+failures=
+failed() { printf '%s\n' "Failed: $1 '$2' '$3'"; failures=x$failures; }
+# We do not treat a backslash specially in this case,
+# but this is not the case in all shells.
+netestmatch() { case $2 in $1) ;; *) failed netestmatch "$@";; esac; }
+netestnomatch() { case $2 in $1) failed netestnomatch "$@";; esac; }
+netestmatch '' ''
+netestmatch 'a' 'a'
+netestnomatch 'a' 'b'
+netestnomatch 'a' 'A'
+netestmatch '*' 'a'
+netestmatch '*' 'aa'
+netestmatch '*a' 'a'
+netestnomatch '*a' 'b'
+netestnomatch '*a*' 'b'
+netestmatch '*a*b*' 'ab'
+netestmatch '*a*b*' 'qaqbq'
+netestmatch '*a*bb*' 'qaqbqbbq'
+netestmatch '*a*bc*' 'qaqbqbcq'
+netestmatch '*a*bb*' 'qaqbqbb'
+netestmatch '*a*bc*' 'qaqbqbc'
+netestmatch '*a*bb' 'qaqbqbb'
+netestmatch '*a*bc' 'qaqbqbc'
+netestnomatch '*a*bb' 'qaqbqbbq'
+netestnomatch '*a*bc' 'qaqbqbcq'
+netestnomatch '*a*a*a*a*a*a*a*a*a*a*' 'aaaaaaaaa'
+netestmatch '*a*a*a*a*a*a*a*a*a*a*' 'aaaaaaaaaa'
+netestmatch '*a*a*a*a*a*a*a*a*a*a*' 'aaaaaaaaaaa'
+netestnomatch '.*.*.*.*.*.*.*.*.*.*' '.........'
+netestmatch '.*.*.*.*.*.*.*.*.*.*' '..........'
+netestmatch '.*.*.*.*.*.*.*.*.*.*' '...........'
+netestnomatch '*?*?*?*?*?*?*?*?*?*?*' '123456789'
+netestnomatch '??????????*' '123456789'
+netestnomatch '*??????????' '123456789'
+netestmatch '*?*?*?*?*?*?*?*?*?*?*' '1234567890'
+netestmatch '??????????*' '1234567890'
+netestmatch '*??????????' '1234567890'
+netestmatch '*?*?*?*?*?*?*?*?*?*?*' '12345678901'
+netestmatch '??????????*' '12345678901'
+netestmatch '*??????????' '12345678901'
+netestmatch '[x]' 'x'
+netestmatch '[*]' '*'
+netestmatch '[?]' '?'
+netestmatch '[' '['
+netestmatch '[[]' '['
+netestnomatch '[[]' 'x'
+netestnomatch '[*]' ''
+netestnomatch '[*]' 'x'
+netestnomatch '[?]' 'x'
+netestmatch '*[*]*' 'foo*foo'
+netestnomatch '*[*]*' 'foo'
+netestmatch '[0-9]' '0'
+netestmatch '[0-9]' '5'
+netestmatch '[0-9]' '9'
+netestnomatch '[0-9]' '/'
+netestnomatch '[0-9]' ':'
+netestnomatch '[0-9]' '*'
+netestnomatch '[!0-9]' '0'
+netestnomatch '[!0-9]' '5'
+netestnomatch '[!0-9]' '9'
+netestmatch '[!0-9]' '/'
+netestmatch '[!0-9]' ':'
+netestmatch '[!0-9]' '*'
+netestmatch '*[0-9]' 'a0'
+netestmatch '*[0-9]' 'a5'
+netestmatch '*[0-9]' 'a9'
+netestnomatch '*[0-9]' 'a/'
+netestnomatch '*[0-9]' 'a:'
+netestnomatch '*[0-9]' 'a*'
+netestnomatch '*[!0-9]' 'a0'
+netestnomatch '*[!0-9]' 'a5'
+netestnomatch '*[!0-9]' 'a9'
+netestmatch '*[!0-9]' 'a/'
+netestmatch '*[!0-9]' 'a:'
+netestmatch '*[!0-9]' 'a*'
+netestmatch '*[0-9]' 'a00'
+netestmatch '*[0-9]' 'a55'
+netestmatch '*[0-9]' 'a99'
+netestmatch '*[0-9]' 'a0a0'
+netestmatch '*[0-9]' 'a5a5'
+netestmatch '*[0-9]' 'a9a9'
+netestmatch '\*' '\*'
+netestmatch '\?' '\?'
+netestmatch '\' '\'
+netestnomatch '\\' '\'
+netestmatch '\\' '\\'
+netestmatch '*\*' 'foo\foo'
+netestnomatch '*\*' 'foo'
+netestmatch '.*' '.'
+netestmatch '.*' '..'
+netestmatch '.*' '.a'
+netestmatch 'a*' 'a.'
+[ -z "$failures" ]
diff --git a/shell_cmds/sh/tests/builtins/case4.0 b/shell_cmds/sh/tests/builtins/case4.0
new file mode 100644
index 0000000..7ba29ee
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/case4.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/builtins/case4.0 220654 2011-04-15 15:14:58Z jilles $
+
+set -- "*"
+case x in
+"$1") echo failed ;;
+esac
diff --git a/shell_cmds/sh/tests/builtins/case5.0 b/shell_cmds/sh/tests/builtins/case5.0
new file mode 100644
index 0000000..e8b141a
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/case5.0
@@ -0,0 +1,57 @@
+# $FreeBSD: head/bin/sh/tests/builtins/case5.0 221646 2011-05-08 11:32:20Z jilles $
+
+unset LC_ALL
+LC_CTYPE=en_US.UTF-8
+export LC_CTYPE
+
+c1=e
+# a umlaut
+c2=$(printf '\303\244')
+# euro sign
+c3=$(printf '\342\202\254')
+# some sort of 't' outside BMP
+c4=$(printf '\360\235\225\245')
+
+ok=0
+case $c1$c2$c3$c4 in
+*) ok=1 ;;
+esac
+if [ $ok = 0 ]; then
+ echo wrong at $LINENO
+ exit 3
+fi
+
+case $c1$c2$c3$c4 in
+$c1$c2$c3$c4) ;;
+*) echo wrong at $LINENO ;;
+esac
+
+case $c1$c2$c3$c4 in
+"$c1$c2$c3$c4") ;;
+*) echo wrong at $LINENO ;;
+esac
+
+case $c1$c2$c3$c4 in
+????) ;;
+*) echo wrong at $LINENO ;;
+esac
+
+case $c1.$c2.$c3.$c4 in
+?.?.?.?) ;;
+*) echo wrong at $LINENO ;;
+esac
+
+case $c1$c2$c3$c4 in
+[!a][!b][!c][!d]) ;;
+*) echo wrong at $LINENO ;;
+esac
+
+case $c1$c2$c3$c4 in
+[$c1][$c2][$c3][$c4]) ;;
+*) echo wrong at $LINENO ;;
+esac
+
+case $c1$c2$c3$c4 in
+["$c1"]["$c2"]["$c3"]["$c4"]) ;;
+*) echo wrong at $LINENO ;;
+esac
diff --git a/shell_cmds/sh/tests/builtins/case6.0 b/shell_cmds/sh/tests/builtins/case6.0
new file mode 100644
index 0000000..7bc1da8
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/case6.0
@@ -0,0 +1,52 @@
+# $FreeBSD: head/bin/sh/tests/builtins/case6.0 223007 2011-06-12 12:27:17Z jilles $
+
+unset LC_ALL
+LC_CTYPE=de_DE.ISO8859-1
+export LC_CTYPE
+
+c1=e
+# o umlaut
+c2=$(printf '\366')
+# non-break space
+c3=$(printf '\240')
+c4=$(printf '\240')
+# $c2$c3$c4 form one utf-8 character
+
+ok=0
+case $c1$c2$c3$c4 in
+*) ok=1 ;;
+esac
+if [ $ok = 0 ]; then
+ echo wrong at $LINENO
+ exit 3
+fi
+
+case $c1$c2$c3$c4 in
+$c1$c2$c3$c4) ;;
+*) echo wrong at $LINENO ;;
+esac
+
+case $c1$c2$c3$c4 in
+"$c1$c2$c3$c4") ;;
+*) echo wrong at $LINENO ;;
+esac
+
+case $c1$c2$c3$c4 in
+????) ;;
+*) echo wrong at $LINENO ;;
+esac
+
+case $c1$c2$c3$c4 in
+[!$c2][!b][!c][!d]) ;;
+*) echo wrong at $LINENO ;;
+esac
+
+case $c1$c2$c3$c4 in
+[$c1][$c2][$c3][$c4]) ;;
+*) echo wrong at $LINENO ;;
+esac
+
+case $c1$c2$c3$c4 in
+["$c1"]["$c2"]["$c3"]["$c4"]) ;;
+*) echo wrong at $LINENO ;;
+esac
diff --git a/shell_cmds/sh/tests/builtins/case7.0 b/shell_cmds/sh/tests/builtins/case7.0
new file mode 100644
index 0000000..b351ad5
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/case7.0
@@ -0,0 +1,24 @@
+# $FreeBSD: head/bin/sh/tests/builtins/case7.0 302829 2016-07-14 09:34:42Z ache $
+
+# Character ranges in a locale other than the POSIX locale, not specified
+# by POSIX.
+
+unset LC_ALL
+LC_CTYPE=de_DE.ISO8859-1
+export LC_CTYPE
+LC_COLLATE=de_DE.ISO8859-1
+export LC_COLLATE
+
+c1=e
+# o umlaut
+c2=$(printf '\366')
+
+case $c1$c2 in
+[a-z][a-z]) ;;
+*) echo wrong at $LINENO ;;
+esac
+
+case $c1$c2 in
+[a-f][n-p]) ;;
+*) echo wrong at $LINENO ;;
+esac
diff --git a/shell_cmds/sh/tests/builtins/case8.0 b/shell_cmds/sh/tests/builtins/case8.0
new file mode 100644
index 0000000..c63c6e7
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/case8.0
@@ -0,0 +1,32 @@
+# $FreeBSD: head/bin/sh/tests/builtins/case8.0 223120 2011-06-15 21:48:10Z jilles $
+
+case aZ_ in
+[[:alpha:]_][[:upper:]_][[:alpha:]_]) ;;
+*) echo Failed at $LINENO ;;
+esac
+
+case ' ' in
+[[:alpha:][:digit:]]) echo Failed at $LINENO ;;
+[![:alpha:][:digit:]]) ;;
+*) echo Failed at $LINENO ;;
+esac
+
+case '.X.' in
+*[[:lower:]]*) echo Failed at $LINENO ;;
+*[[:upper:]]*) ;;
+*) echo Failed at $LINENO ;;
+esac
+
+case ' ' in
+[![:print:]]) echo Failed at $LINENO ;;
+[![:alnum:][:punct:]]) ;;
+*) echo Failed at $LINENO ;;
+esac
+
+case '
+' in
+[[:print:]]) echo Failed at $LINENO ;;
+['
+'[:digit:]]) ;;
+*) echo Failed at $LINENO ;;
+esac
diff --git a/shell_cmds/sh/tests/builtins/case9.0 b/shell_cmds/sh/tests/builtins/case9.0
new file mode 100644
index 0000000..e374ef0
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/case9.0
@@ -0,0 +1,39 @@
+# $FreeBSD: head/bin/sh/tests/builtins/case9.0 223186 2011-06-17 13:03:49Z jilles $
+
+errors=0
+
+f() {
+ result=
+ case $1 in
+ a) result=${result}a ;;
+ b) result=${result}b ;&
+ c) result=${result}c ;&
+ d) result=${result}d ;;
+ e) result=${result}e ;&
+ esac
+}
+
+check() {
+ f "$1"
+ if [ "$result" != "$2" ]; then
+ printf "For %s, expected %s got %s\n" "$1" "$2" "$result"
+ errors=$((errors + 1))
+ fi
+}
+
+check '' ''
+check a a
+check b bcd
+check c cd
+check d d
+check e e
+
+if ! (case 1 in
+ 1) false ;&
+ 2) true ;;
+esac) then
+ echo "Subshell bad"
+ errors=$((errors + 1))
+fi
+
+exit $((errors != 0))
diff --git a/shell_cmds/sh/tests/builtins/cd1.0 b/shell_cmds/sh/tests/builtins/cd1.0
new file mode 100644
index 0000000..d797157
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/cd1.0
@@ -0,0 +1,30 @@
+# $FreeBSD: head/bin/sh/tests/builtins/cd1.0 228975 2011-12-30 00:04:11Z uqs $
+set -e
+
+P=${TMPDIR:-/tmp}
+cd $P
+T=$(mktemp -d sh-test.XXXXXX)
+
+chmod 0 $T
+if [ `id -u` -ne 0 ]; then
+ # Root can always cd, regardless of directory permissions.
+ cd -L $T 2>/dev/null && exit 1
+ [ "$PWD" = "$P" ]
+ [ "$(pwd)" = "$P" ]
+ cd -P $T 2>/dev/null && exit 1
+ [ "$PWD" = "$P" ]
+ [ "$(pwd)" = "$P" ]
+fi
+
+chmod 755 $T
+cd $T
+mkdir -p 1/2/3
+ln -s 1/2 link1
+ln -s 2/3 1/link2
+(cd -L 1/../1 && [ "$(pwd -L)" = "$P/$T/1" ])
+(cd -L link1 && [ "$(pwd -L)" = "$P/$T/link1" ])
+(cd -L link1 && [ "$(pwd -P)" = "$P/$T/1/2" ])
+(cd -P link1 && [ "$(pwd -L)" = "$P/$T/1/2" ])
+(cd -P link1 && [ "$(pwd -P)" = "$P/$T/1/2" ])
+
+rm -rf ${P}/${T}
diff --git a/shell_cmds/sh/tests/builtins/cd10.0 b/shell_cmds/sh/tests/builtins/cd10.0
new file mode 100644
index 0000000..79d540f
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/cd10.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/builtins/cd10.0 320340 2017-06-25 21:53:08Z jilles $
+
+# Precondition
+(cd /bin) || exit
+# Verify write error is ignored.
+$SH +m -ic 'CDPATH=/:; cd bin 1</dev/null'
diff --git a/shell_cmds/sh/tests/builtins/cd2.0 b/shell_cmds/sh/tests/builtins/cd2.0
new file mode 100644
index 0000000..b7d39f3
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/cd2.0
@@ -0,0 +1,16 @@
+# $FreeBSD: head/bin/sh/tests/builtins/cd2.0 216019 2010-11-28 22:49:58Z jilles $
+set -e
+
+L=$(getconf PATH_MAX / 2>/dev/null) || L=4096
+[ "$L" -lt 100000 ] 2>/dev/null || L=4096
+L=$((L+100))
+T=$(mktemp -d ${TMPDIR:-/tmp}/sh-test.XXXXXX)
+trap 'rm -rf ${T}' 0
+cd $T
+D=$T
+while [ ${#D} -lt $L ]; do
+ mkdir veryverylongdirectoryname
+ cd veryverylongdirectoryname
+ D=$D/veryverylongdirectoryname
+done
+[ $(pwd | wc -c) -eq $((${#D} + 1)) ] # +\n
diff --git a/shell_cmds/sh/tests/builtins/cd3.0 b/shell_cmds/sh/tests/builtins/cd3.0
new file mode 100644
index 0000000..aab8bc0
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/cd3.0
@@ -0,0 +1,21 @@
+# $FreeBSD: head/bin/sh/tests/builtins/cd3.0 222154 2011-05-20 22:55:18Z jilles $
+
+# If fully successful, cd -Pe must be like cd -P.
+
+set -e
+
+cd "${TMPDIR:-/tmp}"
+cd -Pe /
+[ "$PWD" = / ]
+[ "$(pwd)" = / ]
+cd "${TMPDIR:-/tmp}"
+cd -eP /
+[ "$PWD" = / ]
+[ "$(pwd)" = / ]
+
+set +e
+
+# If cd -Pe cannot chdir, the exit status must be greater than 1.
+
+v=$( (cd -Pe /var/empty/nonexistent) 2>&1 >/dev/null)
+[ $? -gt 1 ] && [ -n "$v" ]
diff --git a/shell_cmds/sh/tests/builtins/cd4.0 b/shell_cmds/sh/tests/builtins/cd4.0
new file mode 100644
index 0000000..da01b31
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/cd4.0
@@ -0,0 +1,38 @@
+# $FreeBSD: head/bin/sh/tests/builtins/cd4.0 222154 2011-05-20 22:55:18Z jilles $
+
+# This test assumes that whatever mechanism cd -P uses to determine the
+# pathname to the current directory if it is longer than PATH_MAX requires
+# read permission on all parent directories. It also works if this
+# requirement always applies.
+
+set -e
+L=$(getconf PATH_MAX / 2>/dev/null) || L=4096
+[ "$L" -lt 100000 ] 2>/dev/null || L=4096
+L=$((L+100))
+T=$(mktemp -d ${TMPDIR:-/tmp}/sh-test.XXXXXX)
+trap 'chmod u+r ${T}; rm -rf ${T}' 0
+cd -Pe $T
+D=$(pwd)
+chmod u-r "$D"
+if [ -r "$D" ]; then
+ # Running as root, cannot test.
+ exit 0
+fi
+set +e
+while [ ${#D} -lt $L ]; do
+ mkdir veryverylongdirectoryname || exit
+ cd -Pe veryverylongdirectoryname 2>/dev/null
+ r=$?
+ [ $r -gt 1 ] && exit $r
+ if [ $r -eq 1 ]; then
+ # Verify that the directory was changed correctly.
+ cd -Pe .. || exit
+ [ "$(pwd)" = "$D" ] || exit
+ # Verify that omitting -e results in success.
+ cd -P veryverylongdirectoryname 2>/dev/null || exit
+ exit 0
+ fi
+ D=$D/veryverylongdirectoryname
+done
+echo "cd -Pe never returned 1"
+exit 0
diff --git a/shell_cmds/sh/tests/builtins/cd5.0 b/shell_cmds/sh/tests/builtins/cd5.0
new file mode 100644
index 0000000..8a285e0
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/cd5.0
@@ -0,0 +1,23 @@
+# $FreeBSD: head/bin/sh/tests/builtins/cd5.0 222379 2011-05-27 19:36:07Z jilles $
+
+set -e
+T=$(mktemp -d "${TMPDIR:-/tmp}/sh-test.XXXXXX")
+trap 'rm -rf "$T"' 0
+
+cd -P "$T"
+D=$(pwd)
+
+mkdir a a/1 b b/1 b/2
+
+CDPATH=$D/a:
+# Basic test.
+cd 1 >/dev/null
+[ "$(pwd)" = "$D/a/1" ]
+# Test that the current directory is not checked before CDPATH.
+cd "$D/b"
+cd 1 >/dev/null
+[ "$(pwd)" = "$D/a/1" ]
+# Test not using a CDPATH entry.
+cd "$D/b"
+cd 2
+[ "$(pwd)" = "$D/b/2" ]
diff --git a/shell_cmds/sh/tests/builtins/cd6.0 b/shell_cmds/sh/tests/builtins/cd6.0
new file mode 100644
index 0000000..171c996
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/cd6.0
@@ -0,0 +1,10 @@
+# $FreeBSD: head/bin/sh/tests/builtins/cd6.0 222381 2011-05-27 20:01:46Z jilles $
+
+set -e
+cd -P /bin
+d=$PWD
+CDPATH=/:
+cd -P .
+[ "$d" = "$PWD" ]
+cd -P ./
+[ "$d" = "$PWD" ]
diff --git a/shell_cmds/sh/tests/builtins/cd7.0 b/shell_cmds/sh/tests/builtins/cd7.0
new file mode 100644
index 0000000..d4cae39
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/cd7.0
@@ -0,0 +1,15 @@
+# $FreeBSD: head/bin/sh/tests/builtins/cd7.0 222381 2011-05-27 20:01:46Z jilles $
+
+set -e
+cd /usr/bin
+[ "$PWD" = /usr/bin ]
+CDPATH=/:
+cd .
+[ "$PWD" = /usr/bin ]
+cd ./
+[ "$PWD" = /usr/bin ]
+cd ..
+[ "$PWD" = /usr ]
+cd /usr/bin
+cd ../
+[ "$PWD" = /usr ]
diff --git a/shell_cmds/sh/tests/builtins/cd8.0 b/shell_cmds/sh/tests/builtins/cd8.0
new file mode 100644
index 0000000..ab17d38
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/cd8.0
@@ -0,0 +1,26 @@
+# $FreeBSD: head/bin/sh/tests/builtins/cd8.0 230095 2012-01-13 23:32:27Z jilles $
+
+# The exact wording of the error message is not standardized, but giving
+# a description of the errno is useful.
+
+LC_ALL=C
+export LC_ALL
+r=0
+
+t() {
+ exec 3>&1
+ errmsg=`cd "$1" 2>&1 >&3 3>&-`
+ exec 3>&-
+ case $errmsg in
+ *[Nn]ot\ a\ directory*)
+ ;;
+ *)
+ printf "Wrong error message for %s: %s\n" "$1" "$errmsg"
+ r=3
+ ;;
+ esac
+}
+
+t /dev/tty
+t /dev/tty/x
+exit $r
diff --git a/shell_cmds/sh/tests/builtins/cd9.0 b/shell_cmds/sh/tests/builtins/cd9.0
new file mode 100644
index 0000000..e929878
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/cd9.0
@@ -0,0 +1,8 @@
+# $FreeBSD: head/bin/sh/tests/builtins/cd9.0 293371 2016-01-07 21:46:07Z jilles $
+
+cd /dev
+cd /bin
+cd - >/dev/null
+pwd
+cd - >/dev/null
+pwd
diff --git a/shell_cmds/sh/tests/builtins/cd9.0.stdout b/shell_cmds/sh/tests/builtins/cd9.0.stdout
new file mode 100644
index 0000000..dac16a7
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/cd9.0.stdout
@@ -0,0 +1,2 @@
+/dev
+/bin
diff --git a/shell_cmds/sh/tests/builtins/command1.0 b/shell_cmds/sh/tests/builtins/command1.0
new file mode 100644
index 0000000..5454c3f
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/command1.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/builtins/command1.0 151797 2005-10-28 14:02:42Z stefanf $
+true() {
+ false
+}
+command true
diff --git a/shell_cmds/sh/tests/builtins/command10.0 b/shell_cmds/sh/tests/builtins/command10.0
new file mode 100644
index 0000000..08bddaf
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/command10.0
@@ -0,0 +1,14 @@
+# $FreeBSD: head/bin/sh/tests/builtins/command10.0 204802 2010-03-06 17:31:09Z jilles $
+
+failures=0
+
+check() {
+ if ! eval "[ $* ]"; then
+ echo "Failed: $*"
+ : $((failures += 1))
+ fi
+}
+
+check '"$(f() { shift x; }; { command eval f 2>/dev/null; } >/dev/null; echo hi)" = hi'
+
+exit $((failures > 0))
diff --git a/shell_cmds/sh/tests/builtins/command11.0 b/shell_cmds/sh/tests/builtins/command11.0
new file mode 100644
index 0000000..0eb2047
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/command11.0
@@ -0,0 +1,14 @@
+# $FreeBSD: head/bin/sh/tests/builtins/command11.0 205154 2010-03-14 14:24:35Z jilles $
+
+failures=0
+
+check() {
+ if ! eval "[ $* ]"; then
+ echo "Failed: $*"
+ : $((failures += 1))
+ fi
+}
+
+check '"$({ command eval \{ shift x\; \} 2\>/dev/null; } >/dev/null; echo hi)" = hi'
+
+exit $((failures > 0))
diff --git a/shell_cmds/sh/tests/builtins/command12.0 b/shell_cmds/sh/tests/builtins/command12.0
new file mode 100644
index 0000000..6d9e8e7
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/command12.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/builtins/command12.0 257929 2013-11-10 23:00:39Z jilles $
+
+alias aa=echo\ \'\"\'
+cmd=$(command -v aa)
+alias aa=echo\ bad
+eval "$cmd"
+[ "$(eval aa)" = \" ]
diff --git a/shell_cmds/sh/tests/builtins/command2.0 b/shell_cmds/sh/tests/builtins/command2.0
new file mode 100644
index 0000000..7b49092
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/command2.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/builtins/command2.0 151797 2005-10-28 14:02:42Z stefanf $
+PATH=
+command -p cat < /dev/null
diff --git a/shell_cmds/sh/tests/builtins/command3.0 b/shell_cmds/sh/tests/builtins/command3.0
new file mode 100644
index 0000000..6d6355d
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/command3.0
@@ -0,0 +1,14 @@
+# $FreeBSD: head/bin/sh/tests/builtins/command3.0 211399 2010-08-16 17:18:08Z jilles $
+command -v ls
+command -v true
+command -v /bin/ls
+
+fun() {
+ :
+}
+command -v fun
+command -v break
+command -v if
+
+alias foo=bar
+command -v foo
diff --git a/shell_cmds/sh/tests/builtins/command3.0.stdout b/shell_cmds/sh/tests/builtins/command3.0.stdout
new file mode 100644
index 0000000..67b8691
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/command3.0.stdout
@@ -0,0 +1,7 @@
+/bin/ls
+true
+/bin/ls
+fun
+break
+if
+alias foo=bar
diff --git a/shell_cmds/sh/tests/builtins/command4.0 b/shell_cmds/sh/tests/builtins/command4.0
new file mode 100644
index 0000000..2349669
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/command4.0
@@ -0,0 +1,2 @@
+# $FreeBSD: head/bin/sh/tests/builtins/command4.0 211973 2010-08-29 20:53:24Z jilles $
+! command -v nonexisting
diff --git a/shell_cmds/sh/tests/builtins/command5.0 b/shell_cmds/sh/tests/builtins/command5.0
new file mode 100644
index 0000000..7c99b52
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/command5.0
@@ -0,0 +1,15 @@
+# $FreeBSD: head/bin/sh/tests/builtins/command5.0 211399 2010-08-16 17:18:08Z jilles $
+command -V ls
+command -V true
+command -V /bin/ls
+
+fun() {
+ :
+}
+command -V fun
+command -V break
+command -V if
+command -V {
+
+alias foo=bar
+command -V foo
diff --git a/shell_cmds/sh/tests/builtins/command5.0.stdout b/shell_cmds/sh/tests/builtins/command5.0.stdout
new file mode 100644
index 0000000..523f7b2
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/command5.0.stdout
@@ -0,0 +1,8 @@
+ls is /bin/ls
+true is a shell builtin
+/bin/ls is /bin/ls
+fun is a shell function
+break is a special shell builtin
+if is a shell keyword
+{ is a shell keyword
+foo is an alias for bar
diff --git a/shell_cmds/sh/tests/builtins/command6.0 b/shell_cmds/sh/tests/builtins/command6.0
new file mode 100644
index 0000000..d1902ed
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/command6.0
@@ -0,0 +1,22 @@
+# $FreeBSD: head/bin/sh/tests/builtins/command6.0 218356 2011-02-05 23:00:24Z jilles $
+PATH=/var/empty
+case $(command -pV ls) in
+*/var/empty/ls*)
+ echo "Failed: \$(command -pV ls) should not match */var/empty/ls*" ;;
+"ls is"*" "/*/ls) ;;
+*)
+ echo "Failed: \$(command -pV ls) match \"ls is\"*\" \"/*/ls" ;;
+esac
+command -pV true
+command -pV /bin/ls
+
+fun() {
+ :
+}
+command -pV fun
+command -pV break
+command -pV if
+command -pV {
+
+alias foo=bar
+command -pV foo
diff --git a/shell_cmds/sh/tests/builtins/command6.0.stdout b/shell_cmds/sh/tests/builtins/command6.0.stdout
new file mode 100644
index 0000000..3180207
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/command6.0.stdout
@@ -0,0 +1,7 @@
+true is a shell builtin
+/bin/ls is /bin/ls
+fun is a shell function
+break is a special shell builtin
+if is a shell keyword
+{ is a shell keyword
+foo is an alias for bar
diff --git a/shell_cmds/sh/tests/builtins/command7.0 b/shell_cmds/sh/tests/builtins/command7.0
new file mode 100644
index 0000000..b8351f2
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/command7.0
@@ -0,0 +1,34 @@
+# $FreeBSD: head/bin/sh/tests/builtins/command7.0 218356 2011-02-05 23:00:24Z jilles $
+
+failures=0
+
+check() {
+ if ! eval "[ $* ]"; then
+ echo "Failed: $*"
+ : $((failures += 1))
+ fi
+}
+
+check '"$(PATH=/libexec command -V ld-elf.so.1)" = "ld-elf.so.1 is /libexec/ld-elf.so.1"'
+check '"$(PATH=/libexec command -V ld-elf.so.1; :)" = "ld-elf.so.1 is /libexec/ld-elf.so.1"'
+check '"$(PATH=/libexec command -pv ld-elf.so.1)" = ""'
+check '"$(PATH=/libexec command -pv ld-elf.so.1; :)" = ""'
+
+PATH=/libexec:$PATH
+
+check '"$(command -V ld-elf.so.1)" = "ld-elf.so.1 is /libexec/ld-elf.so.1"'
+check '"$(command -V ld-elf.so.1; :)" = "ld-elf.so.1 is /libexec/ld-elf.so.1"'
+check '"$(command -pv ld-elf.so.1)" = ""'
+check '"$(command -pv ld-elf.so.1; :)" = ""'
+
+PATH=/libexec
+
+check '"$(command -v ls)" = ""'
+case $(command -pv ls) in
+/*/ls) ;;
+*)
+ echo "Failed: \$(command -pv ls) match /*/ls"
+ : $((failures += 1)) ;;
+esac
+
+exit $((failures > 0))
diff --git a/shell_cmds/sh/tests/builtins/command8.0 b/shell_cmds/sh/tests/builtins/command8.0
new file mode 100644
index 0000000..54848d1
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/command8.0
@@ -0,0 +1,45 @@
+# $FreeBSD: head/bin/sh/tests/builtins/command8.0 213738 2010-10-12 18:20:38Z obrien $
+IFS=,
+
+SPECIAL="break,\
+ :,\
+ continue,\
+ . /dev/null,\
+ eval,\
+ exec,\
+ export -p,\
+ readonly -p,\
+ set,\
+ shift 0,\
+ times,\
+ trap,\
+ unset foo"
+
+set -e
+
+# Check that special builtins can be executed via "command".
+
+set -- ${SPECIAL}
+for cmd in "$@"
+do
+ ${SH} -c "v=:; while \$v; do v=false; command ${cmd}; done" >/dev/null
+done
+
+while :; do
+ command break
+ echo Error on line $LINENO
+done
+
+set p q r
+command shift 2
+if [ $# -ne 1 ]; then
+ echo Error on line $LINENO
+fi
+
+(
+ command exec >/dev/null
+ echo Error on line $LINENO
+)
+
+set +e
+! command shift 2 2>/dev/null
diff --git a/shell_cmds/sh/tests/builtins/command9.0 b/shell_cmds/sh/tests/builtins/command9.0
new file mode 100644
index 0000000..40f98c1
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/command9.0
@@ -0,0 +1,14 @@
+# $FreeBSD: head/bin/sh/tests/builtins/command9.0 204801 2010-03-06 17:09:22Z jilles $
+
+failures=0
+
+check() {
+ if ! eval "[ $* ]"; then
+ echo "Failed: $*"
+ : $((failures += 1))
+ fi
+}
+
+check '"$({ command eval shift x 2>/dev/null; } >/dev/null; echo hi)" = hi'
+
+exit $((failures > 0))
diff --git a/shell_cmds/sh/tests/builtins/dot1.0 b/shell_cmds/sh/tests/builtins/dot1.0
new file mode 100644
index 0000000..0aa69a8
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/dot1.0
@@ -0,0 +1,21 @@
+# $FreeBSD: head/bin/sh/tests/builtins/dot1.0 208629 2010-05-28 22:08:34Z jilles $
+
+failures=
+failure() {
+ echo "Error at line $1" >&2
+ failures=x$failures
+}
+
+T=$(mktemp -d ${TMPDIR:-/tmp}/sh-test.XXXXXX) || exit
+trap 'rm -rf $T' 0
+cd $T || exit 3
+unset x
+echo 'x=2' >testscript
+. ./testscript
+[ "$x" = 2 ] || failure $LINENO
+cd / || exit 3
+x=1
+PATH=$T:$PATH . testscript
+[ "$x" = 2 ] || failure $LINENO
+
+test -z "$failures"
diff --git a/shell_cmds/sh/tests/builtins/dot2.0 b/shell_cmds/sh/tests/builtins/dot2.0
new file mode 100644
index 0000000..dba591e
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/dot2.0
@@ -0,0 +1,21 @@
+# $FreeBSD: head/bin/sh/tests/builtins/dot2.0 208630 2010-05-28 22:40:24Z jilles $
+
+failures=
+failure() {
+ echo "Error at line $1" >&2
+ failures=x$failures
+}
+
+T=$(mktemp -d ${TMPDIR:-/tmp}/sh-test.XXXXXX) || exit
+trap 'rm -rf $T' 0
+cd $T || exit 3
+unset x
+echo 'x=2' >testscript
+. -- ./testscript
+[ "$x" = 2 ] || failure $LINENO
+cd / || exit 3
+x=1
+PATH=$T:$PATH . -- testscript
+[ "$x" = 2 ] || failure $LINENO
+
+test -z "$failures"
diff --git a/shell_cmds/sh/tests/builtins/dot3.0 b/shell_cmds/sh/tests/builtins/dot3.0
new file mode 100644
index 0000000..d1589a0
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/dot3.0
@@ -0,0 +1,10 @@
+# $FreeBSD: head/bin/sh/tests/builtins/dot3.0 219390 2011-03-07 23:52:23Z jilles $
+
+# . should return 0 if no command was executed.
+
+if false; then
+ exit 3
+else
+ . /dev/null
+ exit $?
+fi
diff --git a/shell_cmds/sh/tests/builtins/dot4.0 b/shell_cmds/sh/tests/builtins/dot4.0
new file mode 100644
index 0000000..d280f35
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/dot4.0
@@ -0,0 +1,12 @@
+# $FreeBSD: head/bin/sh/tests/builtins/dot4.0 222174 2011-05-22 12:15:14Z jilles $
+
+v=abcd
+v=$v$v$v$v
+v=$v$v$v$v
+v=$v$v$v$v
+v=$v$v$v$v
+v=$v$v$v$v
+r=$( (
+ trap 'exit 0' 0
+ . "$v"
+) 2>&1 >/dev/null) && [ -n "$r" ]
diff --git a/shell_cmds/sh/tests/builtins/echo1.0 b/shell_cmds/sh/tests/builtins/echo1.0
new file mode 100644
index 0000000..34d75a6
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/echo1.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/builtins/echo1.0 305305 2016-09-02 21:13:46Z jilles $
+
+# Not specified by POSIX.
+
+[ "`echo -n a b; echo c d; echo e f`" = "a bc d
+e f" ]
diff --git a/shell_cmds/sh/tests/builtins/echo2.0 b/shell_cmds/sh/tests/builtins/echo2.0
new file mode 100644
index 0000000..3eae51b
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/echo2.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/builtins/echo2.0 305305 2016-09-02 21:13:46Z jilles $
+
+# Not specified by POSIX.
+
+a=`echo -e '\a\b\e\f\n\r\t\v\\\\\0041\c'; echo .`
+b=`printf '\a\b\033\f\n\r\t\v\\\\!.'`
+[ "$a" = "$b" ]
diff --git a/shell_cmds/sh/tests/builtins/echo3.0 b/shell_cmds/sh/tests/builtins/echo3.0
new file mode 100644
index 0000000..aa86443
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/echo3.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/builtins/echo3.0 305305 2016-09-02 21:13:46Z jilles $
+
+# Not specified by POSIX.
+
+[ "`echo -e 'a\cb' c; echo d`" = "ad" ]
diff --git a/shell_cmds/sh/tests/builtins/eval1.0 b/shell_cmds/sh/tests/builtins/eval1.0
new file mode 100644
index 0000000..ad099ce
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/eval1.0
@@ -0,0 +1,9 @@
+# $FreeBSD: head/bin/sh/tests/builtins/eval1.0 193178 2009-05-31 17:23:27Z stefanf $
+set -e
+
+eval
+eval "" ""
+eval "true"
+! eval "false
+
+"
diff --git a/shell_cmds/sh/tests/builtins/eval2.0 b/shell_cmds/sh/tests/builtins/eval2.0
new file mode 100644
index 0000000..4df41ea
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/eval2.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/builtins/eval2.0 194897 2009-06-24 20:22:54Z jilles $
+
+eval '
+false
+
+' && exit 1
+exit 0
diff --git a/shell_cmds/sh/tests/builtins/eval3.0 b/shell_cmds/sh/tests/builtins/eval3.0
new file mode 100644
index 0000000..04f9720
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/eval3.0
@@ -0,0 +1,9 @@
+# $FreeBSD: head/bin/sh/tests/builtins/eval3.0 196607 2009-08-27 22:23:23Z jilles $
+
+eval 'false;' && exit 1
+eval 'true;' || exit 1
+eval 'false;
+' && exit 1
+eval 'true;
+' || exit 1
+exit 0
diff --git a/shell_cmds/sh/tests/builtins/eval4.0 b/shell_cmds/sh/tests/builtins/eval4.0
new file mode 100644
index 0000000..82c3ea9
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/eval4.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/builtins/eval4.0 210738 2010-08-01 22:39:07Z jilles $
+
+# eval should preserve $? from command substitutions when starting
+# the parsed command.
+[ $(eval 'echo $?' $(false)) = 1 ]
diff --git a/shell_cmds/sh/tests/builtins/eval5.0 b/shell_cmds/sh/tests/builtins/eval5.0
new file mode 100644
index 0000000..89e79b8
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/eval5.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/builtins/eval5.0 210829 2010-08-03 22:17:29Z jilles $
+
+# eval should return 0 if no command was executed.
+eval $(false)
diff --git a/shell_cmds/sh/tests/builtins/eval6.0 b/shell_cmds/sh/tests/builtins/eval6.0
new file mode 100644
index 0000000..bfce89f
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/eval6.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/builtins/eval6.0 249220 2013-04-06 22:30:46Z jilles $
+
+# eval should preserve $? from command substitutions when starting
+# the parsed command.
+[ $(false; eval 'echo $?' $(:)) = 0 ]
diff --git a/shell_cmds/sh/tests/builtins/eval7.0 b/shell_cmds/sh/tests/builtins/eval7.0
new file mode 100644
index 0000000..f694e73
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/eval7.0
@@ -0,0 +1,9 @@
+# $FreeBSD: head/bin/sh/tests/builtins/eval7.0 272983 2014-10-12 13:12:06Z jilles $
+# Assumes that break can break out of a loop outside eval.
+
+while :; do
+ eval "break
+echo bad1"
+ echo bad2
+ exit 3
+done
diff --git a/shell_cmds/sh/tests/builtins/eval8.7 b/shell_cmds/sh/tests/builtins/eval8.7
new file mode 100644
index 0000000..30902cc
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/eval8.7
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/builtins/eval8.7 272983 2014-10-12 13:12:06Z jilles $
+
+f() {
+ eval "return 7
+echo bad2"
+}
+f
diff --git a/shell_cmds/sh/tests/builtins/exec1.0 b/shell_cmds/sh/tests/builtins/exec1.0
new file mode 100644
index 0000000..8c5bb01
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/exec1.0
@@ -0,0 +1,25 @@
+# $FreeBSD: head/bin/sh/tests/builtins/exec1.0 213738 2010-10-12 18:20:38Z obrien $
+
+failures=
+failure() {
+ echo "Error at line $1" >&2
+ failures=x$failures
+}
+
+(
+ exec >/dev/null
+ echo bad
+)
+[ $? = 0 ] || failure $LINENO
+(
+ exec ${SH} -c 'exit 42'
+ echo bad
+)
+[ $? = 42 ] || failure $LINENO
+(
+ exec /var/empty/nosuch
+ echo bad
+) 2>/dev/null
+[ $? = 127 ] || failure $LINENO
+
+test -z "$failures"
diff --git a/shell_cmds/sh/tests/builtins/exec2.0 b/shell_cmds/sh/tests/builtins/exec2.0
new file mode 100644
index 0000000..5395ba6
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/exec2.0
@@ -0,0 +1,25 @@
+# $FreeBSD: head/bin/sh/tests/builtins/exec2.0 213738 2010-10-12 18:20:38Z obrien $
+
+failures=
+failure() {
+ echo "Error at line $1" >&2
+ failures=x$failures
+}
+
+(
+ exec -- >/dev/null
+ echo bad
+)
+[ $? = 0 ] || failure $LINENO
+(
+ exec -- ${SH} -c 'exit 42'
+ echo bad
+)
+[ $? = 42 ] || failure $LINENO
+(
+ exec -- /var/empty/nosuch
+ echo bad
+) 2>/dev/null
+[ $? = 127 ] || failure $LINENO
+
+test -z "$failures"
diff --git a/shell_cmds/sh/tests/builtins/exit1.0 b/shell_cmds/sh/tests/builtins/exit1.0
new file mode 100644
index 0000000..4c378f2
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/exit1.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/builtins/exit1.0 216871 2011-01-01 15:25:15Z jilles $
+
+# exit with an argument should overwrite the exit status in an EXIT trap.
+
+trap 'true; exit $?' 0
+false
diff --git a/shell_cmds/sh/tests/builtins/exit2.8 b/shell_cmds/sh/tests/builtins/exit2.8
new file mode 100644
index 0000000..51d38f7
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/exit2.8
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/builtins/exit2.8 217172 2011-01-08 23:00:38Z jilles $
+
+# exit without arguments is the same as exit $? outside a trap.
+
+trap 'true; true' 0
+(exit 8)
+exit
diff --git a/shell_cmds/sh/tests/builtins/exit3.0 b/shell_cmds/sh/tests/builtins/exit3.0
new file mode 100644
index 0000000..4e0c96c
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/exit3.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/builtins/exit3.0 217175 2011-01-08 23:08:13Z jilles $
+
+# exit without arguments differs from exit $? in an EXIT trap.
+
+trap 'false; exit' 0
diff --git a/shell_cmds/sh/tests/builtins/export1.0 b/shell_cmds/sh/tests/builtins/export1.0
new file mode 100644
index 0000000..a09263a
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/export1.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/builtins/export1.0 223183 2011-06-17 10:21:24Z jilles $
+
+env @badness=1 ${SH} -c 'v=`export -p`; eval "$v"'
diff --git a/shell_cmds/sh/tests/builtins/fc1.0 b/shell_cmds/sh/tests/builtins/fc1.0
new file mode 100644
index 0000000..042cb33
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/fc1.0
@@ -0,0 +1,27 @@
+# $FreeBSD: head/bin/sh/tests/builtins/fc1.0 213738 2010-10-12 18:20:38Z obrien $
+set -e
+trap 'echo Broken pipe -- test failed' PIPE
+
+P=${TMPDIR:-/tmp}
+cd $P
+T=$(mktemp -d sh-test.XXXXXX)
+cd $T
+
+mkfifo input output error
+HISTFILE=/dev/null ${SH} +m -i <input >output 2>error &
+{
+ # Syntax error
+ echo ')' >&3
+ # Read error message, shell will read new input now
+ read dummy <&5
+ # Execute bad command again
+ echo 'fc -e true' >&3
+ # Verify that the shell is still running
+ echo 'echo continued' >&3 || rc=3
+ echo 'exit' >&3 || rc=3
+ read line <&4 && [ "$line" = continued ] && : ${rc:=0}
+} 3>input 4<output 5<error
+
+rm input output error
+rmdir ${P}/${T}
+exit ${rc:-3}
diff --git a/shell_cmds/sh/tests/builtins/fc2.0 b/shell_cmds/sh/tests/builtins/fc2.0
new file mode 100644
index 0000000..a6151f7
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/fc2.0
@@ -0,0 +1,34 @@
+# $FreeBSD: head/bin/sh/tests/builtins/fc2.0 213738 2010-10-12 18:20:38Z obrien $
+set -e
+trap 'echo Broken pipe -- test failed' PIPE
+
+P=${TMPDIR:-/tmp}
+cd $P
+T=$(mktemp -d sh-test.XXXXXX)
+cd $T
+
+mkfifo input output error
+HISTFILE=/dev/null ${SH} +m -i <input >output 2>error &
+exec 3>input
+{
+ # Command not found, containing slash
+ echo '/var/empty/nonexistent' >&3
+ # Read error message, shell will read new input now
+ read dummy <&5
+ # Execute bad command again
+ echo 'fc -e true; echo continued' >&3
+ read dummy <&5
+ read line <&4 && [ "$line" = continued ] && : ${rc:=0}
+ exec 3>&-
+ # Old sh duplicates itself after the fc, producing another line
+ # of output.
+ if read line <&4; then
+ echo "Extraneous output: $line"
+ rc=1
+ fi
+} 4<output 5<error
+exec 3>&-
+
+rm input output error
+rmdir ${P}/${T}
+exit ${rc:-3}
diff --git a/shell_cmds/sh/tests/builtins/for1.0 b/shell_cmds/sh/tests/builtins/for1.0
new file mode 100644
index 0000000..276cb0a
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/for1.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/builtins/for1.0 226892 2011-10-28 23:02:21Z jilles $
+
+false
+for i in `false`; do exit 3; done
diff --git a/shell_cmds/sh/tests/builtins/for2.0 b/shell_cmds/sh/tests/builtins/for2.0
new file mode 100644
index 0000000..2b702ce
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/for2.0
@@ -0,0 +1,9 @@
+# $FreeBSD: head/bin/sh/tests/builtins/for2.0 230463 2012-01-22 14:00:33Z jilles $
+
+r=x
+f() { return 42; }
+f
+for i in x; do
+ r=$?
+done
+[ "$r" = 42 ]
diff --git a/shell_cmds/sh/tests/builtins/for3.0 b/shell_cmds/sh/tests/builtins/for3.0
new file mode 100644
index 0000000..a345caa
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/for3.0
@@ -0,0 +1,8 @@
+# $FreeBSD: head/bin/sh/tests/builtins/for3.0 230463 2012-01-22 14:00:33Z jilles $
+
+r=x
+f() { return 42; }
+for i in x`f`; do
+ r=$?
+done
+[ "$r" = 42 ]
diff --git a/shell_cmds/sh/tests/builtins/getopts1.0 b/shell_cmds/sh/tests/builtins/getopts1.0
new file mode 100644
index 0000000..d3e7415
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/getopts1.0
@@ -0,0 +1,25 @@
+# $FreeBSD: head/bin/sh/tests/builtins/getopts1.0 297752 2016-04-09 16:06:13Z jilles $
+
+printf -- '-1-\n'
+set -- -abc
+getopts "ab:" OPTION
+printf '%s\n' "${OPTION}"
+
+# In this case 'getopts' should realize that we have not provided the
+# required argument for "-b".
+# Note that Solaris 10's (UNIX 03) /usr/xpg4/bin/sh, /bin/sh, and /bin/ksh;
+# ksh93 20090505; pdksh 5.2.14p2; mksh R39c; bash 4.1 PL7; and zsh 4.3.10.
+# all recognize that "b" is missing its argument on the *first* iteration
+# of 'getopts' and do not produce the "a" in $OPTION.
+printf -- '-2-\n'
+set -- -ab
+getopts "ab:" OPTION
+printf '%s\n' "${OPTION}"
+getopts "ab:" OPTION 3>&2 2>&1 >&3 3>&-
+printf '%s\n' "${OPTION}"
+
+# The 'shift' is aimed at causing an error.
+printf -- '-3-\n'
+shift 1
+getopts "ab:" OPTION
+printf '%s\n' "${OPTION}"
diff --git a/shell_cmds/sh/tests/builtins/getopts1.0.stdout b/shell_cmds/sh/tests/builtins/getopts1.0.stdout
new file mode 100644
index 0000000..a0a347e
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/getopts1.0.stdout
@@ -0,0 +1,8 @@
+-1-
+a
+-2-
+a
+No arg for -b option
+?
+-3-
+?
diff --git a/shell_cmds/sh/tests/builtins/getopts10.0 b/shell_cmds/sh/tests/builtins/getopts10.0
new file mode 100644
index 0000000..7d34ddc
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/getopts10.0
@@ -0,0 +1,11 @@
+# $FreeBSD: head/bin/sh/tests/builtins/getopts10.0 293359 2016-01-07 20:48:24Z jilles $
+
+set -- -x arg
+opt=not
+getopts x opt
+r1=$? OPTIND1=$OPTIND opt1=$opt
+: $(: $((OPTIND = 1)))
+getopts x opt
+r2=$? OPTIND2=$OPTIND
+[ "$r1" = 0 ] && [ "$OPTIND1" = 2 ] && [ "$opt1" = x ] && [ "$r2" != 0 ] &&
+ [ "$OPTIND2" = 2 ]
diff --git a/shell_cmds/sh/tests/builtins/getopts2.0 b/shell_cmds/sh/tests/builtins/getopts2.0
new file mode 100644
index 0000000..607d35e
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/getopts2.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/builtins/getopts2.0 297752 2016-04-09 16:06:13Z jilles $
+set - -ax
+getopts ax option
+set -C
+getopts ax option
+printf '%s\n' "$option"
diff --git a/shell_cmds/sh/tests/builtins/getopts2.0.stdout b/shell_cmds/sh/tests/builtins/getopts2.0.stdout
new file mode 100644
index 0000000..587be6b
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/getopts2.0.stdout
@@ -0,0 +1 @@
+x
diff --git a/shell_cmds/sh/tests/builtins/getopts3.0 b/shell_cmds/sh/tests/builtins/getopts3.0
new file mode 100644
index 0000000..6087d73
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/getopts3.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/builtins/getopts3.0 265616 2014-05-07 21:45:25Z jilles $
+
+shift $#
+getopts x opt
+r=$?
+[ "$r" != 0 ] && [ "$OPTIND" = 1 ]
diff --git a/shell_cmds/sh/tests/builtins/getopts4.0 b/shell_cmds/sh/tests/builtins/getopts4.0
new file mode 100644
index 0000000..ea8cc3f
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/getopts4.0
@@ -0,0 +1,10 @@
+# $FreeBSD: head/bin/sh/tests/builtins/getopts4.0 265616 2014-05-07 21:45:25Z jilles $
+
+set -- -x
+opt=not
+getopts x opt
+r1=$? OPTIND1=$OPTIND opt1=$opt
+getopts x opt
+r2=$? OPTIND2=$OPTIND
+[ "$r1" = 0 ] && [ "$OPTIND1" = 2 ] && [ "$opt1" = x ] && [ "$r2" != 0 ] &&
+ [ "$OPTIND2" = 2 ]
diff --git a/shell_cmds/sh/tests/builtins/getopts5.0 b/shell_cmds/sh/tests/builtins/getopts5.0
new file mode 100644
index 0000000..cd4eca6
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/getopts5.0
@@ -0,0 +1,10 @@
+# $FreeBSD: head/bin/sh/tests/builtins/getopts5.0 265616 2014-05-07 21:45:25Z jilles $
+
+set -- -x arg
+opt=not
+getopts x opt
+r1=$? OPTIND1=$OPTIND opt1=$opt
+getopts x opt
+r2=$? OPTIND2=$OPTIND
+[ "$r1" = 0 ] && [ "$OPTIND1" = 2 ] && [ "$opt1" = x ] && [ "$r2" != 0 ] &&
+ [ "$OPTIND2" = 2 ]
diff --git a/shell_cmds/sh/tests/builtins/getopts6.0 b/shell_cmds/sh/tests/builtins/getopts6.0
new file mode 100644
index 0000000..c415eda
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/getopts6.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/builtins/getopts6.0 265844 2014-05-10 17:42:21Z jilles $
+
+set -- -x -y
+getopts :x var || echo "First getopts bad: $?"
+getopts :x var
+r=$?
+[ r != 0 ] && [ "$OPTIND" = 3 ]
diff --git a/shell_cmds/sh/tests/builtins/getopts7.0 b/shell_cmds/sh/tests/builtins/getopts7.0
new file mode 100644
index 0000000..58afa50
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/getopts7.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/builtins/getopts7.0 265844 2014-05-10 17:42:21Z jilles $
+
+set -- -x
+getopts :x: var
+r=$?
+[ r != 0 ] && [ "$OPTIND" = 2 ]
diff --git a/shell_cmds/sh/tests/builtins/getopts8.0 b/shell_cmds/sh/tests/builtins/getopts8.0
new file mode 100644
index 0000000..35814b9
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/getopts8.0
@@ -0,0 +1,8 @@
+# $FreeBSD: head/bin/sh/tests/builtins/getopts8.0 265849 2014-05-10 19:18:49Z jilles $
+
+set -- -yz -wx
+opt=wrong1 OPTARG=wrong2
+while getopts :x opt; do
+ echo "$opt:${OPTARG-unset}"
+done
+echo "OPTIND=$OPTIND"
diff --git a/shell_cmds/sh/tests/builtins/getopts8.0.stdout b/shell_cmds/sh/tests/builtins/getopts8.0.stdout
new file mode 100644
index 0000000..f10cefc
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/getopts8.0.stdout
@@ -0,0 +1,5 @@
+?:y
+?:z
+?:w
+x:unset
+OPTIND=3
diff --git a/shell_cmds/sh/tests/builtins/getopts9.0 b/shell_cmds/sh/tests/builtins/getopts9.0
new file mode 100644
index 0000000..aa4abbc
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/getopts9.0
@@ -0,0 +1,9 @@
+# $FreeBSD: head/bin/sh/tests/builtins/getopts9.0 297752 2016-04-09 16:06:13Z jilles $
+
+args='-ab'
+getopts ab opt $args
+printf '%s\n' "$?:$opt:$OPTARG"
+for dummy in dummy1 dummy2; do
+ getopts ab opt $args
+ printf '%s\n' "$?:$opt:$OPTARG"
+done
diff --git a/shell_cmds/sh/tests/builtins/getopts9.0.stdout b/shell_cmds/sh/tests/builtins/getopts9.0.stdout
new file mode 100644
index 0000000..4d32063
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/getopts9.0.stdout
@@ -0,0 +1,3 @@
+0:a:
+0:b:
+1:?:
diff --git a/shell_cmds/sh/tests/builtins/hash1.0 b/shell_cmds/sh/tests/builtins/hash1.0
new file mode 100644
index 0000000..a5cae20
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/hash1.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/builtins/hash1.0 149791 2005-09-05 09:42:10Z stefanf $
+cat /dev/null
+hash
+hash -r
+hash
diff --git a/shell_cmds/sh/tests/builtins/hash1.0.stdout b/shell_cmds/sh/tests/builtins/hash1.0.stdout
new file mode 100644
index 0000000..3afc3e7
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/hash1.0.stdout
@@ -0,0 +1 @@
+/bin/cat
diff --git a/shell_cmds/sh/tests/builtins/hash2.0 b/shell_cmds/sh/tests/builtins/hash2.0
new file mode 100644
index 0000000..4ef151a
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/hash2.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/builtins/hash2.0 149791 2005-09-05 09:42:10Z stefanf $
+hash
+hash cat
+hash
diff --git a/shell_cmds/sh/tests/builtins/hash2.0.stdout b/shell_cmds/sh/tests/builtins/hash2.0.stdout
new file mode 100644
index 0000000..3afc3e7
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/hash2.0.stdout
@@ -0,0 +1 @@
+/bin/cat
diff --git a/shell_cmds/sh/tests/builtins/hash3.0 b/shell_cmds/sh/tests/builtins/hash3.0
new file mode 100644
index 0000000..6a155f4
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/hash3.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/builtins/hash3.0 149791 2005-09-05 09:42:10Z stefanf $
+hash -v cat
+hash
diff --git a/shell_cmds/sh/tests/builtins/hash3.0.stdout b/shell_cmds/sh/tests/builtins/hash3.0.stdout
new file mode 100644
index 0000000..a34864c
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/hash3.0.stdout
@@ -0,0 +1,2 @@
+/bin/cat
+/bin/cat
diff --git a/shell_cmds/sh/tests/builtins/hash4.0 b/shell_cmds/sh/tests/builtins/hash4.0
new file mode 100644
index 0000000..9e85f92
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/hash4.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/builtins/hash4.0 231535 2012-02-11 21:06:45Z jilles $
+
+exec 3>&1
+m=`hash nosuchtool 2>&1 >&3`
+r=$?
+[ "$r" != 0 ] && [ -n "$m" ]
diff --git a/shell_cmds/sh/tests/builtins/jobid1.0 b/shell_cmds/sh/tests/builtins/jobid1.0
new file mode 100644
index 0000000..8ba11c1
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/jobid1.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/builtins/jobid1.0 254412 2013-08-16 13:48:11Z jilles $
+# Non-standard builtin.
+
+: &
+p1=$!
+p2=$(jobid)
+[ "${p1:?}" = "${p2:?}" ]
diff --git a/shell_cmds/sh/tests/builtins/jobid2.0 b/shell_cmds/sh/tests/builtins/jobid2.0
new file mode 100644
index 0000000..4aca7d5
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/jobid2.0
@@ -0,0 +1,9 @@
+# $FreeBSD: head/bin/sh/tests/builtins/jobid2.0 254413 2013-08-16 13:56:43Z jilles $
+
+: &
+p1=$(jobid)
+p2=$(jobid --)
+p3=$(jobid %+)
+p4=$(jobid -- %+)
+[ "${p1:?}" = "${p2:?}" ] && [ "${p2:?}" = "${p3:?}" ] &&
+[ "${p3:?}" = "${p4:?}" ] && [ "${p4:?}" = "${p1:?}" ]
diff --git a/shell_cmds/sh/tests/builtins/kill1.0 b/shell_cmds/sh/tests/builtins/kill1.0
new file mode 100644
index 0000000..c15c86d
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/kill1.0
@@ -0,0 +1,8 @@
+# $FreeBSD: head/bin/sh/tests/builtins/kill1.0 262931 2014-03-08 19:44:34Z jilles $
+
+: &
+p1=$!
+: &
+p2=$!
+wait $p2
+kill %1
diff --git a/shell_cmds/sh/tests/builtins/kill2.0 b/shell_cmds/sh/tests/builtins/kill2.0
new file mode 100644
index 0000000..3b2360b
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/kill2.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/builtins/kill2.0 263206 2014-03-15 14:58:48Z jilles $
+
+sleep 1 | sleep 1 &
+kill %+
+wait "$!"
+r=$?
+[ "$r" -gt 128 ] && [ "$(kill -l "$r")" = TERM ]
diff --git a/shell_cmds/sh/tests/builtins/lineno.0 b/shell_cmds/sh/tests/builtins/lineno.0
new file mode 100644
index 0000000..e678ad8
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/lineno.0
@@ -0,0 +1,16 @@
+# $FreeBSD: head/bin/sh/tests/builtins/lineno.0 179023 2008-05-15 19:58:44Z stefanf $
+echo $LINENO
+echo $LINENO
+
+f() {
+ echo $LINENO
+ echo $LINENO
+}
+
+f
+
+echo ${LINENO:-foo}
+echo ${LINENO=foo}
+echo ${LINENO:+foo}
+echo ${LINENO+foo}
+echo ${#LINENO}
diff --git a/shell_cmds/sh/tests/builtins/lineno.0.stdout b/shell_cmds/sh/tests/builtins/lineno.0.stdout
new file mode 100644
index 0000000..82583a9
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/lineno.0.stdout
@@ -0,0 +1,9 @@
+2
+3
+2
+3
+12
+13
+foo
+foo
+2
diff --git a/shell_cmds/sh/tests/builtins/lineno2.0 b/shell_cmds/sh/tests/builtins/lineno2.0
new file mode 100644
index 0000000..f60ed11
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/lineno2.0
@@ -0,0 +1,10 @@
+# $FreeBSD: head/bin/sh/tests/builtins/lineno2.0 262565 2014-02-27 16:54:43Z jilles $
+
+f() {
+ : ${LINENO+${x?}}
+}
+
+unset -v x
+command eval f 2>/dev/null && exit 3
+x=1
+f
diff --git a/shell_cmds/sh/tests/builtins/lineno3.0 b/shell_cmds/sh/tests/builtins/lineno3.0
new file mode 100644
index 0000000..3271262
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/lineno3.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/builtins/lineno3.0 272482 2014-10-03 20:24:56Z jilles $
+
+echo before: $LINENO
+dummy=$'a\0
+'
+echo after: $LINENO
diff --git a/shell_cmds/sh/tests/builtins/lineno3.0.stdout b/shell_cmds/sh/tests/builtins/lineno3.0.stdout
new file mode 100644
index 0000000..6e0e4ac
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/lineno3.0.stdout
@@ -0,0 +1,2 @@
+before: 3
+after: 6
diff --git a/shell_cmds/sh/tests/builtins/local1.0 b/shell_cmds/sh/tests/builtins/local1.0
new file mode 100644
index 0000000..6100274
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/local1.0
@@ -0,0 +1,13 @@
+# $FreeBSD: head/bin/sh/tests/builtins/local1.0 238469 2012-07-15 10:22:13Z jilles $
+# A commonly used but non-POSIX builtin.
+
+f() {
+ local x
+ x=2
+ [ "$x" = 2 ]
+}
+x=1
+f || exit 3
+[ "$x" = 1 ] || exit 3
+f || exit 3
+[ "$x" = 1 ] || exit 3
diff --git a/shell_cmds/sh/tests/builtins/local2.0 b/shell_cmds/sh/tests/builtins/local2.0
new file mode 100644
index 0000000..ed78d93
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/local2.0
@@ -0,0 +1,17 @@
+# $FreeBSD: head/bin/sh/tests/builtins/local2.0 251797 2013-06-15 22:22:03Z jilles $
+
+f() {
+ local -
+ set -a
+ case $- in
+ *a*) : ;;
+ *) echo In-function \$- bad
+ esac
+}
+case $- in
+*a*) echo Initial \$- bad
+esac
+f
+case $- in
+*a*) echo Final \$- bad
+esac
diff --git a/shell_cmds/sh/tests/builtins/local3.0 b/shell_cmds/sh/tests/builtins/local3.0
new file mode 100644
index 0000000..f1d135d
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/local3.0
@@ -0,0 +1,26 @@
+# $FreeBSD: head/bin/sh/tests/builtins/local3.0 251797 2013-06-15 22:22:03Z jilles $
+
+f() {
+ local "$@"
+ set -a
+ x=7
+ case $- in
+ *a*) : ;;
+ *) echo In-function \$- bad
+ esac
+ [ "$x" = 7 ] || echo In-function \$x bad
+}
+x=1
+case $- in
+*a*) echo Initial \$- bad
+esac
+f x -
+case $- in
+*a*) echo Intermediate \$- bad
+esac
+[ "$x" = 1 ] || echo Intermediate \$x bad
+f - x
+case $- in
+*a*) echo Final \$- bad
+esac
+[ "$x" = 1 ] || echo Final \$x bad
diff --git a/shell_cmds/sh/tests/builtins/local4.0 b/shell_cmds/sh/tests/builtins/local4.0
new file mode 100644
index 0000000..7d35e6e
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/local4.0
@@ -0,0 +1,12 @@
+# $FreeBSD: head/bin/sh/tests/builtins/local4.0 254339 2013-08-14 21:59:48Z jilles $
+
+f() {
+ local -- x
+ x=2
+ [ "$x" = 2 ]
+}
+x=1
+f || exit 3
+[ "$x" = 1 ] || exit 3
+f || exit 3
+[ "$x" = 1 ] || exit 3
diff --git a/shell_cmds/sh/tests/builtins/local5.0 b/shell_cmds/sh/tests/builtins/local5.0
new file mode 100644
index 0000000..912a77b
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/local5.0
@@ -0,0 +1,15 @@
+# $FreeBSD: head/bin/sh/tests/builtins/local5.0 293635 2016-01-10 16:31:28Z jilles $
+
+f() {
+ local PATH IFS elem
+ IFS=:
+ for elem in ''$PATH''; do
+ PATH=/var/empty/$elem:$PATH
+ done
+ ls -d / >/dev/null
+}
+
+p1=$(command -v ls)
+f
+p2=$(command -v ls)
+[ "$p1" = "$p2" ]
diff --git a/shell_cmds/sh/tests/builtins/local6.0 b/shell_cmds/sh/tests/builtins/local6.0
new file mode 100644
index 0000000..b2e4c68
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/local6.0
@@ -0,0 +1,10 @@
+# $FreeBSD: head/bin/sh/tests/builtins/local6.0 294582 2016-01-22 18:10:36Z jilles $
+
+f() {
+ local x
+ readonly x=2
+}
+x=3
+f
+x=4
+[ "$x" = 4 ]
diff --git a/shell_cmds/sh/tests/builtins/local7.0 b/shell_cmds/sh/tests/builtins/local7.0
new file mode 100644
index 0000000..3819442
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/local7.0
@@ -0,0 +1,10 @@
+# $FreeBSD: head/bin/sh/tests/builtins/local7.0 294593 2016-01-22 20:10:08Z jilles $
+
+f() {
+ local x
+ readonly x=2
+}
+unset x
+f
+x=4
+[ "$x" = 4 ]
diff --git a/shell_cmds/sh/tests/builtins/locale1.0 b/shell_cmds/sh/tests/builtins/locale1.0
new file mode 100644
index 0000000..a560232
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/locale1.0
@@ -0,0 +1,134 @@
+# $FreeBSD: head/bin/sh/tests/builtins/locale1.0 218819 2011-02-18 20:37:09Z jilles $
+# Note: this test depends on strerror() using locale.
+
+failures=0
+
+check() {
+ if ! eval "[ $1 ]"; then
+ echo "Failed: $1 at $2"
+ : $((failures += 1))
+ fi
+}
+
+unset LANG LC_ALL LC_COLLATE LC_CTYPE LC_MONETARY LC_NUMERIC LC_TIME LC_MESSAGES
+unset LANGUAGE
+
+msgeng="No such file or directory"
+msgdut="Bestand of map niet gevonden"
+
+# Verify C locale error message.
+case $(command . /var/empty/foo 2>&1) in
+ *"$msgeng"*) ok=1 ;;
+ *) ok=0 ;;
+esac
+check '$ok -eq 1' $LINENO
+
+# Various locale variables that should not affect the message.
+case $(LC_ALL=C command . /var/empty/foo 2>&1) in
+ *"$msgeng"*) ok=1 ;;
+ *) ok=0 ;;
+esac
+check '$ok -eq 1' $LINENO
+
+case $(LC_ALL=C LANG=nl_NL.ISO8859-1 command . /var/empty/foo 2>&1) in
+ *"$msgeng"*) ok=1 ;;
+ *) ok=0 ;;
+esac
+check '$ok -eq 1' $LINENO
+
+case $(LC_ALL=C LC_MESSAGES=nl_NL.ISO8859-1 command . /var/empty/foo 2>&1) in
+ *"$msgeng"*) ok=1 ;;
+ *) ok=0 ;;
+esac
+check '$ok -eq 1' $LINENO
+
+case $(LC_CTYPE=nl_NL.ISO8859-1 command . /var/empty/foo 2>&1) in
+ *"$msgeng"*) ok=1 ;;
+ *) ok=0 ;;
+esac
+check '$ok -eq 1' $LINENO
+
+# Verify Dutch message.
+case $(export LANG=nl_NL.ISO8859-1; command . /var/empty/foo 2>&1) in
+ *"$msgdut"*) ok=1 ;;
+ *) ok=0 ;;
+esac
+check '$ok -eq 1' $LINENO
+
+case $(export LC_MESSAGES=nl_NL.ISO8859-1; command . /var/empty/foo 2>&1) in
+ *"$msgdut"*) ok=1 ;;
+ *) ok=0 ;;
+esac
+check '$ok -eq 1' $LINENO
+
+case $(export LC_ALL=nl_NL.ISO8859-1; command . /var/empty/foo 2>&1) in
+ *"$msgdut"*) ok=1 ;;
+ *) ok=0 ;;
+esac
+check '$ok -eq 1' $LINENO
+
+case $(LANG=nl_NL.ISO8859-1 command . /var/empty/foo 2>&1) in
+ *"$msgdut"*) ok=1 ;;
+ *) ok=0 ;;
+esac
+check '$ok -eq 1' $LINENO
+
+case $(LC_MESSAGES=nl_NL.ISO8859-1 command . /var/empty/foo 2>&1) in
+ *"$msgdut"*) ok=1 ;;
+ *) ok=0 ;;
+esac
+check '$ok -eq 1' $LINENO
+
+case $(LC_ALL=nl_NL.ISO8859-1 command . /var/empty/foo 2>&1) in
+ *"$msgdut"*) ok=1 ;;
+ *) ok=0 ;;
+esac
+check '$ok -eq 1' $LINENO
+
+# Verify that command assignments do not set the locale persistently.
+case $(command . /var/empty/foo 2>&1) in
+ *"$msgeng"*) ok=1 ;;
+ *) ok=0 ;;
+esac
+check '$ok -eq 1' $LINENO
+
+case $(LANG=nl_NL.ISO8859-1 command . /var/empty/foo 2>&1; command . /var/empty/foo 2>&1) in
+ *"$msgdut"*"$msgeng"*) ok=1 ;;
+ *) ok=0 ;;
+esac
+check '$ok -eq 1' $LINENO
+
+case $(LC_MESSAGES=nl_NL.ISO8859-1 command . /var/empty/foo 2>&1; command . /var/empty/foo 2>&1) in
+ *"$msgdut"*"$msgeng"*) ok=1 ;;
+ *) ok=0 ;;
+esac
+check '$ok -eq 1' $LINENO
+
+case $(LC_ALL=nl_NL.ISO8859-1 command . /var/empty/foo 2>&1; command . /var/empty/foo 2>&1) in
+ *"$msgdut"*"$msgeng"*) ok=1 ;;
+ *) ok=0 ;;
+esac
+check '$ok -eq 1' $LINENO
+
+# Check special builtin; add colon invocation to avoid depending on certain fix.
+case $(LC_ALL=nl_NL.ISO8859-1 . /var/empty/foo 2>&1; :) in
+ *"$msgdut"*) ok=1 ;;
+ *) ok=0 ;;
+esac
+check '$ok -eq 1' $LINENO
+
+# Assignments on special builtins are exported to that builtin; the export
+# is not persistent.
+case $(LC_ALL=nl_NL.ISO8859-1 . /dev/null; . /var/empty/foo 2>&1) in
+ *"$msgeng"*) ok=1 ;;
+ *) ok=0 ;;
+esac
+check '$ok -eq 1' $LINENO
+
+case $(export LC_ALL; LC_ALL=nl_NL.ISO8859-1 . /dev/null; . /var/empty/foo 2>&1) in
+ *"$msgdut"*) ok=1 ;;
+ *) ok=0 ;;
+esac
+check '$ok -eq 1' $LINENO
+
+exit $((failures > 0))
diff --git a/shell_cmds/sh/tests/builtins/locale2.0 b/shell_cmds/sh/tests/builtins/locale2.0
new file mode 100644
index 0000000..fc1b432
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/locale2.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/builtins/locale2.0 317912 2017-05-07 19:49:46Z jilles $
+
+$SH -c 'LC_ALL=C true; kill -INT $$; echo continued'
+r=$?
+[ "$r" -gt 128 ] && [ "$(kill -l "$r")" = INT ]
diff --git a/shell_cmds/sh/tests/builtins/printf1.0 b/shell_cmds/sh/tests/builtins/printf1.0
new file mode 100644
index 0000000..5730c5b
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/printf1.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/builtins/printf1.0 214853 2010-11-05 21:47:58Z jilles $
+
+[ "$(printf '%c\0%s%d' x '\' 010 | tr '\0' Z)" = 'xZ\8' ]
diff --git a/shell_cmds/sh/tests/builtins/printf2.0 b/shell_cmds/sh/tests/builtins/printf2.0
new file mode 100644
index 0000000..7084db7
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/printf2.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/builtins/printf2.0 214853 2010-11-05 21:47:58Z jilles $
+
+[ "$(printf '%cZ%s%d' x '\' 010)" = 'xZ\8' ]
diff --git a/shell_cmds/sh/tests/builtins/printf3.0 b/shell_cmds/sh/tests/builtins/printf3.0
new file mode 100644
index 0000000..ba54866
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/printf3.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/builtins/printf3.0 216606 2010-12-20 23:06:57Z jilles $
+
+set -e
+v=$(! printf "%d" @wrong 2>/dev/null)
+[ "$v" = "0" ]
diff --git a/shell_cmds/sh/tests/builtins/printf4.0 b/shell_cmds/sh/tests/builtins/printf4.0
new file mode 100644
index 0000000..5213dd6
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/printf4.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/builtins/printf4.0 216606 2010-12-20 23:06:57Z jilles $
+
+set -e
+v=$(! printf "%d" 4wrong 2>/dev/null)
+[ "$v" = "4" ]
diff --git a/shell_cmds/sh/tests/builtins/read1.0 b/shell_cmds/sh/tests/builtins/read1.0
new file mode 100644
index 0000000..b32272c
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/read1.0
@@ -0,0 +1,26 @@
+# $FreeBSD: head/bin/sh/tests/builtins/read1.0 190300 2009-03-22 23:00:52Z stefanf $
+set -e
+
+echo "1 2 3" | { read a; echo "x${a}x"; }
+echo "1 2 3" | { read a b; echo "x${a}x${b}x"; }
+echo "1 2 3" | { read a b c; echo "x${a}x${b}x${c}x"; }
+echo "1 2 3" | { read a b c d; echo "x${a}x${b}x${c}x${d}x"; }
+
+echo " 1 2 3 " | { read a b c; echo "x${a}x${b}x${c}x"; }
+echo " 1 2 3 " | { unset IFS; read a b c; echo "x${a}x${b}x${c}x"; }
+echo " 1 2 3 " | { IFS=$(printf ' \t\n') read a b c; echo "x${a}x${b}x${c}x"; }
+echo " 1 2 3 " | { IFS= read a b; echo "x${a}x${b}x"; }
+
+echo " 1,2 3 " | { IFS=' ,' read a b c; echo "x${a}x${b}x${c}x"; }
+echo ", 2 ,3" | { IFS=' ,' read a b c; echo "x${a}x${b}x${c}x"; }
+echo " 1 ,,3" | { IFS=' ,' read a b c; echo "x${a}x${b}x${c}x"; }
+echo " 1 , , 3" | { IFS=' ,' read a b c; echo "x${a}x${b}x${c}x"; }
+echo " 1 ,2 3," | { IFS=' ,' read a b c; echo "x${a}x${b}x${c}x"; }
+echo " 1 ,2 3,," | { IFS=' ,' read a b c; echo "x${a}x${b}x${c}x"; }
+
+echo " 1,2 3 " | { IFS=', ' read a b c; echo "x${a}x${b}x${c}x"; }
+echo ", 2 ,3" | { IFS=', ' read a b c; echo "x${a}x${b}x${c}x"; }
+echo " 1 ,,3" | { IFS=', ' read a b c; echo "x${a}x${b}x${c}x"; }
+echo " 1 , , 3" | { IFS=', ' read a b c; echo "x${a}x${b}x${c}x"; }
+echo " 1 ,2 3," | { IFS=', ' read a b c; echo "x${a}x${b}x${c}x"; }
+echo " 1 ,2 3,," | { IFS=', ' read a b c; echo "x${a}x${b}x${c}x"; }
diff --git a/shell_cmds/sh/tests/builtins/read1.0.stdout b/shell_cmds/sh/tests/builtins/read1.0.stdout
new file mode 100644
index 0000000..dbcb1af
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/read1.0.stdout
@@ -0,0 +1,20 @@
+x1 2 3x
+x1x2 3x
+x1x2x3x
+x1x2x3xx
+x1x2x3x
+x1x2x3x
+x1x2x3x
+x 1 2 3 xx
+x1x2x3x
+xx2x3x
+x1xx3x
+x1xx3x
+x1x2x3x
+x1x2x3,,x
+x1x2x3x
+xx2x3x
+x1xx3x
+x1xx3x
+x1x2x3x
+x1x2x3,,x
diff --git a/shell_cmds/sh/tests/builtins/read2.0 b/shell_cmds/sh/tests/builtins/read2.0
new file mode 100644
index 0000000..3255a48
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/read2.0
@@ -0,0 +1,31 @@
+# $FreeBSD: head/bin/sh/tests/builtins/read2.0 212187 2010-09-03 21:17:33Z jilles $
+
+set -e
+{
+ echo 1
+ echo two
+ echo three
+} | {
+ read x
+ [ "$x" = 1 ]
+ (read x
+ [ "$x" = two ])
+ read x
+ [ "$x" = three ]
+}
+
+T=`mktemp sh-test.XXXXXX`
+trap 'rm -f "$T"' 0
+{
+ echo 1
+ echo two
+ echo three
+} >$T
+{
+ read x
+ [ "$x" = 1 ]
+ (read x
+ [ "$x" = two ])
+ read x
+ [ "$x" = three ]
+} <$T
diff --git a/shell_cmds/sh/tests/builtins/read3.0 b/shell_cmds/sh/tests/builtins/read3.0
new file mode 100644
index 0000000..7cd5b4b
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/read3.0
@@ -0,0 +1,11 @@
+# $FreeBSD: head/bin/sh/tests/builtins/read3.0 212330 2010-09-08 18:32:23Z jilles $
+
+printf '%s\n' 'a\ b c' | { read a b; printf '%s\n' "x${a}x${b}x"; }
+printf '%s\n' 'a b\ c' | { read a b; printf '%s\n' "x${a}x${b}x"; }
+printf '%s\n' 'a\:b:c' | { IFS=: read a b; printf '%s\n' "x${a}x${b}x"; }
+printf '%s\n' 'a:b\:c' | { IFS=: read a b; printf '%s\n' "x${a}x${b}x"; }
+printf '%s\n' '\ a' | { read a b; printf '%s\n' "x${a}x${b}x"; }
+printf '%s\n' '\:a' | { IFS=: read a b; printf '%s\n' "x${a}x${b}x"; }
+printf '%s\n' '\\' | { read a b; printf '%s\n' "x${a}x${b}x"; }
+printf '%s\n' '\\\ a' | { read a b; printf '%s\n' "x${a}x${b}x"; }
+printf '%s\n' '\\\ a' | { read -r a b; printf '%s\n' "x${a}x${b}x"; }
diff --git a/shell_cmds/sh/tests/builtins/read3.0.stdout b/shell_cmds/sh/tests/builtins/read3.0.stdout
new file mode 100644
index 0000000..8ed98ca
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/read3.0.stdout
@@ -0,0 +1,9 @@
+xa bxcx
+xaxb cx
+xa:bxcx
+xaxb:cx
+x axx
+x:axx
+x\xx
+x\ axx
+x\\\xax
diff --git a/shell_cmds/sh/tests/builtins/read4.0 b/shell_cmds/sh/tests/builtins/read4.0
new file mode 100644
index 0000000..abd08af
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/read4.0
@@ -0,0 +1,10 @@
+# $FreeBSD: head/bin/sh/tests/builtins/read4.0 212339 2010-09-08 20:35:43Z jilles $
+
+printf '%s\n' '\a\ b c' | { read a b; printf '%s\n' "x${a}x${b}x"; }
+printf '%s\n' '\a b\ c' | { read a b; printf '%s\n' "x${a}x${b}x"; }
+printf '%s\n' '\a\:b:c' | { IFS=: read a b; printf '%s\n' "x${a}x${b}x"; }
+printf '%s\n' '\a:b\:c' | { IFS=: read a b; printf '%s\n' "x${a}x${b}x"; }
+printf '%s\n' '\\ a' | { read a b; printf '%s\n' "x${a}x${b}x"; }
+printf '%s\n' '\\:a' | { IFS=: read a b; printf '%s\n' "x${a}x${b}x"; }
+printf '%s\n' '\\\ a' | { read a b; printf '%s\n' "x${a}x${b}x"; }
+printf '%s\n' '\\\:a' | { IFS=: read a b; printf '%s\n' "x${a}x${b}x"; }
diff --git a/shell_cmds/sh/tests/builtins/read4.0.stdout b/shell_cmds/sh/tests/builtins/read4.0.stdout
new file mode 100644
index 0000000..a8747a4
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/read4.0.stdout
@@ -0,0 +1,8 @@
+xa bxcx
+xaxb cx
+xa:bxcx
+xaxb:cx
+x\xax
+x\xax
+x\ axx
+x\:axx
diff --git a/shell_cmds/sh/tests/builtins/read5.0 b/shell_cmds/sh/tests/builtins/read5.0
new file mode 100644
index 0000000..659aebb
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/read5.0
@@ -0,0 +1,32 @@
+# $FreeBSD: head/bin/sh/tests/builtins/read5.0 218821 2011-02-18 20:51:13Z jilles $
+
+unset LC_ALL
+LC_CTYPE=en_US.ISO8859-1
+export LC_CTYPE
+
+# Note: the first and last characters are not whitespace.
+# Exclude backslash and newline.
+bad1=`printf %03o \'\\\\`
+bad2=`printf %03o \''
+'`
+e=
+for i in 0 1 2 3; do
+ for j in 0 1 2 3 4 5 6 7; do
+ for k in 0 1 2 3 4 5 6 7; do
+ case $i$j$k in
+ 000|$bad1|$bad2) continue ;;
+ esac
+ e="$e\\$i$j$k"
+ done
+ done
+done
+e=`printf "$e"`
+[ "${#e}" = 253 ] || echo length bad
+
+r1=`printf '%s\n' "$e" | { read -r x; printf '%s' "$x"; }`
+[ "$r1" = "$e" ] || echo "read with -r bad"
+r2=`printf '%s\n' "$e" | { read x; printf '%s' "$x"; }`
+[ "$r2" = "$e" ] || echo "read without -r bad 1"
+IFS=
+r3=`printf '%s\n' "$e" | { read x; printf '%s' "$x"; }`
+[ "$r3" = "$e" ] || echo "read without -r bad 2"
diff --git a/shell_cmds/sh/tests/builtins/read6.0 b/shell_cmds/sh/tests/builtins/read6.0
new file mode 100644
index 0000000..3f78ee1
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/read6.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/builtins/read6.0 247190 2013-02-23 15:15:41Z jilles $
+
+: | read x
+r=$?
+[ "$r" = 1 ]
diff --git a/shell_cmds/sh/tests/builtins/read7.0 b/shell_cmds/sh/tests/builtins/read7.0
new file mode 100644
index 0000000..a01082d
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/read7.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/builtins/read7.0 250214 2013-05-03 15:28:31Z jilles $
+
+{ errmsg=`read x <&- 2>&1 >&3`; } 3>&1
+r=$?
+[ "$r" -ge 2 ] && [ "$r" -le 128 ] && [ -n "$errmsg" ]
diff --git a/shell_cmds/sh/tests/builtins/read8.0 b/shell_cmds/sh/tests/builtins/read8.0
new file mode 100644
index 0000000..b488279
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/read8.0
@@ -0,0 +1,17 @@
+# $FreeBSD: head/bin/sh/tests/builtins/read8.0 286826 2015-08-16 12:57:17Z jilles $
+
+read a b c <<\EOF
+\
+A\
+ \
+ \
+ \
+B\
+ \
+ \
+C\
+ \
+ \
+ \
+EOF
+[ "$a.$b.$c" = "A.B.C" ]
diff --git a/shell_cmds/sh/tests/builtins/read9.0 b/shell_cmds/sh/tests/builtins/read9.0
new file mode 100644
index 0000000..16f0687
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/read9.0
@@ -0,0 +1,10 @@
+# $FreeBSD: head/bin/sh/tests/builtins/read9.0 287308 2015-08-30 17:24:22Z jilles $
+
+empty=''
+read a b c <<EOF
+\ \ A B\ \ B C\ \ $empty
+EOF
+read d e <<EOF
+D\ $empty
+EOF
+[ "$a.$b.$c.$d.$e" = " A.B B.C .D ." ]
diff --git a/shell_cmds/sh/tests/builtins/return1.0 b/shell_cmds/sh/tests/builtins/return1.0
new file mode 100644
index 0000000..46de0ae
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/return1.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/builtins/return1.0 149791 2005-09-05 09:42:10Z stefanf $
+f() {
+ return 0
+ exit 1
+}
+
+f
diff --git a/shell_cmds/sh/tests/builtins/return2.1 b/shell_cmds/sh/tests/builtins/return2.1
new file mode 100644
index 0000000..4da86f5
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/return2.1
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/builtins/return2.1 149791 2005-09-05 09:42:10Z stefanf $
+f() {
+ true && return 1
+ return 0
+}
+
+f
diff --git a/shell_cmds/sh/tests/builtins/return3.1 b/shell_cmds/sh/tests/builtins/return3.1
new file mode 100644
index 0000000..bc65c1f
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/return3.1
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/builtins/return3.1 149791 2005-09-05 09:42:10Z stefanf $
+return 1
+exit 0
diff --git a/shell_cmds/sh/tests/builtins/return4.0 b/shell_cmds/sh/tests/builtins/return4.0
new file mode 100644
index 0000000..1a702ef
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/return4.0
@@ -0,0 +1,16 @@
+# $FreeBSD: head/bin/sh/tests/builtins/return4.0 208629 2010-05-28 22:08:34Z jilles $
+
+failures=
+failure() {
+ echo "Error at line $1" >&2
+ failures=x$failures
+}
+
+T=$(mktemp -d ${TMPDIR:-/tmp}/sh-test.XXXXXX) || exit
+trap 'rm -rf $T' 0
+cd $T || exit 3
+echo 'return 42; exit 4' >testscript
+. ./testscript
+[ "$?" = 42 ] || failure $LINENO
+
+test -z "$failures"
diff --git a/shell_cmds/sh/tests/builtins/return5.0 b/shell_cmds/sh/tests/builtins/return5.0
new file mode 100644
index 0000000..476ae7b
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/return5.0
@@ -0,0 +1,17 @@
+# $FreeBSD: head/bin/sh/tests/builtins/return5.0 211349 2010-08-15 21:06:53Z jilles $
+
+if [ "$1" != nested ]; then
+ f() {
+ set -- nested
+ . "$0"
+ # Allow return to return from the function or the dot script.
+ return 4
+ }
+ f
+ exit $(($? ^ 4))
+fi
+# To trigger the bug, the following commands must be at the top level,
+# with newlines in between.
+return 4
+echo bad
+exit 1
diff --git a/shell_cmds/sh/tests/builtins/return6.4 b/shell_cmds/sh/tests/builtins/return6.4
new file mode 100644
index 0000000..1bddbeb
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/return6.4
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/builtins/return6.4 212475 2010-09-11 15:07:40Z jilles $
+
+while return 4; do exit 3; done
diff --git a/shell_cmds/sh/tests/builtins/return7.4 b/shell_cmds/sh/tests/builtins/return7.4
new file mode 100644
index 0000000..3efdd7f
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/return7.4
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/builtins/return7.4 212475 2010-09-11 15:07:40Z jilles $
+
+f() {
+ while return 4; do exit 3; done
+}
+f
diff --git a/shell_cmds/sh/tests/builtins/return8.0 b/shell_cmds/sh/tests/builtins/return8.0
new file mode 100644
index 0000000..025f068
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/return8.0
@@ -0,0 +1,13 @@
+# $FreeBSD: head/bin/sh/tests/builtins/return8.0 255215 2013-09-04 22:10:16Z jilles $
+
+if [ "$1" = nested ]; then
+ return 17
+fi
+
+f() {
+ set -- nested
+ . "$0"
+ return $(($? ^ 1))
+}
+f
+exit $(($? ^ 16))
diff --git a/shell_cmds/sh/tests/builtins/set1.0 b/shell_cmds/sh/tests/builtins/set1.0
new file mode 100644
index 0000000..fc39fad
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/set1.0
@@ -0,0 +1,32 @@
+# $FreeBSD$
+
+set +C
+set +f
+set -e
+
+settings=$(set +o)
+set -C
+set -f
+set +e
+case $- in
+*C*) ;;
+*) echo missing C ;;
+esac
+case $- in
+*f*) ;;
+*) echo missing C ;;
+esac
+case $- in
+*e*) echo bad e ;;
+esac
+eval "$settings"
+case $- in
+*C*) echo bad C ;;
+esac
+case $- in
+*f*) echo bad f ;;
+esac
+case $- in
+*e*) ;;
+*) echo missing e ;;
+esac
diff --git a/shell_cmds/sh/tests/builtins/set2.0 b/shell_cmds/sh/tests/builtins/set2.0
new file mode 100644
index 0000000..844da91
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/set2.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/builtins/set2.0 223183 2011-06-17 10:21:24Z jilles $
+
+! env @badness=1 ${SH} -c 'v=`set`; eval "$v"' 2>&1 | grep @badness
diff --git a/shell_cmds/sh/tests/builtins/set3.0 b/shell_cmds/sh/tests/builtins/set3.0
new file mode 100644
index 0000000..419f702
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/set3.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/builtins/set3.0 296578 2016-03-09 21:05:21Z jilles $
+
+settings1=$(set +o) && set -o nolog && settings2=$(set +o) &&
+[ "$settings1" != "$settings2" ]
diff --git a/shell_cmds/sh/tests/builtins/trap1.0 b/shell_cmds/sh/tests/builtins/trap1.0
new file mode 100644
index 0000000..9f60be4
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/trap1.0
@@ -0,0 +1,22 @@
+# $FreeBSD: head/bin/sh/tests/builtins/trap1.0 213738 2010-10-12 18:20:38Z obrien $
+
+test "$(trap 'echo trapped' EXIT; :)" = trapped || exit 1
+
+test "$(trap 'echo trapped' EXIT; /usr/bin/true)" = trapped || exit 1
+
+result=$(${SH} -c 'trap "echo trapped" EXIT; /usr/bin/false')
+test $? -eq 1 || exit 1
+test "$result" = trapped || exit 1
+
+result=$(${SH} -c 'trap "echo trapped" EXIT; exec /usr/bin/false')
+test $? -eq 1 || exit 1
+test -z "$result" || exit 1
+
+result=0
+trap 'result=$((result+1))' INT
+kill -INT $$
+test "$result" -eq 1 || exit 1
+(kill -INT $$)
+test "$result" -eq 2 || exit 1
+
+exit 0
diff --git a/shell_cmds/sh/tests/builtins/trap10.0 b/shell_cmds/sh/tests/builtins/trap10.0
new file mode 100644
index 0000000..66c5106
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/trap10.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/builtins/trap10.0 230212 2012-01-16 11:07:46Z dumbbell $
+
+# Check that the return statement will not break the EXIT trap, ie. all
+# trap commands are executed before the script exits.
+
+test "$(trap 'printf trap; echo ped' EXIT; f() { return; }; f)" = trapped || exit 1
diff --git a/shell_cmds/sh/tests/builtins/trap11.0 b/shell_cmds/sh/tests/builtins/trap11.0
new file mode 100644
index 0000000..acb4d0f
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/trap11.0
@@ -0,0 +1,8 @@
+# $FreeBSD: head/bin/sh/tests/builtins/trap11.0 230212 2012-01-16 11:07:46Z dumbbell $
+
+# Check that the return statement will not break the USR1 trap, ie. all
+# trap commands are executed before the script resumes.
+
+result=$(${SH} -c 'trap "printf trap; echo ped" USR1; f() { return $(kill -USR1 $$); }; f')
+test $? -eq 0 || exit 1
+test "$result" = trapped || exit 1
diff --git a/shell_cmds/sh/tests/builtins/trap12.0 b/shell_cmds/sh/tests/builtins/trap12.0
new file mode 100644
index 0000000..a7a953c
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/trap12.0
@@ -0,0 +1,10 @@
+# $FreeBSD: head/bin/sh/tests/builtins/trap12.0 247720 2013-03-03 17:33:59Z jilles $
+
+f() {
+ trap 'return 42' USR1
+ kill -USR1 $$
+ return 3
+}
+f
+r=$?
+[ "$r" = 42 ]
diff --git a/shell_cmds/sh/tests/builtins/trap13.0 b/shell_cmds/sh/tests/builtins/trap13.0
new file mode 100644
index 0000000..1069b8f
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/trap13.0
@@ -0,0 +1,8 @@
+# $FreeBSD: head/bin/sh/tests/builtins/trap13.0 257399 2013-10-30 21:36:15Z jilles $
+
+{
+ trap 'exit 0' INT
+ ${SH} -c 'kill -INT $PPID'
+ exit 3
+} &
+wait $!
diff --git a/shell_cmds/sh/tests/builtins/trap14.0 b/shell_cmds/sh/tests/builtins/trap14.0
new file mode 100644
index 0000000..8c982b2
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/trap14.0
@@ -0,0 +1,10 @@
+# $FreeBSD: head/bin/sh/tests/builtins/trap14.0 257399 2013-10-30 21:36:15Z jilles $
+
+{
+ trap - INT
+ ${SH} -c 'kill -INT $PPID' &
+ wait
+} &
+wait $!
+r=$?
+[ "$r" -gt 128 ] && [ "$(kill -l "$r")" = INT ]
diff --git a/shell_cmds/sh/tests/builtins/trap15.0 b/shell_cmds/sh/tests/builtins/trap15.0
new file mode 100644
index 0000000..eaf8e8e
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/trap15.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/builtins/trap15.0 281718 2015-04-18 23:49:57Z bdrewery $
+
+(${SH} -c 'term(){ exit 5;}; trap term TERM; kill -TERM $$') &
+wait >/dev/null 2>&1 $!
+[ $? -eq 5 ]
diff --git a/shell_cmds/sh/tests/builtins/trap16.0 b/shell_cmds/sh/tests/builtins/trap16.0
new file mode 100644
index 0000000..b72fa11
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/trap16.0
@@ -0,0 +1,20 @@
+# $FreeBSD: head/bin/sh/tests/builtins/trap16.0 281718 2015-04-18 23:49:57Z bdrewery $
+
+traps=$(${SH} -c 'trap "echo bad" 0; trap - 0; trap')
+[ -z "$traps" ] || exit 1
+traps=$(${SH} -c 'trap "echo bad" 0; trap "" 0; trap')
+expected_traps=$(${SH} -c 'trap "" EXIT; trap')
+[ "$traps" = "$expected_traps" ] || exit 2
+traps=$(${SH} -c 'trap "echo bad" 0; trap 0; trap')
+[ -z "$traps" ] || exit 3
+traps=$(${SH} -c 'trap "echo bad" 0; trap -- 0; trap')
+[ -z "$traps" ] || exit 4
+traps=$(${SH} -c 'trap "echo bad" 0 1 2; trap - 0 1 2; trap')
+[ -z "$traps" ] || exit 5
+traps=$(${SH} -c 'trap "echo bad" 0 1 2; trap "" 0 1 2; trap')
+expected_traps=$(${SH} -c 'trap "" EXIT HUP INT; trap')
+[ "$traps" = "$expected_traps" ] || exit 6
+traps=$(${SH} -c 'trap "echo bad" 0 1 2; trap 0 1 2; trap')
+[ -z "$traps" ] || exit 7
+traps=$(${SH} -c 'trap "echo bad" 0 1 2; trap -- 0 1 2; trap')
+[ -z "$traps" ] || exit 8
diff --git a/shell_cmds/sh/tests/builtins/trap17.0 b/shell_cmds/sh/tests/builtins/trap17.0
new file mode 100644
index 0000000..35aafe7
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/trap17.0
@@ -0,0 +1,10 @@
+# $FreeBSD: head/bin/sh/tests/builtins/trap17.0 297360 2016-03-28 18:58:40Z jilles $
+# This use-after-free bug probably needs non-default settings to show up.
+
+v1=nothing v2=nothing
+trap 'trap "echo bad" USR1
+v1=trap_received
+v2=trap_invoked
+:' USR1
+kill -USR1 "$$"
+[ "$v1.$v2" = trap_received.trap_invoked ]
diff --git a/shell_cmds/sh/tests/builtins/trap2.0 b/shell_cmds/sh/tests/builtins/trap2.0
new file mode 100644
index 0000000..b64bb24
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/trap2.0
@@ -0,0 +1,52 @@
+# $FreeBSD: head/bin/sh/tests/builtins/trap2.0 194517 2009-06-19 22:15:59Z jilles $
+# This is really a test for outqstr(), which is readily accessible via trap.
+
+runtest()
+{
+ teststring=$1
+ trap -- "$teststring" USR1
+ traps=$(trap)
+ if [ "$teststring" != "-" ] && [ -z "$traps" ]; then
+ # One possible reading of POSIX requires the above to return an
+ # empty string because backquote commands are executed in a
+ # subshell and subshells shall reset traps. However, an example
+ # in the normative description of the trap builtin shows the
+ # same usage as here, it is useful and our /bin/sh allows it.
+ echo '$(trap) is broken'
+ exit 1
+ fi
+ trap - USR1
+ eval "$traps"
+ traps2=$(trap)
+ if [ "$traps" != "$traps2" ]; then
+ echo "Mismatch for '$teststring'"
+ exit 1
+ fi
+}
+
+runtest 'echo'
+runtest 'echo hi'
+runtest "'echo' 'hi'"
+runtest '"echo" $PATH'
+runtest '\echo "$PATH"'
+runtest ' 0'
+runtest '0 '
+runtest ' 1'
+runtest '1 '
+i=1
+while [ $i -le 127 ]; do
+ c=$(printf \\"$(printf %o $i)")
+ if [ $i -lt 48 ] || [ $i -gt 57 ]; then
+ runtest "$c"
+ fi
+ runtest " $c$c"
+ runtest "a$c"
+ i=$((i+1))
+done
+IFS=,
+runtest ' '
+runtest ','
+unset IFS
+runtest ' '
+
+exit 0
diff --git a/shell_cmds/sh/tests/builtins/trap3.0 b/shell_cmds/sh/tests/builtins/trap3.0
new file mode 100644
index 0000000..d442f8b
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/trap3.0
@@ -0,0 +1,11 @@
+# $FreeBSD: head/bin/sh/tests/builtins/trap3.0 218889 2011-02-20 14:18:58Z jilles $
+
+{
+ trap '' garbage && exit 3
+ trap - garbage && exit 3
+ trap true garbage && exit 3
+ trap '' 99999 && exit 3
+ trap - 99999 && exit 3
+ trap true 99999 && exit 3
+} 2>/dev/null
+exit 0
diff --git a/shell_cmds/sh/tests/builtins/trap4.0 b/shell_cmds/sh/tests/builtins/trap4.0
new file mode 100644
index 0000000..9fdab81
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/trap4.0
@@ -0,0 +1,17 @@
+# $FreeBSD: head/bin/sh/tests/builtins/trap4.0 217035 2011-01-05 23:17:29Z jilles $
+
+T=$(mktemp -d ${TMPDIR:-/tmp}/sh-test.XXXXXX)
+trap 'rm -rf $T' 0
+cd $T || exit 3
+mkfifo fifo1
+
+v=$(
+ exec 3>&1
+ : <fifo1 &
+ {
+ wait $!
+ trap 'trap "" PIPE; echo trapped >&3 2>/dev/null' PIPE
+ echo x 2>/dev/null
+ } >fifo1
+)
+test "$v" = trapped
diff --git a/shell_cmds/sh/tests/builtins/trap5.0 b/shell_cmds/sh/tests/builtins/trap5.0
new file mode 100644
index 0000000..26eeb50
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/trap5.0
@@ -0,0 +1,19 @@
+# $FreeBSD: head/bin/sh/tests/builtins/trap5.0 217461 2011-01-15 21:09:00Z jilles $
+
+set -e
+trap - USR1
+initial=$(trap)
+trap -- -l USR1
+added=$(trap)
+[ -n "$added" ]
+trap - USR1
+second=$(trap)
+[ "$initial" = "$second" ]
+eval "$added"
+added2=$(trap)
+added3=$(trap --)
+[ "$added" = "$added2" ]
+[ "$added2" = "$added3" ]
+trap -- - USR1
+third=$(trap)
+[ "$initial" = "$third" ]
diff --git a/shell_cmds/sh/tests/builtins/trap6.0 b/shell_cmds/sh/tests/builtins/trap6.0
new file mode 100644
index 0000000..1e79ae7
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/trap6.0
@@ -0,0 +1,9 @@
+# $FreeBSD: head/bin/sh/tests/builtins/trap6.0 217472 2011-01-16 13:56:41Z jilles $
+
+v=$(
+ ${SH} -c 'trap "echo ok; exit" USR1; kill -USR1 $$' &
+ # Suppress possible message about exit on signal
+ wait $! >/dev/null 2>&1
+)
+r=$(kill -l $?)
+[ "$v" = "ok" ] && { [ "$r" = "USR1" ] || [ "$r" = "usr1" ]; }
diff --git a/shell_cmds/sh/tests/builtins/trap7.0 b/shell_cmds/sh/tests/builtins/trap7.0
new file mode 100644
index 0000000..b62ffb7
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/trap7.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/builtins/trap7.0 217996 2011-01-27 23:08:20Z jilles $
+
+[ "$(trap 'echo trapped' EXIT)" = trapped ]
diff --git a/shell_cmds/sh/tests/builtins/trap8.0 b/shell_cmds/sh/tests/builtins/trap8.0
new file mode 100644
index 0000000..24752b1
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/trap8.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/builtins/trap8.0 218889 2011-02-20 14:18:58Z jilles $
+
+# I am not sure if POSIX requires the shell to continue processing
+# further trap names in the same trap command after an invalid one.
+
+test -n "$(trap true garbage TERM 2>/dev/null || trap)" || exit 3
+exit 0
diff --git a/shell_cmds/sh/tests/builtins/trap9.0 b/shell_cmds/sh/tests/builtins/trap9.0
new file mode 100644
index 0000000..bbc35e9
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/trap9.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/builtins/trap9.0 230211 2012-01-16 10:59:44Z dumbbell $
+
+test "$(trap 'printf trap; echo ped' EXIT; f() { :; }; f)" = trapped || exit 1
diff --git a/shell_cmds/sh/tests/builtins/type1.0 b/shell_cmds/sh/tests/builtins/type1.0
new file mode 100644
index 0000000..2f04997
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/type1.0
@@ -0,0 +1,8 @@
+# $FreeBSD: head/bin/sh/tests/builtins/type1.0 165931 2007-01-11 00:25:20Z stefanf $
+command -v not-here && exit 1
+command -v /not-here && exit 1
+command -V not-here && exit 1
+command -V /not-here && exit 1
+type not-here && exit 1
+type /not-here && exit 1
+exit 0
diff --git a/shell_cmds/sh/tests/builtins/type1.0.stderr b/shell_cmds/sh/tests/builtins/type1.0.stderr
new file mode 100644
index 0000000..7853418
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/type1.0.stderr
@@ -0,0 +1,4 @@
+not-here: not found
+/not-here: No such file or directory
+not-here: not found
+/not-here: No such file or directory
diff --git a/shell_cmds/sh/tests/builtins/type2.0 b/shell_cmds/sh/tests/builtins/type2.0
new file mode 100644
index 0000000..7e0581e
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/type2.0
@@ -0,0 +1,26 @@
+# $FreeBSD: head/bin/sh/tests/builtins/type2.0 201344 2009-12-31 17:44:24Z jilles $
+
+failures=0
+
+check() {
+ if ! eval "$*"; then
+ echo "Failed: $*"
+ : $((failures += 1))
+ fi
+}
+
+check 'PATH=/libexec type ld-elf.so.1 >/dev/null'
+check '! PATH=/libexec type ls 2>/dev/null'
+
+PATH=/libexec:$PATH
+
+check 'type ld-elf.so.1 >/dev/null'
+
+PATH=/libexec
+
+check 'type ld-elf.so.1 >/dev/null'
+check '! type ls 2>/dev/null'
+check 'PATH=/bin type ls >/dev/null'
+check '! PATH=/bin type ld-elf.so.1 2>/dev/null'
+
+exit $((failures > 0))
diff --git a/shell_cmds/sh/tests/builtins/type3.0 b/shell_cmds/sh/tests/builtins/type3.0
new file mode 100644
index 0000000..dad07e9
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/type3.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/builtins/type3.0 255072 2013-08-30 12:09:59Z jilles $
+
+[ "$(type type)" = "$(type -- type)" ]
diff --git a/shell_cmds/sh/tests/builtins/unalias.0 b/shell_cmds/sh/tests/builtins/unalias.0
new file mode 100644
index 0000000..ffdc756
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/unalias.0
@@ -0,0 +1,21 @@
+# $FreeBSD: head/bin/sh/tests/builtins/unalias.0 149781 2005-09-04 11:59:59Z stefanf $
+set -e
+
+alias false=true
+false
+unalias false
+false && exit 1
+unalias false && exit 1
+
+alias a1=foo a2=bar
+unalias a1 a2
+unalias a1 && exit 1
+unalias a2 && exit 1
+alias a2=bar
+unalias a1 a2 && exit 1
+
+alias a1=foo a2=bar
+unalias -a
+unalias a1 && exit 1
+unalias a2 && exit 1
+exit 0
diff --git a/shell_cmds/sh/tests/builtins/var-assign.0 b/shell_cmds/sh/tests/builtins/var-assign.0
new file mode 100644
index 0000000..41b59b1
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/var-assign.0
@@ -0,0 +1,55 @@
+# $FreeBSD: head/bin/sh/tests/builtins/var-assign.0 327281 2017-12-28 08:22:26Z eadler $
+IFS=,
+
+SPECIAL="break,\
+ :,\
+ continue,\
+ . /dev/null,
+ eval,
+ exec,
+ export -p,
+ readonly -p,
+ set,
+ shift 0,
+ times,
+ trap,
+ unset foo"
+
+UTILS="alias,\
+ bg,\
+ bind,\
+ cd,\
+ command echo,\
+ echo,\
+ false,\
+ fc -l,\
+ fg,\
+ getopts a var,\
+ hash,\
+ jobs,\
+ printf a,\
+ pwd,\
+ read var < /dev/null,\
+ test,\
+ true,\
+ type ls,\
+ ulimit,\
+ umask,\
+ unalias -a,\
+ wait"
+
+set -e
+
+# For special built-ins variable assignments affect the shell environment.
+set -- ${SPECIAL}
+for cmd in "$@"
+do
+ ${SH} -c "VAR=1; VAR=0 ${cmd}; exit \${VAR}" >/dev/null 2>&1
+done
+
+# For other built-ins and utilities they do not.
+set -- ${UTILS}
+for cmd in "$@"
+do
+ ${SH} -c "VAR=0; VAR=1 ${cmd}; exit \${VAR}" >/dev/null 2>&1
+done
diff --git a/shell_cmds/sh/tests/builtins/var-assign2.0 b/shell_cmds/sh/tests/builtins/var-assign2.0
new file mode 100644
index 0000000..b9afb55
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/var-assign2.0
@@ -0,0 +1,55 @@
+# $FreeBSD: head/bin/sh/tests/builtins/var-assign2.0 213738 2010-10-12 18:20:38Z obrien $
+IFS=,
+
+SPECIAL="break,\
+ :,\
+ continue,\
+ . /dev/null,\
+ eval,\
+ exec,\
+ export -p,\
+ readonly -p,\
+ set,\
+ shift 0,\
+ times,\
+ trap,\
+ unset foo"
+
+UTILS="alias,\
+ bg,\
+ bind,\
+ cd,\
+ command echo,\
+ echo,\
+ false,\
+ fc -l,\
+ fg,\
+ getopts a var,\
+ hash,\
+ jobs,\
+ printf a,\
+ pwd,\
+ read var < /dev/null,\
+ test,\
+ true,\
+ type ls,\
+ ulimit,\
+ umask,\
+ unalias -a,\
+ wait"
+
+set -e
+
+# With 'command', variable assignments do not affect the shell environment.
+
+set -- ${SPECIAL}
+for cmd in "$@"
+do
+ ${SH} -c "VAR=0; VAR=1 command ${cmd}; exit \${VAR}" >/dev/null 2>&1
+done
+
+set -- ${UTILS}
+for cmd in "$@"
+do
+ ${SH} -c "VAR=0; VAR=1 command ${cmd}; exit \${VAR}" >/dev/null 2>&1
+done
diff --git a/shell_cmds/sh/tests/builtins/wait1.0 b/shell_cmds/sh/tests/builtins/wait1.0
new file mode 100644
index 0000000..8538415
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/wait1.0
@@ -0,0 +1,23 @@
+# $FreeBSD: head/bin/sh/tests/builtins/wait1.0 208476 2010-05-23 22:10:20Z jilles $
+
+failures=
+failure() {
+ echo "Error at line $1" >&2
+ failures=x$failures
+}
+
+exit 4 & p4=$!
+exit 8 & p8=$!
+wait $p4
+[ $? = 4 ] || failure $LINENO
+wait $p8
+[ $? = 8 ] || failure $LINENO
+
+exit 3 & p3=$!
+exit 7 & p7=$!
+wait $p7
+[ $? = 7 ] || failure $LINENO
+wait $p3
+[ $? = 3 ] || failure $LINENO
+
+test -z "$failures"
diff --git a/shell_cmds/sh/tests/builtins/wait10.0 b/shell_cmds/sh/tests/builtins/wait10.0
new file mode 100644
index 0000000..c7e3975
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/wait10.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/builtins/wait10.0 251430 2013-06-05 19:40:52Z jilles $
+# Init cannot be a child of the shell.
+exit 49 & p49=$!
+wait 1 "$p49"
+[ "$?" = 49 ]
diff --git a/shell_cmds/sh/tests/builtins/wait2.0 b/shell_cmds/sh/tests/builtins/wait2.0
new file mode 100644
index 0000000..71adfde
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/wait2.0
@@ -0,0 +1,15 @@
+# $FreeBSD: head/bin/sh/tests/builtins/wait2.0 208476 2010-05-23 22:10:20Z jilles $
+
+failures=
+failure() {
+ echo "Error at line $1" >&2
+ failures=x$failures
+}
+
+for i in 1 2 3 4 5 6 7 8 9 10; do
+ exit $i &
+done
+wait || failure $LINENO
+wait || failure $LINENO
+
+test -z "$failures"
diff --git a/shell_cmds/sh/tests/builtins/wait3.0 b/shell_cmds/sh/tests/builtins/wait3.0
new file mode 100644
index 0000000..d3561ae
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/wait3.0
@@ -0,0 +1,21 @@
+# $FreeBSD: head/bin/sh/tests/builtins/wait3.0 236771 2012-06-08 22:54:25Z jilles $
+
+failures=
+failure() {
+ echo "Error at line $1" >&2
+ failures=x$failures
+}
+
+T=$(mktemp -d ${TMPDIR:-/tmp}/sh-test.XXXXXX)
+trap 'rm -rf $T' 0
+cd $T || exit 3
+mkfifo fifo1
+for i in 1 2 3 4 5 6 7 8 9 10; do
+ exit $i 4<fifo1 &
+done
+exec 3>fifo1
+wait || failure $LINENO
+(${SH} -c echo >&3) 2>/dev/null && failure $LINENO
+wait || failure $LINENO
+
+test -z "$failures"
diff --git a/shell_cmds/sh/tests/builtins/wait4.0 b/shell_cmds/sh/tests/builtins/wait4.0
new file mode 100644
index 0000000..358513c
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/wait4.0
@@ -0,0 +1,12 @@
+# $FreeBSD: head/bin/sh/tests/builtins/wait4.0 247206 2013-02-23 22:50:57Z jilles $
+
+T=`mktemp -d ${TMPDIR:-/tmp}/sh-test.XXXXXX`
+trap 'rm -rf $T' 0
+cd $T || exit 3
+mkfifo fifo1
+trapped=
+trap trapped=1 QUIT
+{ kill -QUIT $$; sleep 1; exit 4; } >fifo1 &
+wait $! <fifo1
+r=$?
+[ "$r" -gt 128 ] && [ -n "$trapped" ]
diff --git a/shell_cmds/sh/tests/builtins/wait5.0 b/shell_cmds/sh/tests/builtins/wait5.0
new file mode 100644
index 0000000..48e1d2e
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/wait5.0
@@ -0,0 +1,12 @@
+# $FreeBSD: head/bin/sh/tests/builtins/wait5.0 247206 2013-02-23 22:50:57Z jilles $
+
+T=`mktemp -d ${TMPDIR:-/tmp}/sh-test.XXXXXX`
+trap 'rm -rf $T' 0
+cd $T || exit 3
+mkfifo fifo1
+trapped=
+trap trapped=1 QUIT
+{ kill -QUIT $$; sleep 1; exit 4; } >fifo1 &
+wait <fifo1
+r=$?
+[ "$r" -gt 128 ] && [ -n "$trapped" ]
diff --git a/shell_cmds/sh/tests/builtins/wait6.0 b/shell_cmds/sh/tests/builtins/wait6.0
new file mode 100644
index 0000000..e87b9c9
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/wait6.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/builtins/wait6.0 248349 2013-03-15 20:29:31Z jilles $
+
+wait --
diff --git a/shell_cmds/sh/tests/builtins/wait7.0 b/shell_cmds/sh/tests/builtins/wait7.0
new file mode 100644
index 0000000..2c50674
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/wait7.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/builtins/wait7.0 248349 2013-03-15 20:29:31Z jilles $
+
+: &
+wait -- $!
diff --git a/shell_cmds/sh/tests/builtins/wait8.0 b/shell_cmds/sh/tests/builtins/wait8.0
new file mode 100644
index 0000000..15e23b7
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/wait8.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/builtins/wait8.0 251429 2013-06-05 19:08:22Z jilles $
+
+exit 44 & p44=$!
+exit 45 & p45=$!
+exit 7 & p7=$!
+wait "$p44" "$p7" "$p45"
+[ "$?" = 45 ]
diff --git a/shell_cmds/sh/tests/builtins/wait9.127 b/shell_cmds/sh/tests/builtins/wait9.127
new file mode 100644
index 0000000..9bed737
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/wait9.127
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/builtins/wait9.127 251430 2013-06-05 19:40:52Z jilles $
+# Init cannot be a child of the shell.
+wait 1
diff --git a/shell_cmds/sh/tests/errors/Makefile b/shell_cmds/sh/tests/errors/Makefile
new file mode 100644
index 0000000..a234a05
--- /dev/null
+++ b/shell_cmds/sh/tests/errors/Makefile
@@ -0,0 +1,35 @@
+# $FreeBSD: head/bin/sh/tests/errors/Makefile 319575 2017-06-04 20:52:55Z jilles $
+
+PACKAGE= tests
+
+TESTSDIR= ${TESTSBASE}/bin/sh/${.CURDIR:T}
+
+.PATH: ${.CURDIR:H}
+ATF_TESTS_SH= functional_test
+
+${PACKAGE}FILES+= assignment-error1.0
+${PACKAGE}FILES+= assignment-error2.0
+${PACKAGE}FILES+= backquote-error1.0
+${PACKAGE}FILES+= backquote-error2.0
+${PACKAGE}FILES+= bad-binary1.126
+${PACKAGE}FILES+= bad-keyword1.0
+${PACKAGE}FILES+= bad-parm-exp1.0
+${PACKAGE}FILES+= bad-parm-exp2.2 bad-parm-exp2.2.stderr
+${PACKAGE}FILES+= bad-parm-exp3.2 bad-parm-exp3.2.stderr
+${PACKAGE}FILES+= bad-parm-exp4.2 bad-parm-exp4.2.stderr
+${PACKAGE}FILES+= bad-parm-exp5.2 bad-parm-exp5.2.stderr
+${PACKAGE}FILES+= bad-parm-exp6.2 bad-parm-exp6.2.stderr
+${PACKAGE}FILES+= bad-parm-exp7.0
+${PACKAGE}FILES+= bad-parm-exp8.0
+${PACKAGE}FILES+= option-error.0
+${PACKAGE}FILES+= redirection-error.0
+${PACKAGE}FILES+= redirection-error2.2
+${PACKAGE}FILES+= redirection-error3.0
+${PACKAGE}FILES+= redirection-error4.0
+${PACKAGE}FILES+= redirection-error5.0
+${PACKAGE}FILES+= redirection-error6.0
+${PACKAGE}FILES+= redirection-error7.0
+${PACKAGE}FILES+= redirection-error8.0
+${PACKAGE}FILES+= write-error1.0
+
+.include <bsd.test.mk>
diff --git a/shell_cmds/sh/tests/errors/Makefile.depend b/shell_cmds/sh/tests/errors/Makefile.depend
new file mode 100644
index 0000000..dbfdc34
--- /dev/null
+++ b/shell_cmds/sh/tests/errors/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD: head/bin/sh/tests/errors/Makefile.depend 296587 2016-03-09 22:46:01Z bdrewery $
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/shell_cmds/sh/tests/errors/assignment-error1.0 b/shell_cmds/sh/tests/errors/assignment-error1.0
new file mode 100644
index 0000000..2106b5a
--- /dev/null
+++ b/shell_cmds/sh/tests/errors/assignment-error1.0
@@ -0,0 +1,30 @@
+# $FreeBSD: head/bin/sh/tests/errors/assignment-error1.0 213738 2010-10-12 18:20:38Z obrien $
+IFS=,
+
+SPECIAL="break,\
+ :,\
+ continue,\
+ . /dev/null,\
+ eval,\
+ exec,\
+ export -p,\
+ readonly -p,\
+ set,\
+ shift,\
+ times,\
+ trap,\
+ unset foo"
+
+# If there is no command word, the shell must abort on an assignment error.
+${SH} -c "readonly a=0; a=2; exit 0" 2>/dev/null && exit 1
+
+# Special built-in utilities must abort on an assignment error.
+set -- ${SPECIAL}
+for cmd in "$@"
+do
+ ${SH} -c "readonly a=0; a=2 ${cmd}; exit 0" 2>/dev/null && exit 1
+done
+
+# Other utilities must not abort; we currently still execute them.
+${SH} -c 'readonly a=0; a=1 true; exit $a' 2>/dev/null || exit 1
+${SH} -c 'readonly a=0; a=1 command :; exit $a' 2>/dev/null || exit 1
diff --git a/shell_cmds/sh/tests/errors/assignment-error2.0 b/shell_cmds/sh/tests/errors/assignment-error2.0
new file mode 100644
index 0000000..68f2d48
--- /dev/null
+++ b/shell_cmds/sh/tests/errors/assignment-error2.0
@@ -0,0 +1,8 @@
+# $FreeBSD: head/bin/sh/tests/errors/assignment-error2.0 216870 2011-01-01 13:26:18Z jilles $
+
+set -e
+HOME=/
+readonly HOME
+cd /sbin
+{ HOME=/bin cd; } 2>/dev/null || :
+[ "$(pwd)" != /bin ]
diff --git a/shell_cmds/sh/tests/errors/backquote-error1.0 b/shell_cmds/sh/tests/errors/backquote-error1.0
new file mode 100644
index 0000000..d35d0b7
--- /dev/null
+++ b/shell_cmds/sh/tests/errors/backquote-error1.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/errors/backquote-error1.0 213738 2010-10-12 18:20:38Z obrien $
+
+echo 'echo `for` echo ".BAD"CODE.' | ${SH} +m -i 2>&1 | grep -q BADCODE && exit 1
+exit 0
diff --git a/shell_cmds/sh/tests/errors/backquote-error2.0 b/shell_cmds/sh/tests/errors/backquote-error2.0
new file mode 100644
index 0000000..a5955dd
--- /dev/null
+++ b/shell_cmds/sh/tests/errors/backquote-error2.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/errors/backquote-error2.0 213738 2010-10-12 18:20:38Z obrien $
+
+${SH} -c 'echo `echo .BA"DCODE.`
+echo ".BAD"CODE.' 2>&1 | grep -q BADCODE && exit 1
+echo '`"`' | ${SH} -n 2>/dev/null && exit 1
+echo '`'"'"'`' | ${SH} -n 2>/dev/null && exit 1
+exit 0
diff --git a/shell_cmds/sh/tests/errors/bad-binary1.126 b/shell_cmds/sh/tests/errors/bad-binary1.126
new file mode 100644
index 0000000..7c7c67f
--- /dev/null
+++ b/shell_cmds/sh/tests/errors/bad-binary1.126
@@ -0,0 +1,12 @@
+# $FreeBSD: head/bin/sh/tests/errors/bad-binary1.126 218320 2011-02-05 12:54:59Z jilles $
+# Checking for binary "scripts" without magic number is permitted but not
+# required by POSIX. However, it is preferable to getting errors like
+# Syntax error: word unexpected (expecting ")")
+# from trying to execute ELF binaries for the wrong architecture.
+
+T=`mktemp -d "${TMPDIR:-/tmp}/sh-test.XXXXXXXX"` || exit
+trap 'rm -rf "${T}"' 0
+printf '\0echo bad\n' >"$T/testshellproc"
+chmod 755 "$T/testshellproc"
+PATH=$T:$PATH
+testshellproc 2>/dev/null
diff --git a/shell_cmds/sh/tests/errors/bad-keyword1.0 b/shell_cmds/sh/tests/errors/bad-keyword1.0
new file mode 100644
index 0000000..d2680d6
--- /dev/null
+++ b/shell_cmds/sh/tests/errors/bad-keyword1.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/errors/bad-keyword1.0 216398 2010-12-12 21:18:16Z jilles $
+
+echo ':; fi' | ${SH} -n 2>/dev/null && exit 1
+exit 0
diff --git a/shell_cmds/sh/tests/errors/bad-parm-exp1.0 b/shell_cmds/sh/tests/errors/bad-parm-exp1.0
new file mode 100644
index 0000000..f288294
--- /dev/null
+++ b/shell_cmds/sh/tests/errors/bad-parm-exp1.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/errors/bad-parm-exp1.0 164004 2006-11-05 18:41:23Z stefanf $
+false && {
+ ${}
+ ${foo/}
+ ${foo@bar}
+}
+:
diff --git a/shell_cmds/sh/tests/errors/bad-parm-exp2.2 b/shell_cmds/sh/tests/errors/bad-parm-exp2.2
new file mode 100644
index 0000000..7424840
--- /dev/null
+++ b/shell_cmds/sh/tests/errors/bad-parm-exp2.2
@@ -0,0 +1,2 @@
+# $FreeBSD: head/bin/sh/tests/errors/bad-parm-exp2.2 270101 2014-08-17 14:26:12Z jilles $
+eval '${}'
diff --git a/shell_cmds/sh/tests/errors/bad-parm-exp2.2.stderr b/shell_cmds/sh/tests/errors/bad-parm-exp2.2.stderr
new file mode 100644
index 0000000..51ea69c
--- /dev/null
+++ b/shell_cmds/sh/tests/errors/bad-parm-exp2.2.stderr
@@ -0,0 +1 @@
+eval: ${}: Bad substitution
diff --git a/shell_cmds/sh/tests/errors/bad-parm-exp3.2 b/shell_cmds/sh/tests/errors/bad-parm-exp3.2
new file mode 100644
index 0000000..56a52df
--- /dev/null
+++ b/shell_cmds/sh/tests/errors/bad-parm-exp3.2
@@ -0,0 +1,2 @@
+# $FreeBSD: head/bin/sh/tests/errors/bad-parm-exp3.2 270101 2014-08-17 14:26:12Z jilles $
+eval '${foo/}'
diff --git a/shell_cmds/sh/tests/errors/bad-parm-exp3.2.stderr b/shell_cmds/sh/tests/errors/bad-parm-exp3.2.stderr
new file mode 100644
index 0000000..70473f9
--- /dev/null
+++ b/shell_cmds/sh/tests/errors/bad-parm-exp3.2.stderr
@@ -0,0 +1 @@
+eval: ${foo/}: Bad substitution
diff --git a/shell_cmds/sh/tests/errors/bad-parm-exp4.2 b/shell_cmds/sh/tests/errors/bad-parm-exp4.2
new file mode 100644
index 0000000..e0a7099
--- /dev/null
+++ b/shell_cmds/sh/tests/errors/bad-parm-exp4.2
@@ -0,0 +1,2 @@
+# $FreeBSD: head/bin/sh/tests/errors/bad-parm-exp4.2 270101 2014-08-17 14:26:12Z jilles $
+eval '${foo:@abc}'
diff --git a/shell_cmds/sh/tests/errors/bad-parm-exp4.2.stderr b/shell_cmds/sh/tests/errors/bad-parm-exp4.2.stderr
new file mode 100644
index 0000000..3363f51
--- /dev/null
+++ b/shell_cmds/sh/tests/errors/bad-parm-exp4.2.stderr
@@ -0,0 +1 @@
+eval: ${foo:@...}: Bad substitution
diff --git a/shell_cmds/sh/tests/errors/bad-parm-exp5.2 b/shell_cmds/sh/tests/errors/bad-parm-exp5.2
new file mode 100644
index 0000000..fa26259
--- /dev/null
+++ b/shell_cmds/sh/tests/errors/bad-parm-exp5.2
@@ -0,0 +1,2 @@
+# $FreeBSD: head/bin/sh/tests/errors/bad-parm-exp5.2 270101 2014-08-17 14:26:12Z jilles $
+eval '${/}'
diff --git a/shell_cmds/sh/tests/errors/bad-parm-exp5.2.stderr b/shell_cmds/sh/tests/errors/bad-parm-exp5.2.stderr
new file mode 100644
index 0000000..13763f8
--- /dev/null
+++ b/shell_cmds/sh/tests/errors/bad-parm-exp5.2.stderr
@@ -0,0 +1 @@
+eval: ${/}: Bad substitution
diff --git a/shell_cmds/sh/tests/errors/bad-parm-exp6.2 b/shell_cmds/sh/tests/errors/bad-parm-exp6.2
new file mode 100644
index 0000000..51858e8
--- /dev/null
+++ b/shell_cmds/sh/tests/errors/bad-parm-exp6.2
@@ -0,0 +1,2 @@
+# $FreeBSD: head/bin/sh/tests/errors/bad-parm-exp6.2 270101 2014-08-17 14:26:12Z jilles $
+eval '${#foo^}'
diff --git a/shell_cmds/sh/tests/errors/bad-parm-exp6.2.stderr b/shell_cmds/sh/tests/errors/bad-parm-exp6.2.stderr
new file mode 100644
index 0000000..cc56f65
--- /dev/null
+++ b/shell_cmds/sh/tests/errors/bad-parm-exp6.2.stderr
@@ -0,0 +1 @@
+eval: ${foo...}: Bad substitution
diff --git a/shell_cmds/sh/tests/errors/bad-parm-exp7.0 b/shell_cmds/sh/tests/errors/bad-parm-exp7.0
new file mode 100644
index 0000000..d7bff92
--- /dev/null
+++ b/shell_cmds/sh/tests/errors/bad-parm-exp7.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/errors/bad-parm-exp7.0 287081 2015-08-23 20:44:53Z jilles $
+
+v=1
+eval ": $(printf '${v-${\372}}')"
diff --git a/shell_cmds/sh/tests/errors/bad-parm-exp8.0 b/shell_cmds/sh/tests/errors/bad-parm-exp8.0
new file mode 100644
index 0000000..24f6bff
--- /dev/null
+++ b/shell_cmds/sh/tests/errors/bad-parm-exp8.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/errors/bad-parm-exp8.0 287081 2015-08-23 20:44:53Z jilles $
+
+v=1
+eval ": $(printf '${v-${w\372}}')"
diff --git a/shell_cmds/sh/tests/errors/option-error.0 b/shell_cmds/sh/tests/errors/option-error.0
new file mode 100644
index 0000000..473c0b9
--- /dev/null
+++ b/shell_cmds/sh/tests/errors/option-error.0
@@ -0,0 +1,46 @@
+# $FreeBSD: head/bin/sh/tests/errors/option-error.0 213738 2010-10-12 18:20:38Z obrien $
+IFS=,
+
+SPECIAL="break abc,\
+ continue abc,\
+ .,
+ exit abc,
+ export -x,
+ readonly -x,
+ return abc,
+ set -z,
+ shift abc,
+ trap -y,
+ unset -y"
+
+UTILS="alias -y,\
+ cat -z,\
+ cd abc def,\
+ command break abc,\
+ expr 1 +,\
+ fc -z,\
+ getopts,\
+ hash -z,\
+ jobs -z,\
+ printf,\
+ pwd abc,\
+ read,\
+ test abc =,\
+ ulimit -z,\
+ umask -z,\
+ unalias -z,\
+ wait abc"
+
+# Special built-in utilities must abort on an option or operand error.
+set -- ${SPECIAL}
+for cmd in "$@"
+do
+ ${SH} -c "${cmd}; exit 0" 2>/dev/null && exit 1
+done
+
+# Other utilities must not abort.
+set -- ${UTILS}
+for cmd in "$@"
+do
+ ${SH} -c "${cmd}; exit 0" 2>/dev/null || exit 1
+done
diff --git a/shell_cmds/sh/tests/errors/redirection-error.0 b/shell_cmds/sh/tests/errors/redirection-error.0
new file mode 100644
index 0000000..2a67698
--- /dev/null
+++ b/shell_cmds/sh/tests/errors/redirection-error.0
@@ -0,0 +1,53 @@
+# $FreeBSD: head/bin/sh/tests/errors/redirection-error.0 213738 2010-10-12 18:20:38Z obrien $
+IFS=,
+
+SPECIAL="break,\
+ :,\
+ continue,\
+ . /dev/null,
+ eval,
+ exec,
+ export -p,
+ readonly -p,
+ set,
+ shift,
+ times,
+ trap,
+ unset foo"
+
+UTILS="alias,\
+ bg,\
+ bind,\
+ cd,\
+ command echo,\
+ echo,\
+ false,\
+ fc -l,\
+ fg,\
+ getopts a -a,\
+ hash,\
+ jobs,\
+ printf a,\
+ pwd,\
+ read var < /dev/null,\
+ test,\
+ true,\
+ type ls,\
+ ulimit,\
+ umask,\
+ unalias -a,\
+ wait"
+
+# Special built-in utilities must abort on a redirection error.
+set -- ${SPECIAL}
+for cmd in "$@"
+do
+ ${SH} -c "${cmd} > /; exit 0" 2>/dev/null && exit 1
+done
+
+# Other utilities must not abort.
+set -- ${UTILS}
+for cmd in "$@"
+do
+ ${SH} -c "${cmd} > /; exit 0" 2>/dev/null || exit 1
+done
diff --git a/shell_cmds/sh/tests/errors/redirection-error2.2 b/shell_cmds/sh/tests/errors/redirection-error2.2
new file mode 100644
index 0000000..595e959
--- /dev/null
+++ b/shell_cmds/sh/tests/errors/redirection-error2.2
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/errors/redirection-error2.2 213738 2010-10-12 18:20:38Z obrien $
+
+# sh should fail gracefully on this bad redirect
+${SH} -c 'echo 1 >&$a' 2>/dev/null
diff --git a/shell_cmds/sh/tests/errors/redirection-error3.0 b/shell_cmds/sh/tests/errors/redirection-error3.0
new file mode 100644
index 0000000..fd7a334
--- /dev/null
+++ b/shell_cmds/sh/tests/errors/redirection-error3.0
@@ -0,0 +1,54 @@
+# $FreeBSD: head/bin/sh/tests/errors/redirection-error3.0 213738 2010-10-12 18:20:38Z obrien $
+IFS=,
+
+SPECIAL="break,\
+ :,\
+ continue,\
+ . /dev/null,\
+ eval,\
+ exec,\
+ export -p,\
+ readonly -p,\
+ set,\
+ shift,\
+ times,\
+ trap,\
+ unset foo"
+
+UTILS="alias,\
+ bg,\
+ bind,\
+ cd,\
+ command echo,\
+ echo,\
+ false,\
+ fc -l,\
+ fg,\
+ getopts a -a,\
+ hash,\
+ jobs,\
+ printf a,\
+ pwd,\
+ read var < /dev/null,\
+ test,\
+ true,\
+ type ls,\
+ ulimit,\
+ umask,\
+ unalias -a,\
+ wait"
+
+# When used with 'command', neither special built-in utilities nor other
+# utilities must abort on a redirection error.
+
+set -- ${SPECIAL}
+for cmd in "$@"
+do
+ ${SH} -c "command ${cmd} > /; exit 0" 2>/dev/null || exit 1
+done
+
+set -- ${UTILS}
+for cmd in "$@"
+do
+ ${SH} -c "command ${cmd} > /; exit 0" 2>/dev/null || exit 1
+done
diff --git a/shell_cmds/sh/tests/errors/redirection-error4.0 b/shell_cmds/sh/tests/errors/redirection-error4.0
new file mode 100644
index 0000000..ed58499
--- /dev/null
+++ b/shell_cmds/sh/tests/errors/redirection-error4.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/errors/redirection-error4.0 205138 2010-03-13 22:53:17Z jilles $
+# A redirection error should not abort the shell if there is no command word.
+exec 2>/dev/null
+</var/empty/x
+</var/empty/x y=2
+y=2 </var/empty/x
+exit 0
diff --git a/shell_cmds/sh/tests/errors/redirection-error5.0 b/shell_cmds/sh/tests/errors/redirection-error5.0
new file mode 100644
index 0000000..b96c14e
--- /dev/null
+++ b/shell_cmds/sh/tests/errors/redirection-error5.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/errors/redirection-error5.0 205153 2010-03-14 13:51:12Z jilles $
+# A redirection error on a subshell should not abort the shell.
+exec 2>/dev/null
+( echo bad ) </var/empty/x
+exit 0
diff --git a/shell_cmds/sh/tests/errors/redirection-error6.0 b/shell_cmds/sh/tests/errors/redirection-error6.0
new file mode 100644
index 0000000..1d84e6c
--- /dev/null
+++ b/shell_cmds/sh/tests/errors/redirection-error6.0
@@ -0,0 +1,12 @@
+# $FreeBSD: head/bin/sh/tests/errors/redirection-error6.0 205154 2010-03-14 14:24:35Z jilles $
+# A redirection error on a compound command should not abort the shell.
+exec 2>/dev/null
+{ echo bad; } </var/empty/x
+if :; then echo bad; fi </var/empty/x
+for i in 1; do echo bad; done </var/empty/x
+i=0
+while [ $i = 0 ]; do echo bad; i=1; done </var/empty/x
+i=0
+until [ $i != 0 ]; do echo bad; i=1; done </var/empty/x
+case i in *) echo bad ;; esac </var/empty/x
+exit 0
diff --git a/shell_cmds/sh/tests/errors/redirection-error7.0 b/shell_cmds/sh/tests/errors/redirection-error7.0
new file mode 100644
index 0000000..ef56434
--- /dev/null
+++ b/shell_cmds/sh/tests/errors/redirection-error7.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/errors/redirection-error7.0 216851 2010-12-31 18:20:17Z jilles $
+
+! dummy=$(
+ exec 3>&1 >&2 2>&3
+ ulimit -n 9
+ exec 9<.
+) && [ -n "$dummy" ]
diff --git a/shell_cmds/sh/tests/errors/redirection-error8.0 b/shell_cmds/sh/tests/errors/redirection-error8.0
new file mode 100644
index 0000000..97364ac
--- /dev/null
+++ b/shell_cmds/sh/tests/errors/redirection-error8.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/errors/redirection-error8.0 319575 2017-06-04 20:52:55Z jilles $
+
+$SH -c '{ { :; } </var/empty/x; } 2>/dev/null || kill -INT $$; echo continued'
+r=$?
+[ "$r" -gt 128 ] && [ "$(kill -l "$r")" = INT ]
diff --git a/shell_cmds/sh/tests/errors/write-error1.0 b/shell_cmds/sh/tests/errors/write-error1.0
new file mode 100644
index 0000000..3001e5c
--- /dev/null
+++ b/shell_cmds/sh/tests/errors/write-error1.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/errors/write-error1.0 244924 2013-01-01 12:48:24Z jilles $
+
+! echo >&- 2>/dev/null
diff --git a/shell_cmds/sh/tests/execution/Makefile b/shell_cmds/sh/tests/execution/Makefile
new file mode 100644
index 0000000..6e80719
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/Makefile
@@ -0,0 +1,57 @@
+# $FreeBSD: head/bin/sh/tests/execution/Makefile 308229 2016-11-02 22:33:37Z jilles $
+
+PACKAGE= tests
+
+TESTSDIR= ${TESTSBASE}/bin/sh/${.CURDIR:T}
+
+.PATH: ${.CURDIR:H}
+ATF_TESTS_SH= functional_test
+
+${PACKAGE}FILES+= bg1.0
+${PACKAGE}FILES+= bg2.0
+${PACKAGE}FILES+= bg3.0
+${PACKAGE}FILES+= bg4.0
+${PACKAGE}FILES+= bg5.0
+${PACKAGE}FILES+= bg6.0 bg6.0.stdout
+${PACKAGE}FILES+= bg7.0
+${PACKAGE}FILES+= bg8.0
+${PACKAGE}FILES+= bg9.0
+${PACKAGE}FILES+= bg10.0 bg10.0.stdout
+${PACKAGE}FILES+= fork1.0
+${PACKAGE}FILES+= fork2.0
+${PACKAGE}FILES+= fork3.0
+${PACKAGE}FILES+= func1.0
+${PACKAGE}FILES+= func2.0
+${PACKAGE}FILES+= func3.0
+${PACKAGE}FILES+= hash1.0
+${PACKAGE}FILES+= int-cmd1.0
+${PACKAGE}FILES+= killed1.0
+${PACKAGE}FILES+= killed2.0
+${PACKAGE}FILES+= not1.0
+${PACKAGE}FILES+= not2.0
+${PACKAGE}FILES+= path1.0
+${PACKAGE}FILES+= redir1.0
+${PACKAGE}FILES+= redir2.0
+${PACKAGE}FILES+= redir3.0
+${PACKAGE}FILES+= redir4.0
+${PACKAGE}FILES+= redir5.0
+${PACKAGE}FILES+= redir6.0
+${PACKAGE}FILES+= redir7.0
+${PACKAGE}FILES+= set-C1.0
+${PACKAGE}FILES+= set-n1.0
+${PACKAGE}FILES+= set-n2.0
+${PACKAGE}FILES+= set-n3.0
+${PACKAGE}FILES+= set-n4.0
+${PACKAGE}FILES+= set-x1.0
+${PACKAGE}FILES+= set-x2.0
+${PACKAGE}FILES+= set-x3.0
+${PACKAGE}FILES+= set-x4.0
+${PACKAGE}FILES+= shellproc1.0
+${PACKAGE}FILES+= subshell1.0 subshell1.0.stdout
+${PACKAGE}FILES+= subshell2.0
+${PACKAGE}FILES+= subshell3.0
+${PACKAGE}FILES+= subshell4.0
+${PACKAGE}FILES+= unknown1.0
+${PACKAGE}FILES+= var-assign1.0
+
+.include <bsd.test.mk>
diff --git a/shell_cmds/sh/tests/execution/Makefile.depend b/shell_cmds/sh/tests/execution/Makefile.depend
new file mode 100644
index 0000000..fac3607
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD: head/bin/sh/tests/execution/Makefile.depend 296587 2016-03-09 22:46:01Z bdrewery $
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/shell_cmds/sh/tests/execution/bg1.0 b/shell_cmds/sh/tests/execution/bg1.0
new file mode 100644
index 0000000..95b51c6
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/bg1.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/execution/bg1.0 221027 2011-04-25 20:54:12Z jilles $
+
+: `false` &
diff --git a/shell_cmds/sh/tests/execution/bg10.0 b/shell_cmds/sh/tests/execution/bg10.0
new file mode 100644
index 0000000..06a27f4
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/bg10.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/execution/bg10.0 258535 2013-11-24 23:12:13Z jilles $
+# The redirection overrides the </dev/null implicit in a background command.
+
+echo yes | ${SH} -c '{ cat & wait; } <&0'
diff --git a/shell_cmds/sh/tests/execution/bg10.0.stdout b/shell_cmds/sh/tests/execution/bg10.0.stdout
new file mode 100644
index 0000000..7cfab5b
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/bg10.0.stdout
@@ -0,0 +1 @@
+yes
diff --git a/shell_cmds/sh/tests/execution/bg2.0 b/shell_cmds/sh/tests/execution/bg2.0
new file mode 100644
index 0000000..74ee54a
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/bg2.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/execution/bg2.0 221027 2011-04-25 20:54:12Z jilles $
+
+f() { return 42; }
+f
+: | : &
diff --git a/shell_cmds/sh/tests/execution/bg3.0 b/shell_cmds/sh/tests/execution/bg3.0
new file mode 100644
index 0000000..95f37d3
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/bg3.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/execution/bg3.0 221027 2011-04-25 20:54:12Z jilles $
+
+f() { return 42; }
+f
+(:) &
diff --git a/shell_cmds/sh/tests/execution/bg4.0 b/shell_cmds/sh/tests/execution/bg4.0
new file mode 100644
index 0000000..1220fd3
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/bg4.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/execution/bg4.0 223283 2011-06-19 00:00:36Z jilles $
+
+x=''
+: ${x:=1} &
+wait
+exit ${x:-0}
diff --git a/shell_cmds/sh/tests/execution/bg5.0 b/shell_cmds/sh/tests/execution/bg5.0
new file mode 100644
index 0000000..e820035
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/bg5.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/execution/bg5.0 258489 2013-11-22 21:50:13Z jilles $
+# A background command has an implicit </dev/null redirection.
+
+echo bad | ${SH} -c '{ cat & wait; }'
diff --git a/shell_cmds/sh/tests/execution/bg6.0 b/shell_cmds/sh/tests/execution/bg6.0
new file mode 100644
index 0000000..466adc2
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/bg6.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/execution/bg6.0 258489 2013-11-22 21:50:13Z jilles $
+# The redirection overrides the </dev/null implicit in a background command.
+
+echo yes | ${SH} -c '{ cat & wait; } </dev/stdin'
diff --git a/shell_cmds/sh/tests/execution/bg6.0.stdout b/shell_cmds/sh/tests/execution/bg6.0.stdout
new file mode 100644
index 0000000..7cfab5b
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/bg6.0.stdout
@@ -0,0 +1 @@
+yes
diff --git a/shell_cmds/sh/tests/execution/bg7.0 b/shell_cmds/sh/tests/execution/bg7.0
new file mode 100644
index 0000000..788161e
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/bg7.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/execution/bg7.0 258533 2013-11-24 22:45:49Z jilles $
+# The redirection does not apply to the background command, and therefore
+# does not override the implicit </dev/null.
+
+echo bad | ${SH} -c '</dev/null; { cat & wait; }'
diff --git a/shell_cmds/sh/tests/execution/bg8.0 b/shell_cmds/sh/tests/execution/bg8.0
new file mode 100644
index 0000000..aa571dc
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/bg8.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/execution/bg8.0 258533 2013-11-24 22:45:49Z jilles $
+# The redirection does not apply to the background command, and therefore
+# does not override the implicit </dev/null.
+
+echo bad | ${SH} -c 'command eval \) </dev/null 2>/dev/null; { cat & wait; }'
diff --git a/shell_cmds/sh/tests/execution/bg9.0 b/shell_cmds/sh/tests/execution/bg9.0
new file mode 100644
index 0000000..4af1bae
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/bg9.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/execution/bg9.0 258533 2013-11-24 22:45:49Z jilles $
+# The redirection does not apply to the background command, and therefore
+# does not override the implicit </dev/null.
+
+echo bad | ${SH} -c 'command eval eval \\\) \</dev/null 2>/dev/null; { cat & wait; }'
diff --git a/shell_cmds/sh/tests/execution/fork1.0 b/shell_cmds/sh/tests/execution/fork1.0
new file mode 100644
index 0000000..80b013b
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/fork1.0
@@ -0,0 +1,10 @@
+# $FreeBSD: head/bin/sh/tests/execution/fork1.0 218850 2011-02-19 13:22:18Z jilles $
+
+shname=${SH%% *}
+shname=${shname##*/}
+
+result=$(${SH} -c 'ps -p $$ -o comm=')
+test "$result" = "ps" || exit 1
+
+result=$(${SH} -c 'ps -p $$ -o comm=; :')
+test "$result" = "$shname" || exit 1
diff --git a/shell_cmds/sh/tests/execution/fork2.0 b/shell_cmds/sh/tests/execution/fork2.0
new file mode 100644
index 0000000..2639165
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/fork2.0
@@ -0,0 +1,9 @@
+# $FreeBSD: head/bin/sh/tests/execution/fork2.0 213738 2010-10-12 18:20:38Z obrien $
+
+result=$(${SH} -c '(/bin/sleep 1)& sleep 0.1; ps -p $! -o comm=; kill $!')
+test "$result" = sleep || exit 1
+
+result=$(${SH} -c '{ trap "echo trapped" EXIT; (/usr/bin/true); } & wait')
+test "$result" = trapped || exit 1
+
+exit 0
diff --git a/shell_cmds/sh/tests/execution/fork3.0 b/shell_cmds/sh/tests/execution/fork3.0
new file mode 100644
index 0000000..008be7b
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/fork3.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/execution/fork3.0 220978 2011-04-23 22:28:56Z jilles $
+
+result=$(${SH} -c 'f() { ps -p $$ -o comm=; }; f')
+test "$result" = "ps"
diff --git a/shell_cmds/sh/tests/execution/func1.0 b/shell_cmds/sh/tests/execution/func1.0
new file mode 100644
index 0000000..1af5495
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/func1.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/execution/func1.0 213738 2010-10-12 18:20:38Z obrien $
+
+MALLOC_OPTIONS=J ${SH} -c 'g() { g() { :; }; :; }; g' &&
+MALLOC_OPTIONS=J ${SH} -c 'g() { unset -f g; :; }; g'
diff --git a/shell_cmds/sh/tests/execution/func2.0 b/shell_cmds/sh/tests/execution/func2.0
new file mode 100644
index 0000000..eb48cc8
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/func2.0
@@ -0,0 +1,12 @@
+# $FreeBSD: head/bin/sh/tests/execution/func2.0 211399 2010-08-16 17:18:08Z jilles $
+# The empty pairs of braces here are to test that this does not cause a crash.
+
+f() { }
+f
+hash -v f >/dev/null
+f() { { }; }
+f
+hash -v f >/dev/null
+f() { { } }
+f
+hash -v f >/dev/null
diff --git a/shell_cmds/sh/tests/execution/func3.0 b/shell_cmds/sh/tests/execution/func3.0
new file mode 100644
index 0000000..209e255
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/func3.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/execution/func3.0 216398 2010-12-12 21:18:16Z jilles $
+
+# This may fail when parsing or when defining the function, or the definition
+# may silently do nothing. In no event may the function be executed.
+
+${SH} -c 'unset() { echo overriding function executed, bad; }; v=1; unset v; exit "${v-0}"' 2>/dev/null
+:
diff --git a/shell_cmds/sh/tests/execution/hash1.0 b/shell_cmds/sh/tests/execution/hash1.0
new file mode 100644
index 0000000..d019296
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/hash1.0
@@ -0,0 +1,12 @@
+# $FreeBSD: head/bin/sh/tests/execution/hash1.0 218323 2011-02-05 14:01:46Z jilles $
+
+T=`mktemp -d "${TMPDIR:-/tmp}/sh-test.XXXXXXXX"` || exit
+trap 'rm -rf "${T}"' 0
+PATH=$T:$PATH
+ls -ld . >/dev/null
+cat <<EOF >"$T/ls"
+:
+EOF
+chmod 755 "$T/ls"
+PATH=$PATH
+ls -ld .
diff --git a/shell_cmds/sh/tests/execution/int-cmd1.0 b/shell_cmds/sh/tests/execution/int-cmd1.0
new file mode 100644
index 0000000..e980461
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/int-cmd1.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/execution/int-cmd1.0 253271 2013-07-12 15:29:41Z jilles $
+
+! echo echo bad | $SH -ic 'fi' 2>/dev/null
diff --git a/shell_cmds/sh/tests/execution/killed1.0 b/shell_cmds/sh/tests/execution/killed1.0
new file mode 100644
index 0000000..ef9221d
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/killed1.0
@@ -0,0 +1,8 @@
+# $FreeBSD: head/bin/sh/tests/execution/killed1.0 217557 2011-01-18 21:18:31Z jilles $
+# Sometimes the "Killed" message is not flushed soon enough and it
+# is redirected along with the output of a builtin.
+# Do not change the semicolon to a newline as it would hide the bug.
+
+exec 3>&1
+exec >/dev/null 2>&1
+${SH} -c 'kill -9 $$'; : >&3 2>&3
diff --git a/shell_cmds/sh/tests/execution/killed2.0 b/shell_cmds/sh/tests/execution/killed2.0
new file mode 100644
index 0000000..4d6de16
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/killed2.0
@@ -0,0 +1,10 @@
+# $FreeBSD: head/bin/sh/tests/execution/killed2.0 218105 2011-01-30 22:57:52Z jilles $
+# Most shells print a message when a foreground job is killed by a signal.
+# POSIX allows this, provided the message is sent to stderr, not stdout.
+# Some trickery is needed to capture the message as redirecting stderr of
+# the command itself does not affect it. The colon command ensures that
+# the subshell forks for ${SH}.
+
+exec 3>&1
+r=`(${SH} -c 'kill $$'; :) 2>&1 >&3`
+[ -n "$r" ]
diff --git a/shell_cmds/sh/tests/execution/not1.0 b/shell_cmds/sh/tests/execution/not1.0
new file mode 100644
index 0000000..c825e13
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/not1.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/execution/not1.0 249407 2013-04-12 15:19:35Z jilles $
+
+f() { ! return $1; }
+f 0 && ! f 1
diff --git a/shell_cmds/sh/tests/execution/not2.0 b/shell_cmds/sh/tests/execution/not2.0
new file mode 100644
index 0000000..e4155a9
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/not2.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/execution/not2.0 249407 2013-04-12 15:19:35Z jilles $
+
+while :; do
+ ! break
+ exit 3
+done
diff --git a/shell_cmds/sh/tests/execution/path1.0 b/shell_cmds/sh/tests/execution/path1.0
new file mode 100644
index 0000000..3d5c67b
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/path1.0
@@ -0,0 +1,15 @@
+# $FreeBSD: head/bin/sh/tests/execution/path1.0 217206 2011-01-09 21:07:30Z jilles $
+# Some builtins should not be overridable via PATH.
+
+set -e
+T=$(mktemp -d ${TMPDIR:-/tmp}/sh-test.XXXXXX)
+trap 'rm -rf ${T}' 0
+echo '#!/bin/sh
+echo bad' >"$T/cd"
+chmod 755 "$T/cd"
+cd /bin
+oPATH=$PATH
+PATH=$T:$PATH:%builtin
+cd /
+PATH=$oPATH
+[ "$(pwd)" = / ]
diff --git a/shell_cmds/sh/tests/execution/redir1.0 b/shell_cmds/sh/tests/execution/redir1.0
new file mode 100644
index 0000000..6310478
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/redir1.0
@@ -0,0 +1,27 @@
+# $FreeBSD: head/bin/sh/tests/execution/redir1.0 211408 2010-08-16 22:23:19Z jilles $
+trap ': $((brokenpipe+=1))' PIPE
+
+P=${TMPDIR:-/tmp}
+cd $P
+T=$(mktemp -d sh-test.XXXXXX)
+cd $T
+
+brokenpipe=0
+mkfifo fifo1 fifo2
+read dummy >fifo2 <fifo1 &
+{
+ exec 4>fifo2
+} 3<fifo2 # Formerly, sh would keep fd 3 and a duplicate of it open.
+echo dummy >fifo1
+if [ $brokenpipe -ne 0 ]; then
+ rc=3
+fi
+wait
+echo dummy >&4 2>/dev/null
+if [ $brokenpipe -eq 1 ]; then
+ : ${rc:=0}
+fi
+
+rm fifo1 fifo2
+rmdir ${P}/${T}
+exit ${rc:-3}
diff --git a/shell_cmds/sh/tests/execution/redir2.0 b/shell_cmds/sh/tests/execution/redir2.0
new file mode 100644
index 0000000..27509c7
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/redir2.0
@@ -0,0 +1,29 @@
+# $FreeBSD: head/bin/sh/tests/execution/redir2.0 213738 2010-10-12 18:20:38Z obrien $
+trap ': $((brokenpipe+=1))' PIPE
+
+P=${TMPDIR:-/tmp}
+cd $P
+T=$(mktemp -d sh-test.XXXXXX)
+cd $T
+
+brokenpipe=0
+mkfifo fifo1 fifo2
+{
+ {
+ exec ${SH} -c 'exec <fifo1; read dummy'
+ } 7<&- # fifo2 should be kept open, but not passed to programs
+ true
+} 7<fifo2 &
+
+exec 4>fifo2
+exec 3>fifo1
+echo dummy >&4 2>/dev/null
+if [ $brokenpipe -eq 1 ]; then
+ : ${rc:=0}
+fi
+echo dummy >&3
+wait
+
+rm fifo1 fifo2
+rmdir ${P}/${T}
+exit ${rc:-3}
diff --git a/shell_cmds/sh/tests/execution/redir3.0 b/shell_cmds/sh/tests/execution/redir3.0
new file mode 100644
index 0000000..1b72098
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/redir3.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/execution/redir3.0 214289 2010-10-24 19:56:34Z jilles $
+
+3>&- 3>&-
diff --git a/shell_cmds/sh/tests/execution/redir4.0 b/shell_cmds/sh/tests/execution/redir4.0
new file mode 100644
index 0000000..01b1f87
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/redir4.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/execution/redir4.0 214290 2010-10-24 20:09:49Z jilles $
+
+{ echo bad 0>&3; } 2>/dev/null 3>/dev/null 3>&-
+exit 0
diff --git a/shell_cmds/sh/tests/execution/redir5.0 b/shell_cmds/sh/tests/execution/redir5.0
new file mode 100644
index 0000000..346c132
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/redir5.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/execution/redir5.0 218325 2011-02-05 15:02:19Z jilles $
+
+{ (echo bad) >/dev/null; } </dev/null
diff --git a/shell_cmds/sh/tests/execution/redir6.0 b/shell_cmds/sh/tests/execution/redir6.0
new file mode 100644
index 0000000..f663e51
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/redir6.0
@@ -0,0 +1,21 @@
+# $FreeBSD: head/bin/sh/tests/execution/redir6.0 220978 2011-04-23 22:28:56Z jilles $
+
+failures=0
+
+check() {
+ if [ "$2" != "$3" ]; then
+ echo "Failure at $1" >&2
+ failures=$((failures + 1))
+ fi
+}
+
+check $LINENO "$(trap "echo bye" EXIT; : >/dev/null)" bye
+check $LINENO "$(trap "echo bye" EXIT; { :; } >/dev/null)" bye
+check $LINENO "$(trap "echo bye" EXIT; (:) >/dev/null)" bye
+check $LINENO "$(trap "echo bye" EXIT; (: >/dev/null))" bye
+check $LINENO "$(${SH} -c 'trap "echo bye" EXIT; : >/dev/null')" bye
+check $LINENO "$(${SH} -c 'trap "echo bye" EXIT; { :; } >/dev/null')" bye
+check $LINENO "$(${SH} -c 'trap "echo bye" EXIT; (:) >/dev/null')" bye
+check $LINENO "$(${SH} -c 'trap "echo bye" EXIT; (: >/dev/null)')" bye
+
+exit $((failures > 0))
diff --git a/shell_cmds/sh/tests/execution/redir7.0 b/shell_cmds/sh/tests/execution/redir7.0
new file mode 100644
index 0000000..0e309a7
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/redir7.0
@@ -0,0 +1,21 @@
+# $FreeBSD: head/bin/sh/tests/execution/redir7.0 220978 2011-04-23 22:28:56Z jilles $
+
+failures=0
+
+check() {
+ if [ "$2" != "$3" ]; then
+ echo "Failure at $1" >&2
+ failures=$((failures + 1))
+ fi
+}
+
+check $LINENO "$(trap "echo bye" EXIT; f() { :; }; f >/dev/null)" bye
+check $LINENO "$(trap "echo bye" EXIT; f() { :; }; { f; } >/dev/null)" bye
+check $LINENO "$(trap "echo bye" EXIT; f() { :; }; (f) >/dev/null)" bye
+check $LINENO "$(trap "echo bye" EXIT; f() { :; }; (f >/dev/null))" bye
+check $LINENO "$(${SH} -c 'trap "echo bye" EXIT; f() { :; }; f >/dev/null')" bye
+check $LINENO "$(${SH} -c 'trap "echo bye" EXIT; f() { :; }; { f; } >/dev/null')" bye
+check $LINENO "$(${SH} -c 'trap "echo bye" EXIT; f() { :; }; (f) >/dev/null')" bye
+check $LINENO "$(${SH} -c 'trap "echo bye" EXIT; f() { :; }; (f >/dev/null)')" bye
+
+exit $((failures > 0))
diff --git a/shell_cmds/sh/tests/execution/set-C1.0 b/shell_cmds/sh/tests/execution/set-C1.0
new file mode 100644
index 0000000..b7d5a4c
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/set-C1.0
@@ -0,0 +1,12 @@
+# $FreeBSD: head/bin/sh/tests/execution/set-C1.0 308229 2016-11-02 22:33:37Z jilles $
+
+T=$(mktemp -d "${TMPDIR:-/tmp}/sh-test.XXXXXXXX") || exit
+trap 'rm -rf "$T"' 0
+
+set -C
+echo . >"$T/a" &&
+[ -s "$T/a" ] &&
+{ ! true >"$T/a"; } 2>/dev/null &&
+[ -s "$T/a" ] &&
+ln -s /dev/null "$T/b" &&
+true >"$T/b"
diff --git a/shell_cmds/sh/tests/execution/set-n1.0 b/shell_cmds/sh/tests/execution/set-n1.0
new file mode 100644
index 0000000..95eb98c
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/set-n1.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/execution/set-n1.0 222661 2011-06-03 21:17:42Z jilles $
+
+v=$( ($SH -n <<'EOF'
+for
+EOF
+) 2>&1 >/dev/null)
+[ $? -ne 0 ] && [ -n "$v" ]
diff --git a/shell_cmds/sh/tests/execution/set-n2.0 b/shell_cmds/sh/tests/execution/set-n2.0
new file mode 100644
index 0000000..d64fcca
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/set-n2.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/execution/set-n2.0 222661 2011-06-03 21:17:42Z jilles $
+
+$SH -n <<'EOF'
+echo bad
+EOF
diff --git a/shell_cmds/sh/tests/execution/set-n3.0 b/shell_cmds/sh/tests/execution/set-n3.0
new file mode 100644
index 0000000..5af1bc4
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/set-n3.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/execution/set-n3.0 222661 2011-06-03 21:17:42Z jilles $
+
+v=$( ($SH -nc 'for') 2>&1 >/dev/null)
+[ $? -ne 0 ] && [ -n "$v" ]
diff --git a/shell_cmds/sh/tests/execution/set-n4.0 b/shell_cmds/sh/tests/execution/set-n4.0
new file mode 100644
index 0000000..2904a34
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/set-n4.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/execution/set-n4.0 222676 2011-06-04 11:28:42Z jilles $
+
+$SH -nc 'echo bad'
diff --git a/shell_cmds/sh/tests/execution/set-x1.0 b/shell_cmds/sh/tests/execution/set-x1.0
new file mode 100644
index 0000000..e498a3f
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/set-x1.0
@@ -0,0 +1,8 @@
+# $FreeBSD: head/bin/sh/tests/execution/set-x1.0 222882 2011-06-08 21:58:19Z jilles $
+
+key='must_contain_this'
+{ r=`set -x; { : "$key"; } 2>&1 >/dev/null`; } 2>/dev/null
+case $r in
+*"$key"*) true ;;
+*) false ;;
+esac
diff --git a/shell_cmds/sh/tests/execution/set-x2.0 b/shell_cmds/sh/tests/execution/set-x2.0
new file mode 100644
index 0000000..42c66a6
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/set-x2.0
@@ -0,0 +1,9 @@
+# $FreeBSD: head/bin/sh/tests/execution/set-x2.0 222882 2011-06-08 21:58:19Z jilles $
+
+key='must contain this'
+PS4="$key+ "
+{ r=`set -x; { :; } 2>&1 >/dev/null`; } 2>/dev/null
+case $r in
+*"$key"*) true ;;
+*) false ;;
+esac
diff --git a/shell_cmds/sh/tests/execution/set-x3.0 b/shell_cmds/sh/tests/execution/set-x3.0
new file mode 100644
index 0000000..29a917e
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/set-x3.0
@@ -0,0 +1,9 @@
+# $FreeBSD: head/bin/sh/tests/execution/set-x3.0 222907 2011-06-09 23:12:23Z jilles $
+
+key='must contain this'
+PS4='$key+ '
+{ r=`set -x; { :; } 2>&1 >/dev/null`; } 2>/dev/null
+case $r in
+*"$key"*) true ;;
+*) false ;;
+esac
diff --git a/shell_cmds/sh/tests/execution/set-x4.0 b/shell_cmds/sh/tests/execution/set-x4.0
new file mode 100644
index 0000000..90dd59a
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/set-x4.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/execution/set-x4.0 275766 2014-12-14 16:26:19Z jilles $
+
+key=`printf '\r\t\001\200\300'`
+r=`{ set -x; : "$key"; } 2>&1 >/dev/null`
+case $r in
+*[![:print:]]*) echo fail; exit 3
+esac
diff --git a/shell_cmds/sh/tests/execution/shellproc1.0 b/shell_cmds/sh/tests/execution/shellproc1.0
new file mode 100644
index 0000000..5150b73
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/shellproc1.0
@@ -0,0 +1,11 @@
+# $FreeBSD: head/bin/sh/tests/execution/shellproc1.0 218205 2011-02-02 22:03:18Z jilles $
+
+T=`mktemp -d "${TMPDIR:-/tmp}/sh-test.XXXXXXXX"` || exit
+trap 'rm -rf "${T}"' 0
+cat <<EOF >"$T/testshellproc"
+printf 'this '
+echo is a test
+EOF
+chmod 755 "$T/testshellproc"
+PATH=$T:$PATH
+[ "`testshellproc`" = "this is a test" ]
diff --git a/shell_cmds/sh/tests/execution/subshell1.0 b/shell_cmds/sh/tests/execution/subshell1.0
new file mode 100644
index 0000000..68b0123
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/subshell1.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/execution/subshell1.0 245383 2013-01-13 19:39:13Z jilles $
+
+(eval "cd /
+v=$(printf %0100000d 1)
+echo \${#v}")
+echo end
diff --git a/shell_cmds/sh/tests/execution/subshell1.0.stdout b/shell_cmds/sh/tests/execution/subshell1.0.stdout
new file mode 100644
index 0000000..8c71af3
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/subshell1.0.stdout
@@ -0,0 +1,2 @@
+100000
+end
diff --git a/shell_cmds/sh/tests/execution/subshell2.0 b/shell_cmds/sh/tests/execution/subshell2.0
new file mode 100644
index 0000000..2d87730
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/subshell2.0
@@ -0,0 +1,10 @@
+# $FreeBSD: head/bin/sh/tests/execution/subshell2.0 245383 2013-01-13 19:39:13Z jilles $
+
+f() {
+ x=2
+}
+(
+ x=1
+ f
+ [ "$x" = 2 ]
+)
diff --git a/shell_cmds/sh/tests/execution/subshell3.0 b/shell_cmds/sh/tests/execution/subshell3.0
new file mode 100644
index 0000000..697ee0b
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/subshell3.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/execution/subshell3.0 245383 2013-01-13 19:39:13Z jilles $
+
+(false; exit) && exit 3
+exit 0
diff --git a/shell_cmds/sh/tests/execution/subshell4.0 b/shell_cmds/sh/tests/execution/subshell4.0
new file mode 100644
index 0000000..009db3d
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/subshell4.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/execution/subshell4.0 245383 2013-01-13 19:39:13Z jilles $
+
+(eval "set v=1"; false) && echo bad; :
diff --git a/shell_cmds/sh/tests/execution/unknown1.0 b/shell_cmds/sh/tests/execution/unknown1.0
new file mode 100644
index 0000000..dd4149e
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/unknown1.0
@@ -0,0 +1,29 @@
+# $FreeBSD: head/bin/sh/tests/execution/unknown1.0 197820 2009-10-06 22:00:14Z jilles $
+
+nosuchtool 2>/dev/null
+[ $? -ne 127 ] && exit 1
+/var/empty/nosuchtool 2>/dev/null
+[ $? -ne 127 ] && exit 1
+(nosuchtool) 2>/dev/null
+[ $? -ne 127 ] && exit 1
+(/var/empty/nosuchtool) 2>/dev/null
+[ $? -ne 127 ] && exit 1
+/ 2>/dev/null
+[ $? -ne 126 ] && exit 1
+PATH=/usr bin 2>/dev/null
+[ $? -ne 126 ] && exit 1
+
+dummy=$(nosuchtool 2>/dev/null)
+[ $? -ne 127 ] && exit 1
+dummy=$(/var/empty/nosuchtool 2>/dev/null)
+[ $? -ne 127 ] && exit 1
+dummy=$( (nosuchtool) 2>/dev/null)
+[ $? -ne 127 ] && exit 1
+dummy=$( (/var/empty/nosuchtool) 2>/dev/null)
+[ $? -ne 127 ] && exit 1
+dummy=$(/ 2>/dev/null)
+[ $? -ne 126 ] && exit 1
+dummy=$(PATH=/usr bin 2>/dev/null)
+[ $? -ne 126 ] && exit 1
+
+exit 0
diff --git a/shell_cmds/sh/tests/execution/var-assign1.0 b/shell_cmds/sh/tests/execution/var-assign1.0
new file mode 100644
index 0000000..b75f969
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/var-assign1.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/execution/var-assign1.0 212467 2010-09-11 14:15:50Z jilles $
+
+[ "$(HOME=/etc HOME=/ cd && pwd)" = / ]
diff --git a/shell_cmds/sh/tests/expansion/Makefile b/shell_cmds/sh/tests/expansion/Makefile
new file mode 100644
index 0000000..1c44a55
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/Makefile
@@ -0,0 +1,105 @@
+# $FreeBSD: head/bin/sh/tests/expansion/Makefile 317514 2017-04-27 18:52:18Z jilles $
+
+PACKAGE= tests
+
+TESTSDIR= ${TESTSBASE}/bin/sh/${.CURDIR:T}
+
+.PATH: ${.CURDIR:H}
+ATF_TESTS_SH= functional_test
+
+${PACKAGE}FILES+= arith1.0
+${PACKAGE}FILES+= arith2.0
+${PACKAGE}FILES+= arith3.0
+${PACKAGE}FILES+= arith4.0
+${PACKAGE}FILES+= arith5.0
+${PACKAGE}FILES+= arith6.0
+${PACKAGE}FILES+= arith7.0
+${PACKAGE}FILES+= arith8.0
+${PACKAGE}FILES+= arith9.0
+${PACKAGE}FILES+= arith10.0
+${PACKAGE}FILES+= arith11.0
+${PACKAGE}FILES+= arith12.0
+${PACKAGE}FILES+= arith13.0
+${PACKAGE}FILES+= arith14.0
+${PACKAGE}FILES+= assign1.0
+${PACKAGE}FILES+= cmdsubst1.0
+${PACKAGE}FILES+= cmdsubst2.0
+${PACKAGE}FILES+= cmdsubst3.0
+${PACKAGE}FILES+= cmdsubst4.0
+${PACKAGE}FILES+= cmdsubst5.0
+${PACKAGE}FILES+= cmdsubst6.0
+${PACKAGE}FILES+= cmdsubst7.0
+${PACKAGE}FILES+= cmdsubst8.0
+${PACKAGE}FILES+= cmdsubst9.0
+${PACKAGE}FILES+= cmdsubst10.0
+${PACKAGE}FILES+= cmdsubst11.0
+${PACKAGE}FILES+= cmdsubst12.0
+${PACKAGE}FILES+= cmdsubst13.0
+${PACKAGE}FILES+= cmdsubst14.0
+${PACKAGE}FILES+= cmdsubst15.0
+${PACKAGE}FILES+= cmdsubst16.0
+${PACKAGE}FILES+= cmdsubst17.0
+${PACKAGE}FILES+= cmdsubst18.0
+${PACKAGE}FILES+= cmdsubst19.0
+${PACKAGE}FILES+= cmdsubst20.0
+${PACKAGE}FILES+= cmdsubst21.0
+${PACKAGE}FILES+= cmdsubst22.0
+${PACKAGE}FILES+= cmdsubst23.0
+${PACKAGE}FILES+= cmdsubst24.0
+${PACKAGE}FILES+= cmdsubst25.0
+${PACKAGE}FILES+= cmdsubst26.0
+${PACKAGE}FILES+= export1.0
+${PACKAGE}FILES+= export2.0
+${PACKAGE}FILES+= export3.0
+${PACKAGE}FILES+= heredoc1.0
+${PACKAGE}FILES+= heredoc2.0
+${PACKAGE}FILES+= ifs1.0
+${PACKAGE}FILES+= ifs2.0
+${PACKAGE}FILES+= ifs3.0
+${PACKAGE}FILES+= ifs4.0
+${PACKAGE}FILES+= ifs5.0
+${PACKAGE}FILES+= ifs6.0
+${PACKAGE}FILES+= ifs7.0
+${PACKAGE}FILES+= length1.0
+${PACKAGE}FILES+= length2.0
+${PACKAGE}FILES+= length3.0
+${PACKAGE}FILES+= length4.0
+${PACKAGE}FILES+= length5.0
+${PACKAGE}FILES+= length6.0
+${PACKAGE}FILES+= length7.0
+${PACKAGE}FILES+= length8.0
+${PACKAGE}FILES+= local1.0
+${PACKAGE}FILES+= local2.0
+${PACKAGE}FILES+= pathname1.0
+${PACKAGE}FILES+= pathname2.0
+${PACKAGE}FILES+= pathname3.0
+${PACKAGE}FILES+= pathname4.0
+${PACKAGE}FILES+= pathname5.0
+${PACKAGE}FILES+= pathname6.0
+${PACKAGE}FILES+= plus-minus1.0
+${PACKAGE}FILES+= plus-minus2.0
+${PACKAGE}FILES+= plus-minus3.0
+${PACKAGE}FILES+= plus-minus4.0
+${PACKAGE}FILES+= plus-minus5.0
+${PACKAGE}FILES+= plus-minus6.0
+${PACKAGE}FILES+= plus-minus7.0
+${PACKAGE}FILES+= plus-minus8.0
+${PACKAGE}FILES+= question1.0
+${PACKAGE}FILES+= readonly1.0
+${PACKAGE}FILES+= redir1.0
+${PACKAGE}FILES+= set-u1.0
+${PACKAGE}FILES+= set-u2.0
+${PACKAGE}FILES+= set-u3.0
+${PACKAGE}FILES+= tilde1.0
+${PACKAGE}FILES+= tilde2.0
+${PACKAGE}FILES+= trim1.0
+${PACKAGE}FILES+= trim2.0
+${PACKAGE}FILES+= trim3.0
+${PACKAGE}FILES+= trim4.0
+${PACKAGE}FILES+= trim5.0
+${PACKAGE}FILES+= trim6.0
+${PACKAGE}FILES+= trim7.0
+${PACKAGE}FILES+= trim8.0
+${PACKAGE}FILES+= trim9.0
+
+.include <bsd.test.mk>
diff --git a/shell_cmds/sh/tests/expansion/Makefile.depend b/shell_cmds/sh/tests/expansion/Makefile.depend
new file mode 100644
index 0000000..547cbb3
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD: head/bin/sh/tests/expansion/Makefile.depend 296587 2016-03-09 22:46:01Z bdrewery $
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/shell_cmds/sh/tests/expansion/arith1.0 b/shell_cmds/sh/tests/expansion/arith1.0
new file mode 100644
index 0000000..c301600
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/arith1.0
@@ -0,0 +1,30 @@
+# $FreeBSD: head/bin/sh/tests/expansion/arith1.0 201259 2009-12-30 15:59:40Z jilles $
+
+failures=0
+
+check() {
+ if [ $(($1)) != $2 ]; then
+ failures=$((failures+1))
+ echo "For $1, expected $2 actual $(($1))"
+ fi
+}
+
+check "0&&0" 0
+check "1&&0" 0
+check "0&&1" 0
+check "1&&1" 1
+check "2&&2" 1
+check "1&&2" 1
+check "1<<40&&1<<40" 1
+check "1<<40&&4" 1
+
+check "0||0" 0
+check "1||0" 1
+check "0||1" 1
+check "1||1" 1
+check "2||2" 1
+check "1||2" 1
+check "1<<40||1<<40" 1
+check "1<<40||4" 1
+
+exit $((failures != 0))
diff --git a/shell_cmds/sh/tests/expansion/arith10.0 b/shell_cmds/sh/tests/expansion/arith10.0
new file mode 100644
index 0000000..9e3db28
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/arith10.0
@@ -0,0 +1,35 @@
+# $FreeBSD: head/bin/sh/tests/expansion/arith10.0 218469 2011-02-08 23:23:55Z jilles $
+
+failures=0
+
+check() {
+ if [ $(($1)) != $2 ]; then
+ failures=$((failures+1))
+ echo "For $1, expected $2 actual $(($1))"
+ fi
+}
+
+readonly ro=4
+rw=1
+check "0 && 0 / 0" 0
+check "1 || 0 / 0" 1
+check "0 && (ro = 2)" 0
+check "ro" 4
+check "1 || (ro = -1)" 1
+check "ro" 4
+check "0 && (rw += 1)" 0
+check "rw" 1
+check "1 || (rw += 1)" 1
+check "rw" 1
+check "0 ? 44 / 0 : 51" 51
+check "0 ? ro = 3 : 52" 52
+check "ro" 4
+check "0 ? rw += 1 : 52" 52
+check "rw" 1
+check "1 ? 68 : 30 / 0" 68
+check "2 ? 1 : (ro += 2)" 1
+check "ro" 4
+check "4 ? 1 : (rw += 1)" 1
+check "rw" 1
+
+exit $((failures != 0))
diff --git a/shell_cmds/sh/tests/expansion/arith11.0 b/shell_cmds/sh/tests/expansion/arith11.0
new file mode 100644
index 0000000..4a33831
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/arith11.0
@@ -0,0 +1,12 @@
+# $FreeBSD: head/bin/sh/tests/expansion/arith11.0 218626 2011-02-12 23:44:05Z jilles $
+# Try to divide the smallest integer by -1.
+# On amd64 this causes SIGFPE, so make sure the shell checks.
+
+# Calculate the minimum possible value, assuming two's complement and
+# a certain interpretation of overflow when shifting left.
+minint=1
+while [ $((minint <<= 1)) -gt 0 ]; do
+ :
+done
+v=$( eval ': $((minint / -1))' 2>&1 >/dev/null)
+[ $? -ne 0 ] && [ -n "$v" ]
diff --git a/shell_cmds/sh/tests/expansion/arith12.0 b/shell_cmds/sh/tests/expansion/arith12.0
new file mode 100644
index 0000000..7d79d7e
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/arith12.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/expansion/arith12.0 232839 2012-03-11 22:12:05Z jilles $
+
+_x=4 y_=5 z_z=6
+[ "$((_x*100+y_*10+z_z))" = 456 ]
diff --git a/shell_cmds/sh/tests/expansion/arith13.0 b/shell_cmds/sh/tests/expansion/arith13.0
new file mode 100644
index 0000000..5421cb0
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/arith13.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/expansion/arith13.0 254806 2013-08-24 20:06:00Z jilles $
+# Pre-increment and pre-decrement in arithmetic expansion are not in POSIX.
+# Require either an error or a correct implementation.
+
+! (eval 'x=4; [ $((++x)) != 5 ] || [ $x != 5 ]') 2>/dev/null &&
+! (eval 'x=2; [ $((--x)) != 1 ] || [ $x != 1 ]') 2>/dev/null
diff --git a/shell_cmds/sh/tests/expansion/arith14.0 b/shell_cmds/sh/tests/expansion/arith14.0
new file mode 100644
index 0000000..a51e916
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/arith14.0
@@ -0,0 +1,40 @@
+# $FreeBSD: head/bin/sh/tests/expansion/arith14.0 270029 2014-08-15 22:36:41Z jilles $
+# Check that <</>> use the low bits of the shift count.
+
+if [ $((1<<16<<16)) = 0 ]; then
+ width=32
+elif [ $((1<<32<<32)) = 0 ]; then
+ width=64
+elif [ $((1<<64<<64)) = 0 ]; then
+ width=128
+elif [ $((1<<64>>64)) = 1 ]; then
+ # Integers are wider than 128 bits; assume arbitrary precision.
+ # Nothing to test here.
+ exit 0
+else
+ echo "Cannot determine integer width"
+ exit 2
+fi
+
+twowidth=$((width * 2))
+j=43 k=$((1 << (width - 2))) r=0
+
+i=0
+while [ $i -lt $twowidth ]; do
+ if [ "$((j << i))" != "$((j << (i + width)))" ]; then
+ echo "Problem with $j << $i"
+ r=2
+ fi
+ i=$((i + 1))
+done
+
+i=0
+while [ $i -lt $twowidth ]; do
+ if [ "$((k >> i))" != "$((k >> (i + width)))" ]; then
+ echo "Problem with $k >> $i"
+ r=2
+ fi
+ i=$((i + 1))
+done
+
+exit $r
diff --git a/shell_cmds/sh/tests/expansion/arith2.0 b/shell_cmds/sh/tests/expansion/arith2.0
new file mode 100644
index 0000000..b5874e5
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/arith2.0
@@ -0,0 +1,77 @@
+# $FreeBSD: head/bin/sh/tests/expansion/arith2.0 209652 2010-07-02 21:31:24Z jilles $
+
+failures=0
+
+check() {
+ if [ $(($1)) != $2 ]; then
+ failures=$((failures+1))
+ echo "For $1, expected $2 actual $(($1))"
+ fi
+}
+
+# variables
+unset v
+check "v=2" 2
+check "v" 2
+check "$(($v))" 2
+check "v+=1" 3
+check "v" 3
+
+# constants
+check "4611686018427387904" 4611686018427387904
+check "0x4000000000000000" 4611686018427387904
+check "0400000000000000000000" 4611686018427387904
+check "0x4Ab0000000000000" 5381801554707742720
+check "010" 8
+
+# try out all operators
+v=42
+check "!v" 0
+check "!!v" 1
+check "!0" 1
+check "~0" -1
+check "~(-1)" 0
+check "-0" 0
+check "-v" -42
+check "v*v" 1764
+check "v/2" 21
+check "v%10" 2
+check "v+v" 84
+check "v-4" 38
+check "v<<1" 84
+check "v>>1" 21
+check "v<43" 1
+check "v>42" 0
+check "v<=43" 1
+check "v>=43" 0
+check "v==41" 0
+check "v!=42" 0
+check "v&3" 2
+check "v^3" 41
+check "v|3" 43
+check "v>=40&&v<=44" 1
+check "v<40||v>44" 0
+check "(v=42)&&(v+=1)==43" 1
+check "v" 43
+check "(v=42)&&(v-=1)==41" 1
+check "v" 41
+check "(v=42)&&(v*=2)==84" 1
+check "v" 84
+check "(v=42)&&(v/=10)==4" 1
+check "v" 4
+check "(v=42)&&(v%=10)==2" 1
+check "v" 2
+check "(v=42)&&(v<<=1)==84" 1
+check "v" 84
+check "(v=42)&&(v>>=2)==10" 1
+check "v" 10
+check "(v=42)&&(v&=32)==32" 1
+check "v" 32
+check "(v=42)&&(v^=32)==10" 1
+check "v" 10
+check "(v=42)&&(v|=32)==42" 1
+check "v" 42
+
+# missing: ternary
+
+exit $((failures != 0))
diff --git a/shell_cmds/sh/tests/expansion/arith3.0 b/shell_cmds/sh/tests/expansion/arith3.0
new file mode 100644
index 0000000..6b60b51
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/arith3.0
@@ -0,0 +1,14 @@
+# $FreeBSD: head/bin/sh/tests/expansion/arith3.0 204017 2010-02-17 22:25:22Z jilles $
+
+failures=0
+
+check() {
+ if [ $(($1)) != $2 ]; then
+ failures=$((failures+1))
+ echo "For $1, expected $2 actual $(($1))"
+ fi
+}
+
+check "1 << 1 + 1 | 1" 5
+
+exit $((failures != 0))
diff --git a/shell_cmds/sh/tests/expansion/arith4.0 b/shell_cmds/sh/tests/expansion/arith4.0
new file mode 100644
index 0000000..a41a0f7
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/arith4.0
@@ -0,0 +1,20 @@
+# $FreeBSD: head/bin/sh/tests/expansion/arith4.0 206167 2010-04-04 16:29:48Z jilles $
+
+failures=0
+
+check() {
+ if [ $(($1)) != $2 ]; then
+ failures=$((failures+1))
+ echo "For $1, expected $2 actual $(($1))"
+ fi
+}
+
+check '20 / 2 / 2' 5
+check '20 - 2 - 2' 16
+unset a b c d
+check "a = b = c = d = 1" 1
+check "a == 1 && b == 1 && c == 1 && d == 1" 1
+check "a += b += c += d" 4
+check "a == 4 && b == 3 && c == 2 && d == 1" 1
+
+exit $((failures != 0))
diff --git a/shell_cmds/sh/tests/expansion/arith5.0 b/shell_cmds/sh/tests/expansion/arith5.0
new file mode 100644
index 0000000..1cd021f
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/arith5.0
@@ -0,0 +1,17 @@
+# $FreeBSD: head/bin/sh/tests/expansion/arith5.0 206168 2010-04-04 16:48:33Z jilles $
+
+failures=0
+
+check() {
+ if [ "$2" != "$3" ]; then
+ failures=$((failures+1))
+ echo "For $1, expected $3 actual $2"
+ fi
+}
+
+unset a
+check '$((1+${a:-$((7+2))}))' "$((1+${a:-$((7+2))}))" 10
+check '$((1+${a:=$((2+2))}))' "$((1+${a:=$((2+2))}))" 5
+check '$a' "$a" 4
+
+exit $((failures != 0))
diff --git a/shell_cmds/sh/tests/expansion/arith6.0 b/shell_cmds/sh/tests/expansion/arith6.0
new file mode 100644
index 0000000..528f4e8
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/arith6.0
@@ -0,0 +1,16 @@
+# $FreeBSD: head/bin/sh/tests/expansion/arith6.0 215550 2010-11-19 22:25:32Z jilles $
+
+v1=1\ +\ 1
+v2=D
+v3=C123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
+f() { v4="$*"; }
+
+while [ ${#v2} -lt 1250 ]; do
+ eval $v2=$((3+${#v2})) $v3=$((4-${#v2}))
+ eval f $(($v2+ $v1 +$v3))
+ if [ $v4 -ne 9 ]; then
+ echo bad: $v4 -ne 9 at ${#v2}
+ fi
+ v2=x$v2
+ v3=y$v3
+done
diff --git a/shell_cmds/sh/tests/expansion/arith7.0 b/shell_cmds/sh/tests/expansion/arith7.0
new file mode 100644
index 0000000..f31dba1
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/arith7.0
@@ -0,0 +1,12 @@
+# $FreeBSD: head/bin/sh/tests/expansion/arith7.0 216395 2010-12-12 16:56:16Z jilles $
+
+v=1+
+v=$v$v$v$v
+v=$v$v$v$v
+v=$v$v$v$v
+v=$v$v$v$v
+v=$v$v$v$v
+[ "$(cat <<EOF
+$(($v 1))
+EOF
+)" = 1025 ]
diff --git a/shell_cmds/sh/tests/expansion/arith8.0 b/shell_cmds/sh/tests/expansion/arith8.0
new file mode 100644
index 0000000..e0739f8
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/arith8.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/expansion/arith8.0 216547 2010-12-18 23:03:51Z jilles $
+
+v=$( (eval ': $((08))') 2>&1 >/dev/null)
+[ $? -ne 0 ] && [ -n "$v" ]
diff --git a/shell_cmds/sh/tests/expansion/arith9.0 b/shell_cmds/sh/tests/expansion/arith9.0
new file mode 100644
index 0000000..e47d003
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/arith9.0
@@ -0,0 +1,20 @@
+# $FreeBSD: head/bin/sh/tests/expansion/arith9.0 218469 2011-02-08 23:23:55Z jilles $
+
+failures=0
+
+check() {
+ if [ $(($1)) != $2 ]; then
+ failures=$((failures+1))
+ echo "For $1, expected $2 actual $(($1))"
+ fi
+}
+
+check "0 ? 44 : 51" 51
+check "1 ? 68 : 30" 68
+check "2 ? 1 : -5" 1
+check "0 ? 4 : 0 ? 5 : 6" 6
+check "0 ? 4 : 1 ? 5 : 6" 5
+check "1 ? 4 : 0 ? 5 : 6" 4
+check "1 ? 4 : 1 ? 5 : 6" 4
+
+exit $((failures != 0))
diff --git a/shell_cmds/sh/tests/expansion/assign1.0 b/shell_cmds/sh/tests/expansion/assign1.0
new file mode 100644
index 0000000..ee4c0d8
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/assign1.0
@@ -0,0 +1,37 @@
+# $FreeBSD: head/bin/sh/tests/expansion/assign1.0 204842 2010-03-07 18:43:29Z jilles $
+
+e= q='?' a='*' t=texttext s='ast*que?non' p='/et[c]/' w='a b c' b='{{(#)}}'
+h='##'
+failures=''
+ok=''
+
+testcase() {
+ code="$1"
+ expected="$2"
+ oIFS="$IFS"
+ eval "$code"
+ IFS='|'
+ result="$#|$*"
+ IFS="$oIFS"
+ if [ "x$result" = "x$expected" ]; then
+ ok=x$ok
+ else
+ failures=x$failures
+ echo "For $code, expected $expected actual $result"
+ fi
+}
+
+testcase 'v=; set -- ${v=a b} $v' '0|'
+testcase 'unset v; set -- ${v=a b} $v' '4|a|b|a|b'
+testcase 'v=; set -- ${v:=a b} $v' '4|a|b|a|b'
+testcase 'v=; set -- "${v:=a b}" "$v"' '2|a b|a b'
+# expect sensible behaviour, although it disagrees with POSIX
+testcase 'v=; set -- ${v:=a\ b} $v' '4|a|b|a|b'
+testcase 'v=; set -- ${v:=$p} $v' '2|/etc/|/etc/'
+testcase 'v=; set -- "${v:=$p}" "$v"' '2|/et[c]/|/et[c]/'
+testcase 'v=; set -- "${v:=a\ b}" "$v"' '2|a\ b|a\ b'
+testcase 'v=; set -- ${v:="$p"} $v' '2|/etc/|/etc/'
+# whether $p is quoted or not shouldn't really matter
+testcase 'v=; set -- "${v:="$p"}" "$v"' '2|/et[c]/|/et[c]/'
+
+test "x$failures" = x
diff --git a/shell_cmds/sh/tests/expansion/cmdsubst1.0 b/shell_cmds/sh/tests/expansion/cmdsubst1.0
new file mode 100644
index 0000000..ea89f42
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/cmdsubst1.0
@@ -0,0 +1,48 @@
+# $FreeBSD: head/bin/sh/tests/expansion/cmdsubst1.0 201366 2010-01-01 18:17:46Z jilles $
+
+failures=0
+
+check() {
+ if ! eval "[ $* ]"; then
+ echo "Failed: $*"
+ : $((failures += 1))
+ fi
+}
+
+check '"$(echo abcde)" = "abcde"'
+check '"$(echo abcde; :)" = "abcde"'
+
+check '"$(printf abcde)" = "abcde"'
+check '"$(printf abcde; :)" = "abcde"'
+
+# regular
+check '-n "$(umask)"'
+check '-n "$(umask; :)"'
+check '-n "$(umask 2>&1)"'
+check '-n "$(umask 2>&1; :)"'
+
+# special
+check '-n "$(times)"'
+check '-n "$(times; :)"'
+check '-n "$(times 2>&1)"'
+check '-n "$(times 2>&1; :)"'
+
+# regular
+check '".$(umask -@ 2>&1)." = ".umask: Illegal option -@."'
+check '".$(umask -@ 2>&1; :)." = ".umask: Illegal option -@."'
+check '".$({ umask -@; } 2>&1)." = ".umask: Illegal option -@."'
+
+# special
+check '".$(shift xyz 2>&1)." = ".shift: Illegal number: xyz."'
+check '".$(shift xyz 2>&1; :)." = ".shift: Illegal number: xyz."'
+check '".$({ shift xyz; } 2>&1)." = ".shift: Illegal number: xyz."'
+
+v=1
+check '-z "$(v=2 :)"'
+check '"$v" = 1'
+check '-z "$(v=3)"'
+check '"$v" = 1'
+check '"$(v=4 eval echo \$v)" = 4'
+check '"$v" = 1'
+
+exit $((failures > 0))
diff --git a/shell_cmds/sh/tests/expansion/cmdsubst10.0 b/shell_cmds/sh/tests/expansion/cmdsubst10.0
new file mode 100644
index 0000000..dc13d39
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/cmdsubst10.0
@@ -0,0 +1,51 @@
+# $FreeBSD: head/bin/sh/tests/expansion/cmdsubst10.0 216826 2010-12-30 22:33:55Z jilles $
+
+a1=$(alias)
+: $(alias testalias=abcd)
+a2=$(alias)
+[ "$a1" = "$a2" ] || echo Error at line $LINENO
+
+alias testalias2=abcd
+a1=$(alias)
+: $(unalias testalias2)
+a2=$(alias)
+[ "$a1" = "$a2" ] || echo Error at line $LINENO
+
+[ "$(command -V pwd)" = "$(command -V pwd; exit $?)" ] || echo Error at line $LINENO
+
+v=1
+: $(export v=2)
+[ "$v" = 1 ] || echo Error at line $LINENO
+
+rotest=1
+: $(readonly rotest=2)
+[ "$rotest" = 1 ] || echo Error at line $LINENO
+
+set +u
+: $(set -u)
+case $- in
+*u*) echo Error at line $LINENO ;;
+esac
+set +u
+
+set +u
+: $(set -o nounset)
+case $- in
+*u*) echo Error at line $LINENO ;;
+esac
+set +u
+
+set +u
+: $(command set -u)
+case $- in
+*u*) echo Error at line $LINENO ;;
+esac
+set +u
+
+umask 77
+u1=$(umask)
+: $(umask 022)
+u2=$(umask)
+[ "$u1" = "$u2" ] || echo Error at line $LINENO
+
+dummy=$(exit 3); [ $? -eq 3 ] || echo Error at line $LINENO
diff --git a/shell_cmds/sh/tests/expansion/cmdsubst11.0 b/shell_cmds/sh/tests/expansion/cmdsubst11.0
new file mode 100644
index 0000000..cb035ae
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/cmdsubst11.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/expansion/cmdsubst11.0 223163 2011-06-16 21:50:28Z jilles $
+
+# Not required by POSIX but useful for efficiency.
+
+[ $$ = $(eval '${SH} -c echo\ \$PPID') ]
diff --git a/shell_cmds/sh/tests/expansion/cmdsubst12.0 b/shell_cmds/sh/tests/expansion/cmdsubst12.0
new file mode 100644
index 0000000..4d330ef
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/cmdsubst12.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/expansion/cmdsubst12.0 230121 2012-01-14 23:10:18Z jilles $
+
+f() {
+ echo x$(printf foo >&2)y
+}
+[ "$(f 2>&1)" = "fooxy" ]
diff --git a/shell_cmds/sh/tests/expansion/cmdsubst13.0 b/shell_cmds/sh/tests/expansion/cmdsubst13.0
new file mode 100644
index 0000000..d3fc399
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/cmdsubst13.0
@@ -0,0 +1,12 @@
+# $FreeBSD: head/bin/sh/tests/expansion/cmdsubst13.0 230121 2012-01-14 23:10:18Z jilles $
+
+x=1 y=2
+[ "$(
+ case $((x+=1)) in
+ ($((y+=1))) echo bad1 ;;
+ ($((y-1))) echo $x.$y ;;
+ ($((y=2))) echo bad2 ;;
+ (*) echo bad3 ;;
+ esac
+)" = "2.3" ] || echo "Error at $LINENO"
+[ "$x.$y" = "1.2" ] || echo "Error at $LINENO"
diff --git a/shell_cmds/sh/tests/expansion/cmdsubst14.0 b/shell_cmds/sh/tests/expansion/cmdsubst14.0
new file mode 100644
index 0000000..8a916af
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/cmdsubst14.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/expansion/cmdsubst14.0 245381 2013-01-13 19:19:40Z jilles $
+
+! v=`false
+
+`
diff --git a/shell_cmds/sh/tests/expansion/cmdsubst15.0 b/shell_cmds/sh/tests/expansion/cmdsubst15.0
new file mode 100644
index 0000000..9599ef8
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/cmdsubst15.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/expansion/cmdsubst15.0 245381 2013-01-13 19:19:40Z jilles $
+
+! v=`false;
+
+`
diff --git a/shell_cmds/sh/tests/expansion/cmdsubst16.0 b/shell_cmds/sh/tests/expansion/cmdsubst16.0
new file mode 100644
index 0000000..2483601
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/cmdsubst16.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/expansion/cmdsubst16.0 245392 2013-01-13 22:35:51Z jilles $
+
+f() { return 3; }
+f
+[ `echo $?` = 3 ]
diff --git a/shell_cmds/sh/tests/expansion/cmdsubst17.0 b/shell_cmds/sh/tests/expansion/cmdsubst17.0
new file mode 100644
index 0000000..d3a2b54
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/cmdsubst17.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/expansion/cmdsubst17.0 245422 2013-01-14 12:20:55Z jilles $
+
+f() { return 3; }
+f
+[ `echo $?; :` = 3 ]
diff --git a/shell_cmds/sh/tests/expansion/cmdsubst18.0 b/shell_cmds/sh/tests/expansion/cmdsubst18.0
new file mode 100644
index 0000000..2c3a1be
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/cmdsubst18.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/expansion/cmdsubst18.0 314637 2017-03-03 22:46:20Z jilles $
+
+x=X
+unset n
+r=${x+$(echo a)}${x-$(echo b)}${n+$(echo c)}${n-$(echo d)}$(echo e)
+[ "$r" = aXde ]
diff --git a/shell_cmds/sh/tests/expansion/cmdsubst19.0 b/shell_cmds/sh/tests/expansion/cmdsubst19.0
new file mode 100644
index 0000000..7813c88
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/cmdsubst19.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/expansion/cmdsubst19.0 314637 2017-03-03 22:46:20Z jilles $
+
+b=200 c=30 d=5 x=4
+r=$(echo a)$(($(echo b) + ${x+$(echo c)} + ${x-$(echo d)}))$(echo e)
+[ "$r" = a234e ]
diff --git a/shell_cmds/sh/tests/expansion/cmdsubst2.0 b/shell_cmds/sh/tests/expansion/cmdsubst2.0
new file mode 100644
index 0000000..35453be
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/cmdsubst2.0
@@ -0,0 +1,43 @@
+# $FreeBSD: head/bin/sh/tests/expansion/cmdsubst2.0 205105 2010-03-12 23:23:46Z jilles $
+
+failures=0
+
+check() {
+ if ! eval "[ $* ]"; then
+ echo "Failed: $*"
+ : $((failures += 1))
+ fi
+}
+
+check '`echo /et[c]/` = "/etc/"'
+check '`printf /var/empty%s /et[c]/` = "/var/empty/etc/"'
+check '"`echo /et[c]/`" = "/etc/"'
+check '`echo "/et[c]/"` = "/etc/"'
+check '`printf /var/empty%s "/et[c]/"` = "/var/empty/et[c]/"'
+check '`printf /var/empty/%s \"/et[c]/\"` = "/var/empty/\"/et[c]/\""'
+check '"`echo \"/et[c]/\"`" = "/et[c]/"'
+check '"`echo "/et[c]/"`" = "/et[c]/"'
+check '`echo $$` = $$'
+check '"`echo $$`" = $$'
+check '`echo \$\$` = $$'
+check '"`echo \$\$`" = $$'
+
+# Command substitutions consisting of a single builtin may be treated
+# differently.
+check '`:; echo /et[c]/` = "/etc/"'
+check '`:; printf /var/empty%s /et[c]/` = "/var/empty/etc/"'
+check '"`:; echo /et[c]/`" = "/etc/"'
+check '`:; echo "/et[c]/"` = "/etc/"'
+check '`:; printf /var/empty%s "/et[c]/"` = "/var/empty/et[c]/"'
+check '`:; printf /var/empty/%s \"/et[c]/\"` = "/var/empty/\"/et[c]/\""'
+check '"`:; echo \"/et[c]/\"`" = "/et[c]/"'
+check '"`:; echo "/et[c]/"`" = "/et[c]/"'
+check '`:; echo $$` = $$'
+check '"`:; echo $$`" = $$'
+check '`:; echo \$\$` = $$'
+check '"`:; echo \$\$`" = $$'
+
+check '`set -f; echo /et[c]/` = "/etc/"'
+check '"`set -f; echo /et[c]/`" = "/et[c]/"'
+
+exit $((failures > 0))
diff --git a/shell_cmds/sh/tests/expansion/cmdsubst20.0 b/shell_cmds/sh/tests/expansion/cmdsubst20.0
new file mode 100644
index 0000000..a92eaac
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/cmdsubst20.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/expansion/cmdsubst20.0 314637 2017-03-03 22:46:20Z jilles $
+
+set -T
+trapped=''
+trap "trapped=x$trapped" USR1
+[ "x$(kill -USR1 $$)y" = xy ] && [ "$trapped" = x ]
diff --git a/shell_cmds/sh/tests/expansion/cmdsubst21.0 b/shell_cmds/sh/tests/expansion/cmdsubst21.0
new file mode 100644
index 0000000..02f938f
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/cmdsubst21.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/expansion/cmdsubst21.0 314686 2017-03-04 22:58:34Z jilles $
+
+set -T
+trapped=''
+trap "trapped=x$trapped" TERM
+[ "x$($SH -c "kill $$")y" = xy ] && [ "$trapped" = x ]
diff --git a/shell_cmds/sh/tests/expansion/cmdsubst22.0 b/shell_cmds/sh/tests/expansion/cmdsubst22.0
new file mode 100644
index 0000000..b33f6d5
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/cmdsubst22.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/expansion/cmdsubst22.0 314686 2017-03-04 22:58:34Z jilles $
+
+set -T
+trapped=''
+trap "trapped=x$trapped" TERM
+[ "x$(:; kill $$)y" = xy ] && [ "$trapped" = x ]
diff --git a/shell_cmds/sh/tests/expansion/cmdsubst23.0 b/shell_cmds/sh/tests/expansion/cmdsubst23.0
new file mode 100644
index 0000000..54b087e
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/cmdsubst23.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/expansion/cmdsubst23.0 315005 2017-03-10 16:04:00Z jilles $
+
+unset n
+x=abcd
+[ "X${n#$(echo a)}X${x#$(echo ab)}X$(echo abc)X" = XXcdXabcX ]
diff --git a/shell_cmds/sh/tests/expansion/cmdsubst24.0 b/shell_cmds/sh/tests/expansion/cmdsubst24.0
new file mode 100644
index 0000000..60da04a
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/cmdsubst24.0
@@ -0,0 +1,24 @@
+# $FreeBSD: head/bin/sh/tests/expansion/cmdsubst24.0 317347 2017-04-23 21:58:17Z jilles $
+# POSIX leaves the effect of NUL bytes in command substitution output
+# unspecified but we have always discarded them.
+
+failures=0
+
+check() {
+ if [ "$2" != "$3" ]; then
+ printf "Failed at line %s: got \"%s\" expected \"%s\"\n" "$1" "$2" "$3"
+ : $((failures += 1))
+ fi
+}
+
+fmt='\0a\0 \0b\0c d\0'
+assign_builtin=$(printf "$fmt")
+check "$LINENO" "$assign_builtin" "a bc d"
+assign_pipeline=$(printf "$fmt" | cat)
+check "$LINENO" "$assign_pipeline" "a bc d"
+set -- $(printf "$fmt") $(printf "$fmt" | cat) "$(printf "$fmt")" "$(printf "$fmt" | cat)"
+IFS=@
+splits="$*"
+check "$LINENO" "$splits" "a@bc@d@a@bc@d@a bc d@a bc d"
+
+[ "$failures" = 0 ]
diff --git a/shell_cmds/sh/tests/expansion/cmdsubst25.0 b/shell_cmds/sh/tests/expansion/cmdsubst25.0
new file mode 100644
index 0000000..0654847
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/cmdsubst25.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/expansion/cmdsubst25.0 317514 2017-04-27 18:52:18Z jilles $
+
+IFS=' '
+set -- `printf '\n '`
+IFS=:
+[ "$*" = '
+' ]
diff --git a/shell_cmds/sh/tests/expansion/cmdsubst26.0 b/shell_cmds/sh/tests/expansion/cmdsubst26.0
new file mode 100644
index 0000000..c0d600a
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/cmdsubst26.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/expansion/cmdsubst26.0 317514 2017-04-27 18:52:18Z jilles $
+
+nl='
+'
+v=$nl`printf '\n'`
+[ "$v" = "$nl" ]
diff --git a/shell_cmds/sh/tests/expansion/cmdsubst3.0 b/shell_cmds/sh/tests/expansion/cmdsubst3.0
new file mode 100644
index 0000000..221b11b
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/cmdsubst3.0
@@ -0,0 +1,23 @@
+# $FreeBSD: head/bin/sh/tests/expansion/cmdsubst3.0 218819 2011-02-18 20:37:09Z jilles $
+
+unset LC_ALL
+export LC_CTYPE=en_US.ISO8859-1
+
+e=
+for i in 0 1 2 3; do
+ for j in 0 1 2 3 4 5 6 7; do
+ for k in 0 1 2 3 4 5 6 7; do
+ case $i$j$k in
+ 000) continue ;;
+ esac
+ e="$e\n\\$i$j$k"
+ done
+ done
+done
+e1=$(printf "$e")
+e2="$(printf "$e")"
+[ "${#e1}" = 510 ] || echo length bad
+[ "$e1" = "$e2" ] || echo e1 != e2
+[ "$e1" = "$(printf "$e")" ] || echo quoted bad
+IFS=
+[ "$e1" = $(printf "$e") ] || echo unquoted bad
diff --git a/shell_cmds/sh/tests/expansion/cmdsubst4.0 b/shell_cmds/sh/tests/expansion/cmdsubst4.0
new file mode 100644
index 0000000..4d5a134
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/cmdsubst4.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/expansion/cmdsubst4.0 216747 2010-12-27 23:56:03Z jilles $
+
+exec 2>/dev/null
+! y=$(: </var/empty/nonexistent)
diff --git a/shell_cmds/sh/tests/expansion/cmdsubst5.0 b/shell_cmds/sh/tests/expansion/cmdsubst5.0
new file mode 100644
index 0000000..70b4298
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/cmdsubst5.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/expansion/cmdsubst5.0 216761 2010-12-28 13:28:24Z jilles $
+
+unset v
+exec 2>/dev/null
+! y=$(: ${v?})
diff --git a/shell_cmds/sh/tests/expansion/cmdsubst6.0 b/shell_cmds/sh/tests/expansion/cmdsubst6.0
new file mode 100644
index 0000000..0e47bce
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/cmdsubst6.0
@@ -0,0 +1,53 @@
+# $FreeBSD: head/bin/sh/tests/expansion/cmdsubst6.0 216763 2010-12-28 14:58:08Z jilles $
+# This tests if the cmdsubst optimization is still used if possible.
+
+failures=''
+ok=''
+
+testcase() {
+ code="$1"
+
+ unset v
+ eval "pid=\$(dummy=$code echo \$(\$SH -c echo\ \\\$PPID))"
+
+ if [ "$pid" = "$$" ]; then
+ ok=x$ok
+ else
+ failures=x$failures
+ echo "Failure for $code"
+ fi
+}
+
+unset v
+w=1
+testcase '$w'
+testcase '1${w+1}'
+testcase '1${w-1}'
+testcase '1${v+1}'
+testcase '1${v-1}'
+testcase '1${w:+1}'
+testcase '1${w:-1}'
+testcase '1${v:+1}'
+testcase '1${v:-1}'
+testcase '${w?}'
+testcase '${w:?}'
+testcase '${w#x}'
+testcase '${w##x}'
+testcase '${w%x}'
+testcase '${w%%x}'
+
+testcase '$((w))'
+testcase '$(((w+4)*2/3))'
+testcase '$((w==1))'
+testcase '$((w>=0 && w<=5 && w!=2))'
+testcase '$((${#w}))'
+testcase '$((${#IFS}))'
+testcase '$((${#w}>=1))'
+testcase '$(($$))'
+testcase '$(($#))'
+testcase '$(($?))'
+
+testcase '$(: $((w=4)))'
+testcase '$(: ${v=2})'
+
+test "x$failures" = x
diff --git a/shell_cmds/sh/tests/expansion/cmdsubst7.0 b/shell_cmds/sh/tests/expansion/cmdsubst7.0
new file mode 100644
index 0000000..6b4cd1d
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/cmdsubst7.0
@@ -0,0 +1,31 @@
+# $FreeBSD: head/bin/sh/tests/expansion/cmdsubst7.0 216778 2010-12-28 21:27:08Z jilles $
+
+failures=''
+ok=''
+
+testcase() {
+ code="$1"
+
+ unset v
+ eval ": \$($code)"
+
+ if [ "${v:+bad}" = "" ]; then
+ ok=x$ok
+ else
+ failures=x$failures
+ echo "Failure for $code"
+ fi
+}
+
+testcase ': ${v=0}'
+testcase ': ${v:=0}'
+testcase ': $((v=1))'
+testcase ': $((v+=1))'
+w='v=1'
+testcase ': $(($w))'
+testcase ': $((${$+v=1}))'
+testcase ': $((v${$+=1}))'
+testcase ': $((v $(echo =) 1))'
+testcase ': $(($(echo $w)))'
+
+test "x$failures" = x
diff --git a/shell_cmds/sh/tests/expansion/cmdsubst8.0 b/shell_cmds/sh/tests/expansion/cmdsubst8.0
new file mode 100644
index 0000000..19ff803
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/cmdsubst8.0
@@ -0,0 +1,17 @@
+# $FreeBSD: head/bin/sh/tests/expansion/cmdsubst8.0 216819 2010-12-30 15:04:59Z jilles $
+# Not required by POSIX (although referenced in a non-normative section),
+# but possibly useful.
+
+: hi there &
+p=$!
+q=$(jobs -l $p)
+
+# Change tabs to spaces.
+set -f
+set -- $q
+r="$*"
+
+case $r in
+*" $p "*) ;;
+*) echo Pid missing; exit 3 ;;
+esac
diff --git a/shell_cmds/sh/tests/expansion/cmdsubst9.0 b/shell_cmds/sh/tests/expansion/cmdsubst9.0
new file mode 100644
index 0000000..8bbf2b9
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/cmdsubst9.0
@@ -0,0 +1,11 @@
+# $FreeBSD: head/bin/sh/tests/expansion/cmdsubst9.0 216819 2010-12-30 15:04:59Z jilles $
+
+set -e
+
+cd /
+dummy=$(cd /bin)
+[ "$(pwd)" = / ]
+
+v=1
+dummy=$(eval v=2)
+[ "$v" = 1 ]
diff --git a/shell_cmds/sh/tests/expansion/export1.0 b/shell_cmds/sh/tests/expansion/export1.0
new file mode 100644
index 0000000..3286fb9
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/export1.0
@@ -0,0 +1,13 @@
+# $FreeBSD: head/bin/sh/tests/expansion/export1.0 238430 2012-07-13 22:29:02Z jilles $
+
+w='@ vv=6'
+
+v=0 vv=0
+export \v=$w
+[ "$v" = "@" ] || echo "Expected @ got $v"
+[ "$vv" = "6" ] || echo "Expected 6 got $vv"
+
+HOME=/known/value
+
+export \v=~
+[ "$v" = \~ ] || echo "Expected ~ got $v"
diff --git a/shell_cmds/sh/tests/expansion/export2.0 b/shell_cmds/sh/tests/expansion/export2.0
new file mode 100644
index 0000000..e8862b8
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/export2.0
@@ -0,0 +1,24 @@
+# $FreeBSD: head/bin/sh/tests/expansion/export2.0 238468 2012-07-15 10:19:43Z jilles $
+
+w='@ @'
+check() {
+ [ "$v" = "$w" ] || echo "Expected $w got $v"
+}
+
+export v=$w
+check
+
+HOME=/known/value
+check() {
+ [ "$v" = ~ ] || echo "Expected $HOME got $v"
+}
+
+export v=~
+check
+
+check() {
+ [ "$v" = "x:$HOME" ] || echo "Expected x:$HOME got $v"
+}
+
+export v=x:~
+check
diff --git a/shell_cmds/sh/tests/expansion/export3.0 b/shell_cmds/sh/tests/expansion/export3.0
new file mode 100644
index 0000000..b82fcc1
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/export3.0
@@ -0,0 +1,30 @@
+# $FreeBSD: head/bin/sh/tests/expansion/export3.0 238468 2012-07-15 10:19:43Z jilles $
+
+w='@ @'
+check() {
+ [ "$v" = "$w" ] || echo "Expected $w got $v"
+}
+
+command export v=$w
+check
+command command export v=$w
+check
+
+HOME=/known/value
+check() {
+ [ "$v" = ~ ] || echo "Expected $HOME got $v"
+}
+
+command export v=~
+check
+command command export v=~
+check
+
+check() {
+ [ "$v" = "x:$HOME" ] || echo "Expected x:$HOME got $v"
+}
+
+command export v=x:~
+check
+command command export v=x:~
+check
diff --git a/shell_cmds/sh/tests/expansion/heredoc1.0 b/shell_cmds/sh/tests/expansion/heredoc1.0
new file mode 100644
index 0000000..94328c0
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/heredoc1.0
@@ -0,0 +1,25 @@
+# $FreeBSD: head/bin/sh/tests/expansion/heredoc1.0 222715 2011-06-05 12:46:26Z jilles $
+
+f() { return $1; }
+
+[ `f 42; { cat; } <<EOF
+$?
+EOF
+` = 42 ] || echo compound command bad
+
+[ `f 42; (cat) <<EOF
+$?
+EOF
+` = 42 ] || echo subshell bad
+
+long=`printf %08192d 0`
+
+[ `f 42; { cat; } <<EOF
+$long.$?
+EOF
+` = $long.42 ] || echo long compound command bad
+
+[ `f 42; (cat) <<EOF
+$long.$?
+EOF
+` = $long.42 ] || echo long subshell bad
diff --git a/shell_cmds/sh/tests/expansion/heredoc2.0 b/shell_cmds/sh/tests/expansion/heredoc2.0
new file mode 100644
index 0000000..24c4cc6
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/heredoc2.0
@@ -0,0 +1,15 @@
+# $FreeBSD: head/bin/sh/tests/expansion/heredoc2.0 222716 2011-06-05 14:13:15Z jilles $
+
+f() { return $1; }
+
+[ `f 42; cat <<EOF
+$?
+EOF
+` = 42 ] || echo simple command bad
+
+long=`printf %08192d 0`
+
+[ `f 42; cat <<EOF
+$long.$?
+EOF
+` = $long.42 ] || echo long simple command bad
diff --git a/shell_cmds/sh/tests/expansion/ifs1.0 b/shell_cmds/sh/tests/expansion/ifs1.0
new file mode 100644
index 0000000..4d5157a
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/ifs1.0
@@ -0,0 +1,35 @@
+# $FreeBSD: head/bin/sh/tests/expansion/ifs1.0 194981 2009-06-25 17:36:08Z jilles $
+
+c=: e= s=' '
+failures=''
+ok=''
+
+check_result() {
+ if [ "x$2" = "x$3" ]; then
+ ok=x$ok
+ else
+ failures=x$failures
+ echo "For $1, expected $3 actual $2"
+ fi
+}
+
+IFS='
+'
+set -- a ''
+set -- "$@"
+check_result 'set -- "$@"' "($#)($1)($2)" "(2)(a)()"
+
+set -- a ''
+set -- "$@"$e
+check_result 'set -- "$@"$e' "($#)($1)($2)" "(2)(a)()"
+
+set -- a ''
+set -- "$@"$s
+check_result 'set -- "$@"$s' "($#)($1)($2)" "(2)(a)()"
+
+IFS="$c"
+set -- a ''
+set -- "$@"$c
+check_result 'set -- "$@"$c' "($#)($1)($2)" "(2)(a)()"
+
+test "x$failures" = x
diff --git a/shell_cmds/sh/tests/expansion/ifs2.0 b/shell_cmds/sh/tests/expansion/ifs2.0
new file mode 100644
index 0000000..3d71b52
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/ifs2.0
@@ -0,0 +1,24 @@
+# $FreeBSD: head/bin/sh/tests/expansion/ifs2.0 211341 2010-08-15 17:14:05Z jilles $
+
+failures=0
+i=1
+set -f
+while [ "$i" -le 127 ]; do
+ # A different byte still in the range 1..127.
+ i2=$((i^2+(i==2)))
+ # Add a character to work around command substitution's removal of
+ # final newlines, then remove it again.
+ c=$(printf \\"$(printf %o@ "$i")")
+ c=${c%@}
+ c2=$(printf \\"$(printf %o@ "$i2")")
+ c2=${c2%@}
+ IFS=$c
+ set -- $c2$c$c2$c$c2
+ if [ "$#" -ne 3 ] || [ "$1" != "$c2" ] || [ "$2" != "$c2" ] ||
+ [ "$3" != "$c2" ]; then
+ echo "Bad results for separator $i (word $i2)" >&2
+ : $((failures += 1))
+ fi
+ i=$((i+1))
+done
+exit $((failures > 0))
diff --git a/shell_cmds/sh/tests/expansion/ifs3.0 b/shell_cmds/sh/tests/expansion/ifs3.0
new file mode 100644
index 0000000..d034654
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/ifs3.0
@@ -0,0 +1,21 @@
+# $FreeBSD: head/bin/sh/tests/expansion/ifs3.0 211622 2010-08-22 13:09:12Z jilles $
+
+failures=0
+unset LC_ALL
+export LC_CTYPE=en_US.ISO8859-1
+i=128
+set -f
+while [ "$i" -le 255 ]; do
+ i2=$((i^2))
+ c=$(printf \\"$(printf %o "$i")")
+ c2=$(printf \\"$(printf %o "$i2")")
+ IFS=$c
+ set -- $c2$c$c2$c$c2
+ if [ "$#" -ne 3 ] || [ "$1" != "$c2" ] || [ "$2" != "$c2" ] ||
+ [ "$3" != "$c2" ]; then
+ echo "Bad results for separator $i (word $i2)" >&2
+ : $((failures += 1))
+ fi
+ i=$((i+1))
+done
+exit $((failures > 0))
diff --git a/shell_cmds/sh/tests/expansion/ifs4.0 b/shell_cmds/sh/tests/expansion/ifs4.0
new file mode 100644
index 0000000..a307ec5
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/ifs4.0
@@ -0,0 +1,39 @@
+# $FreeBSD: head/bin/sh/tests/expansion/ifs4.0 222361 2011-05-27 15:56:13Z jilles $
+
+c=: e= s=' '
+failures=''
+ok=''
+
+check_result() {
+ if [ "x$2" = "x$3" ]; then
+ ok=x$ok
+ else
+ failures=x$failures
+ echo "For $1, expected $3 actual $2"
+ fi
+}
+
+IFS='
+'
+set -- a b '' c
+set -- $@
+check_result 'set -- $@' "($#)($1)($2)($3)($4)" "(3)(a)(b)(c)()"
+
+IFS=''
+set -- a b '' c
+set -- $@
+check_result 'set -- $@' "($#)($1)($2)($3)($4)" "(3)(a)(b)(c)()"
+
+set -- a b '' c
+set -- $*
+check_result 'set -- $*' "($#)($1)($2)($3)($4)" "(3)(a)(b)(c)()"
+
+set -- a b '' c
+set -- "$@"
+check_result 'set -- "$@"' "($#)($1)($2)($3)($4)" "(4)(a)(b)()(c)"
+
+set -- a b '' c
+set -- "$*"
+check_result 'set -- "$*"' "($#)($1)($2)($3)($4)" "(1)(abc)()()()"
+
+test "x$failures" = x
diff --git a/shell_cmds/sh/tests/expansion/ifs5.0 b/shell_cmds/sh/tests/expansion/ifs5.0
new file mode 100644
index 0000000..fc5b4b7
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/ifs5.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/expansion/ifs5.0 278806 2015-02-15 19:48:29Z jilles $
+
+set -- $(echo a b c d)
+[ "$#" = 4 ]
diff --git a/shell_cmds/sh/tests/expansion/ifs6.0 b/shell_cmds/sh/tests/expansion/ifs6.0
new file mode 100644
index 0000000..3ec5dbc
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/ifs6.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/expansion/ifs6.0 280920 2015-03-31 20:59:37Z jilles $
+
+IFS=': '
+x=': :'
+set -- $x
+[ "$#|$1|$2|$3" = "2|||" ]
diff --git a/shell_cmds/sh/tests/expansion/ifs7.0 b/shell_cmds/sh/tests/expansion/ifs7.0
new file mode 100644
index 0000000..a59f313
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/ifs7.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/expansion/ifs7.0 280920 2015-03-31 20:59:37Z jilles $
+
+IFS=2
+set -- $((123))
+[ "$#|$1|$2|$3" = "2|1|3|" ]
diff --git a/shell_cmds/sh/tests/expansion/length1.0 b/shell_cmds/sh/tests/expansion/length1.0
new file mode 100644
index 0000000..cee5808
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/length1.0
@@ -0,0 +1,12 @@
+# $FreeBSD: head/bin/sh/tests/expansion/length1.0 219611 2011-03-13 16:20:38Z jilles $
+
+v=abcd
+[ "${#v}" = 4 ] || echo '${#v} wrong'
+v=$$
+[ "${#$}" = "${#v}" ] || echo '${#$} wrong'
+[ "${#!}" = 0 ] || echo '${#!} wrong'
+set -- 01 2 3 4 5 6 7 8 9 10 11 12 0013
+[ "${#1}" = 2 ] || echo '${#1} wrong'
+[ "${#13}" = 4 ] || echo '${#13} wrong'
+v=$0
+[ "${#0}" = "${#v}" ] || echo '${#0} wrong'
diff --git a/shell_cmds/sh/tests/expansion/length2.0 b/shell_cmds/sh/tests/expansion/length2.0
new file mode 100644
index 0000000..77fd6ad
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/length2.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/expansion/length2.0 219611 2011-03-13 16:20:38Z jilles $
+
+v=$-
+[ "${#-}" = "${#v}" ] || echo '${#-} wrong'
diff --git a/shell_cmds/sh/tests/expansion/length3.0 b/shell_cmds/sh/tests/expansion/length3.0
new file mode 100644
index 0000000..27045b7
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/length3.0
@@ -0,0 +1,10 @@
+# $FreeBSD: head/bin/sh/tests/expansion/length3.0 219611 2011-03-13 16:20:38Z jilles $
+
+set -- 1 2 3 4 5 6 7 8 9 10 11 12 13
+[ "$#" = 13 ] || echo '$# wrong'
+[ "${#}" = 13 ] || echo '${#} wrong'
+[ "${##}" = 2 ] || echo '${##} wrong'
+set --
+[ "$#" = 0 ] || echo '$# wrong'
+[ "${#}" = 0 ] || echo '${#} wrong'
+[ "${##}" = 1 ] || echo '${##} wrong'
diff --git a/shell_cmds/sh/tests/expansion/length4.0 b/shell_cmds/sh/tests/expansion/length4.0
new file mode 100644
index 0000000..c1ff021
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/length4.0
@@ -0,0 +1,11 @@
+# $FreeBSD: head/bin/sh/tests/expansion/length4.0 220655 2011-04-15 15:26:05Z jilles $
+
+# The construct ${#?} is ambiguous in POSIX.1-2008: it could be the length
+# of $? or it could be $# giving an error in the (impossible) case that it
+# is not set.
+# We use the former interpretation; it seems more useful.
+
+:
+[ "${#?}" = 1 ] || echo '${#?} wrong'
+(exit 42)
+[ "${#?}" = 2 ] || echo '${#?} wrong'
diff --git a/shell_cmds/sh/tests/expansion/length5.0 b/shell_cmds/sh/tests/expansion/length5.0
new file mode 100644
index 0000000..da8ebb5
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/length5.0
@@ -0,0 +1,27 @@
+# $FreeBSD: head/bin/sh/tests/expansion/length5.0 220656 2011-04-15 15:33:24Z jilles $
+
+unset LC_ALL
+LC_CTYPE=en_US.ISO8859-1
+export LC_CTYPE
+
+e=
+for i in 0 1 2 3; do
+ for j in 0 1 2 3 4 5 6 7; do
+ for k in 0 1 2 3 4 5 6 7; do
+ case $i$j$k in
+ 000) continue ;;
+ esac
+ e="$e\\$i$j$k"
+ done
+ done
+done
+ee=`printf "$e"`
+[ ${#ee} = 255 ] || echo bad 1
+[ "${#ee}" = 255 ] || echo bad 2
+[ $((${#ee})) = 255 ] || echo bad 3
+[ "$((${#ee}))" = 255 ] || echo bad 4
+set -- "$ee"
+[ ${#1} = 255 ] || echo bad 5
+[ "${#1}" = 255 ] || echo bad 6
+[ $((${#1})) = 255 ] || echo bad 7
+[ "$((${#1}))" = 255 ] || echo bad 8
diff --git a/shell_cmds/sh/tests/expansion/length6.0 b/shell_cmds/sh/tests/expansion/length6.0
new file mode 100644
index 0000000..8da2da8
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/length6.0
@@ -0,0 +1,8 @@
+# $FreeBSD: head/bin/sh/tests/expansion/length6.0 220903 2011-04-20 22:24:54Z jilles $
+
+x='!@#$%^&*()[]'
+[ ${#x} = 12 ] || echo bad 1
+[ "${#x}" = 12 ] || echo bad 2
+IFS=2
+[ ${#x} = 1 ] || echo bad 3
+[ "${#x}" = 12 ] || echo bad 4
diff --git a/shell_cmds/sh/tests/expansion/length7.0 b/shell_cmds/sh/tests/expansion/length7.0
new file mode 100644
index 0000000..500b7e7
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/length7.0
@@ -0,0 +1,14 @@
+# $FreeBSD: head/bin/sh/tests/expansion/length7.0 221602 2011-05-07 14:32:16Z jilles $
+
+unset LC_ALL
+LC_CTYPE=en_US.UTF-8
+export LC_CTYPE
+
+# a umlaut
+s=$(printf '\303\244')
+# euro sign
+s=$s$(printf '\342\202\254')
+# some sort of 't' outside BMP
+s=$s$(printf '\360\235\225\245')
+set -- "$s"
+[ ${#s} = 3 ] && [ ${#1} = 3 ]
diff --git a/shell_cmds/sh/tests/expansion/length8.0 b/shell_cmds/sh/tests/expansion/length8.0
new file mode 100644
index 0000000..d4f91d8
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/length8.0
@@ -0,0 +1,14 @@
+# $FreeBSD: head/bin/sh/tests/expansion/length8.0 221602 2011-05-07 14:32:16Z jilles $
+
+unset LC_ALL
+LC_CTYPE=en_US.ISO8859-1
+export LC_CTYPE
+
+# a umlaut
+s=$(printf '\303\244')
+# euro sign
+s=$s$(printf '\342\202\254')
+# some sort of 't' outside BMP
+s=$s$(printf '\360\235\225\245')
+set -- "$s"
+[ ${#s} = 9 ] && [ ${#1} = 9 ]
diff --git a/shell_cmds/sh/tests/expansion/local1.0 b/shell_cmds/sh/tests/expansion/local1.0
new file mode 100644
index 0000000..9f16eb0
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/local1.0
@@ -0,0 +1,28 @@
+# $FreeBSD: head/bin/sh/tests/expansion/local1.0 238468 2012-07-15 10:19:43Z jilles $
+
+run_test() {
+ w='@ @'
+ check() {
+ [ "$v" = "$w" ] || echo "Expected $w got $v"
+ }
+
+ local v=$w
+ check
+
+ HOME=/known/value
+ check() {
+ [ "$v" = ~ ] || echo "Expected $HOME got $v"
+ }
+
+ local v=~
+ check
+
+ check() {
+ [ "$v" = "x:$HOME" ] || echo "Expected x:$HOME got $v"
+ }
+
+ local v=x:~
+ check
+}
+
+run_test
diff --git a/shell_cmds/sh/tests/expansion/local2.0 b/shell_cmds/sh/tests/expansion/local2.0
new file mode 100644
index 0000000..9d1a38a
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/local2.0
@@ -0,0 +1,34 @@
+# $FreeBSD: head/bin/sh/tests/expansion/local2.0 238468 2012-07-15 10:19:43Z jilles $
+
+run_test() {
+ w='@ @'
+ check() {
+ [ "$v" = "$w" ] || echo "Expected $w got $v"
+ }
+
+ command local v=$w
+ check
+ command command local v=$w
+ check
+
+ HOME=/known/value
+ check() {
+ [ "$v" = ~ ] || echo "Expected $HOME got $v"
+ }
+
+ command local v=~
+ check
+ command command local v=~
+ check
+
+ check() {
+ [ "$v" = "x:$HOME" ] || echo "Expected x:$HOME got $v"
+ }
+
+ command local v=x:~
+ check
+ command command local v=x:~
+ check
+}
+
+run_test
diff --git a/shell_cmds/sh/tests/expansion/pathname1.0 b/shell_cmds/sh/tests/expansion/pathname1.0
new file mode 100644
index 0000000..6f40004
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/pathname1.0
@@ -0,0 +1,65 @@
+# $FreeBSD: head/bin/sh/tests/expansion/pathname1.0 302937 2016-07-16 13:26:18Z ache $
+
+unset LC_ALL
+LC_COLLATE=C
+export LC_COLLATE
+
+failures=0
+
+check() {
+ testcase=$1
+ expect=$2
+ eval "set -- $testcase"
+ actual="$*"
+ if [ "$actual" != "$expect" ]; then
+ failures=$((failures+1))
+ printf '%s\n' "For $testcase, expected $expect actual $actual"
+ fi
+}
+
+set -e
+T=$(mktemp -d ${TMPDIR:-/tmp}/sh-test.XXXXXX)
+trap 'rm -rf $T' 0
+cd -P $T
+
+mkdir testdir testdir2 'testdir/*' 'testdir/?' testdir/a testdir/b testdir2/b
+mkdir testdir2/.c
+touch testf 'testdir/*/1' 'testdir/?/1' testdir/a/1 testdir/b/1 testdir2/b/.a
+
+check '' ''
+check 'testdir/b' 'testdir/b'
+check 'testdir/c' 'testdir/c'
+check '\*' '*'
+check '\?' '?'
+check '*' 'testdir testdir2 testf'
+check '*""' 'testdir testdir2 testf'
+check '""*' 'testdir testdir2 testf'
+check '*/' 'testdir/ testdir2/'
+check 'testdir*/a' 'testdir/a'
+check 'testdir*/b' 'testdir/b testdir2/b'
+check '*/.c' 'testdir2/.c'
+check 'testdir2/*' 'testdir2/b'
+check 'testdir2/b/*' 'testdir2/b/*'
+check 'testdir/*' 'testdir/* testdir/? testdir/a testdir/b'
+check 'testdir/*/1' 'testdir/*/1 testdir/?/1 testdir/a/1 testdir/b/1'
+check '"testdir/"*/1' 'testdir/*/1 testdir/?/1 testdir/a/1 testdir/b/1'
+check 'testdir/\*/*' 'testdir/*/1'
+check 'testdir/\?/*' 'testdir/?/1'
+check 'testdir/"?"/*' 'testdir/?/1'
+check '"testdir"/"?"/*' 'testdir/?/1'
+check '"testdir"/"?"*/*' 'testdir/?/1'
+check '"testdir"/*"?"/*' 'testdir/?/1'
+check '"testdir/?"*/*' 'testdir/?/1'
+check 'testdir/\*/' 'testdir/*/'
+check 'testdir/\?/' 'testdir/?/'
+check 'testdir/"?"/' 'testdir/?/'
+check '"testdir"/"?"/' 'testdir/?/'
+check '"testdir"/"?"*/' 'testdir/?/'
+check '"testdir"/*"?"/' 'testdir/?/'
+check '"testdir/?"*/' 'testdir/?/'
+check 'testdir/[*]/' 'testdir/*/'
+check 'testdir/[?]/' 'testdir/?/'
+check 'testdir/[*?]/' 'testdir/*/ testdir/?/'
+check '[tz]estdir/[*]/' 'testdir/*/'
+
+exit $((failures != 0))
diff --git a/shell_cmds/sh/tests/expansion/pathname2.0 b/shell_cmds/sh/tests/expansion/pathname2.0
new file mode 100644
index 0000000..3efffb7
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/pathname2.0
@@ -0,0 +1,35 @@
+# $FreeBSD: head/bin/sh/tests/expansion/pathname2.0 302937 2016-07-16 13:26:18Z ache $
+
+unset LC_ALL
+LC_COLLATE=C
+export LC_COLLATE
+
+failures=0
+
+check() {
+ testcase=$1
+ expect=$2
+ eval "set -- $testcase"
+ actual="$*"
+ if [ "$actual" != "$expect" ]; then
+ failures=$((failures+1))
+ printf '%s\n' "For $testcase, expected $expect actual $actual"
+ fi
+}
+
+set -e
+T=$(mktemp -d ${TMPDIR:-/tmp}/sh-test.XXXXXX)
+trap 'rm -rf $T' 0
+cd -P $T
+
+mkdir testdir testdir2 'testdir/*' 'testdir/?' testdir/a testdir/b testdir2/b
+mkdir testdir2/.c
+touch testf 'testdir/*/1' 'testdir/?/1' testdir/a/1 testdir/b/1 testdir2/b/.a
+
+check '*\/' 'testdir/ testdir2/'
+check '"testdir/"*"/1"' 'testdir/*/1 testdir/?/1 testdir/a/1 testdir/b/1'
+check '"testdir/"*"/"*' 'testdir/*/1 testdir/?/1 testdir/a/1 testdir/b/1'
+check '"testdir/"*\/*' 'testdir/*/1 testdir/?/1 testdir/a/1 testdir/b/1'
+check '"testdir"*"/"*"/"*' 'testdir/*/1 testdir/?/1 testdir/a/1 testdir/b/1'
+
+exit $((failures != 0))
diff --git a/shell_cmds/sh/tests/expansion/pathname3.0 b/shell_cmds/sh/tests/expansion/pathname3.0
new file mode 100644
index 0000000..80d6478
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/pathname3.0
@@ -0,0 +1,29 @@
+# $FreeBSD: head/bin/sh/tests/expansion/pathname3.0 211155 2010-08-10 22:45:59Z jilles $
+
+v=12345678
+v=$v$v$v$v
+v=$v$v$v$v
+v=$v$v$v$v
+v=$v$v$v$v
+v=$v$v$v$v
+# 8192 bytes
+v=${v##???}
+[ /*/$v = "/*/$v" ] || exit 1
+
+s=////
+s=$s$s$s$s
+s=$s$s$s$s
+s=$s$s$s$s
+s=$s$s$s$s
+# 1024 bytes
+s=${s##??????????}
+[ /var/empt[y]/$s/$v = "/var/empt[y]/$s/$v" ] || exit 2
+while [ ${#s} -lt 1034 ]; do
+ set -- /.${s}et[c]
+ [ ${#s} -gt 1018 ] || [ "$1" = /.${s}etc ] || exit 3
+ set -- /.${s}et[c]/
+ [ ${#s} -gt 1017 ] || [ "$1" = /.${s}etc/ ] || exit 4
+ set -- /.${s}et[c]/.
+ [ ${#s} -gt 1016 ] || [ "$1" = /.${s}etc/. ] || exit 5
+ s=$s/
+done
diff --git a/shell_cmds/sh/tests/expansion/pathname4.0 b/shell_cmds/sh/tests/expansion/pathname4.0
new file mode 100644
index 0000000..d316c0a
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/pathname4.0
@@ -0,0 +1,28 @@
+# $FreeBSD: head/bin/sh/tests/expansion/pathname4.0 211646 2010-08-22 21:18:21Z jilles $
+
+failures=0
+
+check() {
+ testcase=$1
+ expect=$2
+ eval "set -- $testcase"
+ actual="$*"
+ if [ "$actual" != "$expect" ]; then
+ failures=$((failures+1))
+ printf '%s\n' "For $testcase, expected $expect actual $actual"
+ fi
+}
+
+set -e
+T=$(mktemp -d ${TMPDIR:-/tmp}/sh-test.XXXXXX)
+trap 'rm -rf $T' 0
+cd -P $T
+
+mkdir !!a
+touch !!a/fff
+
+chmod u-r .
+check '!!a/ff*' '!!a/fff'
+chmod u+r .
+
+exit $((failures != 0))
diff --git a/shell_cmds/sh/tests/expansion/pathname5.0 b/shell_cmds/sh/tests/expansion/pathname5.0
new file mode 100644
index 0000000..42cd119
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/pathname5.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/expansion/pathname5.0 278806 2015-02-15 19:48:29Z jilles $
+
+[ `echo '/[e]tc'` = /etc ]
diff --git a/shell_cmds/sh/tests/expansion/pathname6.0 b/shell_cmds/sh/tests/expansion/pathname6.0
new file mode 100644
index 0000000..e763c6a
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/pathname6.0
@@ -0,0 +1,29 @@
+# $FreeBSD: head/bin/sh/tests/expansion/pathname6.0 302937 2016-07-16 13:26:18Z ache $
+
+unset LC_ALL
+LC_COLLATE=en_US.US-ASCII
+export LC_COLLATE
+
+failures=0
+
+check() {
+ testcase=$1
+ expect=$2
+ eval "set -- $testcase"
+ actual="$*"
+ if [ "$actual" != "$expect" ]; then
+ failures=$((failures+1))
+ printf '%s\n' "For $testcase, expected $expect actual $actual"
+ fi
+}
+
+set -e
+T=$(mktemp -d ${TMPDIR:-/tmp}/sh-test.XXXXXX)
+trap 'rm -rf $T' 0
+cd -P $T
+
+touch A B a b
+
+check '*' 'a A b B'
+
+exit $((failures != 0))
diff --git a/shell_cmds/sh/tests/expansion/plus-minus1.0 b/shell_cmds/sh/tests/expansion/plus-minus1.0
new file mode 100644
index 0000000..088ed7f
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/plus-minus1.0
@@ -0,0 +1,76 @@
+# $FreeBSD: head/bin/sh/tests/expansion/plus-minus1.0 216738 2010-12-27 15:57:41Z emaste $
+
+e= q='?' a='*' t=texttext s='ast*que?non' p='/et[c]/' w='a b c' b='{{(#)}}'
+h='##'
+failures=''
+ok=''
+
+testcase() {
+ code="$1"
+ expected="$2"
+ oIFS="$IFS"
+ eval "$code"
+ IFS='|'
+ result="$#|$*"
+ IFS="$oIFS"
+ if [ "x$result" = "x$expected" ]; then
+ ok=x$ok
+ else
+ failures=x$failures
+ echo "For $code, expected $expected actual $result"
+ fi
+}
+
+testcase 'set -- a b' '2|a|b'
+testcase 'set --' '0|'
+testcase 'set -- ${e}' '0|'
+testcase 'set -- "${e}"' '1|'
+
+testcase 'set -- $p' '1|/etc/'
+testcase 'set -- "$p"' '1|/et[c]/'
+testcase 'set -- ${s+$p}' '1|/etc/'
+testcase 'set -- "${s+$p}"' '1|/et[c]/'
+testcase 'set -- ${s+"$p"}' '1|/et[c]/'
+# Dquotes in dquotes is undefined for Bourne shell operators
+#testcase 'set -- "${s+"$p"}"' '1|/et[c]/'
+testcase 'set -- ${e:-$p}' '1|/etc/'
+testcase 'set -- "${e:-$p}"' '1|/et[c]/'
+testcase 'set -- ${e:-"$p"}' '1|/et[c]/'
+# Dquotes in dquotes is undefined for Bourne shell operators
+#testcase 'set -- "${e:-"$p"}"' '1|/et[c]/'
+testcase 'set -- ${e:+"$e"}' '0|'
+testcase 'set -- ${e:+$w"$e"}' '0|'
+testcase 'set -- ${w:+"$w"}' '1|a b c'
+testcase 'set -- ${w:+$w"$w"}' '3|a|b|ca b c'
+
+testcase 'set -- "${s+a b}"' '1|a b'
+testcase 'set -- "${e:-a b}"' '1|a b'
+testcase 'set -- ${e:-\}}' '1|}'
+testcase 'set -- ${e:+{}}' '1|}'
+testcase 'set -- "${e:+{}}"' '1|}'
+
+testcase 'set -- ${e+x}${e+x}' '1|xx'
+testcase 'set -- "${e+x}"${e+x}' '1|xx'
+testcase 'set -- ${e+x}"${e+x}"' '1|xx'
+testcase 'set -- "${e+x}${e+x}"' '1|xx'
+testcase 'set -- "${e+x}""${e+x}"' '1|xx'
+
+testcase 'set -- ${e:-${e:-$p}}' '1|/etc/'
+testcase 'set -- "${e:-${e:-$p}}"' '1|/et[c]/'
+testcase 'set -- ${e:-"${e:-$p}"}' '1|/et[c]/'
+testcase 'set -- ${e:-${e:-"$p"}}' '1|/et[c]/'
+testcase 'set -- ${e:-${e:-${e:-$w}}}' '3|a|b|c'
+testcase 'set -- ${e:-${e:-${e:-"$w"}}}' '1|a b c'
+testcase 'set -- ${e:-${e:-"${e:-$w}"}}' '1|a b c'
+testcase 'set -- ${e:-"${e:-${e:-$w}}"}' '1|a b c'
+testcase 'set -- "${e:-${e:-${e:-$w}}}"' '1|a b c'
+
+testcase 'shift $#; set -- ${1+"$@"}' '0|'
+testcase 'set -- ""; set -- ${1+"$@"}' '1|'
+testcase 'set -- "" a; set -- ${1+"$@"}' '2||a'
+testcase 'set -- a ""; set -- ${1+"$@"}' '2|a|'
+testcase 'set -- a b; set -- ${1+"$@"}' '2|a|b'
+testcase 'set -- a\ b; set -- ${1+"$@"}' '1|a b'
+testcase 'set -- " " ""; set -- ${1+"$@"}' '2| |'
+
+test "x$failures" = x
diff --git a/shell_cmds/sh/tests/expansion/plus-minus2.0 b/shell_cmds/sh/tests/expansion/plus-minus2.0
new file mode 100644
index 0000000..2f22988
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/plus-minus2.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/expansion/plus-minus2.0 206145 2010-04-03 20:55:56Z jilles $
+
+e=
+test "${e:-\}}" = '}'
diff --git a/shell_cmds/sh/tests/expansion/plus-minus3.0 b/shell_cmds/sh/tests/expansion/plus-minus3.0
new file mode 100644
index 0000000..d7fc923
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/plus-minus3.0
@@ -0,0 +1,44 @@
+# $FreeBSD: head/bin/sh/tests/expansion/plus-minus3.0 206817 2010-04-18 22:13:45Z jilles $
+
+e= q='?' a='*' t=texttext s='ast*que?non' p='/et[c]/' w='a b c' b='{{(#)}}'
+h='##'
+failures=''
+ok=''
+
+testcase() {
+ code="$1"
+ expected="$2"
+ oIFS="$IFS"
+ eval "$code"
+ IFS='|'
+ result="$#|$*"
+ IFS="$oIFS"
+ if [ "x$result" = "x$expected" ]; then
+ ok=x$ok
+ else
+ failures=x$failures
+ echo "For $code, expected $expected actual $result"
+ fi
+}
+
+# We follow original ash behaviour for quoted ${var+-=?} expansions:
+# a double-quote in one switches back to unquoted state.
+# This allows expanding a variable as a single word if it is set
+# and substituting multiple words otherwise.
+# It is also close to the Bourne and Korn shells.
+# POSIX leaves this undefined, and various other shells treat
+# such double-quotes as introducing a second level of quoting
+# which does not do much except quoting close braces.
+
+testcase 'set -- "${p+"/et[c]/"}"' '1|/etc/'
+testcase 'set -- "${p-"/et[c]/"}"' '1|/et[c]/'
+testcase 'set -- "${p+"$p"}"' '1|/etc/'
+testcase 'set -- "${p-"$p"}"' '1|/et[c]/'
+testcase 'set -- "${p+"""/et[c]/"}"' '1|/etc/'
+testcase 'set -- "${p-"""/et[c]/"}"' '1|/et[c]/'
+testcase 'set -- "${p+"""$p"}"' '1|/etc/'
+testcase 'set -- "${p-"""$p"}"' '1|/et[c]/'
+testcase 'set -- "${p+"\@"}"' '1|@'
+testcase 'set -- "${p+"'\''/et[c]/'\''"}"' '1|/et[c]/'
+
+test "x$failures" = x
diff --git a/shell_cmds/sh/tests/expansion/plus-minus4.0 b/shell_cmds/sh/tests/expansion/plus-minus4.0
new file mode 100644
index 0000000..4d2d37d
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/plus-minus4.0
@@ -0,0 +1,38 @@
+# $FreeBSD: head/bin/sh/tests/expansion/plus-minus4.0 211080 2010-08-08 17:03:23Z jilles $
+
+# These may be a bit unclear in the POSIX spec or the proposed revisions,
+# and conflict with bash's interpretation, but I think ksh93's interpretation
+# makes most sense. In particular, it makes no sense to me that single-quotes
+# must match but are not removed.
+
+e= q='?' a='*' t=texttext s='ast*que?non' p='/et[c]/' w='a b c' b='{{(#)}}'
+h='##'
+failures=''
+ok=''
+
+testcase() {
+ code="$1"
+ expected="$2"
+ oIFS="$IFS"
+ eval "$code"
+ IFS='|'
+ result="$#|$*"
+ IFS="$oIFS"
+ if [ "x$result" = "x$expected" ]; then
+ ok=x$ok
+ else
+ failures=x$failures
+ echo "For $code, expected $expected actual $result"
+ fi
+}
+
+testcase 'set -- ${e:-'"'"'}'"'"'}' '1|}'
+testcase "set -- \${e:-\\'}" "1|'"
+testcase "set -- \${e:-\\'\\'}" "1|''"
+testcase "set -- \"\${e:-'}\"" "1|'"
+testcase "set -- \"\${e:-'}'}\"" "1|''}"
+testcase "set -- \"\${e:-''}\"" "1|''"
+testcase 'set -- ${e:-\a}' '1|a'
+testcase 'set -- "${e:-\a}"' '1|\a'
+
+test "x$failures" = x
diff --git a/shell_cmds/sh/tests/expansion/plus-minus5.0 b/shell_cmds/sh/tests/expansion/plus-minus5.0
new file mode 100644
index 0000000..02db26c
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/plus-minus5.0
@@ -0,0 +1,31 @@
+# $FreeBSD: head/bin/sh/tests/expansion/plus-minus5.0 214492 2010-10-28 22:34:49Z jilles $
+
+e= q='?' a='*' t=texttext s='ast*que?non' p='/et[c]/' w='a b c' b='{{(#)}}'
+h='##'
+failures=''
+ok=''
+
+testcase() {
+ code="$1"
+ expected="$2"
+ oIFS="$IFS"
+ eval "$code"
+ IFS='|'
+ result="$#|$*"
+ IFS="$oIFS"
+ if [ "x$result" = "x$expected" ]; then
+ ok=x$ok
+ else
+ failures=x$failures
+ echo "For $code, expected $expected actual $result"
+ fi
+}
+
+testcase 'set -- ${e:-"{x}"}' '1|{x}'
+testcase 'set -- "${e:-"{x}"}"' '1|{x}'
+testcase 'set -- ${h+"{x}"}' '1|{x}'
+testcase 'set -- "${h+"{x}"}"' '1|{x}'
+testcase 'set -- ${h:-"{x}"}' '1|##'
+testcase 'set -- "${h:-"{x}"}"' '1|##'
+
+test "x$failures" = x
diff --git a/shell_cmds/sh/tests/expansion/plus-minus6.0 b/shell_cmds/sh/tests/expansion/plus-minus6.0
new file mode 100644
index 0000000..1bd3f7a
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/plus-minus6.0
@@ -0,0 +1,34 @@
+# $FreeBSD: head/bin/sh/tests/expansion/plus-minus6.0 214512 2010-10-29 13:42:18Z jilles $
+
+failures=0
+unset LC_ALL
+export LC_CTYPE=en_US.ISO8859-1
+nl='
+'
+i=1
+set -f
+while [ "$i" -le 255 ]; do
+ # A different byte still in the range 1..255.
+ i2=$((i^2+(i==2)))
+ # Add a character to work around command substitution's removal of
+ # final newlines, then remove it again.
+ c=$(printf \\"$(printf %o@ "$i")")
+ c=${c%@}
+ c2=$(printf \\"$(printf %o@ "$i2")")
+ c2=${c2%@}
+ case $c in
+ [\'$nl'$}();&|\"`']) c=M
+ esac
+ case $c2 in
+ [\'$nl'$}();&|\"`']) c2=N
+ esac
+ IFS=$c
+ command eval "set -- \${\$+$c2$c$c2$c$c2}"
+ if [ "$#" -ne 3 ] || [ "$1" != "$c2" ] || [ "$2" != "$c2" ] ||
+ [ "$3" != "$c2" ]; then
+ echo "Bad results for separator $i (word $i2)" >&2
+ : $((failures += 1))
+ fi
+ i=$((i+1))
+done
+exit $((failures > 0))
diff --git a/shell_cmds/sh/tests/expansion/plus-minus7.0 b/shell_cmds/sh/tests/expansion/plus-minus7.0
new file mode 100644
index 0000000..440cfdd
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/plus-minus7.0
@@ -0,0 +1,26 @@
+# $FreeBSD: head/bin/sh/tests/expansion/plus-minus7.0 216738 2010-12-27 15:57:41Z emaste $
+
+e= s='foo'
+failures=''
+ok=''
+
+testcase() {
+ code="$1"
+ expected="$2"
+ oIFS="$IFS"
+ eval "$code"
+ IFS='|'
+ result="$#|$*"
+ IFS="$oIFS"
+ if [ "x$result" = "x$expected" ]; then
+ ok=x$ok
+ else
+ failures=x$failures
+ echo "For $code, expected $expected actual $result"
+ fi
+}
+
+testcase 'set -- ${s+a b}' '2|a|b'
+testcase 'set -- ${e:-a b}' '2|a|b'
+
+test "x$failures" = x
diff --git a/shell_cmds/sh/tests/expansion/plus-minus8.0 b/shell_cmds/sh/tests/expansion/plus-minus8.0
new file mode 100644
index 0000000..dd7e770
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/plus-minus8.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/expansion/plus-minus8.0 219623 2011-03-13 20:02:39Z jilles $
+
+set -- 1 2 3 4 5 6 7 8 9 10 11 12 13
+[ "${#+hi}" = hi ] || echo '${#+hi} wrong'
+[ "${#-hi}" = 13 ] || echo '${#-hi} wrong'
diff --git a/shell_cmds/sh/tests/expansion/question1.0 b/shell_cmds/sh/tests/expansion/question1.0
new file mode 100644
index 0000000..2f07597
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/question1.0
@@ -0,0 +1,22 @@
+# $FreeBSD: head/bin/sh/tests/expansion/question1.0 213738 2010-10-12 18:20:38Z obrien $
+
+x=a\ b
+[ "$x" = "${x?}" ] || exit 1
+set -- ${x?}
+{ [ "$#" = 2 ] && [ "$1" = a ] && [ "$2" = b ]; } || exit 1
+unset x
+(echo ${x?abcdefg}) 2>&1 | grep -q abcdefg || exit 1
+${SH} -c 'unset foo; echo ${foo?}' 2>/dev/null && exit 1
+${SH} -c 'foo=; echo ${foo:?}' 2>/dev/null && exit 1
+${SH} -c 'foo=; echo ${foo?}' >/dev/null || exit 1
+${SH} -c 'foo=1; echo ${foo:?}' >/dev/null || exit 1
+${SH} -c 'echo ${!?}' 2>/dev/null && exit 1
+${SH} -c ':& echo ${!?}' >/dev/null || exit 1
+${SH} -c 'echo ${#?}' >/dev/null || exit 1
+${SH} -c 'echo ${*?}' 2>/dev/null && exit 1
+${SH} -c 'echo ${*?}' ${SH} x >/dev/null || exit 1
+${SH} -c 'echo ${1?}' 2>/dev/null && exit 1
+${SH} -c 'echo ${1?}' ${SH} x >/dev/null || exit 1
+${SH} -c 'echo ${2?}' ${SH} x 2>/dev/null && exit 1
+${SH} -c 'echo ${2?}' ${SH} x y >/dev/null || exit 1
+exit 0
diff --git a/shell_cmds/sh/tests/expansion/readonly1.0 b/shell_cmds/sh/tests/expansion/readonly1.0
new file mode 100644
index 0000000..e1e950a
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/readonly1.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/expansion/readonly1.0 238468 2012-07-15 10:19:43Z jilles $
+
+w='@ @'
+
+v=0 HOME=/known/value
+readonly v=~:~/:$w
+[ "$v" = "$HOME:$HOME/:$w" ] || echo "Expected $HOME/:$w got $v"
diff --git a/shell_cmds/sh/tests/expansion/redir1.0 b/shell_cmds/sh/tests/expansion/redir1.0
new file mode 100644
index 0000000..fd5c981
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/redir1.0
@@ -0,0 +1,26 @@
+# $FreeBSD: head/bin/sh/tests/expansion/redir1.0 273920 2014-10-31 22:28:10Z jilles $
+
+bad=0
+for i in 0 1 2 3; do
+ for j in 0 1 2 3 4 5 6 7; do
+ for k in 0 1 2 3 4 5 6 7; do
+ case $i$j$k in
+ 000) continue ;;
+ esac
+ set -- "$(printf \\$i$j$k@)"
+ set -- "${1%@}"
+ ff=
+ for f in /dev/null /dev/zero /; do
+ if [ -e "$f" ] && [ ! -e "$f$1" ]; then
+ ff=$f
+ fi
+ done
+ [ -n "$ff" ] || continue
+ if { true <$ff$1; } 2>/dev/null; then
+ echo "Bad: $i$j$k ($ff)" >&2
+ : $((bad += 1))
+ fi
+ done
+ done
+done
+exit $((bad ? 2 : 0))
diff --git a/shell_cmds/sh/tests/expansion/set-u1.0 b/shell_cmds/sh/tests/expansion/set-u1.0
new file mode 100644
index 0000000..045d6ad
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/set-u1.0
@@ -0,0 +1,29 @@
+# $FreeBSD: head/bin/sh/tests/expansion/set-u1.0 213738 2010-10-12 18:20:38Z obrien $
+
+${SH} -uc 'unset foo; echo $foo' 2>/dev/null && exit 1
+${SH} -uc 'foo=; echo $foo' >/dev/null || exit 1
+${SH} -uc 'foo=1; echo $foo' >/dev/null || exit 1
+# -/+/= are unaffected by set -u
+${SH} -uc 'unset foo; echo ${foo-}' >/dev/null || exit 1
+${SH} -uc 'unset foo; echo ${foo+}' >/dev/null || exit 1
+${SH} -uc 'unset foo; echo ${foo=}' >/dev/null || exit 1
+# length/trimming are affected
+${SH} -uc 'unset foo; echo ${#foo}' 2>/dev/null && exit 1
+${SH} -uc 'foo=; echo ${#foo}' >/dev/null || exit 1
+${SH} -uc 'unset foo; echo ${foo#?}' 2>/dev/null && exit 1
+${SH} -uc 'foo=1; echo ${foo#?}' >/dev/null || exit 1
+${SH} -uc 'unset foo; echo ${foo##?}' 2>/dev/null && exit 1
+${SH} -uc 'foo=1; echo ${foo##?}' >/dev/null || exit 1
+${SH} -uc 'unset foo; echo ${foo%?}' 2>/dev/null && exit 1
+${SH} -uc 'foo=1; echo ${foo%?}' >/dev/null || exit 1
+${SH} -uc 'unset foo; echo ${foo%%?}' 2>/dev/null && exit 1
+${SH} -uc 'foo=1; echo ${foo%%?}' >/dev/null || exit 1
+
+${SH} -uc 'echo $!' 2>/dev/null && exit 1
+${SH} -uc ':& echo $!' >/dev/null || exit 1
+${SH} -uc 'echo $#' >/dev/null || exit 1
+${SH} -uc 'echo $1' 2>/dev/null && exit 1
+${SH} -uc 'echo $1' ${SH} x >/dev/null || exit 1
+${SH} -uc 'echo $2' ${SH} x 2>/dev/null && exit 1
+${SH} -uc 'echo $2' ${SH} x y >/dev/null || exit 1
+exit 0
diff --git a/shell_cmds/sh/tests/expansion/set-u2.0 b/shell_cmds/sh/tests/expansion/set-u2.0
new file mode 100644
index 0000000..55da8aa
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/set-u2.0
@@ -0,0 +1,12 @@
+# $FreeBSD: head/bin/sh/tests/expansion/set-u2.0 198454 2009-10-24 21:20:04Z jilles $
+
+set -u
+: $* $@ "$@" "$*"
+set -- x
+: $* $@ "$@" "$*"
+shift $#
+: $* $@ "$@" "$*"
+set -- y
+set --
+: $* $@ "$@" "$*"
+exit 0
diff --git a/shell_cmds/sh/tests/expansion/set-u3.0 b/shell_cmds/sh/tests/expansion/set-u3.0
new file mode 100644
index 0000000..ea848f7
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/set-u3.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/expansion/set-u3.0 221463 2011-05-04 22:12:22Z jilles $
+
+set -u
+unset x
+v=$( (eval ': $((x))') 2>&1 >/dev/null)
+[ $? -ne 0 ] && [ -n "$v" ]
diff --git a/shell_cmds/sh/tests/expansion/tilde1.0 b/shell_cmds/sh/tests/expansion/tilde1.0
new file mode 100644
index 0000000..c0a7f5b
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/tilde1.0
@@ -0,0 +1,56 @@
+# $FreeBSD: head/bin/sh/tests/expansion/tilde1.0 206149 2010-04-03 21:56:24Z jilles $
+
+HOME=/tmp
+roothome=~root
+if [ "$roothome" = "~root" ]; then
+ echo "~root is not expanded!"
+ exit 2
+fi
+
+testcase() {
+ code="$1"
+ expected="$2"
+ oIFS="$IFS"
+ eval "$code"
+ IFS='|'
+ result="$#|$*"
+ IFS="$oIFS"
+ if [ "x$result" = "x$expected" ]; then
+ ok=x$ok
+ else
+ failures=x$failures
+ echo "For $code, expected $expected actual $result"
+ fi
+}
+
+testcase 'set -- ~' '1|/tmp'
+testcase 'set -- ~/foo' '1|/tmp/foo'
+testcase 'set -- x~' '1|x~'
+testcase 'set -- ~root' "1|$roothome"
+h=~
+testcase 'set -- "$h"' '1|/tmp'
+ooIFS=$IFS
+IFS=m
+testcase 'set -- ~' '1|/tmp'
+testcase 'set -- ~/foo' '1|/tmp/foo'
+testcase 'set -- $h' '2|/t|p'
+IFS=$ooIFS
+t=\~
+testcase 'set -- $t' '1|~'
+r=$(cat <<EOF
+~
+EOF
+)
+testcase 'set -- $r' '1|~'
+r=$(cat <<EOF
+${t+~}
+EOF
+)
+testcase 'set -- $r' '1|~'
+r=$(cat <<EOF
+${t+~/.}
+EOF
+)
+testcase 'set -- $r' '1|~/.'
+
+test "x$failures" = x
diff --git a/shell_cmds/sh/tests/expansion/tilde2.0 b/shell_cmds/sh/tests/expansion/tilde2.0
new file mode 100644
index 0000000..7827c22
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/tilde2.0
@@ -0,0 +1,90 @@
+# $FreeBSD: head/bin/sh/tests/expansion/tilde2.0 206150 2010-04-03 22:04:44Z jilles $
+
+HOME=/tmp
+roothome=~root
+if [ "$roothome" = "~root" ]; then
+ echo "~root is not expanded!"
+ exit 2
+fi
+
+testcase() {
+ code="$1"
+ expected="$2"
+ oIFS="$IFS"
+ eval "$code"
+ IFS='|'
+ result="$#|$*"
+ IFS="$oIFS"
+ if [ "x$result" = "x$expected" ]; then
+ ok=x$ok
+ else
+ failures=x$failures
+ echo "For $code, expected $expected actual $result"
+ fi
+}
+
+testcase 'set -- ${$+~}' '1|/tmp'
+testcase 'set -- ${$+~/}' '1|/tmp/'
+testcase 'set -- ${$+~/foo}' '1|/tmp/foo'
+testcase 'set -- ${$+x~}' '1|x~'
+testcase 'set -- ${$+~root}' "1|$roothome"
+testcase 'set -- ${$+"~"}' '1|~'
+testcase 'set -- ${$+"~/"}' '1|~/'
+testcase 'set -- ${$+"~/foo"}' '1|~/foo'
+testcase 'set -- ${$+"x~"}' '1|x~'
+testcase 'set -- ${$+"~root"}' "1|~root"
+testcase 'set -- "${$+~}"' '1|~'
+testcase 'set -- "${$+~/}"' '1|~/'
+testcase 'set -- "${$+~/foo}"' '1|~/foo'
+testcase 'set -- "${$+x~}"' '1|x~'
+testcase 'set -- "${$+~root}"' "1|~root"
+testcase 'set -- ${HOME#~}' '0|'
+h=~
+testcase 'set -- "$h"' '1|/tmp'
+f=~/foo
+testcase 'set -- "$f"' '1|/tmp/foo'
+testcase 'set -- ${f#~}' '1|/foo'
+testcase 'set -- ${f#~/}' '1|foo'
+
+ooIFS=$IFS
+IFS=m
+testcase 'set -- ${$+~}' '1|/tmp'
+testcase 'set -- ${$+~/foo}' '1|/tmp/foo'
+testcase 'set -- ${$+$h}' '2|/t|p'
+testcase 'set -- ${HOME#~}' '0|'
+IFS=$ooIFS
+
+t=\~
+testcase 'set -- ${$+$t}' '1|~'
+r=$(cat <<EOF
+${HOME#~}
+EOF
+)
+testcase 'set -- $r' '0|'
+r=$(cat <<EOF
+${HOME#'~'}
+EOF
+)
+testcase 'set -- $r' '1|/tmp'
+r=$(cat <<EOF
+${t#'~'}
+EOF
+)
+testcase 'set -- $r' '0|'
+r=$(cat <<EOF
+${roothome#~root}
+EOF
+)
+testcase 'set -- $r' '0|'
+r=$(cat <<EOF
+${f#~}
+EOF
+)
+testcase 'set -- $r' '1|/foo'
+r=$(cat <<EOF
+${f#~/}
+EOF
+)
+testcase 'set -- $r' '1|foo'
+
+test "x$failures" = x
diff --git a/shell_cmds/sh/tests/expansion/trim1.0 b/shell_cmds/sh/tests/expansion/trim1.0
new file mode 100644
index 0000000..16dd838
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/trim1.0
@@ -0,0 +1,85 @@
+# $FreeBSD: head/bin/sh/tests/expansion/trim1.0 206143 2010-04-03 20:14:10Z jilles $
+
+e= q='?' a='*' t=texttext s='ast*que?non' p='/et[c]/' w='a b c' b='{{(#)}}'
+h='##'
+failures=''
+ok=''
+
+testcase() {
+ code="$1"
+ expected="$2"
+ oIFS="$IFS"
+ eval "$code"
+ IFS='|'
+ result="$#|$*"
+ IFS="$oIFS"
+ if [ "x$result" = "x$expected" ]; then
+ ok=x$ok
+ else
+ failures=x$failures
+ echo "For $code, expected $expected actual $result"
+ fi
+}
+
+testcase 'set -- ${t%t}' '1|texttex'
+testcase 'set -- "${t%t}"' '1|texttex'
+testcase 'set -- ${t%e*}' '1|textt'
+testcase 'set -- "${t%e*}"' '1|textt'
+testcase 'set -- ${t%%e*}' '1|t'
+testcase 'set -- "${t%%e*}"' '1|t'
+testcase 'set -- ${t%%*}' '0|'
+testcase 'set -- "${t%%*}"' '1|'
+testcase 'set -- ${t#t}' '1|exttext'
+testcase 'set -- "${t#t}"' '1|exttext'
+testcase 'set -- ${t#*x}' '1|ttext'
+testcase 'set -- "${t#*x}"' '1|ttext'
+testcase 'set -- ${t##*x}' '1|t'
+testcase 'set -- "${t##*x}"' '1|t'
+testcase 'set -- ${t##*}' '0|'
+testcase 'set -- "${t##*}"' '1|'
+testcase 'set -- ${t%e$a}' '1|textt'
+
+set -f
+testcase 'set -- ${s%[?]*}' '1|ast*que'
+testcase 'set -- "${s%[?]*}"' '1|ast*que'
+testcase 'set -- ${s%[*]*}' '1|ast'
+testcase 'set -- "${s%[*]*}"' '1|ast'
+set +f
+
+testcase 'set -- $b' '1|{{(#)}}'
+testcase 'set -- ${b%\}}' '1|{{(#)}'
+testcase 'set -- ${b#{}' '1|{(#)}}'
+testcase 'set -- "${b#{}"' '1|{(#)}}'
+# Parentheses are special in ksh, check that they can be escaped
+testcase 'set -- ${b%\)*}' '1|{{(#'
+testcase 'set -- ${b#{}' '1|{(#)}}'
+testcase 'set -- $h' '1|##'
+testcase 'set -- ${h#\#}' '1|#'
+testcase 'set -- ${h###}' '1|#'
+testcase 'set -- "${h###}"' '1|#'
+testcase 'set -- ${h%#}' '1|#'
+testcase 'set -- "${h%#}"' '1|#'
+
+set -f
+testcase 'set -- ${s%"${s#?}"}' '1|a'
+testcase 'set -- ${s%"${s#????}"}' '1|ast*'
+testcase 'set -- ${s%"${s#????????}"}' '1|ast*que?'
+testcase 'set -- ${s#"${s%?}"}' '1|n'
+testcase 'set -- ${s#"${s%????}"}' '1|?non'
+testcase 'set -- ${s#"${s%????????}"}' '1|*que?non'
+set +f
+testcase 'set -- "${s%"${s#?}"}"' '1|a'
+testcase 'set -- "${s%"${s#????}"}"' '1|ast*'
+testcase 'set -- "${s%"${s#????????}"}"' '1|ast*que?'
+testcase 'set -- "${s#"${s%?}"}"' '1|n'
+testcase 'set -- "${s#"${s%????}"}"' '1|?non'
+testcase 'set -- "${s#"${s%????????}"}"' '1|*que?non'
+testcase 'set -- ${p#${p}}' '1|/etc/'
+testcase 'set -- "${p#${p}}"' '1|/et[c]/'
+testcase 'set -- ${p#*[[]}' '1|c]/'
+testcase 'set -- "${p#*[[]}"' '1|c]/'
+testcase 'set -- ${p#*\[}' '1|c]/'
+testcase 'set -- ${p#*"["}' '1|c]/'
+testcase 'set -- "${p#*"["}"' '1|c]/'
+
+test "x$failures" = x
diff --git a/shell_cmds/sh/tests/expansion/trim2.0 b/shell_cmds/sh/tests/expansion/trim2.0
new file mode 100644
index 0000000..15651b9
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/trim2.0
@@ -0,0 +1,55 @@
+# $FreeBSD: head/bin/sh/tests/expansion/trim2.0 206147 2010-04-03 21:07:50Z jilles $
+
+e= q='?' a='*' t=texttext s='ast*que?non' p='/et[c]/' w='a b c' b='{{(#)}}'
+h='##'
+failures=''
+ok=''
+
+testcase() {
+ code="$1"
+ expected="$2"
+ oIFS="$IFS"
+ eval "$code"
+ IFS='|'
+ result="$#|$*"
+ IFS="$oIFS"
+ if [ "x$result" = "x$expected" ]; then
+ ok=x$ok
+ else
+ failures=x$failures
+ echo "For $code, expected $expected actual $result"
+ fi
+}
+
+set -f
+testcase 'set -- $s' '1|ast*que?non'
+testcase 'set -- ${s%\?*}' '1|ast*que'
+testcase 'set -- "${s%\?*}"' '1|ast*que'
+testcase 'set -- ${s%\**}' '1|ast'
+testcase 'set -- "${s%\**}"' '1|ast'
+testcase 'set -- ${s%"$q"*}' '1|ast*que'
+testcase 'set -- "${s%"$q"*}"' '1|ast*que'
+testcase 'set -- ${s%"$a"*}' '1|ast'
+testcase 'set -- "${s%"$a"*}"' '1|ast'
+testcase 'set -- ${s%"$q"$a}' '1|ast*que'
+testcase 'set -- "${s%"$q"$a}"' '1|ast*que'
+testcase 'set -- ${s%"$a"$a}' '1|ast'
+testcase 'set -- "${s%"$a"$a}"' '1|ast'
+set +f
+
+testcase 'set -- "${b%\}}"' '1|{{(#)}'
+# Parentheses are special in ksh, check that they can be escaped
+testcase 'set -- "${b%\)*}"' '1|{{(#'
+testcase 'set -- "${h#\#}"' '1|#'
+
+testcase 'set -- ${p%"${p#?}"}' '1|/'
+testcase 'set -- ${p%"${p#??????}"}' '1|/etc'
+testcase 'set -- ${p%"${p#???????}"}' '1|/etc/'
+testcase 'set -- "${p%"${p#?}"}"' '1|/'
+testcase 'set -- "${p%"${p#??????}"}"' '1|/et[c]'
+testcase 'set -- "${p%"${p#???????}"}"' '1|/et[c]/'
+testcase 'set -- ${p#"${p}"}' '0|'
+testcase 'set -- "${p#"${p}"}"' '1|'
+testcase 'set -- "${p#*\[}"' '1|c]/'
+
+test "x$failures" = x
diff --git a/shell_cmds/sh/tests/expansion/trim3.0 b/shell_cmds/sh/tests/expansion/trim3.0
new file mode 100644
index 0000000..28c59ae
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/trim3.0
@@ -0,0 +1,46 @@
+# $FreeBSD: head/bin/sh/tests/expansion/trim3.0 207127 2010-04-23 17:26:49Z jilles $
+
+e= q='?' a='*' t=texttext s='ast*que?non' p='/et[c]/' w='a b c' b='{{(#)}}'
+h='##' c='\\\\'
+failures=''
+ok=''
+
+testcase() {
+ code="$1"
+ expected="$2"
+ oIFS="$IFS"
+ eval "$code"
+ IFS='|'
+ result="$#|$*"
+ IFS="$oIFS"
+ if [ "x$result" = "x$expected" ]; then
+ ok=x$ok
+ else
+ failures=x$failures
+ echo "For $code, expected $expected actual $result"
+ fi
+}
+
+# This doesn't make much sense, but it fails in dash so I'm adding it here:
+testcase 'set -- "${w%${w#???}}"' '1|a b'
+
+testcase 'set -- ${p#/et[}' '1|c]/'
+testcase 'set -- "${p#/et[}"' '1|c]/'
+testcase 'set -- "${p%${p#????}}"' '1|/et['
+
+testcase 'set -- ${b%'\'}\''}' '1|{{(#)}'
+
+testcase 'set -- ${c#\\}' '1|\\\'
+testcase 'set -- ${c#\\\\}' '1|\\'
+testcase 'set -- ${c#\\\\\\}' '1|\'
+testcase 'set -- ${c#\\\\\\\\}' '0|'
+testcase 'set -- "${c#\\}"' '1|\\\'
+testcase 'set -- "${c#\\\\}"' '1|\\'
+testcase 'set -- "${c#\\\\\\}"' '1|\'
+testcase 'set -- "${c#\\\\\\\\}"' '1|'
+testcase 'set -- "${c#"$c"}"' '1|'
+testcase 'set -- ${c#"$c"}' '0|'
+testcase 'set -- "${c%"$c"}"' '1|'
+testcase 'set -- ${c%"$c"}' '0|'
+
+test "x$failures" = x
diff --git a/shell_cmds/sh/tests/expansion/trim4.0 b/shell_cmds/sh/tests/expansion/trim4.0
new file mode 100644
index 0000000..f79b6fd
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/trim4.0
@@ -0,0 +1,15 @@
+# $FreeBSD: head/bin/sh/tests/expansion/trim4.0 213814 2010-10-13 23:29:09Z obrien $
+
+v1=/homes/SOME_USER
+v2=
+v3=C123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
+
+# Trigger bug in VSTRIMRIGHT processing STADJUST() call in expand.c:subevalvar()
+while [ ${#v2} -lt 2000 ]; do
+ v4="${v2} ${v1%/*} $v3"
+ if [ ${#v4} -ne $((${#v2} + ${#v3} + 8)) ]; then
+ echo bad: ${#v4} -ne $((${#v2} + ${#v3} + 8))
+ fi
+ v2=x$v2
+ v3=y$v3
+done
diff --git a/shell_cmds/sh/tests/expansion/trim5.0 b/shell_cmds/sh/tests/expansion/trim5.0
new file mode 100644
index 0000000..8045eb6
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/trim5.0
@@ -0,0 +1,28 @@
+# $FreeBSD: head/bin/sh/tests/expansion/trim5.0 214490 2010-10-28 21:51:14Z jilles $
+
+e= q='?' a='*' t=texttext s='ast*que?non' p='/et[c]/' w='a b c' b='{{(#)}}'
+h='##'
+failures=''
+ok=''
+
+testcase() {
+ code="$1"
+ expected="$2"
+ oIFS="$IFS"
+ eval "$code"
+ IFS='|'
+ result="$#|$*"
+ IFS="$oIFS"
+ if [ "x$result" = "x$expected" ]; then
+ ok=x$ok
+ else
+ failures=x$failures
+ echo "For $code, expected $expected actual $result"
+ fi
+}
+
+testcase 'set -- "${b%'\'}\''}"' '1|{{(#)}'
+testcase 'set -- ${b%"}"}' '1|{{(#)}'
+testcase 'set -- "${b%"}"}"' '1|{{(#)}'
+
+test "x$failures" = x
diff --git a/shell_cmds/sh/tests/expansion/trim6.0 b/shell_cmds/sh/tests/expansion/trim6.0
new file mode 100644
index 0000000..e34a09f
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/trim6.0
@@ -0,0 +1,22 @@
+# $FreeBSD: head/bin/sh/tests/expansion/trim6.0 214524 2010-10-29 19:34:57Z jilles $
+
+e=
+for i in 0 1 2 3; do
+ for j in 0 1 2 3 4 5 6 7; do
+ for k in 0 1 2 3 4 5 6 7; do
+ case $i$j$k in
+ 000) continue ;;
+ esac
+ e="$e\\$i$j$k"
+ done
+ done
+done
+e=$(printf "$e")
+v=@$e@$e@
+y=${v##*"$e"}
+yq="${v##*"$e"}"
+[ "$y" = @ ] || echo "error when unquoted in non-splitting context"
+[ "$yq" = @ ] || echo "error when quoted in non-splitting context"
+[ "${v##*"$e"}" = @ ] || echo "error when quoted in splitting context"
+IFS=
+[ ${v##*"$e"} = @ ] || echo "error when unquoted in splitting context"
diff --git a/shell_cmds/sh/tests/expansion/trim7.0 b/shell_cmds/sh/tests/expansion/trim7.0
new file mode 100644
index 0000000..4f237cc
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/trim7.0
@@ -0,0 +1,16 @@
+# $FreeBSD: head/bin/sh/tests/expansion/trim7.0 219623 2011-03-13 20:02:39Z jilles $
+
+set -- 1 2 3 4 5 6 7 8 9 10 11 12 13
+[ "${##1}" = 3 ] || echo '${##1} wrong'
+[ "${###1}" = 3 ] || echo '${###1} wrong'
+[ "${###}" = 13 ] || echo '${###} wrong'
+[ "${#%3}" = 1 ] || echo '${#%3} wrong'
+[ "${#%%3}" = 1 ] || echo '${#%%3} wrong'
+[ "${#%%}" = 13 ] || echo '${#%%} wrong'
+set --
+[ "${##0}" = "" ] || echo '${##0} wrong'
+[ "${###0}" = "" ] || echo '${###0} wrong'
+[ "${###}" = 0 ] || echo '${###} wrong'
+[ "${#%0}" = "" ] || echo '${#%0} wrong'
+[ "${#%%0}" = "" ] || echo '${#%%0} wrong'
+[ "${#%%}" = 0 ] || echo '${#%%} wrong'
diff --git a/shell_cmds/sh/tests/expansion/trim8.0 b/shell_cmds/sh/tests/expansion/trim8.0
new file mode 100644
index 0000000..c4b6ce4
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/trim8.0
@@ -0,0 +1,75 @@
+# $FreeBSD: head/bin/sh/tests/expansion/trim8.0 221646 2011-05-08 11:32:20Z jilles $
+
+unset LC_ALL
+LC_CTYPE=en_US.UTF-8
+export LC_CTYPE
+
+c1=e
+# a umlaut
+c2=$(printf '\303\244')
+# euro sign
+c3=$(printf '\342\202\254')
+# some sort of 't' outside BMP
+c4=$(printf '\360\235\225\245')
+
+s=$c1$c2$c3$c4
+
+testcase() {
+ code="$1"
+ expected="$2"
+ oIFS="$IFS"
+ eval "$code"
+ IFS='|'
+ result="$#|$*"
+ IFS="$oIFS"
+ if [ "x$result" = "x$expected" ]; then
+ ok=x$ok
+ else
+ failures=x$failures
+ echo "For $code, expected $expected actual $result"
+ fi
+}
+
+testcase 'set -- "$s"' "1|$s"
+testcase 'set -- "${s#$c2}"' "1|$s"
+testcase 'set -- "${s#*}"' "1|$s"
+testcase 'set -- "${s#$c1}"' "1|$c2$c3$c4"
+testcase 'set -- "${s#$c1$c2}"' "1|$c3$c4"
+testcase 'set -- "${s#$c1$c2$c3}"' "1|$c4"
+testcase 'set -- "${s#$c1$c2$c3$c4}"' "1|"
+testcase 'set -- "${s#?}"' "1|$c2$c3$c4"
+testcase 'set -- "${s#??}"' "1|$c3$c4"
+testcase 'set -- "${s#???}"' "1|$c4"
+testcase 'set -- "${s#????}"' "1|"
+testcase 'set -- "${s#*$c3}"' "1|$c4"
+testcase 'set -- "${s%$c4}"' "1|$c1$c2$c3"
+testcase 'set -- "${s%$c3$c4}"' "1|$c1$c2"
+testcase 'set -- "${s%$c2$c3$c4}"' "1|$c1"
+testcase 'set -- "${s%$c1$c2$c3$c4}"' "1|"
+testcase 'set -- "${s%?}"' "1|$c1$c2$c3"
+testcase 'set -- "${s%??}"' "1|$c1$c2"
+testcase 'set -- "${s%???}"' "1|$c1"
+testcase 'set -- "${s%????}"' "1|"
+testcase 'set -- "${s%$c2*}"' "1|$c1"
+testcase 'set -- "${s##$c2}"' "1|$s"
+testcase 'set -- "${s##*}"' "1|"
+testcase 'set -- "${s##$c1}"' "1|$c2$c3$c4"
+testcase 'set -- "${s##$c1$c2}"' "1|$c3$c4"
+testcase 'set -- "${s##$c1$c2$c3}"' "1|$c4"
+testcase 'set -- "${s##$c1$c2$c3$c4}"' "1|"
+testcase 'set -- "${s##?}"' "1|$c2$c3$c4"
+testcase 'set -- "${s##??}"' "1|$c3$c4"
+testcase 'set -- "${s##???}"' "1|$c4"
+testcase 'set -- "${s##????}"' "1|"
+testcase 'set -- "${s##*$c3}"' "1|$c4"
+testcase 'set -- "${s%%$c4}"' "1|$c1$c2$c3"
+testcase 'set -- "${s%%$c3$c4}"' "1|$c1$c2"
+testcase 'set -- "${s%%$c2$c3$c4}"' "1|$c1"
+testcase 'set -- "${s%%$c1$c2$c3$c4}"' "1|"
+testcase 'set -- "${s%%?}"' "1|$c1$c2$c3"
+testcase 'set -- "${s%%??}"' "1|$c1$c2"
+testcase 'set -- "${s%%???}"' "1|$c1"
+testcase 'set -- "${s%%????}"' "1|"
+testcase 'set -- "${s%%$c2*}"' "1|$c1"
+
+test "x$failures" = x
diff --git a/shell_cmds/sh/tests/expansion/trim9.0 b/shell_cmds/sh/tests/expansion/trim9.0
new file mode 100644
index 0000000..f0b08ab
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/trim9.0
@@ -0,0 +1,61 @@
+# $FreeBSD: head/bin/sh/tests/expansion/trim9.0 292758 2015-12-26 22:27:48Z jilles $
+
+# POSIX does not specify these but they occasionally occur in the wild.
+# This just serves to keep working what currently works.
+
+failures=''
+ok=''
+
+testcase() {
+ code="$1"
+ expected="$2"
+ oIFS="$IFS"
+ eval "$code"
+ IFS='|'
+ result="$#|$*"
+ IFS="$oIFS"
+ if [ "x$result" = "x$expected" ]; then
+ ok=x$ok
+ else
+ failures=x$failures
+ echo "For $code, expected $expected actual $result"
+ fi
+}
+
+testcase 'shift $#; set -- "${*#Q}"' '1|'
+testcase 'shift $#; set -- "${*##Q}"' '1|'
+testcase 'shift $#; set -- "${*%Q}"' '1|'
+testcase 'shift $#; set -- "${*%%Q}"' '1|'
+testcase 'set -- Q R; set -- "${*#Q}"' '1| R'
+testcase 'set -- Q R; set -- "${*##Q}"' '1| R'
+testcase 'set -- Q R; set -- "${*%R}"' '1|Q '
+testcase 'set -- Q R; set -- "${*%%R}"' '1|Q '
+testcase 'set -- Q R; set -- "${*#S}"' '1|Q R'
+testcase 'set -- Q R; set -- "${*##S}"' '1|Q R'
+testcase 'set -- Q R; set -- "${*%S}"' '1|Q R'
+testcase 'set -- Q R; set -- "${*%%S}"' '1|Q R'
+testcase 'set -- Q R; set -- ${*#Q}' '1|R'
+testcase 'set -- Q R; set -- ${*##Q}' '1|R'
+testcase 'set -- Q R; set -- ${*%R}' '1|Q'
+testcase 'set -- Q R; set -- ${*%%R}' '1|Q'
+testcase 'set -- Q R; set -- ${*#S}' '2|Q|R'
+testcase 'set -- Q R; set -- ${*##S}' '2|Q|R'
+testcase 'set -- Q R; set -- ${*%S}' '2|Q|R'
+testcase 'set -- Q R; set -- ${*%%S}' '2|Q|R'
+testcase 'set -- Q R; set -- ${@#Q}' '1|R'
+testcase 'set -- Q R; set -- ${@##Q}' '1|R'
+testcase 'set -- Q R; set -- ${@%R}' '1|Q'
+testcase 'set -- Q R; set -- ${@%%R}' '1|Q'
+testcase 'set -- Q R; set -- ${@#S}' '2|Q|R'
+testcase 'set -- Q R; set -- ${@##S}' '2|Q|R'
+testcase 'set -- Q R; set -- ${@%S}' '2|Q|R'
+testcase 'set -- Q R; set -- ${@%%S}' '2|Q|R'
+testcase 'set -- Q R; set -- "${@#Q}"' '2||R'
+testcase 'set -- Q R; set -- "${@%R}"' '2|Q|'
+testcase 'set -- Q R; set -- "${@%%R}"' '2|Q|'
+testcase 'set -- Q R; set -- "${@#S}"' '2|Q|R'
+testcase 'set -- Q R; set -- "${@##S}"' '2|Q|R'
+testcase 'set -- Q R; set -- "${@%S}"' '2|Q|R'
+testcase 'set -- Q R; set -- "${@%%S}"' '2|Q|R'
+
+test "x$failures" = x
diff --git a/shell_cmds/sh/tests/functional_test.sh b/shell_cmds/sh/tests/functional_test.sh
new file mode 100755
index 0000000..c2a1f81
--- /dev/null
+++ b/shell_cmds/sh/tests/functional_test.sh
@@ -0,0 +1,72 @@
+#
+# Copyright 2014 EMC Corp.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# $FreeBSD: head/bin/sh/tests/functional_test.sh 270101 2014-08-17 14:26:12Z jilles $
+
+SRCDIR=$(atf_get_srcdir)
+
+check()
+{
+ local tc=${1}; shift
+
+ export SH=$(atf_config_get bin.sh.test_shell /bin/sh)
+
+ local err_file="${SRCDIR}/${tc}.stderr"
+ [ -f "${err_file}" ] && err_flag="-e file:${err_file}"
+ local out_file="${SRCDIR}/${tc}.stdout"
+ [ -f "${out_file}" ] && out_flag="-o file:${out_file}"
+
+ atf_check -s exit:${tc##*.} ${err_flag} ${out_flag} ${SH} "${SRCDIR}/${tc}"
+}
+
+add_testcase()
+{
+ local tc=${1}
+ local tc_escaped word
+
+ case "${tc%.*}" in
+ *-*)
+ local IFS="-"
+ for word in ${tc%.*}; do
+ tc_escaped="${tc_escaped:+${tc_escaped}_}${word}"
+ done
+ ;;
+ *)
+ tc_escaped=${tc%.*}
+ ;;
+ esac
+
+ atf_test_case ${tc_escaped}
+ eval "${tc_escaped}_body() { check ${tc}; }"
+ atf_add_test_case ${tc_escaped}
+}
+
+atf_init_test_cases()
+{
+ for path in $(find -Es "${SRCDIR}" -regex '.*\.[0-9]+$'); do
+ add_testcase ${path##*/}
+ done
+}
diff --git a/shell_cmds/sh/tests/invocation/Makefile b/shell_cmds/sh/tests/invocation/Makefile
new file mode 100644
index 0000000..473990b
--- /dev/null
+++ b/shell_cmds/sh/tests/invocation/Makefile
@@ -0,0 +1,16 @@
+# $FreeBSD: head/bin/sh/tests/invocation/Makefile 322455 2017-08-13 14:36:10Z jilles $
+
+PACKAGE= tests
+
+TESTSDIR= ${TESTSBASE}/bin/sh/${.CURDIR:T}
+
+.PATH: ${.CURDIR:H}
+ATF_TESTS_SH= functional_test
+
+${PACKAGE}FILES+= sh-ac1.0
+${PACKAGE}FILES+= sh-c-missing1.0
+${PACKAGE}FILES+= sh-c1.0
+${PACKAGE}FILES+= sh-ca1.0
+${PACKAGE}FILES+= sh-fca1.0
+
+.include <bsd.test.mk>
diff --git a/shell_cmds/sh/tests/invocation/Makefile.depend b/shell_cmds/sh/tests/invocation/Makefile.depend
new file mode 100644
index 0000000..d01d96a
--- /dev/null
+++ b/shell_cmds/sh/tests/invocation/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD: head/bin/sh/tests/invocation/Makefile.depend 325187 2017-10-31 00:04:07Z bdrewery $
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/shell_cmds/sh/tests/invocation/sh-ac1.0 b/shell_cmds/sh/tests/invocation/sh-ac1.0
new file mode 100644
index 0000000..fa7bdac
--- /dev/null
+++ b/shell_cmds/sh/tests/invocation/sh-ac1.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/invocation/sh-ac1.0 322438 2017-08-12 19:17:48Z jilles $
+# Test that attached options before c are processed
+
+case `${SH} -ac 'echo $-:$0' moo` in
+*a*:moo) true ;;
+*) false ;;
+esac
diff --git a/shell_cmds/sh/tests/invocation/sh-c-missing1.0 b/shell_cmds/sh/tests/invocation/sh-c-missing1.0
new file mode 100644
index 0000000..8f6a850
--- /dev/null
+++ b/shell_cmds/sh/tests/invocation/sh-c-missing1.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/invocation/sh-c-missing1.0 322455 2017-08-13 14:36:10Z jilles $
+
+! echo echo bad | ${SH} -c 2>/dev/null
diff --git a/shell_cmds/sh/tests/invocation/sh-c1.0 b/shell_cmds/sh/tests/invocation/sh-c1.0
new file mode 100644
index 0000000..6142225
--- /dev/null
+++ b/shell_cmds/sh/tests/invocation/sh-c1.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/invocation/sh-c1.0 322438 2017-08-12 19:17:48Z jilles $
+# Test that -c executes command_string with the given name and arg
+
+${SH} -c 'echo $0 $@' moo foo | grep -qx -- "moo foo"
diff --git a/shell_cmds/sh/tests/invocation/sh-ca1.0 b/shell_cmds/sh/tests/invocation/sh-ca1.0
new file mode 100644
index 0000000..c743a1e
--- /dev/null
+++ b/shell_cmds/sh/tests/invocation/sh-ca1.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/invocation/sh-ca1.0 322438 2017-08-12 19:17:48Z jilles $
+# Test that attached options after c are processed
+
+case `${SH} -ca 'echo $-:$0' moo` in
+*a*:moo) true ;;
+*) false ;;
+esac
diff --git a/shell_cmds/sh/tests/invocation/sh-fca1.0 b/shell_cmds/sh/tests/invocation/sh-fca1.0
new file mode 100644
index 0000000..f28b761
--- /dev/null
+++ b/shell_cmds/sh/tests/invocation/sh-fca1.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/invocation/sh-fca1.0 322438 2017-08-12 19:17:48Z jilles $
+# Test that attached options before and after c are processed
+
+case `${SH} -fca 'echo $-:$-:$0:$@' foo -bar` in
+*f*:*a*:foo:-bar) true ;;
+*) false ;;
+esac
diff --git a/shell_cmds/sh/tests/parameters/Makefile b/shell_cmds/sh/tests/parameters/Makefile
new file mode 100644
index 0000000..30708db
--- /dev/null
+++ b/shell_cmds/sh/tests/parameters/Makefile
@@ -0,0 +1,29 @@
+# $FreeBSD: head/bin/sh/tests/parameters/Makefile 306843 2016-10-08 13:40:12Z jilles $
+
+PACKAGE= tests
+
+TESTSDIR= ${TESTSBASE}/bin/sh/${.CURDIR:T}
+
+.PATH: ${.CURDIR:H}
+ATF_TESTS_SH= functional_test
+
+${PACKAGE}FILES+= env1.0
+${PACKAGE}FILES+= exitstatus1.0
+${PACKAGE}FILES+= ifs1.0
+${PACKAGE}FILES+= mail1.0
+${PACKAGE}FILES+= mail2.0
+${PACKAGE}FILES+= optind1.0
+${PACKAGE}FILES+= optind2.0
+${PACKAGE}FILES+= positional1.0
+${PACKAGE}FILES+= positional2.0
+${PACKAGE}FILES+= positional3.0
+${PACKAGE}FILES+= positional4.0
+${PACKAGE}FILES+= positional5.0
+${PACKAGE}FILES+= positional6.0
+${PACKAGE}FILES+= positional7.0
+${PACKAGE}FILES+= positional8.0
+${PACKAGE}FILES+= positional9.0
+${PACKAGE}FILES+= pwd1.0
+${PACKAGE}FILES+= pwd2.0
+
+.include <bsd.test.mk>
diff --git a/shell_cmds/sh/tests/parameters/Makefile.depend b/shell_cmds/sh/tests/parameters/Makefile.depend
new file mode 100644
index 0000000..41114a3
--- /dev/null
+++ b/shell_cmds/sh/tests/parameters/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD: head/bin/sh/tests/parameters/Makefile.depend 296587 2016-03-09 22:46:01Z bdrewery $
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/shell_cmds/sh/tests/parameters/env1.0 b/shell_cmds/sh/tests/parameters/env1.0
new file mode 100644
index 0000000..0842856
--- /dev/null
+++ b/shell_cmds/sh/tests/parameters/env1.0
@@ -0,0 +1,11 @@
+# $FreeBSD: head/bin/sh/tests/parameters/env1.0 222957 2011-06-10 22:42:00Z jilles $
+
+export key='must contain this'
+unset x
+r=$(ENV="\${x?\$key}" ${SH} -i +m 2>&1 >/dev/null <<\EOF
+exit 0
+EOF
+) && case $r in
+*"$key"*) true ;;
+*) false ;;
+esac
diff --git a/shell_cmds/sh/tests/parameters/exitstatus1.0 b/shell_cmds/sh/tests/parameters/exitstatus1.0
new file mode 100644
index 0000000..709600e
--- /dev/null
+++ b/shell_cmds/sh/tests/parameters/exitstatus1.0
@@ -0,0 +1,9 @@
+# $FreeBSD: head/bin/sh/tests/parameters/exitstatus1.0 185232 2008-11-23 20:27:03Z stefanf $
+f() {
+ [ $? = $1 ] || exit 1
+}
+
+true
+f 0
+false
+f 1
diff --git a/shell_cmds/sh/tests/parameters/ifs1.0 b/shell_cmds/sh/tests/parameters/ifs1.0
new file mode 100644
index 0000000..e88d7a4
--- /dev/null
+++ b/shell_cmds/sh/tests/parameters/ifs1.0
@@ -0,0 +1,10 @@
+# $FreeBSD: head/bin/sh/tests/parameters/ifs1.0 306843 2016-10-08 13:40:12Z jilles $
+
+env IFS=_ ${SH} -c '
+rc=2
+nosuchtool_function() {
+ rc=0
+}
+v=nosuchtool_function
+$v && exit "$rc"
+'
diff --git a/shell_cmds/sh/tests/parameters/mail1.0 b/shell_cmds/sh/tests/parameters/mail1.0
new file mode 100644
index 0000000..af69211
--- /dev/null
+++ b/shell_cmds/sh/tests/parameters/mail1.0
@@ -0,0 +1,15 @@
+# $FreeBSD: head/bin/sh/tests/parameters/mail1.0 213738 2010-10-12 18:20:38Z obrien $
+# Test that a non-interactive shell does not access $MAIL.
+
+goodfile=/var/empty/sh-test-goodfile
+mailfile=/var/empty/sh-test-mailfile
+T=$(mktemp sh-test.XXXXXX) || exit
+MAIL=$mailfile ktrace -i -f "$T" ${SH} -c "[ -s $goodfile ]" 2>/dev/null
+if ! grep -q $goodfile "$T"; then
+ # ktrace problem
+ rc=0
+elif ! grep -q $mailfile "$T"; then
+ rc=0
+fi
+rm "$T"
+exit ${rc:-3}
diff --git a/shell_cmds/sh/tests/parameters/mail2.0 b/shell_cmds/sh/tests/parameters/mail2.0
new file mode 100644
index 0000000..74dc416
--- /dev/null
+++ b/shell_cmds/sh/tests/parameters/mail2.0
@@ -0,0 +1,15 @@
+# $FreeBSD: head/bin/sh/tests/parameters/mail2.0 213738 2010-10-12 18:20:38Z obrien $
+# Test that an interactive shell accesses $MAIL.
+
+goodfile=/var/empty/sh-test-goodfile
+mailfile=/var/empty/sh-test-mailfile
+T=$(mktemp sh-test.XXXXXX) || exit
+ENV=$goodfile MAIL=$mailfile ktrace -i -f "$T" ${SH} +m -i </dev/null >/dev/null 2>&1
+if ! grep -q $goodfile "$T"; then
+ # ktrace problem
+ rc=0
+elif grep -q $mailfile "$T"; then
+ rc=0
+fi
+rm "$T"
+exit ${rc:-3}
diff --git a/shell_cmds/sh/tests/parameters/optind1.0 b/shell_cmds/sh/tests/parameters/optind1.0
new file mode 100644
index 0000000..30fc9d8
--- /dev/null
+++ b/shell_cmds/sh/tests/parameters/optind1.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/parameters/optind1.0 227773 2011-11-20 21:48:50Z jilles $
+
+unset OPTIND && [ -z "$OPTIND" ]
diff --git a/shell_cmds/sh/tests/parameters/optind2.0 b/shell_cmds/sh/tests/parameters/optind2.0
new file mode 100644
index 0000000..0837a17
--- /dev/null
+++ b/shell_cmds/sh/tests/parameters/optind2.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/parameters/optind2.0 259846 2013-12-24 22:38:24Z jilles $
+
+[ "$(OPTIND=42 ${SH} -c 'printf %s "$OPTIND"')" = 1 ]
diff --git a/shell_cmds/sh/tests/parameters/positional1.0 b/shell_cmds/sh/tests/parameters/positional1.0
new file mode 100644
index 0000000..ef95be3
--- /dev/null
+++ b/shell_cmds/sh/tests/parameters/positional1.0
@@ -0,0 +1,13 @@
+# $FreeBSD: head/bin/sh/tests/parameters/positional1.0 222158 2011-05-21 14:52:26Z jilles $
+
+set -- a b c d e f g h i j
+[ "$1" = a ] || echo "error at line $LINENO"
+[ "${1}" = a ] || echo "error at line $LINENO"
+[ "${1-foo}" = a ] || echo "error at line $LINENO"
+[ "${1+foo}" = foo ] || echo "error at line $LINENO"
+[ "$1+foo" = a+foo ] || echo "error at line $LINENO"
+[ "$10" = a0 ] || echo "error at line $LINENO"
+[ "$100" = a00 ] || echo "error at line $LINENO"
+[ "${10}" = j ] || echo "error at line $LINENO"
+[ "${10-foo}" = j ] || echo "error at line $LINENO"
+[ "${100-foo}" = foo ] || echo "error at line $LINENO"
diff --git a/shell_cmds/sh/tests/parameters/positional2.0 b/shell_cmds/sh/tests/parameters/positional2.0
new file mode 100644
index 0000000..ea29250
--- /dev/null
+++ b/shell_cmds/sh/tests/parameters/positional2.0
@@ -0,0 +1,65 @@
+# $FreeBSD: head/bin/sh/tests/parameters/positional2.0 228873 2011-12-25 13:24:48Z jilles $
+
+failures=''
+ok=''
+
+testcase() {
+ code="$1"
+ expected="$2"
+ oIFS="$IFS"
+ eval "$code"
+ IFS='|'
+ result="$#|$*"
+ IFS="$oIFS"
+ if [ "x$result" = "x$expected" ]; then
+ ok=x$ok
+ else
+ failures=x$failures
+ echo "For $code, expected $expected actual $result"
+ fi
+}
+
+testcase 'set -- a b; set -- p$@q' '2|pa|bq'
+testcase 'set -- a b; set -- $@q' '2|a|bq'
+testcase 'set -- a b; set -- p$@' '2|pa|b'
+testcase 'set -- a b; set -- p$@q' '2|pa|bq'
+testcase 'set -- a b; set -- $@q' '2|a|bq'
+testcase 'set -- a b; set -- p$@' '2|pa|b'
+testcase 'set -- a b; set -- p$*q' '2|pa|bq'
+testcase 'set -- a b; set -- $*q' '2|a|bq'
+testcase 'set -- a b; set -- p$*' '2|pa|b'
+testcase 'set -- a b; set -- p$*q' '2|pa|bq'
+testcase 'set -- a b; set -- $*q' '2|a|bq'
+testcase 'set -- a b; set -- p$*' '2|pa|b'
+testcase 'set -- a b; set -- "p$@q"' '2|pa|bq'
+testcase 'set -- a b; set -- "$@q"' '2|a|bq'
+testcase 'set -- a b; set -- "p$@"' '2|pa|b'
+testcase 'set -- a b; set -- p"$@"q' '2|pa|bq'
+testcase 'set -- a b; set -- "$@"q' '2|a|bq'
+testcase 'set -- a b; set -- p"$@"' '2|pa|b'
+testcase 'set -- "" a b; set -- "p$@q"' '3|p|a|bq'
+testcase 'set -- "" a b; set -- "$@q"' '3||a|bq'
+testcase 'set -- "" a b; set -- "p$@"' '3|p|a|b'
+testcase 'set -- "" a b; set -- p"$@"q' '3|p|a|bq'
+testcase 'set -- "" a b; set -- "$@"q' '3||a|bq'
+testcase 'set -- "" a b; set -- p"$@"' '3|p|a|b'
+testcase 'set -- a; set -- p$@q' '1|paq'
+testcase 'set -- a; set -- $@q' '1|aq'
+testcase 'set -- a; set -- p$@' '1|pa'
+testcase 'set -- a; set -- p$@q' '1|paq'
+testcase 'set -- a; set -- $@q' '1|aq'
+testcase 'set -- a; set -- p$@' '1|pa'
+testcase 'set -- a; set -- p$*q' '1|paq'
+testcase 'set -- a; set -- $*q' '1|aq'
+testcase 'set -- a; set -- p$*' '1|pa'
+testcase 'set -- a; set -- p$*q' '1|paq'
+testcase 'set -- a; set -- $*q' '1|aq'
+testcase 'set -- a; set -- p$*' '1|pa'
+testcase 'set -- a; set -- "p$@q"' '1|paq'
+testcase 'set -- a; set -- "$@q"' '1|aq'
+testcase 'set -- a; set -- "p$@"' '1|pa'
+testcase 'set -- a; set -- p"$@"q' '1|paq'
+testcase 'set -- a; set -- "$@"q' '1|aq'
+testcase 'set -- a; set -- p"$@"' '1|pa'
+
+test "x$failures" = x
diff --git a/shell_cmds/sh/tests/parameters/positional3.0 b/shell_cmds/sh/tests/parameters/positional3.0
new file mode 100644
index 0000000..d164ed9
--- /dev/null
+++ b/shell_cmds/sh/tests/parameters/positional3.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/parameters/positional3.0 268436 2014-07-08 22:04:44Z jilles $
+
+r=$(${SH} -c 'echo ${01:+yes}${010:+yes}' '' a '' '' '' '' '' '' '' '' b)
+[ "$r" = yesyes ]
diff --git a/shell_cmds/sh/tests/parameters/positional4.0 b/shell_cmds/sh/tests/parameters/positional4.0
new file mode 100644
index 0000000..48c2f01
--- /dev/null
+++ b/shell_cmds/sh/tests/parameters/positional4.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/parameters/positional4.0 268568 2014-07-12 10:27:30Z jilles $
+
+set -- "x$0" 2 3 4 5 6 7 8 9 "y$0"
+[ "${01}.${010}" = "$1.${10}" ]
diff --git a/shell_cmds/sh/tests/parameters/positional5.0 b/shell_cmds/sh/tests/parameters/positional5.0
new file mode 100644
index 0000000..80ef805
--- /dev/null
+++ b/shell_cmds/sh/tests/parameters/positional5.0
@@ -0,0 +1,14 @@
+# $FreeBSD: head/bin/sh/tests/parameters/positional5.0 268576 2014-07-12 21:54:11Z jilles $
+
+i=1
+r=0
+while [ $i -lt $((0x100000000)) ]; do
+ t=
+ eval t=\${$i-x}
+ case $t in
+ x) ;;
+ *) echo "Problem with \${$i}" >&2; r=1 ;;
+ esac
+ i=$((i + 0x10000000))
+done
+exit $r
diff --git a/shell_cmds/sh/tests/parameters/positional6.0 b/shell_cmds/sh/tests/parameters/positional6.0
new file mode 100644
index 0000000..c1d5e4c
--- /dev/null
+++ b/shell_cmds/sh/tests/parameters/positional6.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/parameters/positional6.0 273802 2014-10-28 22:14:31Z jilles $
+
+IFS=?
+set p r
+v=pqrs
+r=${v#"$*"}
+[ "$r" = pqrs ]
diff --git a/shell_cmds/sh/tests/parameters/positional7.0 b/shell_cmds/sh/tests/parameters/positional7.0
new file mode 100644
index 0000000..df36b6f
--- /dev/null
+++ b/shell_cmds/sh/tests/parameters/positional7.0
@@ -0,0 +1,8 @@
+# $FreeBSD: head/bin/sh/tests/parameters/positional7.0 273802 2014-10-28 22:14:31Z jilles $
+
+set -- / ''
+IFS=*
+set -- "$*"
+IFS=:
+args="$*"
+[ "$#:$args" = "1:/*" ]
diff --git a/shell_cmds/sh/tests/parameters/positional8.0 b/shell_cmds/sh/tests/parameters/positional8.0
new file mode 100644
index 0000000..69717ce
--- /dev/null
+++ b/shell_cmds/sh/tests/parameters/positional8.0
@@ -0,0 +1,31 @@
+# $FreeBSD: head/bin/sh/tests/parameters/positional8.0 291025 2015-11-18 21:09:03Z jilles $
+
+failures=''
+ok=''
+
+testcase() {
+ code="$1"
+ expected="$2"
+ oIFS="$IFS"
+ eval "$code"
+ IFS='|'
+ result="$#|$*"
+ IFS="$oIFS"
+ if [ "x$result" = "x$expected" ]; then
+ ok=x$ok
+ else
+ failures=x$failures
+ echo "For $code, expected $expected actual $result"
+ fi
+}
+
+testcase 'shift $#; set -- ""$*' '1|'
+testcase 'shift $#; set -- $*""' '1|'
+testcase 'shift $#; set -- ""$@' '1|'
+testcase 'shift $#; set -- $@""' '1|'
+testcase 'shift $#; set -- """$*"' '1|'
+testcase 'shift $#; set -- "$*"""' '1|'
+testcase 'shift $#; set -- """$@"' '1|'
+testcase 'shift $#; set -- "$@"""' '1|'
+
+test "x$failures" = x
diff --git a/shell_cmds/sh/tests/parameters/positional9.0 b/shell_cmds/sh/tests/parameters/positional9.0
new file mode 100644
index 0000000..c353e85
--- /dev/null
+++ b/shell_cmds/sh/tests/parameters/positional9.0
@@ -0,0 +1,18 @@
+# $FreeBSD: head/bin/sh/tests/parameters/positional9.0 291903 2015-12-06 14:09:31Z jilles $
+# Although POSIX leaves the result of expanding ${#@} and ${#*} unspecified,
+# make sure it is at least numeric.
+
+set -- bb cc ddd
+set -f
+lengths=${#*}${#@}"${#*}${#@}"$(echo ${#*}${#@}"${#*}${#@}")
+IFS=
+lengths=$lengths${#*}${#@}"${#*}${#@}"$(echo ${#*}${#@}"${#*}${#@}")
+case $lengths in
+*[!0-9]*)
+ printf 'bad: %s\n' "$lengths"
+ exit 3 ;;
+????????????????*) ;;
+*)
+ printf 'too short: %s\n' "$lengths"
+ exit 3 ;;
+esac
diff --git a/shell_cmds/sh/tests/parameters/pwd1.0 b/shell_cmds/sh/tests/parameters/pwd1.0
new file mode 100644
index 0000000..8393ef6
--- /dev/null
+++ b/shell_cmds/sh/tests/parameters/pwd1.0
@@ -0,0 +1,11 @@
+# $FreeBSD: head/bin/sh/tests/parameters/pwd1.0 213738 2010-10-12 18:20:38Z obrien $
+# Check that bogus PWD values are not accepted from the environment.
+
+cd / || exit 3
+failures=0
+[ "$(PWD=foo ${SH} -c 'pwd')" = / ] || : $((failures += 1))
+[ "$(PWD=/var/empty ${SH} -c 'pwd')" = / ] || : $((failures += 1))
+[ "$(PWD=/var/empty/foo ${SH} -c 'pwd')" = / ] || : $((failures += 1))
+[ "$(PWD=/bin/ls ${SH} -c 'pwd')" = / ] || : $((failures += 1))
+
+exit $((failures != 0))
diff --git a/shell_cmds/sh/tests/parameters/pwd2.0 b/shell_cmds/sh/tests/parameters/pwd2.0
new file mode 100644
index 0000000..d0cecf5
--- /dev/null
+++ b/shell_cmds/sh/tests/parameters/pwd2.0
@@ -0,0 +1,24 @@
+# $FreeBSD: head/bin/sh/tests/parameters/pwd2.0 213738 2010-10-12 18:20:38Z obrien $
+# Check that PWD is exported and accepted from the environment.
+set -e
+
+T=$(mktemp -d ${TMPDIR:-/tmp}/sh-test.XXXXXX)
+trap 'rm -rf $T' 0
+cd -P $T
+TP=$(pwd)
+mkdir test1
+ln -s test1 link
+cd link
+[ "$PWD" = "$TP/link" ]
+[ "$(pwd)" = "$TP/link" ]
+[ "$(pwd -P)" = "$TP/test1" ]
+[ "$(${SH} -c pwd)" = "$TP/link" ]
+[ "$(${SH} -c pwd\ -P)" = "$TP/test1" ]
+cd ..
+[ "$(pwd)" = "$TP" ]
+cd -P link
+[ "$PWD" = "$TP/test1" ]
+[ "$(pwd)" = "$TP/test1" ]
+[ "$(pwd -P)" = "$TP/test1" ]
+[ "$(${SH} -c pwd)" = "$TP/test1" ]
+[ "$(${SH} -c pwd\ -P)" = "$TP/test1" ]
diff --git a/shell_cmds/sh/tests/parser/Makefile b/shell_cmds/sh/tests/parser/Makefile
new file mode 100644
index 0000000..cd83a50
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/Makefile
@@ -0,0 +1,88 @@
+# $FreeBSD: head/bin/sh/tests/parser/Makefile 317039 2017-04-16 22:10:02Z jilles $
+
+PACKAGE= tests
+
+TESTSDIR= ${TESTSBASE}/bin/sh/${.CURDIR:T}
+
+.PATH: ${.CURDIR:H}
+ATF_TESTS_SH= functional_test
+
+${PACKAGE}FILES+= alias1.0
+${PACKAGE}FILES+= alias2.0
+${PACKAGE}FILES+= alias3.0
+${PACKAGE}FILES+= alias4.0
+${PACKAGE}FILES+= alias5.0
+${PACKAGE}FILES+= alias6.0
+${PACKAGE}FILES+= alias7.0
+${PACKAGE}FILES+= alias8.0
+${PACKAGE}FILES+= alias9.0
+${PACKAGE}FILES+= alias10.0
+${PACKAGE}FILES+= alias11.0
+${PACKAGE}FILES+= alias12.0
+${PACKAGE}FILES+= alias13.0
+${PACKAGE}FILES+= alias14.0
+${PACKAGE}FILES+= alias15.0 alias15.0.stdout
+${PACKAGE}FILES+= alias16.0
+${PACKAGE}FILES+= alias17.0
+${PACKAGE}FILES+= alias18.0
+${PACKAGE}FILES+= and-pipe-not.0
+${PACKAGE}FILES+= case1.0
+${PACKAGE}FILES+= case2.0
+${PACKAGE}FILES+= comment1.0
+${PACKAGE}FILES+= comment2.42
+${PACKAGE}FILES+= dollar-quote1.0
+${PACKAGE}FILES+= dollar-quote2.0
+${PACKAGE}FILES+= dollar-quote3.0
+${PACKAGE}FILES+= dollar-quote4.0
+${PACKAGE}FILES+= dollar-quote5.0
+${PACKAGE}FILES+= dollar-quote6.0
+${PACKAGE}FILES+= dollar-quote7.0
+${PACKAGE}FILES+= dollar-quote8.0
+${PACKAGE}FILES+= dollar-quote9.0
+${PACKAGE}FILES+= dollar-quote10.0
+${PACKAGE}FILES+= dollar-quote11.0
+${PACKAGE}FILES+= dollar-quote12.0
+${PACKAGE}FILES+= dollar-quote13.0
+${PACKAGE}FILES+= empty-braces1.0
+${PACKAGE}FILES+= empty-cmd1.0
+${PACKAGE}FILES+= for1.0
+${PACKAGE}FILES+= for2.0
+${PACKAGE}FILES+= func1.0
+${PACKAGE}FILES+= func2.0
+${PACKAGE}FILES+= func3.0
+${PACKAGE}FILES+= heredoc1.0
+${PACKAGE}FILES+= heredoc2.0
+${PACKAGE}FILES+= heredoc3.0
+${PACKAGE}FILES+= heredoc4.0
+${PACKAGE}FILES+= heredoc5.0
+${PACKAGE}FILES+= heredoc6.0
+${PACKAGE}FILES+= heredoc7.0
+${PACKAGE}FILES+= heredoc8.0
+${PACKAGE}FILES+= heredoc9.0
+${PACKAGE}FILES+= heredoc10.0
+${PACKAGE}FILES+= heredoc11.0
+${PACKAGE}FILES+= heredoc12.0
+${PACKAGE}FILES+= heredoc13.0
+${PACKAGE}FILES+= line-cont1.0
+${PACKAGE}FILES+= line-cont2.0
+${PACKAGE}FILES+= line-cont3.0
+${PACKAGE}FILES+= line-cont4.0
+${PACKAGE}FILES+= line-cont5.0
+${PACKAGE}FILES+= line-cont6.0
+${PACKAGE}FILES+= line-cont7.0
+${PACKAGE}FILES+= line-cont8.0
+${PACKAGE}FILES+= line-cont9.0
+${PACKAGE}FILES+= line-cont10.0
+${PACKAGE}FILES+= line-cont11.0
+${PACKAGE}FILES+= no-space1.0
+${PACKAGE}FILES+= no-space2.0
+${PACKAGE}FILES+= nul1.0
+${PACKAGE}FILES+= only-redir1.0
+${PACKAGE}FILES+= only-redir2.0
+${PACKAGE}FILES+= only-redir3.0
+${PACKAGE}FILES+= only-redir4.0
+${PACKAGE}FILES+= pipe-not1.0
+${PACKAGE}FILES+= set-v1.0 set-v1.0.stderr
+${PACKAGE}FILES+= var-assign1.0
+
+.include <bsd.test.mk>
diff --git a/shell_cmds/sh/tests/parser/Makefile.depend b/shell_cmds/sh/tests/parser/Makefile.depend
new file mode 100644
index 0000000..af589a4
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD: head/bin/sh/tests/parser/Makefile.depend 296587 2016-03-09 22:46:01Z bdrewery $
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/shell_cmds/sh/tests/parser/alias1.0 b/shell_cmds/sh/tests/parser/alias1.0
new file mode 100644
index 0000000..9b67211
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/alias1.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/parser/alias1.0 214280 2010-10-24 16:55:17Z jilles $
+
+alias alias0=exit
+eval 'alias0 0'
+exit 1
diff --git a/shell_cmds/sh/tests/parser/alias10.0 b/shell_cmds/sh/tests/parser/alias10.0
new file mode 100644
index 0000000..b8684f4
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/alias10.0
@@ -0,0 +1,9 @@
+# $FreeBSD: head/bin/sh/tests/parser/alias10.0 243252 2012-11-18 23:15:22Z jilles $
+
+# This test may start consuming memory indefinitely if it fails.
+ulimit -t 5 2>/dev/null
+ulimit -v 100000 2>/dev/null
+
+alias echo='echo'
+alias echo='echo'
+[ "`eval echo b`" = b ]
diff --git a/shell_cmds/sh/tests/parser/alias11.0 b/shell_cmds/sh/tests/parser/alias11.0
new file mode 100644
index 0000000..10fd827
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/alias11.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/parser/alias11.0 261141 2014-01-24 23:00:35Z jilles $
+
+alias alias0=alias1
+alias alias1=exit
+eval 'alias0 0'
+exit 3
diff --git a/shell_cmds/sh/tests/parser/alias12.0 b/shell_cmds/sh/tests/parser/alias12.0
new file mode 100644
index 0000000..52cc4b0
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/alias12.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/parser/alias12.0 261160 2014-01-25 14:59:08Z jilles $
+
+unalias -a
+alias alias0=command
+alias true='echo bad'
+eval 'alias0 true'
diff --git a/shell_cmds/sh/tests/parser/alias13.0 b/shell_cmds/sh/tests/parser/alias13.0
new file mode 100644
index 0000000..9f45067
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/alias13.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/parser/alias13.0 261160 2014-01-25 14:59:08Z jilles $
+
+unalias -a
+alias command=command
+alias true='echo bad'
+eval 'command true'
diff --git a/shell_cmds/sh/tests/parser/alias14.0 b/shell_cmds/sh/tests/parser/alias14.0
new file mode 100644
index 0000000..2d1bc51
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/alias14.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/parser/alias14.0 261192 2014-01-26 21:19:33Z jilles $
+
+alias command='command '
+alias alias0=exit
+eval 'command alias0 0'
+exit 3
diff --git a/shell_cmds/sh/tests/parser/alias15.0 b/shell_cmds/sh/tests/parser/alias15.0
new file mode 100644
index 0000000..c2e6117
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/alias15.0
@@ -0,0 +1,12 @@
+# $FreeBSD: head/bin/sh/tests/parser/alias15.0 261192 2014-01-26 21:19:33Z jilles $
+
+f_echoanddo() {
+ printf '%s\n' "$*"
+ "$@"
+}
+
+alias echoanddo='f_echoanddo '
+alias alias0='echo test2'
+eval 'echoanddo echo test1'
+eval 'echoanddo alias0'
+exit 0
diff --git a/shell_cmds/sh/tests/parser/alias15.0.stdout b/shell_cmds/sh/tests/parser/alias15.0.stdout
new file mode 100644
index 0000000..6dd179c
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/alias15.0.stdout
@@ -0,0 +1,4 @@
+echo test1
+test1
+echo test2
+test2
diff --git a/shell_cmds/sh/tests/parser/alias16.0 b/shell_cmds/sh/tests/parser/alias16.0
new file mode 100644
index 0000000..b551216
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/alias16.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/parser/alias16.0 316646 2017-04-08 21:57:59Z jilles $
+
+v=1
+alias a='unalias a
+v=2'
+eval a
+[ "$v" = 2 ]
diff --git a/shell_cmds/sh/tests/parser/alias17.0 b/shell_cmds/sh/tests/parser/alias17.0
new file mode 100644
index 0000000..fd233ef
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/alias17.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/parser/alias17.0 317037 2017-04-16 21:42:43Z jilles $
+
+v=1
+alias a='unalias -a
+v=2'
+eval a
+[ "$v" = 2 ]
diff --git a/shell_cmds/sh/tests/parser/alias18.0 b/shell_cmds/sh/tests/parser/alias18.0
new file mode 100644
index 0000000..4b072e8
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/alias18.0
@@ -0,0 +1,8 @@
+# $FreeBSD: head/bin/sh/tests/parser/alias18.0 317039 2017-04-16 22:10:02Z jilles $
+
+v=1
+alias a='alias a=v=2
+v=3
+a'
+eval a
+[ "$v" = 2 ]
diff --git a/shell_cmds/sh/tests/parser/alias2.0 b/shell_cmds/sh/tests/parser/alias2.0
new file mode 100644
index 0000000..f412756
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/alias2.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/parser/alias2.0 214280 2010-10-24 16:55:17Z jilles $
+
+alias alias0=exit
+x=alias0
+eval 'case $x in alias0) exit 0;; esac'
+exit 1
diff --git a/shell_cmds/sh/tests/parser/alias3.0 b/shell_cmds/sh/tests/parser/alias3.0
new file mode 100644
index 0000000..97aac19
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/alias3.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/parser/alias3.0 214709 2010-11-02 23:44:29Z jilles $
+
+alias alias0=exit
+x=alias0
+eval 'case $x in "alias0") alias0 0;; esac'
+exit 1
diff --git a/shell_cmds/sh/tests/parser/alias4.0 b/shell_cmds/sh/tests/parser/alias4.0
new file mode 100644
index 0000000..4c82c6c
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/alias4.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/parser/alias4.0 222165 2011-05-21 22:03:06Z jilles $
+
+alias alias0=exit
+eval 'x=1 alias0 0'
+exit 1
diff --git a/shell_cmds/sh/tests/parser/alias5.0 b/shell_cmds/sh/tests/parser/alias5.0
new file mode 100644
index 0000000..c649562
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/alias5.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/parser/alias5.0 222165 2011-05-21 22:03:06Z jilles $
+
+alias alias0=exit
+eval '</dev/null alias0 0'
+exit 1
diff --git a/shell_cmds/sh/tests/parser/alias6.0 b/shell_cmds/sh/tests/parser/alias6.0
new file mode 100644
index 0000000..86e1bfb
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/alias6.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/parser/alias6.0 224104 2011-07-16 16:14:14Z jilles $
+
+alias alias0='| cat >/dev/null'
+
+eval '{ echo bad; } alias0'
+eval '(echo bad)alias0'
diff --git a/shell_cmds/sh/tests/parser/alias7.0 b/shell_cmds/sh/tests/parser/alias7.0
new file mode 100644
index 0000000..a5b9077
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/alias7.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/parser/alias7.0 240825 2012-09-22 12:52:41Z jilles $
+
+alias echo='echo a'
+[ "`eval echo b`" = "a b" ]
diff --git a/shell_cmds/sh/tests/parser/alias8.0 b/shell_cmds/sh/tests/parser/alias8.0
new file mode 100644
index 0000000..f22dfd4
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/alias8.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/parser/alias8.0 240825 2012-09-22 12:52:41Z jilles $
+
+alias echo='echo'
+[ "`eval echo b`" = b ]
diff --git a/shell_cmds/sh/tests/parser/alias9.0 b/shell_cmds/sh/tests/parser/alias9.0
new file mode 100644
index 0000000..bbcb4ce
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/alias9.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/parser/alias9.0 242721 2012-11-07 23:15:36Z jilles $
+
+alias alias0=:
+alias alias0=exit
+eval 'alias0 0'
+exit 1
diff --git a/shell_cmds/sh/tests/parser/and-pipe-not.0 b/shell_cmds/sh/tests/parser/and-pipe-not.0
new file mode 100644
index 0000000..fffb1d4
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/and-pipe-not.0
@@ -0,0 +1,2 @@
+# $FreeBSD: head/bin/sh/tests/parser/and-pipe-not.0 191010 2009-04-13 19:12:28Z stefanf $
+true && ! true | false
diff --git a/shell_cmds/sh/tests/parser/case1.0 b/shell_cmds/sh/tests/parser/case1.0
new file mode 100644
index 0000000..d146399
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/case1.0
@@ -0,0 +1,14 @@
+# $FreeBSD: head/bin/sh/tests/parser/case1.0 207824 2010-05-09 17:10:50Z jilles $
+
+keywords='if then else elif fi while until for do done { } case esac ! in'
+
+# Keywords can be used unquoted in case statements, except the keyword
+# esac as the first pattern of a '|' alternation without a starting '('.
+# (POSIX doesn't seem to require (esac) to work.)
+for k in $keywords; do
+ eval "case $k in (foo|$k) ;; *) echo bad ;; esac"
+ eval "case $k in ($k) ;; *) echo bad ;; esac"
+ eval "case $k in foo|$k) ;; *) echo bad ;; esac"
+ [ "$k" = esac ] && continue
+ eval "case $k in $k) ;; *) echo bad ;; esac"
+done
diff --git a/shell_cmds/sh/tests/parser/case2.0 b/shell_cmds/sh/tests/parser/case2.0
new file mode 100644
index 0000000..df5a319
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/case2.0
@@ -0,0 +1,32 @@
+# $FreeBSD: head/bin/sh/tests/parser/case2.0 207824 2010-05-09 17:10:50Z jilles $
+
+# Pretty much only ash derivatives can parse all of this.
+
+f1() {
+ x=$(case x in
+ (x|esac) ;;
+ (*) echo bad >&2 ;;
+ esac)
+}
+f1
+f2() {
+ x=$(case x in
+ (x|esac) ;;
+ (*) echo bad >&2
+ esac)
+}
+f2
+f3() {
+ x=$(case x in
+ x|esac) ;;
+ *) echo bad >&2 ;;
+ esac)
+}
+f3
+f4() {
+ x=$(case x in
+ x|esac) ;;
+ *) echo bad >&2
+ esac)
+}
+f4
diff --git a/shell_cmds/sh/tests/parser/comment1.0 b/shell_cmds/sh/tests/parser/comment1.0
new file mode 100644
index 0000000..bdf9c3b
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/comment1.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/parser/comment1.0 295818 2016-02-19 16:56:07Z jilles $
+
+${SH} -c '#'
diff --git a/shell_cmds/sh/tests/parser/comment2.42 b/shell_cmds/sh/tests/parser/comment2.42
new file mode 100644
index 0000000..7e623c9
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/comment2.42
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/parser/comment2.42 295818 2016-02-19 16:56:07Z jilles $
+
+${SH} -c '#
+exit 42'
diff --git a/shell_cmds/sh/tests/parser/dollar-quote1.0 b/shell_cmds/sh/tests/parser/dollar-quote1.0
new file mode 100644
index 0000000..1206141
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/dollar-quote1.0
@@ -0,0 +1,12 @@
+# $FreeBSD$
+
+set -e
+
+[ $'hi' = hi ]
+[ $'hi
+there' = 'hi
+there' ]
+[ $'\"\'\\\a\b\f\t\v' = "\"'\\$(printf "\a\b\f\t\v")" ]
+[ $'hi\nthere' = 'hi
+there' ]
+[ $'a\rb' = "$(printf "a\rb")" ]
diff --git a/shell_cmds/sh/tests/parser/dollar-quote10.0 b/shell_cmds/sh/tests/parser/dollar-quote10.0
new file mode 100644
index 0000000..745d3aa
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/dollar-quote10.0
@@ -0,0 +1,10 @@
+# $FreeBSD: head/bin/sh/tests/parser/dollar-quote10.0 221669 2011-05-08 17:40:10Z jilles $
+
+# a umlaut
+s=$(printf '\303\244')
+# euro sign
+s=$s$(printf '\342\202\254')
+
+# Start a new shell so the locale change is picked up.
+ss="$(LC_ALL=en_US.UTF-8 ${SH} -c "printf %s \$'\u00e4\u20ac'")"
+[ "$s" = "$ss" ]
diff --git a/shell_cmds/sh/tests/parser/dollar-quote11.0 b/shell_cmds/sh/tests/parser/dollar-quote11.0
new file mode 100644
index 0000000..b9db067
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/dollar-quote11.0
@@ -0,0 +1,8 @@
+# $FreeBSD: head/bin/sh/tests/parser/dollar-quote11.0 221669 2011-05-08 17:40:10Z jilles $
+
+# some sort of 't' outside BMP
+s=$s$(printf '\360\235\225\245')
+
+# Start a new shell so the locale change is picked up.
+ss="$(LC_ALL=en_US.UTF-8 ${SH} -c "printf %s \$'\U0001d565'")"
+[ "$s" = "$ss" ]
diff --git a/shell_cmds/sh/tests/parser/dollar-quote12.0 b/shell_cmds/sh/tests/parser/dollar-quote12.0
new file mode 100644
index 0000000..bb06e3c
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/dollar-quote12.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/parser/dollar-quote12.0 286971 2015-08-20 21:31:36Z jilles $
+
+# \u without any digits at all remains invalid.
+# Our choice is a parse error.
+
+v=$( (eval ": \$'\u'") 2>&1 >/dev/null)
+[ $? -ne 0 ] && [ -n "$v" ]
diff --git a/shell_cmds/sh/tests/parser/dollar-quote13.0 b/shell_cmds/sh/tests/parser/dollar-quote13.0
new file mode 100644
index 0000000..fe31d9d
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/dollar-quote13.0
@@ -0,0 +1,8 @@
+# $FreeBSD: head/bin/sh/tests/parser/dollar-quote13.0 286973 2015-08-20 22:05:55Z jilles $
+
+# This Unicode escape sequence that has never been in range should either
+# fail to expand or expand to a fallback.
+
+c=$(eval printf %s \$\'\\Uffffff41\' 2>/dev/null)
+r=$(($? != 0))
+[ "$r.$c" = '1.' ] || [ "$r.$c" = '0.?' ] || [ "$r.$c" = $'0.\u2222' ]
diff --git a/shell_cmds/sh/tests/parser/dollar-quote2.0 b/shell_cmds/sh/tests/parser/dollar-quote2.0
new file mode 100644
index 0000000..4617ed8
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/dollar-quote2.0
@@ -0,0 +1,5 @@
+# $FreeBSD$
+
+# This depends on the ASCII character set.
+
+[ $'\e' = "$(printf "\033")" ]
diff --git a/shell_cmds/sh/tests/parser/dollar-quote3.0 b/shell_cmds/sh/tests/parser/dollar-quote3.0
new file mode 100644
index 0000000..a7e6852
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/dollar-quote3.0
@@ -0,0 +1,22 @@
+# $FreeBSD$
+
+unset LC_ALL
+LC_CTYPE=en_US.ISO8859-1
+export LC_CTYPE
+
+e=
+for i in 0 1 2 3; do
+ for j in 0 1 2 3 4 5 6 7; do
+ for k in 0 1 2 3 4 5 6 7; do
+ case $i$j$k in
+ 000) continue ;;
+ esac
+ e="$e\\$i$j$k"
+ done
+ done
+done
+ee=`printf "$e"`
+[ "${#ee}" = 255 ] || echo length bad
+
+# Start a new shell so the locale change is picked up.
+[ "$(${SH} -c "printf %s \$'$e'")" = "$ee" ]
diff --git a/shell_cmds/sh/tests/parser/dollar-quote4.0 b/shell_cmds/sh/tests/parser/dollar-quote4.0
new file mode 100644
index 0000000..f620af5
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/dollar-quote4.0
@@ -0,0 +1,19 @@
+# $FreeBSD$
+
+unset LC_ALL
+LC_CTYPE=en_US.ISO8859-1
+export LC_CTYPE
+
+e=
+for i in 0 1 2 3 4 5 6 7 8 9 a b c d e f; do
+ for j in 0 1 2 3 4 5 6 7 8 9 a b c d e f; do
+ case $i$j in
+ 00) continue ;;
+ esac
+ e="$e\x$i$j"
+ done
+done
+
+# Start a new shell so the locale change is picked up.
+ee="$(${SH} -c "printf %s \$'$e'")"
+[ "${#ee}" = 255 ] || echo length bad
diff --git a/shell_cmds/sh/tests/parser/dollar-quote5.0 b/shell_cmds/sh/tests/parser/dollar-quote5.0
new file mode 100644
index 0000000..c2c44ca
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/dollar-quote5.0
@@ -0,0 +1,12 @@
+# $FreeBSD$
+
+# This depends on the ASCII character set.
+
+set -e
+
+[ $'\ca\cb\cc\cd\ce\cf\cg\ch\ci\cj\ck\cl\cm\cn\co\cp\cq\cr\cs\ct\cu\cv\cw\cx\cy\cz' = $'\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032' ]
+[ $'\cA\cB\cC\cD\cE\cF\cG\cH\cI\cJ\cK\cL\cM\cN\cO\cP\cQ\cR\cS\cT\cU\cV\cW\cX\cY\cZ' = $'\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032' ]
+[ $'\c[' = $'\033' ]
+[ $'\c]' = $'\035' ]
+[ $'\c^' = $'\036' ]
+[ $'\c_' = $'\037' ]
diff --git a/shell_cmds/sh/tests/parser/dollar-quote6.0 b/shell_cmds/sh/tests/parser/dollar-quote6.0
new file mode 100644
index 0000000..a4b1e3f
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/dollar-quote6.0
@@ -0,0 +1,5 @@
+# $FreeBSD$
+
+# This depends on the ASCII character set.
+
+[ $'\c\\' = $'\034' ]
diff --git a/shell_cmds/sh/tests/parser/dollar-quote7.0 b/shell_cmds/sh/tests/parser/dollar-quote7.0
new file mode 100644
index 0000000..c866b1a
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/dollar-quote7.0
@@ -0,0 +1,6 @@
+# $FreeBSD$
+
+set -e
+
+[ $'\u0024\u0040\u0060' = '$@`' ]
+[ $'\U00000024\U00000040\U00000060' = '$@`' ]
diff --git a/shell_cmds/sh/tests/parser/dollar-quote8.0 b/shell_cmds/sh/tests/parser/dollar-quote8.0
new file mode 100644
index 0000000..8f0b41a
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/dollar-quote8.0
@@ -0,0 +1,11 @@
+# $FreeBSD$
+
+[ $'hello\0' = hello ]
+[ $'hello\0world' = hello ]
+[ $'hello\0'$'world' = helloworld ]
+[ $'hello\000' = hello ]
+[ $'hello\000world' = hello ]
+[ $'hello\000'$'world' = helloworld ]
+[ $'hello\x00' = hello ]
+[ $'hello\x00world' = hello ]
+[ $'hello\x00'$'world' = helloworld ]
diff --git a/shell_cmds/sh/tests/parser/dollar-quote9.0 b/shell_cmds/sh/tests/parser/dollar-quote9.0
new file mode 100644
index 0000000..df64b7d
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/dollar-quote9.0
@@ -0,0 +1,8 @@
+# $FreeBSD$
+
+# POSIX and C99 say D800-DFFF are undefined in a universal character name.
+# We reject this but many other shells expand to something that looks like
+# CESU-8.
+
+v=$( (eval ": \$'\uD800'") 2>&1 >/dev/null)
+[ $? -ne 0 ] && [ -n "$v" ]
diff --git a/shell_cmds/sh/tests/parser/empty-braces1.0 b/shell_cmds/sh/tests/parser/empty-braces1.0
new file mode 100644
index 0000000..4aac806
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/empty-braces1.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/parser/empty-braces1.0 245382 2013-01-13 19:26:33Z jilles $
+
+# Unfortunately, some scripts depend on the extension of allowing an empty
+# pair of braces.
+
+{ } &
+wait $!
diff --git a/shell_cmds/sh/tests/parser/empty-cmd1.0 b/shell_cmds/sh/tests/parser/empty-cmd1.0
new file mode 100644
index 0000000..60aaa00
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/empty-cmd1.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/parser/empty-cmd1.0 254843 2013-08-25 10:57:48Z jilles $
+
+! (eval ': || f()') 2>/dev/null
diff --git a/shell_cmds/sh/tests/parser/for1.0 b/shell_cmds/sh/tests/parser/for1.0
new file mode 100644
index 0000000..d863f0a
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/for1.0
@@ -0,0 +1,29 @@
+# $FreeBSD: head/bin/sh/tests/parser/for1.0 218889 2011-02-20 14:18:58Z jilles $
+
+nl='
+'
+list=' a b c'
+for s1 in "$nl" " "; do
+ for s2 in "$nl" ";" ";$nl"; do
+ for s3 in "$nl" " "; do
+ r=''
+ eval "for i${s1}in ${list}${s2}do${s3}r=\"\$r \$i\"; done"
+ [ "$r" = "$list" ] || exit 1
+ done
+ done
+done
+set -- $list
+for s2 in "$nl" " "; do
+ for s3 in "$nl" " "; do
+ r=''
+ eval "for i${s2}do${s3}r=\"\$r \$i\"; done"
+ [ "$r" = "$list" ] || exit 1
+ done
+done
+for s1 in "$nl" " "; do
+ for s2 in "$nl" ";" ";$nl"; do
+ for s3 in "$nl" " "; do
+ eval "for i${s1}in${s2}do${s3}exit 1; done"
+ done
+ done
+done
diff --git a/shell_cmds/sh/tests/parser/for2.0 b/shell_cmds/sh/tests/parser/for2.0
new file mode 100644
index 0000000..8ed92dc
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/for2.0
@@ -0,0 +1,15 @@
+# $FreeBSD: head/bin/sh/tests/parser/for2.0 218889 2011-02-20 14:18:58Z jilles $
+
+# Common extensions to the 'for' syntax.
+
+nl='
+'
+list=' a b c'
+set -- $list
+for s2 in ";" ";$nl"; do
+ for s3 in "$nl" " "; do
+ r=''
+ eval "for i${s2}do${s3}r=\"\$r \$i\"; done"
+ [ "$r" = "$list" ] || exit 1
+ done
+done
diff --git a/shell_cmds/sh/tests/parser/func1.0 b/shell_cmds/sh/tests/parser/func1.0
new file mode 100644
index 0000000..4e82da4
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/func1.0
@@ -0,0 +1,25 @@
+# $FreeBSD: head/bin/sh/tests/parser/func1.0 214291 2010-10-24 20:45:13Z jilles $
+# POSIX does not require these bytes to work in function names,
+# but making them all work seems a good goal.
+
+failures=0
+unset LC_ALL
+export LC_CTYPE=en_US.ISO8859-1
+i=128
+set -f
+while [ "$i" -le 255 ]; do
+ c=$(printf \\"$(printf %o "$i")")
+ ok=0
+ eval "$c() { ok=1; }"
+ $c
+ ok1=$ok
+ ok=0
+ "$c"
+ if [ "$ok" != 1 ] || [ "$ok1" != 1 ]; then
+ echo "Bad results for character $i" >&2
+ : $((failures += 1))
+ fi
+ unset -f $c
+ i=$((i+1))
+done
+exit $((failures > 0))
diff --git a/shell_cmds/sh/tests/parser/func2.0 b/shell_cmds/sh/tests/parser/func2.0
new file mode 100644
index 0000000..5b86522
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/func2.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/parser/func2.0 222512 2011-05-30 21:49:59Z jilles $
+
+f() { return 42; }
+f() { return 3; } &
+f
+[ $? -eq 42 ]
diff --git a/shell_cmds/sh/tests/parser/func3.0 b/shell_cmds/sh/tests/parser/func3.0
new file mode 100644
index 0000000..c4f4922
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/func3.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/parser/func3.0 222512 2011-05-30 21:49:59Z jilles $
+
+name=/var/empty/nosuch
+f() { true; } <$name
+name=/dev/null
+f
diff --git a/shell_cmds/sh/tests/parser/heredoc1.0 b/shell_cmds/sh/tests/parser/heredoc1.0
new file mode 100644
index 0000000..4020249
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/heredoc1.0
@@ -0,0 +1,85 @@
+# $FreeBSD: head/bin/sh/tests/parser/heredoc1.0 204836 2010-03-07 15:08:42Z jilles $
+
+failures=0
+
+check() {
+ if ! eval "[ $* ]"; then
+ echo "Failed: $*"
+ : $((failures += 1))
+ fi
+}
+
+check '"$(cat <<EOF
+hi
+EOF
+)" = hi'
+
+check '"$(cat <<EOF
+${$+hi}
+EOF
+)" = hi'
+
+unset yy
+check '"$(cat <<EOF
+${yy-hi}
+EOF
+)" = hi'
+
+check '"$(cat <<EOF
+${$+hi
+there}
+EOF
+)" = "hi
+there"'
+
+check '"$(cat <<EOF
+$((1+1))
+EOF
+)" = 2'
+
+check '"$(cat <<EOF
+$(echo hi)
+EOF
+)" = hi'
+
+check '"$(cat <<EOF
+`echo hi`
+EOF
+)" = hi'
+
+check '"$(cat <<\EOF
+${$+hi}
+EOF
+)" = "\${\$+hi}"'
+
+check '"$(cat <<\EOF
+$(
+EOF
+)" = \$\('
+
+check '"$(cat <<\EOF
+`
+EOF
+)" = \`'
+
+check '"$(cat <<EOF
+"
+EOF
+)" = \"'
+
+check '"$(cat <<\EOF
+"
+EOF
+)" = \"'
+
+check '"$(cat <<esac
+'"'"'
+esac
+)" = "'"'"'"'
+
+check '"$(cat <<\)
+'"'"'
+)
+)" = "'"'"'"'
+
+exit $((failures != 0))
diff --git a/shell_cmds/sh/tests/parser/heredoc10.0 b/shell_cmds/sh/tests/parser/heredoc10.0
new file mode 100644
index 0000000..f5133b9
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/heredoc10.0
@@ -0,0 +1,49 @@
+# $FreeBSD: head/bin/sh/tests/parser/heredoc10.0 221887 2011-05-14 14:19:30Z jilles $
+
+# It may be argued that
+# x=$(cat <<EOF
+# foo
+# EOF)
+# is a valid complete command that sets x to foo, because
+# cat <<EOF
+# foo
+# EOF
+# is a valid script even without the final newline.
+# However, if the here-document is not within a new-style command substitution
+# or there are other constructs nested inside the command substitution that
+# need terminators, the delimiter at the start of a line followed by a close
+# parenthesis is clearly a literal part of the here-document.
+
+# This file contains tests that may not work with simplistic $(...) parsers.
+# The open parentheses in comments help mksh, but not zsh.
+
+failures=0
+
+check() {
+ if ! eval "[ $* ]"; then
+ echo "Failed: $*"
+ : $((failures += 1))
+ fi
+}
+
+check '"$(cat <<EOF # (
+EOF )
+EOF
+)" = "EOF )"'
+
+check '"$({ cat <<EOF # (
+EOF)
+EOF
+})" = "EOF)"'
+
+check '"$(if :; then cat <<EOF # (
+EOF)
+EOF
+fi)" = "EOF)"'
+
+check '"$( (cat <<EOF # (
+EOF)
+EOF
+))" = "EOF)"'
+
+exit $((failures != 0))
diff --git a/shell_cmds/sh/tests/parser/heredoc11.0 b/shell_cmds/sh/tests/parser/heredoc11.0
new file mode 100644
index 0000000..3e74aea
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/heredoc11.0
@@ -0,0 +1,26 @@
+# $FreeBSD: head/bin/sh/tests/parser/heredoc11.0 222134 2011-05-20 16:03:36Z jilles $
+
+failures=''
+
+check() {
+ if eval "[ $* ]"; then
+ :
+ else
+ echo "Failed: $*"
+ failures=x$failures
+ fi
+}
+
+check '`cat <<EOF
+foo
+EOF` = foo'
+
+check '"`cat <<EOF
+foo
+EOF`" = foo'
+
+check '`eval "cat <<EOF
+foo
+EOF"` = foo'
+
+test "x$failures" = x
diff --git a/shell_cmds/sh/tests/parser/heredoc12.0 b/shell_cmds/sh/tests/parser/heredoc12.0
new file mode 100644
index 0000000..644cae1
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/heredoc12.0
@@ -0,0 +1,47 @@
+# $FreeBSD: head/bin/sh/tests/parser/heredoc12.0 271593 2014-09-14 16:46:30Z jilles $
+
+failures=0
+
+check() {
+ if ! eval "[ $* ]"; then
+ echo "Failed: $*"
+ : $((failures += 1))
+ fi
+}
+
+longmark=`printf %01000d 4`
+longmarkstripped=`printf %0999d 0`
+
+check '"$(cat <<'"$longmark
+$longmark"'
+echo yes)" = "yes"'
+
+check '"$(cat <<\'"$longmark
+$longmark"'
+echo yes)" = "yes"'
+
+check '"$(cat <<'"$longmark
+yes
+$longmark"'
+)" = "yes"'
+
+check '"$(cat <<\'"$longmark
+yes
+$longmark"'
+)" = "yes"'
+
+check '"$(cat <<'"$longmark
+$longmarkstripped
+$longmark.
+$longmark"'
+)" = "'"$longmarkstripped
+$longmark."'"'
+
+check '"$(cat <<\'"$longmark
+$longmarkstripped
+$longmark.
+$longmark"'
+)" = "'"$longmarkstripped
+$longmark."'"'
+
+exit $((failures != 0))
diff --git a/shell_cmds/sh/tests/parser/heredoc13.0 b/shell_cmds/sh/tests/parser/heredoc13.0
new file mode 100644
index 0000000..4eb45e0
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/heredoc13.0
@@ -0,0 +1,21 @@
+# $FreeBSD: head/bin/sh/tests/parser/heredoc13.0 287408 2015-09-02 19:49:55Z jilles $
+
+failures=0
+
+check() {
+ if ! eval "[ $* ]"; then
+ echo "Failed: $*"
+ : $((failures += 1))
+ fi
+}
+
+check '"$(cat <<""
+
+echo yes)" = "yes"'
+
+check '"$(cat <<""
+yes
+
+)" = "yes"'
+
+exit $((failures != 0))
diff --git a/shell_cmds/sh/tests/parser/heredoc2.0 b/shell_cmds/sh/tests/parser/heredoc2.0
new file mode 100644
index 0000000..f07f5d4
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/heredoc2.0
@@ -0,0 +1,39 @@
+# $FreeBSD: head/bin/sh/tests/parser/heredoc2.0 211405 2010-08-16 21:14:49Z jilles $
+
+failures=0
+
+check() {
+ if ! eval "[ $* ]"; then
+ echo "Failed: $*"
+ : $((failures += 1))
+ fi
+}
+
+s='ast*que?non' sq=\' dq=\"
+
+check '"$(cat <<EOF
+${s}
+EOF
+)" = "ast*que?non"'
+
+check '"$(cat <<EOF
+${s+'$sq'x'$sq'}
+EOF
+)" = ${sq}x${sq}'
+
+check '"$(cat <<EOF
+${s#ast}
+EOF
+)" = "*que?non"'
+
+check '"$(cat <<EOF
+${s##"ast"}
+EOF
+)" = "*que?non"'
+
+check '"$(cat <<EOF
+${s##'$sq'ast'$sq'}
+EOF
+)" = "*que?non"'
+
+exit $((failures != 0))
diff --git a/shell_cmds/sh/tests/parser/heredoc3.0 b/shell_cmds/sh/tests/parser/heredoc3.0
new file mode 100644
index 0000000..15c0a1c
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/heredoc3.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/parser/heredoc3.0 207824 2010-05-09 17:10:50Z jilles $
+
+# This may be expected to work, but pretty much only ash derivatives allow it.
+
+test "$(cat <<EOF)" = "hi there"
+hi there
+EOF
diff --git a/shell_cmds/sh/tests/parser/heredoc4.0 b/shell_cmds/sh/tests/parser/heredoc4.0
new file mode 100644
index 0000000..a544354
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/heredoc4.0
@@ -0,0 +1,44 @@
+# $FreeBSD: head/bin/sh/tests/parser/heredoc4.0 208655 2010-05-30 14:11:27Z jilles $
+
+failures=0
+
+check() {
+ if ! eval "[ $* ]"; then
+ echo "Failed: $*"
+ : $((failures += 1))
+ fi
+}
+
+f() {
+ cat <<EOF && echo `echo bar`
+foo
+EOF
+}
+check '"`f`" = "foo
+bar"'
+
+f() {
+ cat <<EOF && echo $(echo bar)
+foo
+EOF
+}
+check '"$(f)" = "foo
+bar"'
+
+f() {
+ echo `echo bar` && cat <<EOF
+foo
+EOF
+}
+check '"`f`" = "bar
+foo"'
+
+f() {
+ echo $(echo bar) && cat <<EOF
+foo
+EOF
+}
+check '"$(f)" = "bar
+foo"'
+
+exit $((failures != 0))
diff --git a/shell_cmds/sh/tests/parser/heredoc5.0 b/shell_cmds/sh/tests/parser/heredoc5.0
new file mode 100644
index 0000000..0bcc617
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/heredoc5.0
@@ -0,0 +1,56 @@
+# $FreeBSD: head/bin/sh/tests/parser/heredoc5.0 208655 2010-05-30 14:11:27Z jilles $
+
+failures=0
+
+check() {
+ if ! eval "[ $* ]"; then
+ echo "Failed: $*"
+ : $((failures += 1))
+ fi
+}
+
+f() {
+ cat <<EOF && echo `cat <<EOF
+bar
+EOF
+`
+foo
+EOF
+}
+check '"`f`" = "foo
+bar"'
+
+f() {
+ cat <<EOF && echo $(cat <<EOF
+bar
+EOF
+)
+foo
+EOF
+}
+check '"$(f)" = "foo
+bar"'
+
+f() {
+ echo `cat <<EOF
+bar
+EOF
+` && cat <<EOF
+foo
+EOF
+}
+check '"`f`" = "bar
+foo"'
+
+f() {
+ echo $(cat <<EOF
+bar
+EOF
+) && cat <<EOF
+foo
+EOF
+}
+check '"$(f)" = "bar
+foo"'
+
+exit $((failures != 0))
diff --git a/shell_cmds/sh/tests/parser/heredoc6.0 b/shell_cmds/sh/tests/parser/heredoc6.0
new file mode 100644
index 0000000..003f548
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/heredoc6.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/parser/heredoc6.0 208656 2010-05-30 14:20:32Z jilles $
+
+r=
+! command eval ": <<EOF; )" 2>/dev/null; command eval : hi \${r:=0}
+exit ${r:-3}
diff --git a/shell_cmds/sh/tests/parser/heredoc7.0 b/shell_cmds/sh/tests/parser/heredoc7.0
new file mode 100644
index 0000000..28d867c
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/heredoc7.0
@@ -0,0 +1,19 @@
+# $FreeBSD: head/bin/sh/tests/parser/heredoc7.0 210488 2010-07-25 22:25:52Z jilles $
+
+# Some of these created malformed parse trees with null pointers for here
+# documents, causing the here document writing process to segfault.
+eval ': <<EOF'
+eval ': <<EOF;'
+eval '`: <<EOF`'
+eval '`: <<EOF;`'
+eval '`: <<EOF`;'
+eval '`: <<EOF;`;'
+
+# Some of these created malformed parse trees with null pointers for here
+# documents, causing sh to segfault.
+eval ': <<\EOF'
+eval ': <<\EOF;'
+eval '`: <<\EOF`'
+eval '`: <<\EOF;`'
+eval '`: <<\EOF`;'
+eval '`: <<\EOF;`;'
diff --git a/shell_cmds/sh/tests/parser/heredoc8.0 b/shell_cmds/sh/tests/parser/heredoc8.0
new file mode 100644
index 0000000..482c060
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/heredoc8.0
@@ -0,0 +1,20 @@
+# $FreeBSD: head/bin/sh/tests/parser/heredoc8.0 211405 2010-08-16 21:14:49Z jilles $
+
+failures=0
+
+check() {
+ if ! eval "[ $* ]"; then
+ echo "Failed: $*"
+ : $((failures += 1))
+ fi
+}
+
+s='ast*que?non' sq=\' dq=\"
+
+# This is possibly useful but differs from other shells.
+check '"$(cat <<EOF
+${s+"x"}
+EOF
+)" = ${dq}x${dq}'
+
+exit $((failures != 0))
diff --git a/shell_cmds/sh/tests/parser/heredoc9.0 b/shell_cmds/sh/tests/parser/heredoc9.0
new file mode 100644
index 0000000..bb4a04c
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/heredoc9.0
@@ -0,0 +1,58 @@
+# $FreeBSD: head/bin/sh/tests/parser/heredoc9.0 221887 2011-05-14 14:19:30Z jilles $
+
+# It may be argued that
+# x=$(cat <<EOF
+# foo
+# EOF)
+# is a valid complete command that sets x to foo, because
+# cat <<EOF
+# foo
+# EOF
+# is a valid script even without the final newline.
+# However, if the here-document is not within a new-style command substitution
+# or there are other constructs nested inside the command substitution that
+# need terminators, the delimiter at the start of a line followed by a close
+# parenthesis is clearly a literal part of the here-document.
+
+# This file contains tests that also work with simplistic $(...) parsers.
+
+failures=0
+
+check() {
+ if ! eval "[ $* ]"; then
+ echo "Failed: $*"
+ : $((failures += 1))
+ fi
+}
+
+check '`${SH} -c "cat <<EOF
+EOF)
+EOF
+"` = "EOF)"'
+
+check '`${SH} -c "(cat <<EOF
+EOF)
+EOF
+)"` = "EOF)"'
+
+check '"`cat <<EOF
+EOF x
+EOF
+`" = "EOF x"'
+
+check '"`cat <<EOF
+EOF )
+EOF
+`" = "EOF )"'
+
+check '"`cat <<EOF
+EOF)
+EOF
+`" = "EOF)"'
+
+check '"$(cat <<EOF
+EOF x
+EOF
+)" = "EOF x"'
+
+exit $((failures != 0))
diff --git a/shell_cmds/sh/tests/parser/line-cont1.0 b/shell_cmds/sh/tests/parser/line-cont1.0
new file mode 100644
index 0000000..717c2c2
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/line-cont1.0
@@ -0,0 +1,16 @@
+# $FreeBSD: head/bin/sh/tests/parser/line-cont1.0 273243 2014-10-17 21:52:57Z jilles $
+
+i\
+f
+t\
+r\
+u\
+e
+t\
+h\
+e\
+n
+:
+\
+f\
+i
diff --git a/shell_cmds/sh/tests/parser/line-cont10.0 b/shell_cmds/sh/tests/parser/line-cont10.0
new file mode 100644
index 0000000..dbb064b
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/line-cont10.0
@@ -0,0 +1,18 @@
+# $FreeBSD: head/bin/sh/tests/parser/line-cont10.0 273276 2014-10-19 11:59:15Z jilles $
+
+v=XaaaXbbbX
+[ "${v\
+#\
+*\
+a}.${v\
+#\
+#\
+*\
+a}.${v\
+%\
+b\
+*}.${v\
+%\
+%\
+b\
+*}" = aaXbbbX.XbbbX.XaaaXbb.XaaaX ]
diff --git a/shell_cmds/sh/tests/parser/line-cont11.0 b/shell_cmds/sh/tests/parser/line-cont11.0
new file mode 100644
index 0000000..f398a98
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/line-cont11.0
@@ -0,0 +1,23 @@
+# $FreeBSD: head/bin/sh/tests/parser/line-cont11.0 273276 2014-10-19 11:59:15Z jilles $
+
+T=$(mktemp "${TMPDIR:-/tmp}/sh-test.XXXXXXXX") || exit
+trap 'rm -f -- "$T"' 0
+w='#A'
+# A naive pgetc_linecont() would push back two characters here, which
+# fails if a new buffer is read between the two characters.
+c='${w#\#}'
+c=$c$c$c$c
+c=$c$c$c$c
+c=$c$c$c$c
+c=$c$c$c$c
+c=$c$c$c$c
+c=$c$c$c$c
+printf 'v=%s\n' "$c" >"$T"
+. "$T"
+if [ "${#v}" != 4096 ]; then
+ echo "Length is bad (${#v})"
+ exit 3
+fi
+case $v in
+*[!A]*) echo "Content is bad"; exit 3 ;;
+esac
diff --git a/shell_cmds/sh/tests/parser/line-cont2.0 b/shell_cmds/sh/tests/parser/line-cont2.0
new file mode 100644
index 0000000..83928cf
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/line-cont2.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/parser/line-cont2.0 273243 2014-10-17 21:52:57Z jilles $
+
+[ "a\
+b" = ab ]
diff --git a/shell_cmds/sh/tests/parser/line-cont3.0 b/shell_cmds/sh/tests/parser/line-cont3.0
new file mode 100644
index 0000000..cc2af7b
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/line-cont3.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/parser/line-cont3.0 273243 2014-10-17 21:52:57Z jilles $
+
+v=`printf %s 'a\
+b'`
+w="`printf %s 'c\
+d'`"
+[ "$v$w" = abcd ]
diff --git a/shell_cmds/sh/tests/parser/line-cont4.0 b/shell_cmds/sh/tests/parser/line-cont4.0
new file mode 100644
index 0000000..7d59c19
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/line-cont4.0
@@ -0,0 +1,8 @@
+# $FreeBSD: head/bin/sh/tests/parser/line-cont4.0 273276 2014-10-19 11:59:15Z jilles $
+
+v=abcd
+[ "$\
+v.$\
+{v}.${\
+v}.${v\
+}" = abcd.abcd.abcd.abcd ]
diff --git a/shell_cmds/sh/tests/parser/line-cont5.0 b/shell_cmds/sh/tests/parser/line-cont5.0
new file mode 100644
index 0000000..23a4d94
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/line-cont5.0
@@ -0,0 +1,14 @@
+# $FreeBSD: head/bin/sh/tests/parser/line-cont5.0 273276 2014-10-19 11:59:15Z jilles $
+
+bad=1
+case x in
+x\
+) ;\
+; *) exit 7
+esac &\
+& bad= &\
+& : >\
+>/dev/null
+
+false |\
+| [ -z "$bad" ]
diff --git a/shell_cmds/sh/tests/parser/line-cont6.0 b/shell_cmds/sh/tests/parser/line-cont6.0
new file mode 100644
index 0000000..66838e1
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/line-cont6.0
@@ -0,0 +1,23 @@
+# $FreeBSD: head/bin/sh/tests/parser/line-cont6.0 273276 2014-10-19 11:59:15Z jilles $
+
+v0\
+=abc
+
+v=$(cat <\
+<\
+E\
+O\
+F
+${v0}d
+EOF
+)
+
+w=$(cat <\
+<\
+-\
+EOF
+ efgh
+EOF
+)
+
+[ "$v.$w" = "abcd.efgh" ]
diff --git a/shell_cmds/sh/tests/parser/line-cont7.0 b/shell_cmds/sh/tests/parser/line-cont7.0
new file mode 100644
index 0000000..6c48642
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/line-cont7.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/parser/line-cont7.0 273276 2014-10-19 11:59:15Z jilles $
+
+[ "$(\
+(
+1\
++ 1)\
+)" = 2 ]
diff --git a/shell_cmds/sh/tests/parser/line-cont8.0 b/shell_cmds/sh/tests/parser/line-cont8.0
new file mode 100644
index 0000000..8fc84bb
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/line-cont8.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/parser/line-cont8.0 273276 2014-10-19 11:59:15Z jilles $
+
+set -- a b c d e f g h i j
+[ "${1\
+0\
+}" = j ]
diff --git a/shell_cmds/sh/tests/parser/line-cont9.0 b/shell_cmds/sh/tests/parser/line-cont9.0
new file mode 100644
index 0000000..9618ae2
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/line-cont9.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/parser/line-cont9.0 273276 2014-10-19 11:59:15Z jilles $
+
+[ "${$\
+:\
++\
+xyz}" = xyz ]
diff --git a/shell_cmds/sh/tests/parser/no-space1.0 b/shell_cmds/sh/tests/parser/no-space1.0
new file mode 100644
index 0000000..5b15bfe
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/no-space1.0
@@ -0,0 +1,18 @@
+# $FreeBSD: head/bin/sh/tests/parser/no-space1.0 218891 2011-02-20 17:28:58Z jilles $
+
+# These are ugly but are required to work.
+
+set -e
+
+while(false)do(:)done
+if(false)then(:)fi
+if(false)then(:)else(:)fi
+(:&&:)||:
+until(:)do(:)done
+case x in(x);;*)exit 1;(:)esac
+case x in(x);;*)exit 1;;esac
+for i do(:)done
+{(:)}
+f(){(:)}
+:|:
+(:)|(:)
diff --git a/shell_cmds/sh/tests/parser/no-space2.0 b/shell_cmds/sh/tests/parser/no-space2.0
new file mode 100644
index 0000000..0f63e6e
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/no-space2.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/parser/no-space2.0 218891 2011-02-20 17:28:58Z jilles $
+
+# This conflicts with ksh extended patterns but occurs in the wild.
+
+set -e
+
+!(false)
diff --git a/shell_cmds/sh/tests/parser/nul1.0 b/shell_cmds/sh/tests/parser/nul1.0
new file mode 100644
index 0000000..bb5442e
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/nul1.0
@@ -0,0 +1,12 @@
+# $FreeBSD: head/bin/sh/tests/parser/nul1.0 295825 2016-02-19 21:53:12Z jilles $
+# Although POSIX does not specify the effect of NUL bytes in scripts,
+# we ignore them.
+
+{
+ printf 'v=%03000d\0%02000d' 7 2
+ dd if=/dev/zero bs=1000 count=1 status=none
+ printf '1 w=%03000d%02000d1\0\n' 7 2
+ printf '\0l\0v\0=\0$\0{\0#\0v\0}\n'
+ printf '\0l\0w\0=\0\0$\0{\0#\0w}\0\0\0\n'
+ printf '[ "$lv.$lw.$v" = "5001.5001.$w" ]\n'
+} | ${SH}
diff --git a/shell_cmds/sh/tests/parser/only-redir1.0 b/shell_cmds/sh/tests/parser/only-redir1.0
new file mode 100644
index 0000000..7aedde7
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/only-redir1.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/parser/only-redir1.0 210221 2010-07-18 12:45:31Z jilles $
+</dev/null &
+wait $!
diff --git a/shell_cmds/sh/tests/parser/only-redir2.0 b/shell_cmds/sh/tests/parser/only-redir2.0
new file mode 100644
index 0000000..b55be16
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/only-redir2.0
@@ -0,0 +1,2 @@
+# $FreeBSD: head/bin/sh/tests/parser/only-redir2.0 254335 2013-08-14 19:34:13Z jilles $
+</dev/null | :
diff --git a/shell_cmds/sh/tests/parser/only-redir3.0 b/shell_cmds/sh/tests/parser/only-redir3.0
new file mode 100644
index 0000000..f51617b
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/only-redir3.0
@@ -0,0 +1,2 @@
+# $FreeBSD: head/bin/sh/tests/parser/only-redir3.0 254335 2013-08-14 19:34:13Z jilles $
+case x in x) </dev/null ;; esac
diff --git a/shell_cmds/sh/tests/parser/only-redir4.0 b/shell_cmds/sh/tests/parser/only-redir4.0
new file mode 100644
index 0000000..a3ce893
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/only-redir4.0
@@ -0,0 +1,2 @@
+# $FreeBSD: head/bin/sh/tests/parser/only-redir4.0 254335 2013-08-14 19:34:13Z jilles $
+case x in x) </dev/null ;& esac
diff --git a/shell_cmds/sh/tests/parser/pipe-not1.0 b/shell_cmds/sh/tests/parser/pipe-not1.0
new file mode 100644
index 0000000..421e235
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/pipe-not1.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/parser/pipe-not1.0 214281 2010-10-24 17:06:49Z jilles $
+
+: | ! : | false
diff --git a/shell_cmds/sh/tests/parser/set-v1.0 b/shell_cmds/sh/tests/parser/set-v1.0
new file mode 100644
index 0000000..c5ed944
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/set-v1.0
@@ -0,0 +1,8 @@
+# $FreeBSD: head/bin/sh/tests/parser/set-v1.0 295937 2016-02-23 22:44:01Z jilles $
+
+${SH} <<\EOF
+echo one >&2
+set -v
+echo two >&2
+echo three >&2
+EOF
diff --git a/shell_cmds/sh/tests/parser/set-v1.0.stderr b/shell_cmds/sh/tests/parser/set-v1.0.stderr
new file mode 100644
index 0000000..d904fa5
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/set-v1.0.stderr
@@ -0,0 +1,5 @@
+one
+echo two >&2
+two
+echo three >&2
+three
diff --git a/shell_cmds/sh/tests/parser/var-assign1.0 b/shell_cmds/sh/tests/parser/var-assign1.0
new file mode 100644
index 0000000..4949bfd
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/var-assign1.0
@@ -0,0 +1,19 @@
+# $FreeBSD: head/bin/sh/tests/parser/var-assign1.0 257920 2013-11-10 18:46:59Z jilles $
+# In a variable assignment, both the name and the equals sign must be entirely
+# unquoted. Therefore, there is only one assignment below; the other words
+# containing equals signs are command words.
+
+abc=0
+\abc=1 2>/dev/null
+a\bc=2 2>/dev/null
+abc\=3 2>/dev/null
+a\bc\=4 2>/dev/null
+'abc'=5 2>/dev/null
+a'b'c=6 2>/dev/null
+abc'='7 2>/dev/null
+'abc=8' 2>/dev/null
+"abc"=9 2>/dev/null
+a"b"c=10 2>/dev/null
+abc"="11 2>/dev/null
+"abc=12" 2>/dev/null
+[ "$abc" = 0 ]
diff --git a/shell_cmds/sh/tests/set-e/Makefile b/shell_cmds/sh/tests/set-e/Makefile
new file mode 100644
index 0000000..2f13991
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/Makefile
@@ -0,0 +1,46 @@
+# $FreeBSD: head/bin/sh/tests/set-e/Makefile 299094 2016-05-04 23:20:53Z ngie $
+
+PACKAGE= tests
+
+TESTSDIR= ${TESTSBASE}/bin/sh/${.CURDIR:T}
+
+.PATH: ${.CURDIR:H}
+ATF_TESTS_SH= functional_test
+
+${PACKAGE}FILES+= and1.0
+${PACKAGE}FILES+= and2.1
+${PACKAGE}FILES+= and3.0
+${PACKAGE}FILES+= and4.0
+${PACKAGE}FILES+= background1.0
+${PACKAGE}FILES+= cmd1.0
+${PACKAGE}FILES+= cmd2.1
+${PACKAGE}FILES+= elif1.0
+${PACKAGE}FILES+= elif2.0
+${PACKAGE}FILES+= eval1.0
+${PACKAGE}FILES+= eval2.1
+${PACKAGE}FILES+= for1.0
+${PACKAGE}FILES+= func1.0
+${PACKAGE}FILES+= func2.1
+${PACKAGE}FILES+= if1.0
+${PACKAGE}FILES+= if2.0
+${PACKAGE}FILES+= if3.0
+${PACKAGE}FILES+= not1.0
+${PACKAGE}FILES+= not2.0
+${PACKAGE}FILES+= or1.0
+${PACKAGE}FILES+= or2.0
+${PACKAGE}FILES+= or3.1
+${PACKAGE}FILES+= pipe1.1
+${PACKAGE}FILES+= pipe2.0
+${PACKAGE}FILES+= return1.0
+${PACKAGE}FILES+= semi1.1
+${PACKAGE}FILES+= semi2.1
+${PACKAGE}FILES+= subshell1.0
+${PACKAGE}FILES+= subshell2.1
+${PACKAGE}FILES+= until1.0
+${PACKAGE}FILES+= until2.0
+${PACKAGE}FILES+= until3.0
+${PACKAGE}FILES+= while1.0
+${PACKAGE}FILES+= while2.0
+${PACKAGE}FILES+= while3.0
+
+.include <bsd.test.mk>
diff --git a/shell_cmds/sh/tests/set-e/Makefile.depend b/shell_cmds/sh/tests/set-e/Makefile.depend
new file mode 100644
index 0000000..ea8dbbe
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD: head/bin/sh/tests/set-e/Makefile.depend 296587 2016-03-09 22:46:01Z bdrewery $
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/shell_cmds/sh/tests/set-e/and1.0 b/shell_cmds/sh/tests/set-e/and1.0
new file mode 100644
index 0000000..4518124
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/and1.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/set-e/and1.0 149781 2005-09-04 11:59:59Z stefanf $
+set -e
+true && true
diff --git a/shell_cmds/sh/tests/set-e/and2.1 b/shell_cmds/sh/tests/set-e/and2.1
new file mode 100644
index 0000000..2067f10
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/and2.1
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/set-e/and2.1 149781 2005-09-04 11:59:59Z stefanf $
+set -e
+true && false
+exit 0
diff --git a/shell_cmds/sh/tests/set-e/and3.0 b/shell_cmds/sh/tests/set-e/and3.0
new file mode 100644
index 0000000..59dccce
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/and3.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/set-e/and3.0 149781 2005-09-04 11:59:59Z stefanf $
+set -e
+false && true
+exit 0
diff --git a/shell_cmds/sh/tests/set-e/and4.0 b/shell_cmds/sh/tests/set-e/and4.0
new file mode 100644
index 0000000..fd1cc72
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/and4.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/set-e/and4.0 149781 2005-09-04 11:59:59Z stefanf $
+set -e
+false && false
+exit 0
diff --git a/shell_cmds/sh/tests/set-e/background1.0 b/shell_cmds/sh/tests/set-e/background1.0
new file mode 100644
index 0000000..e31b7a3
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/background1.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/set-e/background1.0 149781 2005-09-04 11:59:59Z stefanf $
+set -e
+false &
diff --git a/shell_cmds/sh/tests/set-e/cmd1.0 b/shell_cmds/sh/tests/set-e/cmd1.0
new file mode 100644
index 0000000..7c6c843
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/cmd1.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/set-e/cmd1.0 149781 2005-09-04 11:59:59Z stefanf $
+set -e
+true
diff --git a/shell_cmds/sh/tests/set-e/cmd2.1 b/shell_cmds/sh/tests/set-e/cmd2.1
new file mode 100644
index 0000000..05a4243
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/cmd2.1
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/set-e/cmd2.1 149781 2005-09-04 11:59:59Z stefanf $
+set -e
+false
+exit 0
diff --git a/shell_cmds/sh/tests/set-e/elif1.0 b/shell_cmds/sh/tests/set-e/elif1.0
new file mode 100644
index 0000000..38ccaec
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/elif1.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/set-e/elif1.0 211399 2010-08-16 17:18:08Z jilles $
+set -e
+if false; then
+ :
+elif false; then
+ :
+fi
diff --git a/shell_cmds/sh/tests/set-e/elif2.0 b/shell_cmds/sh/tests/set-e/elif2.0
new file mode 100644
index 0000000..694b3f0
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/elif2.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/set-e/elif2.0 211399 2010-08-16 17:18:08Z jilles $
+set -e
+if false; then
+ :
+elif false; false; then
+ :
+fi
diff --git a/shell_cmds/sh/tests/set-e/eval1.0 b/shell_cmds/sh/tests/set-e/eval1.0
new file mode 100644
index 0000000..cefaf91
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/eval1.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/set-e/eval1.0 193178 2009-05-31 17:23:27Z stefanf $
+set -e
+eval false || true
diff --git a/shell_cmds/sh/tests/set-e/eval2.1 b/shell_cmds/sh/tests/set-e/eval2.1
new file mode 100644
index 0000000..e396e1c
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/eval2.1
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/set-e/eval2.1 193178 2009-05-31 17:23:27Z stefanf $
+set -e
+eval false
+exit 0
diff --git a/shell_cmds/sh/tests/set-e/for1.0 b/shell_cmds/sh/tests/set-e/for1.0
new file mode 100644
index 0000000..d0f7d8f
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/for1.0
@@ -0,0 +1,9 @@
+# $FreeBSD: head/bin/sh/tests/set-e/for1.0 149791 2005-09-05 09:42:10Z stefanf $
+set -e
+f() {
+ for i in a b c; do
+ false
+ true
+ done
+}
+f || true
diff --git a/shell_cmds/sh/tests/set-e/func1.0 b/shell_cmds/sh/tests/set-e/func1.0
new file mode 100644
index 0000000..c76d689
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/func1.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/set-e/func1.0 149791 2005-09-05 09:42:10Z stefanf $
+set -e
+f() {
+ false
+ true
+}
+f || true
diff --git a/shell_cmds/sh/tests/set-e/func2.1 b/shell_cmds/sh/tests/set-e/func2.1
new file mode 100644
index 0000000..267966d
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/func2.1
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/set-e/func2.1 149791 2005-09-05 09:42:10Z stefanf $
+set -e
+f() {
+ false
+ exit 0
+}
+f
diff --git a/shell_cmds/sh/tests/set-e/if1.0 b/shell_cmds/sh/tests/set-e/if1.0
new file mode 100644
index 0000000..5697e2f
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/if1.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/set-e/if1.0 211399 2010-08-16 17:18:08Z jilles $
+set -e
+if false; then
+ :
+fi
diff --git a/shell_cmds/sh/tests/set-e/if2.0 b/shell_cmds/sh/tests/set-e/if2.0
new file mode 100644
index 0000000..188361b
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/if2.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/set-e/if2.0 149781 2005-09-04 11:59:59Z stefanf $
+set -e
+# PR 28852
+if true; then
+ false && true
+fi
+exit 0
diff --git a/shell_cmds/sh/tests/set-e/if3.0 b/shell_cmds/sh/tests/set-e/if3.0
new file mode 100644
index 0000000..e3d8d6e
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/if3.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/set-e/if3.0 211399 2010-08-16 17:18:08Z jilles $
+set -e
+if false; false; then
+ :
+fi
diff --git a/shell_cmds/sh/tests/set-e/not1.0 b/shell_cmds/sh/tests/set-e/not1.0
new file mode 100644
index 0000000..b694be8
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/not1.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/set-e/not1.0 149781 2005-09-04 11:59:59Z stefanf $
+set -e
+! true
+exit 0
diff --git a/shell_cmds/sh/tests/set-e/not2.0 b/shell_cmds/sh/tests/set-e/not2.0
new file mode 100644
index 0000000..d9ea5e9
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/not2.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/set-e/not2.0 193178 2009-05-31 17:23:27Z stefanf $
+set -e
+! false
+! eval false
diff --git a/shell_cmds/sh/tests/set-e/or1.0 b/shell_cmds/sh/tests/set-e/or1.0
new file mode 100644
index 0000000..5000f0b
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/or1.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/set-e/or1.0 149781 2005-09-04 11:59:59Z stefanf $
+set -e
+true || false
diff --git a/shell_cmds/sh/tests/set-e/or2.0 b/shell_cmds/sh/tests/set-e/or2.0
new file mode 100644
index 0000000..6964220
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/or2.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/set-e/or2.0 149781 2005-09-04 11:59:59Z stefanf $
+set -e
+false || true
diff --git a/shell_cmds/sh/tests/set-e/or3.1 b/shell_cmds/sh/tests/set-e/or3.1
new file mode 100644
index 0000000..29af2c2
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/or3.1
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/set-e/or3.1 149781 2005-09-04 11:59:59Z stefanf $
+set -e
+false || false
+exit 0
diff --git a/shell_cmds/sh/tests/set-e/pipe1.1 b/shell_cmds/sh/tests/set-e/pipe1.1
new file mode 100644
index 0000000..122af07
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/pipe1.1
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/set-e/pipe1.1 149781 2005-09-04 11:59:59Z stefanf $
+set -e
+true | false
+exit 0
diff --git a/shell_cmds/sh/tests/set-e/pipe2.0 b/shell_cmds/sh/tests/set-e/pipe2.0
new file mode 100644
index 0000000..d80fd93
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/pipe2.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/set-e/pipe2.0 149781 2005-09-04 11:59:59Z stefanf $
+set -e
+false | true
diff --git a/shell_cmds/sh/tests/set-e/return1.0 b/shell_cmds/sh/tests/set-e/return1.0
new file mode 100644
index 0000000..d157059
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/return1.0
@@ -0,0 +1,11 @@
+# $FreeBSD: head/bin/sh/tests/set-e/return1.0 149788 2005-09-04 21:29:09Z stefanf $
+set -e
+
+# PR 77067, 85267
+f() {
+ return 1
+ true
+}
+
+f || true
+exit 0
diff --git a/shell_cmds/sh/tests/set-e/semi1.1 b/shell_cmds/sh/tests/set-e/semi1.1
new file mode 100644
index 0000000..5991f8d
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/semi1.1
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/set-e/semi1.1 149781 2005-09-04 11:59:59Z stefanf $
+set -e
+false; true
+exit 0
diff --git a/shell_cmds/sh/tests/set-e/semi2.1 b/shell_cmds/sh/tests/set-e/semi2.1
new file mode 100644
index 0000000..6851700
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/semi2.1
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/set-e/semi2.1 149781 2005-09-04 11:59:59Z stefanf $
+set -e
+true; false
+exit 0
diff --git a/shell_cmds/sh/tests/set-e/subshell1.0 b/shell_cmds/sh/tests/set-e/subshell1.0
new file mode 100644
index 0000000..fa2ec82
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/subshell1.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/set-e/subshell1.0 149781 2005-09-04 11:59:59Z stefanf $
+set -e
+(true)
diff --git a/shell_cmds/sh/tests/set-e/subshell2.1 b/shell_cmds/sh/tests/set-e/subshell2.1
new file mode 100644
index 0000000..03b09dc
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/subshell2.1
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/set-e/subshell2.1 149781 2005-09-04 11:59:59Z stefanf $
+set -e
+(false)
+exit 0
diff --git a/shell_cmds/sh/tests/set-e/until1.0 b/shell_cmds/sh/tests/set-e/until1.0
new file mode 100644
index 0000000..c4d2edd
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/until1.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/set-e/until1.0 149781 2005-09-04 11:59:59Z stefanf $
+set -e
+until false; do
+ break
+done
diff --git a/shell_cmds/sh/tests/set-e/until2.0 b/shell_cmds/sh/tests/set-e/until2.0
new file mode 100644
index 0000000..d19a740
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/until2.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/set-e/until2.0 149781 2005-09-04 11:59:59Z stefanf $
+set -e
+until false; false; do
+ break
+done
diff --git a/shell_cmds/sh/tests/set-e/until3.0 b/shell_cmds/sh/tests/set-e/until3.0
new file mode 100644
index 0000000..2f77903
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/until3.0
@@ -0,0 +1,9 @@
+# $FreeBSD: head/bin/sh/tests/set-e/until3.0 149791 2005-09-05 09:42:10Z stefanf $
+set -e
+f() {
+ until false; do
+ false
+ break
+ done
+}
+f || true
diff --git a/shell_cmds/sh/tests/set-e/while1.0 b/shell_cmds/sh/tests/set-e/while1.0
new file mode 100644
index 0000000..6d7fe0a
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/while1.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/set-e/while1.0 211399 2010-08-16 17:18:08Z jilles $
+set -e
+while false; do
+ :
+done
diff --git a/shell_cmds/sh/tests/set-e/while2.0 b/shell_cmds/sh/tests/set-e/while2.0
new file mode 100644
index 0000000..fe2f2ba
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/while2.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/set-e/while2.0 211399 2010-08-16 17:18:08Z jilles $
+set -e
+while false; false; do
+ :
+done
diff --git a/shell_cmds/sh/tests/set-e/while3.0 b/shell_cmds/sh/tests/set-e/while3.0
new file mode 100644
index 0000000..bf87175
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/while3.0
@@ -0,0 +1,9 @@
+# $FreeBSD: head/bin/sh/tests/set-e/while3.0 149791 2005-09-05 09:42:10Z stefanf $
+set -e
+f() {
+ while true; do
+ false
+ break
+ done
+}
+f || true
diff --git a/shell_cmds/sh/trap.c b/shell_cmds/sh/trap.c
new file mode 100644
index 0000000..0f84892
--- /dev/null
+++ b/shell_cmds/sh/trap.c
@@ -0,0 +1,556 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)trap.c 8.5 (Berkeley) 6/5/95";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/bin/sh/trap.c 326025 2017-11-20 19:49:47Z pfg $");
+
+#include <signal.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include "shell.h"
+#include "main.h"
+#include "nodes.h" /* for other headers */
+#include "eval.h"
+#include "jobs.h"
+#include "show.h"
+#include "options.h"
+#include "syntax.h"
+#include "output.h"
+#include "memalloc.h"
+#include "error.h"
+#include "trap.h"
+#include "mystring.h"
+#include "builtins.h"
+#include "myhistedit.h"
+
+#ifdef __APPLE__
+#define sys_nsig (NSIG)
+#endif /* __APPLE__ */
+
+/*
+ * Sigmode records the current value of the signal handlers for the various
+ * modes. A value of zero means that the current handler is not known.
+ * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
+ */
+
+#define S_DFL 1 /* default signal handling (SIG_DFL) */
+#define S_CATCH 2 /* signal is caught */
+#define S_IGN 3 /* signal is ignored (SIG_IGN) */
+#define S_HARD_IGN 4 /* signal is ignored permanently */
+#define S_RESET 5 /* temporary - to reset a hard ignored sig */
+
+
+static char sigmode[NSIG]; /* current value of signal */
+volatile sig_atomic_t pendingsig; /* indicates some signal received */
+volatile sig_atomic_t pendingsig_waitcmd; /* indicates wait builtin should be interrupted */
+static int in_dotrap; /* do we execute in a trap handler? */
+static char *volatile trap[NSIG]; /* trap handler commands */
+static volatile sig_atomic_t gotsig[NSIG];
+ /* indicates specified signal received */
+static int ignore_sigchld; /* Used while handling SIGCHLD traps. */
+static int last_trapsig;
+
+static int exiting; /* exitshell() has been called */
+static int exiting_exitstatus; /* value passed to exitshell() */
+
+static int getsigaction(int, sig_t *);
+
+
+/*
+ * Map a string to a signal number.
+ *
+ * Note: the signal number may exceed NSIG.
+ */
+static int
+sigstring_to_signum(char *sig)
+{
+
+ if (is_number(sig)) {
+ int signo;
+
+ signo = atoi(sig);
+ return ((signo >= 0 && signo < NSIG) ? signo : (-1));
+ } else if (strcasecmp(sig, "EXIT") == 0) {
+ return (0);
+ } else {
+ int n;
+
+ if (strncasecmp(sig, "SIG", 3) == 0)
+ sig += 3;
+ for (n = 1; n < sys_nsig; n++)
+ if (sys_signame[n] &&
+ strcasecmp(sys_signame[n], sig) == 0)
+ return (n);
+ }
+ return (-1);
+}
+
+
+/*
+ * Print a list of valid signal names.
+ */
+static void
+printsignals(void)
+{
+ int n, outlen;
+
+ outlen = 0;
+ for (n = 1; n < sys_nsig; n++) {
+ if (sys_signame[n]) {
+ out1fmt("%s", sys_signame[n]);
+ outlen += strlen(sys_signame[n]);
+ } else {
+ out1fmt("%d", n);
+ outlen += 3; /* good enough */
+ }
+ ++outlen;
+ if (outlen > 71 || n == sys_nsig - 1) {
+ out1str("\n");
+ outlen = 0;
+ } else {
+ out1c(' ');
+ }
+ }
+}
+
+
+/*
+ * The trap builtin.
+ */
+int
+trapcmd(int argc __unused, char **argv)
+{
+ char *action;
+ int signo;
+ int errors = 0;
+ int i;
+
+ while ((i = nextopt("l")) != '\0') {
+ switch (i) {
+ case 'l':
+ printsignals();
+ return (0);
+ }
+ }
+ argv = argptr;
+
+ if (*argv == NULL) {
+ for (signo = 0 ; signo < sys_nsig ; signo++) {
+ if (signo < NSIG && trap[signo] != NULL) {
+ out1str("trap -- ");
+ out1qstr(trap[signo]);
+ if (signo == 0) {
+ out1str(" EXIT\n");
+ } else if (sys_signame[signo]) {
+ out1fmt(" %s\n", sys_signame[signo]);
+ } else {
+ out1fmt(" %d\n", signo);
+ }
+ }
+ }
+ return 0;
+ }
+ action = NULL;
+ if (*argv && !is_number(*argv)) {
+ if (strcmp(*argv, "-") == 0)
+ argv++;
+ else {
+ action = *argv;
+ argv++;
+ }
+ }
+ for (; *argv; argv++) {
+ if ((signo = sigstring_to_signum(*argv)) == -1) {
+ warning("bad signal %s", *argv);
+ errors = 1;
+ continue;
+ }
+ INTOFF;
+ if (action)
+ action = savestr(action);
+ if (trap[signo])
+ ckfree(trap[signo]);
+ trap[signo] = action;
+ if (signo != 0)
+ setsignal(signo);
+ INTON;
+ }
+ return errors;
+}
+
+
+/*
+ * Clear traps on a fork.
+ */
+void
+clear_traps(void)
+{
+ char *volatile *tp;
+
+ for (tp = trap ; tp <= &trap[NSIG - 1] ; tp++) {
+ if (*tp && **tp) { /* trap not NULL or SIG_IGN */
+ INTOFF;
+ ckfree(*tp);
+ *tp = NULL;
+ if (tp != &trap[0])
+ setsignal(tp - trap);
+ INTON;
+ }
+ }
+}
+
+
+/*
+ * Check if we have any traps enabled.
+ */
+int
+have_traps(void)
+{
+ char *volatile *tp;
+
+ for (tp = trap ; tp <= &trap[NSIG - 1] ; tp++) {
+ if (*tp && **tp) /* trap not NULL or SIG_IGN */
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Set the signal handler for the specified signal. The routine figures
+ * out what it should be set to.
+ */
+void
+setsignal(int signo)
+{
+ int action;
+ sig_t sigact = SIG_DFL;
+ struct sigaction sa;
+ char *t;
+
+ if ((t = trap[signo]) == NULL)
+ action = S_DFL;
+ else if (*t != '\0')
+ action = S_CATCH;
+ else
+ action = S_IGN;
+ if (action == S_DFL) {
+ switch (signo) {
+ case SIGINT:
+ action = S_CATCH;
+ break;
+ case SIGQUIT:
+#ifdef DEBUG
+ {
+ extern int debug;
+
+ if (debug)
+ break;
+ }
+#endif
+ action = S_CATCH;
+ break;
+ case SIGTERM:
+ if (rootshell && iflag)
+ action = S_IGN;
+ break;
+#if JOBS
+ case SIGTSTP:
+ case SIGTTOU:
+ if (rootshell && mflag)
+ action = S_IGN;
+ break;
+#endif
+ }
+ }
+
+ t = &sigmode[signo];
+ if (*t == 0) {
+ /*
+ * current setting unknown
+ */
+ if (!getsigaction(signo, &sigact)) {
+ /*
+ * Pretend it worked; maybe we should give a warning
+ * here, but other shells don't. We don't alter
+ * sigmode, so that we retry every time.
+ */
+ return;
+ }
+ if (sigact == SIG_IGN) {
+ if (mflag && (signo == SIGTSTP ||
+ signo == SIGTTIN || signo == SIGTTOU)) {
+ *t = S_IGN; /* don't hard ignore these */
+ } else
+ *t = S_HARD_IGN;
+ } else {
+ *t = S_RESET; /* force to be set */
+ }
+ }
+ if (*t == S_HARD_IGN || *t == action)
+ return;
+ switch (action) {
+ case S_DFL: sigact = SIG_DFL; break;
+ case S_CATCH: sigact = onsig; break;
+ case S_IGN: sigact = SIG_IGN; break;
+ }
+ *t = action;
+ sa.sa_handler = sigact;
+ sa.sa_flags = 0;
+ sigemptyset(&sa.sa_mask);
+ sigaction(signo, &sa, NULL);
+}
+
+
+/*
+ * Return the current setting for sig w/o changing it.
+ */
+static int
+getsigaction(int signo, sig_t *sigact)
+{
+ struct sigaction sa;
+
+ if (sigaction(signo, (struct sigaction *)0, &sa) == -1)
+ return 0;
+ *sigact = (sig_t) sa.sa_handler;
+ return 1;
+}
+
+
+/*
+ * Ignore a signal.
+ */
+void
+ignoresig(int signo)
+{
+
+ if (sigmode[signo] == 0)
+ setsignal(signo);
+ if (sigmode[signo] != S_IGN && sigmode[signo] != S_HARD_IGN) {
+ signal(signo, SIG_IGN);
+ sigmode[signo] = S_IGN;
+ }
+}
+
+
+int
+issigchldtrapped(void)
+{
+
+ return (trap[SIGCHLD] != NULL && *trap[SIGCHLD] != '\0');
+}
+
+
+/*
+ * Signal handler.
+ */
+void
+onsig(int signo)
+{
+
+ if (signo == SIGINT && trap[SIGINT] == NULL) {
+ /*
+ * The !in_dotrap here is safe. The only way we can arrive
+ * here with in_dotrap set is that a trap handler set SIGINT to
+ * SIG_DFL and killed itself.
+ */
+ if (suppressint && !in_dotrap)
+ SET_PENDING_INT;
+ else
+ onint();
+ return;
+ }
+
+ /* If we are currently in a wait builtin, prepare to break it */
+ if (signo == SIGINT || signo == SIGQUIT)
+ pendingsig_waitcmd = signo;
+
+ if (trap[signo] != NULL && trap[signo][0] != '\0' &&
+ (signo != SIGCHLD || !ignore_sigchld)) {
+ gotsig[signo] = 1;
+ pendingsig = signo;
+ pendingsig_waitcmd = signo;
+ }
+}
+
+
+/*
+ * Called to execute a trap. Perhaps we should avoid entering new trap
+ * handlers while we are executing a trap handler.
+ */
+void
+dotrap(void)
+{
+ struct stackmark smark;
+ int i;
+ int savestatus, prev_evalskip, prev_skipcount;
+
+ in_dotrap++;
+ for (;;) {
+ pendingsig = 0;
+ pendingsig_waitcmd = 0;
+ for (i = 1; i < NSIG; i++) {
+ if (gotsig[i]) {
+ gotsig[i] = 0;
+ if (trap[i]) {
+ /*
+ * Ignore SIGCHLD to avoid infinite
+ * recursion if the trap action does
+ * a fork.
+ */
+ if (i == SIGCHLD)
+ ignore_sigchld++;
+
+ /*
+ * Backup current evalskip
+ * state and reset it before
+ * executing a trap, so that the
+ * trap is not disturbed by an
+ * ongoing break/continue/return
+ * statement.
+ */
+ prev_evalskip = evalskip;
+ prev_skipcount = skipcount;
+ evalskip = 0;
+
+ last_trapsig = i;
+ savestatus = exitstatus;
+ setstackmark(&smark);
+ evalstring(stsavestr(trap[i]), 0);
+ popstackmark(&smark);
+
+ /*
+ * If such a command was not
+ * already in progress, allow a
+ * break/continue/return in the
+ * trap action to have an effect
+ * outside of it.
+ */
+ if (evalskip == 0 ||
+ prev_evalskip != 0) {
+ evalskip = prev_evalskip;
+ skipcount = prev_skipcount;
+ exitstatus = savestatus;
+ }
+
+ if (i == SIGCHLD)
+ ignore_sigchld--;
+ }
+ break;
+ }
+ }
+ if (i >= NSIG)
+ break;
+ }
+ in_dotrap--;
+}
+
+
+/*
+ * Controls whether the shell is interactive or not based on iflag.
+ */
+void
+setinteractive(void)
+{
+ setsignal(SIGINT);
+ setsignal(SIGQUIT);
+ setsignal(SIGTERM);
+}
+
+
+/*
+ * Called to exit the shell.
+ */
+void
+exitshell(int status)
+{
+ TRACE(("exitshell(%d) pid=%d\n", status, getpid()));
+ exiting = 1;
+ exiting_exitstatus = status;
+ exitshell_savedstatus();
+}
+
+void
+exitshell_savedstatus(void)
+{
+ struct jmploc loc1, loc2;
+ char *p;
+ int sig = 0;
+ sigset_t sigs;
+
+ if (!exiting) {
+ if (in_dotrap && last_trapsig) {
+ sig = last_trapsig;
+ exiting_exitstatus = sig + 128;
+ } else
+ exiting_exitstatus = oexitstatus;
+ }
+ exitstatus = oexitstatus = exiting_exitstatus;
+ if (!setjmp(loc1.loc)) {
+ handler = &loc1;
+ if ((p = trap[0]) != NULL && *p != '\0') {
+ /*
+ * Reset evalskip, or the trap on EXIT could be
+ * interrupted if the last command was a "return".
+ */
+ evalskip = 0;
+ trap[0] = NULL;
+ FORCEINTON;
+ evalstring(p, 0);
+ }
+ }
+ if (!setjmp(loc2.loc)) {
+ handler = &loc2; /* probably unnecessary */
+ FORCEINTON;
+ flushall();
+#if JOBS
+ setjobctl(0);
+#endif
+ }
+ if (sig != 0 && sig != SIGSTOP && sig != SIGTSTP && sig != SIGTTIN &&
+ sig != SIGTTOU) {
+ signal(sig, SIG_DFL);
+ sigemptyset(&sigs);
+ sigaddset(&sigs, sig);
+ sigprocmask(SIG_UNBLOCK, &sigs, NULL);
+ kill(getpid(), sig);
+ /* If the default action is to ignore, fall back to _exit(). */
+ }
+ _exit(exiting_exitstatus);
+}
diff --git a/shell_cmds/sh/trap.h b/shell_cmds/sh/trap.h
new file mode 100644
index 0000000..90ba054
--- /dev/null
+++ b/shell_cmds/sh/trap.h
@@ -0,0 +1,50 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)trap.h 8.3 (Berkeley) 6/5/95
+ * $FreeBSD: head/bin/sh/trap.h 326025 2017-11-20 19:49:47Z pfg $
+ */
+
+extern volatile sig_atomic_t pendingsig;
+extern volatile sig_atomic_t pendingsig_waitcmd;
+
+void clear_traps(void);
+int have_traps(void);
+void setsignal(int);
+void ignoresig(int);
+int issigchldtrapped(void);
+void onsig(int);
+void dotrap(void);
+void setinteractive(void);
+void exitshell(int) __dead2;
+void exitshell_savedstatus(void) __dead2;
diff --git a/shell_cmds/sh/var.c b/shell_cmds/sh/var.c
new file mode 100644
index 0000000..feeea03
--- /dev/null
+++ b/shell_cmds/sh/var.c
@@ -0,0 +1,971 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)var.c 8.3 (Berkeley) 5/4/95";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/bin/sh/var.c 329221 2018-02-13 16:48:57Z bdrewery $");
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <paths.h>
+
+/*
+ * Shell variables.
+ */
+
+#include <locale.h>
+#include <langinfo.h>
+
+#include "shell.h"
+#include "output.h"
+#include "expand.h"
+#include "nodes.h" /* for other headers */
+#include "eval.h" /* defines cmdenviron */
+#include "exec.h"
+#include "syntax.h"
+#include "options.h"
+#include "mail.h"
+#include "var.h"
+#include "memalloc.h"
+#include "error.h"
+#include "mystring.h"
+#include "parser.h"
+#include "builtins.h"
+#ifndef NO_HISTORY
+#include "myhistedit.h"
+#endif
+
+
+#ifndef VTABSIZE
+#define VTABSIZE 39
+#endif
+
+
+struct varinit {
+ struct var *var;
+ int flags;
+ const char *text;
+ void (*func)(const char *);
+};
+
+
+#ifndef NO_HISTORY
+struct var vhistsize;
+struct var vterm;
+#endif
+struct var vifs;
+struct var vmail;
+struct var vmpath;
+struct var vpath;
+struct var vps1;
+struct var vps2;
+struct var vps4;
+static struct var voptind;
+struct var vdisvfork;
+
+struct localvar *localvars;
+int forcelocal;
+
+static const struct varinit varinit[] = {
+#ifndef NO_HISTORY
+ { &vhistsize, VUNSET, "HISTSIZE=",
+ sethistsize },
+#endif
+ { &vifs, 0, "IFS= \t\n",
+ NULL },
+ { &vmail, VUNSET, "MAIL=",
+ NULL },
+ { &vmpath, VUNSET, "MAILPATH=",
+ NULL },
+ { &vpath, 0, "PATH=" _PATH_DEFPATH,
+ changepath },
+ /*
+ * vps1 depends on uid
+ */
+ { &vps2, 0, "PS2=> ",
+ NULL },
+ { &vps4, 0, "PS4=+ ",
+ NULL },
+#ifndef NO_HISTORY
+ { &vterm, VUNSET, "TERM=",
+ setterm },
+#endif
+ { &voptind, 0, "OPTIND=1",
+ getoptsreset },
+ { &vdisvfork, VUNSET, "SH_DISABLE_VFORK=",
+ NULL },
+ { NULL, 0, NULL,
+ NULL }
+};
+
+static struct var *vartab[VTABSIZE];
+
+static const char *const locale_names[7] = {
+ "LC_COLLATE", "LC_CTYPE", "LC_MONETARY",
+ "LC_NUMERIC", "LC_TIME", "LC_MESSAGES", NULL
+};
+static const int locale_categories[7] = {
+ LC_COLLATE, LC_CTYPE, LC_MONETARY, LC_NUMERIC, LC_TIME, LC_MESSAGES, 0
+};
+
+static int varequal(const char *, const char *);
+static struct var *find_var(const char *, struct var ***, int *);
+static int localevar(const char *);
+static void setvareq_const(const char *s, int flags);
+
+extern char **environ;
+
+/*
+ * This routine initializes the builtin variables and imports the environment.
+ * It is called when the shell is initialized.
+ */
+
+void
+initvar(void)
+{
+ char ppid[20];
+ const struct varinit *ip;
+ struct var *vp;
+ struct var **vpp;
+ char **envp;
+
+ for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
+ if (find_var(ip->text, &vpp, &vp->name_len) != NULL)
+ continue;
+ vp->next = *vpp;
+ *vpp = vp;
+ vp->text = __DECONST(char *, ip->text);
+ vp->flags = ip->flags | VSTRFIXED | VTEXTFIXED;
+ vp->func = ip->func;
+ }
+ /*
+ * PS1 depends on uid
+ */
+ if (find_var("PS1", &vpp, &vps1.name_len) == NULL) {
+ vps1.next = *vpp;
+ *vpp = &vps1;
+ vps1.text = __DECONST(char *, geteuid() ? "PS1=$ " : "PS1=# ");
+ vps1.flags = VSTRFIXED|VTEXTFIXED;
+ }
+ fmtstr(ppid, sizeof(ppid), "%d", (int)getppid());
+ setvarsafe("PPID", ppid, 0);
+ for (envp = environ ; *envp ; envp++) {
+ if (strchr(*envp, '=')) {
+ setvareq(*envp, VEXPORT|VTEXTFIXED);
+ }
+ }
+ setvareq_const("OPTIND=1", 0);
+ setvareq_const("IFS= \t\n", 0);
+}
+
+/*
+ * Safe version of setvar, returns 1 on success 0 on failure.
+ */
+
+int
+setvarsafe(const char *name, const char *val, int flags)
+{
+ struct jmploc jmploc;
+ struct jmploc *const savehandler = handler;
+ int err = 0;
+ int inton;
+
+ inton = is_int_on();
+ if (setjmp(jmploc.loc))
+ err = 1;
+ else {
+ handler = &jmploc;
+ setvar(name, val, flags);
+ }
+ handler = savehandler;
+ SETINTON(inton);
+ return err;
+}
+
+/*
+ * Set the value of a variable. The flags argument is stored with the
+ * flags of the variable. If val is NULL, the variable is unset.
+ */
+
+void
+setvar(const char *name, const char *val, int flags)
+{
+ const char *p;
+ size_t len;
+ size_t namelen;
+ size_t vallen;
+ char *nameeq;
+ int isbad;
+
+ isbad = 0;
+ p = name;
+ if (! is_name(*p))
+ isbad = 1;
+ p++;
+ for (;;) {
+ if (! is_in_name(*p)) {
+ if (*p == '\0' || *p == '=')
+ break;
+ isbad = 1;
+ }
+ p++;
+ }
+ namelen = p - name;
+ if (isbad)
+ error("%.*s: bad variable name", (int)namelen, name);
+ len = namelen + 2; /* 2 is space for '=' and '\0' */
+ if (val == NULL) {
+ flags |= VUNSET;
+ vallen = 0;
+ } else {
+ vallen = strlen(val);
+ len += vallen;
+ }
+ INTOFF;
+ nameeq = ckmalloc(len);
+ memcpy(nameeq, name, namelen);
+ nameeq[namelen] = '=';
+ if (val)
+ memcpy(nameeq + namelen + 1, val, vallen + 1);
+ else
+ nameeq[namelen + 1] = '\0';
+ setvareq(nameeq, flags);
+ INTON;
+}
+
+static int
+localevar(const char *s)
+{
+ const char *const *ss;
+
+ if (*s != 'L')
+ return 0;
+ if (varequal(s + 1, "ANG"))
+ return 1;
+ if (strncmp(s + 1, "C_", 2) != 0)
+ return 0;
+ if (varequal(s + 3, "ALL"))
+ return 1;
+ for (ss = locale_names; *ss ; ss++)
+ if (varequal(s + 3, *ss + 3))
+ return 1;
+ return 0;
+}
+
+
+/*
+ * Sets/unsets an environment variable from a pointer that may actually be a
+ * pointer into environ where the string should not be manipulated.
+ */
+static void
+change_env(const char *s, int set)
+{
+ char *eqp;
+ char *ss;
+
+ INTOFF;
+ ss = savestr(s);
+ if ((eqp = strchr(ss, '=')) != NULL)
+ *eqp = '\0';
+ if (set && eqp != NULL)
+ (void) setenv(ss, eqp + 1, 1);
+ else
+ (void) unsetenv(ss);
+ ckfree(ss);
+ INTON;
+
+ return;
+}
+
+
+/*
+ * Same as setvar except that the variable and value are passed in
+ * the first argument as name=value. Since the first argument will
+ * be actually stored in the table, it should not be a string that
+ * will go away.
+ */
+
+void
+setvareq(char *s, int flags)
+{
+ struct var *vp, **vpp;
+ int nlen;
+
+ if (aflag)
+ flags |= VEXPORT;
+ if (forcelocal && !(flags & (VNOSET | VNOLOCAL)))
+ mklocal(s);
+ vp = find_var(s, &vpp, &nlen);
+ if (vp != NULL) {
+ if (vp->flags & VREADONLY) {
+ if ((flags & (VTEXTFIXED|VSTACK)) == 0)
+ ckfree(s);
+ error("%.*s: is read only", vp->name_len, vp->text);
+ }
+ if (flags & VNOSET) {
+ if ((flags & (VTEXTFIXED|VSTACK)) == 0)
+ ckfree(s);
+ return;
+ }
+ INTOFF;
+
+ if (vp->func && (flags & VNOFUNC) == 0)
+ (*vp->func)(s + vp->name_len + 1);
+
+ if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
+ ckfree(vp->text);
+
+ vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET);
+ vp->flags |= flags;
+ vp->text = s;
+
+ /*
+ * We could roll this to a function, to handle it as
+ * a regular variable function callback, but why bother?
+ *
+ * Note: this assumes iflag is not set to 1 initially.
+ * As part of initvar(), this is called before arguments
+ * are looked at.
+ */
+ if ((vp == &vmpath || (vp == &vmail && ! mpathset())) &&
+ iflag == 1)
+ chkmail(1);
+ if ((vp->flags & VEXPORT) && localevar(s)) {
+ change_env(s, 1);
+ (void) setlocale(LC_ALL, "");
+ updatecharset();
+ }
+ INTON;
+ return;
+ }
+ /* not found */
+ if (flags & VNOSET) {
+ if ((flags & (VTEXTFIXED|VSTACK)) == 0)
+ ckfree(s);
+ return;
+ }
+ INTOFF;
+ vp = ckmalloc(sizeof (*vp));
+ vp->flags = flags;
+ vp->text = s;
+ vp->name_len = nlen;
+ vp->next = *vpp;
+ vp->func = NULL;
+ *vpp = vp;
+ if ((vp->flags & VEXPORT) && localevar(s)) {
+ change_env(s, 1);
+ (void) setlocale(LC_ALL, "");
+ updatecharset();
+ }
+ INTON;
+}
+
+
+static void
+setvareq_const(const char *s, int flags)
+{
+ setvareq(__DECONST(char *, s), flags | VTEXTFIXED);
+}
+
+
+/*
+ * Process a linked list of variable assignments.
+ */
+
+void
+listsetvar(struct arglist *list, int flags)
+{
+ int i;
+
+ INTOFF;
+ for (i = 0; i < list->count; i++)
+ setvareq(savestr(list->args[i]), flags);
+ INTON;
+}
+
+
+
+/*
+ * Find the value of a variable. Returns NULL if not set.
+ */
+
+char *
+lookupvar(const char *name)
+{
+ struct var *v;
+
+ v = find_var(name, NULL, NULL);
+ if (v == NULL || v->flags & VUNSET)
+ return NULL;
+ return v->text + v->name_len + 1;
+}
+
+
+
+/*
+ * Search the environment of a builtin command. If the second argument
+ * is nonzero, return the value of a variable even if it hasn't been
+ * exported.
+ */
+
+char *
+bltinlookup(const char *name, int doall)
+{
+ struct var *v;
+ char *result;
+ int i;
+
+ result = NULL;
+ if (cmdenviron) for (i = 0; i < cmdenviron->count; i++) {
+ if (varequal(cmdenviron->args[i], name))
+ result = strchr(cmdenviron->args[i], '=') + 1;
+ }
+ if (result != NULL)
+ return result;
+
+ v = find_var(name, NULL, NULL);
+ if (v == NULL || v->flags & VUNSET ||
+ (!doall && (v->flags & VEXPORT) == 0))
+ return NULL;
+ return v->text + v->name_len + 1;
+}
+
+
+/*
+ * Set up locale for a builtin (LANG/LC_* assignments).
+ */
+void
+bltinsetlocale(void)
+{
+ int act = 0;
+ char *loc, *locdef;
+ int i;
+
+ if (cmdenviron) for (i = 0; i < cmdenviron->count; i++) {
+ if (localevar(cmdenviron->args[i])) {
+ act = 1;
+ break;
+ }
+ }
+ if (!act)
+ return;
+ loc = bltinlookup("LC_ALL", 0);
+ INTOFF;
+ if (loc != NULL) {
+ setlocale(LC_ALL, loc);
+ INTON;
+ updatecharset();
+ return;
+ }
+ locdef = bltinlookup("LANG", 0);
+ for (i = 0; locale_names[i] != NULL; i++) {
+ loc = bltinlookup(locale_names[i], 0);
+ if (loc == NULL)
+ loc = locdef;
+ if (loc != NULL)
+ setlocale(locale_categories[i], loc);
+ }
+ INTON;
+ updatecharset();
+}
+
+/*
+ * Undo the effect of bltinlocaleset().
+ */
+void
+bltinunsetlocale(void)
+{
+ int i;
+
+ INTOFF;
+ if (cmdenviron) for (i = 0; i < cmdenviron->count; i++) {
+ if (localevar(cmdenviron->args[i])) {
+ setlocale(LC_ALL, "");
+ updatecharset();
+ break;
+ }
+ }
+ INTON;
+}
+
+/*
+ * Update the localeisutf8 flag.
+ */
+void
+updatecharset(void)
+{
+ char *charset;
+
+ charset = nl_langinfo(CODESET);
+ localeisutf8 = !strcmp(charset, "UTF-8");
+}
+
+void
+initcharset(void)
+{
+ updatecharset();
+ initial_localeisutf8 = localeisutf8;
+}
+
+/*
+ * Generate a list of exported variables. This routine is used to construct
+ * the third argument to execve when executing a program.
+ */
+
+char **
+environment(void)
+{
+ int nenv;
+ struct var **vpp;
+ struct var *vp;
+ char **env, **ep;
+
+ nenv = 0;
+ for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
+ for (vp = *vpp ; vp ; vp = vp->next)
+ if (vp->flags & VEXPORT)
+ nenv++;
+ }
+ ep = env = stalloc((nenv + 1) * sizeof *env);
+ for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
+ for (vp = *vpp ; vp ; vp = vp->next)
+ if (vp->flags & VEXPORT)
+ *ep++ = vp->text;
+ }
+ *ep = NULL;
+ return env;
+}
+
+
+static int
+var_compare(const void *a, const void *b)
+{
+ const char *const *sa, *const *sb;
+
+ sa = a;
+ sb = b;
+ /*
+ * This compares two var=value strings which creates a different
+ * order from what you would probably expect. POSIX is somewhat
+ * ambiguous on what should be sorted exactly.
+ */
+ return strcoll(*sa, *sb);
+}
+
+
+/*
+ * Command to list all variables which are set. This is invoked from the
+ * set command when it is called without any options or operands.
+ */
+
+int
+showvarscmd(int argc __unused, char **argv __unused)
+{
+ struct var **vpp;
+ struct var *vp;
+ const char *s;
+ const char **vars;
+ int i, n;
+
+ /*
+ * POSIX requires us to sort the variables.
+ */
+ n = 0;
+ for (vpp = vartab; vpp < vartab + VTABSIZE; vpp++) {
+ for (vp = *vpp; vp; vp = vp->next) {
+ if (!(vp->flags & VUNSET))
+ n++;
+ }
+ }
+
+ INTOFF;
+ vars = ckmalloc(n * sizeof(*vars));
+ i = 0;
+ for (vpp = vartab; vpp < vartab + VTABSIZE; vpp++) {
+ for (vp = *vpp; vp; vp = vp->next) {
+ if (!(vp->flags & VUNSET))
+ vars[i++] = vp->text;
+ }
+ }
+
+ qsort(vars, n, sizeof(*vars), var_compare);
+ for (i = 0; i < n; i++) {
+ /*
+ * Skip improper variable names so the output remains usable as
+ * shell input.
+ */
+ if (!isassignment(vars[i]))
+ continue;
+ s = strchr(vars[i], '=');
+ s++;
+ outbin(vars[i], s - vars[i], out1);
+ out1qstr(s);
+ out1c('\n');
+ }
+ ckfree(vars);
+ INTON;
+
+ return 0;
+}
+
+
+
+/*
+ * The export and readonly commands.
+ */
+
+int
+exportcmd(int argc __unused, char **argv)
+{
+ struct var **vpp;
+ struct var *vp;
+ char **ap;
+ char *name;
+ char *p;
+ char *cmdname;
+ int ch, values;
+ int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
+
+ cmdname = argv[0];
+ values = 0;
+ while ((ch = nextopt("p")) != '\0') {
+ switch (ch) {
+ case 'p':
+ values = 1;
+ break;
+ }
+ }
+
+ if (values && *argptr != NULL)
+ error("-p requires no arguments");
+ if (*argptr != NULL) {
+ for (ap = argptr; (name = *ap) != NULL; ap++) {
+ if ((p = strchr(name, '=')) != NULL) {
+ p++;
+ } else {
+ vp = find_var(name, NULL, NULL);
+ if (vp != NULL) {
+ vp->flags |= flag;
+ if ((vp->flags & VEXPORT) && localevar(vp->text)) {
+ change_env(vp->text, 1);
+ (void) setlocale(LC_ALL, "");
+ updatecharset();
+ }
+ continue;
+ }
+ }
+ setvar(name, p, flag);
+ }
+ } else {
+ for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
+ for (vp = *vpp ; vp ; vp = vp->next) {
+ if (vp->flags & flag) {
+ if (values) {
+ /*
+ * Skip improper variable names
+ * so the output remains usable
+ * as shell input.
+ */
+ if (!isassignment(vp->text))
+ continue;
+ out1str(cmdname);
+ out1c(' ');
+ }
+ if (values && !(vp->flags & VUNSET)) {
+ outbin(vp->text,
+ vp->name_len + 1, out1);
+ out1qstr(vp->text +
+ vp->name_len + 1);
+ } else
+ outbin(vp->text, vp->name_len,
+ out1);
+ out1c('\n');
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+
+/*
+ * The "local" command.
+ */
+
+int
+localcmd(int argc __unused, char **argv __unused)
+{
+ char *name;
+
+ nextopt("");
+ if (! in_function())
+ error("Not in a function");
+ while ((name = *argptr++) != NULL) {
+ mklocal(name);
+ }
+ return 0;
+}
+
+
+/*
+ * Make a variable a local variable. When a variable is made local, it's
+ * value and flags are saved in a localvar structure. The saved values
+ * will be restored when the shell function returns. We handle the name
+ * "-" as a special case.
+ */
+
+void
+mklocal(char *name)
+{
+ struct localvar *lvp;
+ struct var **vpp;
+ struct var *vp;
+
+ INTOFF;
+ lvp = ckmalloc(sizeof (struct localvar));
+ if (name[0] == '-' && name[1] == '\0') {
+ lvp->text = ckmalloc(sizeof optval);
+ memcpy(lvp->text, optval, sizeof optval);
+ vp = NULL;
+ } else {
+ vp = find_var(name, &vpp, NULL);
+ if (vp == NULL) {
+ if (strchr(name, '='))
+ setvareq(savestr(name), VSTRFIXED | VNOLOCAL);
+ else
+ setvar(name, NULL, VSTRFIXED | VNOLOCAL);
+ vp = *vpp; /* the new variable */
+ lvp->text = NULL;
+ lvp->flags = VUNSET;
+ } else {
+ lvp->text = vp->text;
+ lvp->flags = vp->flags;
+ vp->flags |= VSTRFIXED|VTEXTFIXED;
+ if (name[vp->name_len] == '=')
+ setvareq(savestr(name), VNOLOCAL);
+ }
+ }
+ lvp->vp = vp;
+ lvp->next = localvars;
+ localvars = lvp;
+ INTON;
+}
+
+
+/*
+ * Called after a function returns.
+ */
+
+void
+poplocalvars(void)
+{
+ struct localvar *lvp;
+ struct var *vp;
+ int islocalevar;
+
+ INTOFF;
+ while ((lvp = localvars) != NULL) {
+ localvars = lvp->next;
+ vp = lvp->vp;
+ if (vp == NULL) { /* $- saved */
+ memcpy(optval, lvp->text, sizeof optval);
+ ckfree(lvp->text);
+ optschanged();
+ } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
+ vp->flags &= ~VREADONLY;
+ (void)unsetvar(vp->text);
+ } else {
+ islocalevar = (vp->flags | lvp->flags) & VEXPORT &&
+ localevar(lvp->text);
+ if ((vp->flags & VTEXTFIXED) == 0)
+ ckfree(vp->text);
+ vp->flags = lvp->flags;
+ vp->text = lvp->text;
+ if (vp->func)
+ (*vp->func)(vp->text + vp->name_len + 1);
+ if (islocalevar) {
+ change_env(vp->text, vp->flags & VEXPORT &&
+ (vp->flags & VUNSET) == 0);
+ setlocale(LC_ALL, "");
+ updatecharset();
+ }
+ }
+ ckfree(lvp);
+ }
+ INTON;
+}
+
+
+int
+setvarcmd(int argc, char **argv)
+{
+ if (argc <= 2)
+ return unsetcmd(argc, argv);
+ else if (argc == 3)
+ setvar(argv[1], argv[2], 0);
+ else
+ error("too many arguments");
+ return 0;
+}
+
+
+/*
+ * The unset builtin command.
+ */
+
+int
+unsetcmd(int argc __unused, char **argv __unused)
+{
+ char **ap;
+ int i;
+ int flg_func = 0;
+ int flg_var = 0;
+ int ret = 0;
+
+ while ((i = nextopt("vf")) != '\0') {
+ if (i == 'f')
+ flg_func = 1;
+ else
+ flg_var = 1;
+ }
+ if (flg_func == 0 && flg_var == 0)
+ flg_var = 1;
+
+ INTOFF;
+ for (ap = argptr; *ap ; ap++) {
+ if (flg_func)
+ ret |= unsetfunc(*ap);
+ if (flg_var)
+ ret |= unsetvar(*ap);
+ }
+ INTON;
+ return ret;
+}
+
+
+/*
+ * Unset the specified variable.
+ * Called with interrupts off.
+ */
+
+int
+unsetvar(const char *s)
+{
+ struct var **vpp;
+ struct var *vp;
+
+ vp = find_var(s, &vpp, NULL);
+ if (vp == NULL)
+ return (0);
+ if (vp->flags & VREADONLY)
+ return (1);
+ if (vp->text[vp->name_len + 1] != '\0')
+ setvar(s, "", 0);
+ if ((vp->flags & VEXPORT) && localevar(vp->text)) {
+ change_env(s, 0);
+ setlocale(LC_ALL, "");
+ updatecharset();
+ }
+ vp->flags &= ~VEXPORT;
+ vp->flags |= VUNSET;
+ if ((vp->flags & VSTRFIXED) == 0) {
+ if ((vp->flags & VTEXTFIXED) == 0)
+ ckfree(vp->text);
+ *vpp = vp->next;
+ ckfree(vp);
+ }
+ return (0);
+}
+
+
+
+/*
+ * Returns true if the two strings specify the same variable. The first
+ * variable name is terminated by '='; the second may be terminated by
+ * either '=' or '\0'.
+ */
+
+static int
+varequal(const char *p, const char *q)
+{
+ while (*p == *q++) {
+ if (*p++ == '=')
+ return 1;
+ }
+ if (*p == '=' && *(q - 1) == '\0')
+ return 1;
+ return 0;
+}
+
+/*
+ * Search for a variable.
+ * 'name' may be terminated by '=' or a NUL.
+ * vppp is set to the pointer to vp, or the list head if vp isn't found
+ * lenp is set to the number of characters in 'name'
+ */
+
+static struct var *
+find_var(const char *name, struct var ***vppp, int *lenp)
+{
+ unsigned int hashval;
+ int len;
+ struct var *vp, **vpp;
+ const char *p = name;
+
+ hashval = 0;
+ while (*p && *p != '=')
+ hashval = 2 * hashval + (unsigned char)*p++;
+ len = p - name;
+
+ if (lenp)
+ *lenp = len;
+ vpp = &vartab[hashval % VTABSIZE];
+ if (vppp)
+ *vppp = vpp;
+
+ for (vp = *vpp ; vp ; vpp = &vp->next, vp = *vpp) {
+ if (vp->name_len != len)
+ continue;
+ if (memcmp(vp->text, name, len) != 0)
+ continue;
+ if (vppp)
+ *vppp = vpp;
+ return vp;
+ }
+ return NULL;
+}
diff --git a/shell_cmds/sh/var.h b/shell_cmds/sh/var.h
new file mode 100644
index 0000000..c9b5a99
--- /dev/null
+++ b/shell_cmds/sh/var.h
@@ -0,0 +1,132 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)var.h 8.2 (Berkeley) 5/4/95
+ * $FreeBSD: head/bin/sh/var.h 326025 2017-11-20 19:49:47Z pfg $
+ */
+
+/*
+ * Shell variables.
+ */
+
+/* flags */
+#define VEXPORT 0x01 /* variable is exported */
+#define VREADONLY 0x02 /* variable cannot be modified */
+#define VSTRFIXED 0x04 /* variable struct is statically allocated */
+#define VTEXTFIXED 0x08 /* text is statically allocated */
+#define VSTACK 0x10 /* text is allocated on the stack */
+#define VUNSET 0x20 /* the variable is not set */
+#define VNOFUNC 0x40 /* don't call the callback function */
+#define VNOSET 0x80 /* do not set variable - just readonly test */
+#define VNOLOCAL 0x100 /* ignore forcelocal */
+
+
+struct var {
+ struct var *next; /* next entry in hash list */
+ int flags; /* flags are defined above */
+ int name_len; /* length of name */
+ char *text; /* name=value */
+ void (*func)(const char *);
+ /* function to be called when */
+ /* the variable gets set/unset */
+};
+
+
+struct localvar {
+ struct localvar *next; /* next local variable in list */
+ struct var *vp; /* the variable that was made local */
+ int flags; /* saved flags */
+ char *text; /* saved text */
+};
+
+
+extern struct localvar *localvars;
+extern int forcelocal;
+
+extern struct var vifs;
+extern struct var vmail;
+extern struct var vmpath;
+extern struct var vpath;
+extern struct var vps1;
+extern struct var vps2;
+extern struct var vps4;
+extern struct var vdisvfork;
+#ifndef NO_HISTORY
+extern struct var vhistsize;
+extern struct var vterm;
+#endif
+
+extern int localeisutf8;
+/* The parser uses the locale that was in effect at startup. */
+extern int initial_localeisutf8;
+
+/*
+ * The following macros access the values of the above variables.
+ * They have to skip over the name. They return the null string
+ * for unset variables.
+ */
+
+#define ifsval() (vifs.text + 4)
+#define ifsset() ((vifs.flags & VUNSET) == 0)
+#define mailval() (vmail.text + 5)
+#define mpathval() (vmpath.text + 9)
+#define pathval() (vpath.text + 5)
+#define ps1val() (vps1.text + 4)
+#define ps2val() (vps2.text + 4)
+#define ps4val() (vps4.text + 4)
+#define optindval() (voptind.text + 7)
+#ifndef NO_HISTORY
+#define histsizeval() (vhistsize.text + 9)
+#define termval() (vterm.text + 5)
+#endif
+
+#define mpathset() ((vmpath.flags & VUNSET) == 0)
+#define disvforkset() ((vdisvfork.flags & VUNSET) == 0)
+
+void initvar(void);
+void setvar(const char *, const char *, int);
+void setvareq(char *, int);
+struct arglist;
+void listsetvar(struct arglist *, int);
+char *lookupvar(const char *);
+char *bltinlookup(const char *, int);
+void bltinsetlocale(void);
+void bltinunsetlocale(void);
+void updatecharset(void);
+void initcharset(void);
+char **environment(void);
+int showvarscmd(int, char **);
+void mklocal(char *);
+void poplocalvars(void);
+int unsetvar(const char *);
+int setvarsafe(const char *, const char *, int);
diff --git a/shell_cmds/shell_cmds.xcodeproj/project.pbxproj b/shell_cmds/shell_cmds.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..9a52eeb
--- /dev/null
+++ b/shell_cmds/shell_cmds.xcodeproj/project.pbxproj
@@ -0,0 +1,5903 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 46;
+ objects = {
+
+/* Begin PBXAggregateTarget section */
+ FCBA14FD14A144EC00AA698B /* All_OSX */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = FCBA14FE14A144EC00AA698B /* Build configuration list for PBXAggregateTarget "All_OSX" */;
+ buildPhases = (
+ FCE30EB814B531EC00CC0294 /* ShellScript */,
+ );
+ dependencies = (
+ C6868583154725A30025D623 /* PBXTargetDependency */,
+ FCBA150114A144F700AA698B /* PBXTargetDependency */,
+ FCBA150314A144F700AA698B /* PBXTargetDependency */,
+ FCBA150514A144F700AA698B /* PBXTargetDependency */,
+ FCBA150714A144F700AA698B /* PBXTargetDependency */,
+ FCBA150914A144F700AA698B /* PBXTargetDependency */,
+ FCBA150B14A144F700AA698B /* PBXTargetDependency */,
+ FCBA150D14A144F700AA698B /* PBXTargetDependency */,
+ FCBA165514A146D000AA698B /* PBXTargetDependency */,
+ FCBA165714A146D000AA698B /* PBXTargetDependency */,
+ FCBA165914A146D000AA698B /* PBXTargetDependency */,
+ FCBA165B14A146D000AA698B /* PBXTargetDependency */,
+ FC5D63A214B9864400123E48 /* PBXTargetDependency */,
+ FCBA165D14A146D000AA698B /* PBXTargetDependency */,
+ FCBA165F14A146D000AA698B /* PBXTargetDependency */,
+ FCBA166114A146D000AA698B /* PBXTargetDependency */,
+ FCBA166314A146D000AA698B /* PBXTargetDependency */,
+ FCBA166514A146D000AA698B /* PBXTargetDependency */,
+ FCBA166714A146D000AA698B /* PBXTargetDependency */,
+ FCBA166914A146D000AA698B /* PBXTargetDependency */,
+ FCE30EE314B539BF00CC0294 /* PBXTargetDependency */,
+ FCE30EE514B539BF00CC0294 /* PBXTargetDependency */,
+ FCBA166B14A146D000AA698B /* PBXTargetDependency */,
+ FCBA166F14A146D000AA698B /* PBXTargetDependency */,
+ FCBA167114A146D000AA698B /* PBXTargetDependency */,
+ FCBA167314A146D000AA698B /* PBXTargetDependency */,
+ FCBA167514A146D000AA698B /* PBXTargetDependency */,
+ FCBA167714A146D000AA698B /* PBXTargetDependency */,
+ FCBA167914A146D000AA698B /* PBXTargetDependency */,
+ FCBA167B14A146D000AA698B /* PBXTargetDependency */,
+ FCBA167D14A146D000AA698B /* PBXTargetDependency */,
+ FCBA167F14A146D000AA698B /* PBXTargetDependency */,
+ FCBA168114A146D000AA698B /* PBXTargetDependency */,
+ FD6060BB1B7C03BC004BCA6A /* PBXTargetDependency */,
+ FCBA168314A146D000AA698B /* PBXTargetDependency */,
+ FCBA168514A146D000AA698B /* PBXTargetDependency */,
+ FCBA168714A146D000AA698B /* PBXTargetDependency */,
+ FCBA168914A146D000AA698B /* PBXTargetDependency */,
+ FCBA168B14A146D000AA698B /* PBXTargetDependency */,
+ FCBA168D14A146D000AA698B /* PBXTargetDependency */,
+ FCBA168F14A146D000AA698B /* PBXTargetDependency */,
+ FCBA169114A146D000AA698B /* PBXTargetDependency */,
+ FCBA169314A146D000AA698B /* PBXTargetDependency */,
+ FCBA169514A146D000AA698B /* PBXTargetDependency */,
+ FC5D63A414B9864400123E48 /* PBXTargetDependency */,
+ FCBA169714A146D000AA698B /* PBXTargetDependency */,
+ FCBA169914A146D000AA698B /* PBXTargetDependency */,
+ FCBA169B14A146D000AA698B /* PBXTargetDependency */,
+ FCBA169D14A146D000AA698B /* PBXTargetDependency */,
+ FCBA169F14A146D000AA698B /* PBXTargetDependency */,
+ );
+ name = All_OSX;
+ productName = executables;
+ };
+ FCE30F4A14B619B000CC0294 /* All_iOS */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = FCE30F4B14B619B000CC0294 /* Build configuration list for PBXAggregateTarget "All_iOS" */;
+ buildPhases = (
+ FCE30F4D14B619C900CC0294 /* Run Script */,
+ );
+ dependencies = (
+ C6868581154725990025D623 /* PBXTargetDependency */,
+ FCE30F4F14B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F5114B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F5314B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F5514B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F5714B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F5914B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F5B14B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F5D14B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F5F14B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F6114B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F6314B619E600CC0294 /* PBXTargetDependency */,
+ FC5D63A614B9866500123E48 /* PBXTargetDependency */,
+ FCE30F6514B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F6714B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F6914B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F6B14B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F6D14B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F6F14B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F7114B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F7314B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F7514B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F7714B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F7914B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F7B14B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F7D14B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F7F14B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F8114B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F8314B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F8514B619E600CC0294 /* PBXTargetDependency */,
+ FD6060B91B7C03B3004BCA6A /* PBXTargetDependency */,
+ FCE30F8714B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F8914B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F8B14B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F8D14B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F8F14B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F9114B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F9314B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F9514B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F9714B619E600CC0294 /* PBXTargetDependency */,
+ FC5D63A814B9866500123E48 /* PBXTargetDependency */,
+ FCE30F9914B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F9B14B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F9D14B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F9F14B619E600CC0294 /* PBXTargetDependency */,
+ FCE30FA114B619E600CC0294 /* PBXTargetDependency */,
+ );
+ name = All_iOS;
+ productName = embedded;
+ };
+/* End PBXAggregateTarget section */
+
+/* Begin PBXBuildFile section */
+ C686857A154725700025D623 /* systime.c in Sources */ = {isa = PBXBuildFile; fileRef = C6868579154725700025D623 /* systime.c */; };
+ C686857C154725700025D623 /* systime.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = C686857B154725700025D623 /* systime.1 */; };
+ FC2B5BFB14B3CCC600ECF511 /* uname.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA140914A141A300AA698B /* uname.c */; };
+ FC2B5BFD14B3CCD200ECF511 /* uname.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA140814A141A300AA698B /* uname.1 */; };
+ FC2B5BFE14B3CCD700ECF511 /* true.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA140414A141A300AA698B /* true.c */; };
+ FC2B5BFF14B3CCEF00ECF511 /* true.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA140314A141A300AA698B /* true.1 */; };
+ FC2B5C0014B3CCF800ECF511 /* time.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA140014A141A300AA698B /* time.c */; };
+ FC2B5C0114B3CD0300ECF511 /* time.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA13FF14A141A300AA698B /* time.1 */; };
+ FC2B5C0214B3CD0C00ECF511 /* test.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA13FB14A141A300AA698B /* test.c */; };
+ FC2B5C0314B3CD1400ECF511 /* [.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA13F814A141A300AA698B /* [.1 */; };
+ FC2B5C0414B3CD1400ECF511 /* test.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA13FA14A141A300AA698B /* test.1 */; };
+ FC2B5C0514B3CD1D00ECF511 /* tee.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA13F514A141A300AA698B /* tee.1 */; };
+ FC2B5C0614B3CD2800ECF511 /* tee.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA13F614A141A300AA698B /* tee.c */; };
+ FC2B5C0714B3CD2F00ECF511 /* su.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA13F114A141A300AA698B /* su.c */; };
+ FC2B5C0814B3CD3500ECF511 /* su.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA13F014A141A300AA698B /* su.1 */; };
+ FC2B5C0914B3CD3E00ECF511 /* sleep.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA13EC14A141A300AA698B /* sleep.1 */; };
+ FC2B5C0A14B3CD4400ECF511 /* sleep.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA13ED14A141A300AA698B /* sleep.c */; };
+ FC2B5C0B14B3CD4F00ECF511 /* shlock.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA13E914A141A300AA698B /* shlock.c */; };
+ FC2B5C0C14B3CD5B00ECF511 /* shlock.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA13E814A141A300AA698B /* shlock.1 */; };
+ FC5D638D14B981D200123E48 /* what.c in Sources */ = {isa = PBXBuildFile; fileRef = FC5D637314B9808E00123E48 /* what.c */; };
+ FC5D638E14B981D800123E48 /* what.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FC5D637214B9808E00123E48 /* what.1 */; };
+ FC5D639914B9825B00123E48 /* hexdump.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FC5D636A14B9808E00123E48 /* hexdump.1 */; };
+ FC5D639A14B9825B00123E48 /* od.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FC5D636E14B9808E00123E48 /* od.1 */; };
+ FC5D639B14B9826500123E48 /* conv.c in Sources */ = {isa = PBXBuildFile; fileRef = FC5D636814B9808E00123E48 /* conv.c */; };
+ FC5D639C14B9826500123E48 /* display.c in Sources */ = {isa = PBXBuildFile; fileRef = FC5D636914B9808E00123E48 /* display.c */; };
+ FC5D639D14B9826500123E48 /* hexdump.c in Sources */ = {isa = PBXBuildFile; fileRef = FC5D636B14B9808E00123E48 /* hexdump.c */; };
+ FC5D639E14B9826500123E48 /* hexsyntax.c in Sources */ = {isa = PBXBuildFile; fileRef = FC5D636D14B9808E00123E48 /* hexsyntax.c */; };
+ FC5D639F14B9826500123E48 /* odsyntax.c in Sources */ = {isa = PBXBuildFile; fileRef = FC5D636F14B9808E00123E48 /* odsyntax.c */; };
+ FC5D63A014B9826500123E48 /* parse.c in Sources */ = {isa = PBXBuildFile; fileRef = FC5D637014B9808E00123E48 /* parse.c */; };
+ FCBA02E714B5061B0030BEB3 /* seq.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA13E414A141A300AA698B /* seq.1 */; };
+ FCBA02E814B506230030BEB3 /* seq.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA13E514A141A300AA698B /* seq.c */; };
+ FCBA02E914B5062E0030BEB3 /* script.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA13E014A141A300AA698B /* script.1 */; };
+ FCBA02EA14B506340030BEB3 /* script.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA13E114A141A300AA698B /* script.c */; };
+ FCBA02EB14B5063E0030BEB3 /* renice.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA13DC14A141A300AA698B /* renice.8 */; };
+ FCBA02EC14B5064C0030BEB3 /* renice.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA13DD14A141A300AA698B /* renice.c */; };
+ FCBA02ED14B506530030BEB3 /* pwd.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA13D914A141A300AA698B /* pwd.c */; };
+ FCBA02EF14B5065D0030BEB3 /* printf.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA13D414A141A300AA698B /* printf.1 */; };
+ FCBA02F014B506660030BEB3 /* printf.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA13D514A141A300AA698B /* printf.c */; };
+ FCBA02F114B506720030BEB3 /* printenv.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA13D114A141A300AA698B /* printenv.c */; };
+ FCBA02F214B5067C0030BEB3 /* printenv.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA13D014A141A300AA698B /* printenv.1 */; };
+ FCBA02F314B506840030BEB3 /* path_helper.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA13CD14A141A300AA698B /* path_helper.c */; };
+ FCBA02F414B5068C0030BEB3 /* path_helper.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA13CC14A141A300AA698B /* path_helper.8 */; };
+ FCBA02F514B506940030BEB3 /* nohup.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA13C914A141A300AA698B /* nohup.c */; };
+ FCBA02F614B5069C0030BEB3 /* nohup.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA13C814A141A300AA698B /* nohup.1 */; };
+ FCBA02F714B506B10030BEB3 /* nice.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA13C414A141A300AA698B /* nice.1 */; };
+ FCBA02F814B506BB0030BEB3 /* nice.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA13C514A141A300AA698B /* nice.c */; };
+ FCBA02F914B506CB0030BEB3 /* mktemp.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA13C114A141A300AA698B /* mktemp.c */; };
+ FCBA02FA14B506DA0030BEB3 /* mktemp.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA13C014A141A300AA698B /* mktemp.1 */; };
+ FCBA02FD14B506FA0030BEB3 /* logname.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA13B514A141A300AA698B /* logname.c */; };
+ FCBA02FE14B506FF0030BEB3 /* logname.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA13B414A141A300AA698B /* logname.1 */; };
+ FCBA02FF14B507130030BEB3 /* expr.y in Sources */ = {isa = PBXBuildFile; fileRef = FCBA136714A141A300AA698B /* expr.y */; };
+ FCBA030014B5071A0030BEB3 /* expr.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA136614A141A300AA698B /* expr.1 */; };
+ FCBA030114B507220030BEB3 /* false.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA136B14A141A300AA698B /* false.c */; };
+ FCBA030214B5072C0030BEB3 /* false.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA136A14A141A300AA698B /* false.1 */; };
+ FCBA030314B5073F0030BEB3 /* find.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA137114A141A300AA698B /* find.c */; };
+ FCBA030414B5073F0030BEB3 /* function.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA137314A141A300AA698B /* function.c */; };
+ FCBA030514B5073F0030BEB3 /* getdate.y in Sources */ = {isa = PBXBuildFile; fileRef = FCBA137414A141A300AA698B /* getdate.y */; };
+ FCBA030614B5073F0030BEB3 /* ls.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA137514A141A300AA698B /* ls.c */; };
+ FCBA030714B5073F0030BEB3 /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA137614A141A300AA698B /* main.c */; };
+ FCBA030814B5073F0030BEB3 /* misc.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA137814A141A300AA698B /* misc.c */; };
+ FCBA030914B5073F0030BEB3 /* operator.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA137914A141A300AA698B /* operator.c */; };
+ FCBA030A14B5073F0030BEB3 /* option.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA137A14A141A300AA698B /* option.c */; };
+ FCBA030B14B507450030BEB3 /* find.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA137014A141A300AA698B /* find.1 */; };
+ FCBA030C14B5074D0030BEB3 /* getopt.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA137D14A141A300AA698B /* getopt.c */; };
+ FCBA030D14B507580030BEB3 /* getopt.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA137C14A141A300AA698B /* getopt.1 */; };
+ FCBA030E14B5076A0030BEB3 /* hostname.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA138114A141A300AA698B /* hostname.c */; };
+ FCBA030F14B507700030BEB3 /* hostname.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA138014A141A300AA698B /* hostname.1 */; };
+ FCBA031014B507790030BEB3 /* id.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA138614A141A300AA698B /* id.c */; };
+ FCBA031214B507870030BEB3 /* groups.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA138414A141A300AA698B /* groups.1 */; };
+ FCBA031314B507870030BEB3 /* id.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA138514A141A300AA698B /* id.1 */; };
+ FCBA031414B507870030BEB3 /* whoami.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA138A14A141A300AA698B /* whoami.1 */; };
+ FCBA031514B507900030BEB3 /* jot.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA138D14A141A300AA698B /* jot.c */; };
+ FCBA031614B507950030BEB3 /* jot.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA138C14A141A300AA698B /* jot.1 */; };
+ FCBA031714B507A10030BEB3 /* kill.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA139114A141A300AA698B /* kill.c */; };
+ FCBA031814B507A50030BEB3 /* kill.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA139014A141A300AA698B /* kill.1 */; };
+ FCBA031914B507B00030BEB3 /* killall.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA139514A141A300AA698B /* killall.c */; };
+ FCBA031A14B507B60030BEB3 /* killall.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA139414A141A300AA698B /* killall.1 */; };
+ FCBA031B14B507BD0030BEB3 /* lastcomm.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA139914A141A300AA698B /* lastcomm.c */; };
+ FCBA031C14B507C40030BEB3 /* lastcomm.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA139814A141A300AA698B /* lastcomm.1 */; };
+ FCBA031E14B507D10030BEB3 /* locate.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA13A814A141A300AA698B /* locate.c */; };
+ FCBA031F14B507D10030BEB3 /* util.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA13B014A141A300AA698B /* util.c */; };
+ FCBA032014B507E50030BEB3 /* locate.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA13A714A141A300AA698B /* locate.1 */; };
+ FCBA14EB14A1444900AA698B /* apply.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA134714A141A300AA698B /* apply.c */; };
+ FCBA14ED14A1444E00AA698B /* apply.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA134614A141A300AA698B /* apply.1 */; };
+ FCBA14EE14A1446700AA698B /* basename.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA134B14A141A300AA698B /* basename.c */; };
+ FCBA14EF14A1446B00AA698B /* basename.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA134A14A141A300AA698B /* basename.1 */; };
+ FCBA14F114A1448C00AA698B /* chroot.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA135014A141A300AA698B /* chroot.c */; };
+ FCBA14F214A1448F00AA698B /* chroot.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA134F14A141A300AA698B /* chroot.8 */; };
+ FCBA14F314A1449A00AA698B /* date.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA135314A141A300AA698B /* date.1 */; };
+ FCBA14F414A1449C00AA698B /* date.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA135414A141A300AA698B /* date.c */; };
+ FCBA14F514A144AF00AA698B /* netdate.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA135714A141A300AA698B /* netdate.c */; };
+ FCBA14F614A144B200AA698B /* vary.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA135814A141A300AA698B /* vary.c */; };
+ FCBA14F714A144C700AA698B /* dirname.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA135B14A141A300AA698B /* dirname.c */; };
+ FCBA14F814A144CB00AA698B /* dirname.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA134C14A141A300AA698B /* dirname.1 */; };
+ FCBA14F914A144D000AA698B /* echo.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA135E14A141A300AA698B /* echo.1 */; };
+ FCBA14FA14A144D300AA698B /* echo.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA135F14A141A300AA698B /* echo.c */; };
+ FCBA14FB14A144E300AA698B /* env.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA136214A141A300AA698B /* env.1 */; };
+ FCBA14FC14A144E500AA698B /* env.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA136314A141A300AA698B /* env.c */; };
+ FCBA163E14A1466500AA698B /* yes.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA142D14A141A300AA698B /* yes.1 */; };
+ FCBA163F14A1466900AA698B /* yes.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA142E14A141A300AA698B /* yes.c */; };
+ FCBA164014A1466F00AA698B /* xargs.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA142A14A141A300AA698B /* xargs.c */; };
+ FCBA164114A1467200AA698B /* strnsubst.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA142814A141A300AA698B /* strnsubst.c */; };
+ FCBA164214A1467500AA698B /* xargs.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA142914A141A300AA698B /* xargs.1 */; };
+ FCBA164314A1467A00AA698B /* utmpentry.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA142114A141A300AA698B /* utmpentry.c */; };
+ FCBA164414A1467D00AA698B /* who.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA142414A141A300AA698B /* who.c */; };
+ FCBA164514A1468000AA698B /* who.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA142314A141A300AA698B /* who.1 */; };
+ FCBA164614A1468600AA698B /* which.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA141E14A141A300AA698B /* which.c */; };
+ FCBA164714A1468900AA698B /* which.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA141D14A141A300AA698B /* which.1 */; };
+ FCBA164814A1469000AA698B /* whereis.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA141A14A141A300AA698B /* whereis.c */; };
+ FCBA164914A1469300AA698B /* whereis.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA141914A141A300AA698B /* whereis.1 */; };
+ FCBA164A14A1469A00AA698B /* fmt.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA141014A141A300AA698B /* fmt.c */; };
+ FCBA164B14A1469D00AA698B /* pr_time.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA141214A141A300AA698B /* pr_time.c */; };
+ FCBA164C14A1469F00AA698B /* proc_compare.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA141314A141A300AA698B /* proc_compare.c */; };
+ FCBA164D14A146A200AA698B /* w.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA141614A141A300AA698B /* w.c */; };
+ FCBA164E14A146A500AA698B /* uptime.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA141414A141A300AA698B /* uptime.1 */; };
+ FCBA164F14A146A700AA698B /* w.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA141514A141A300AA698B /* w.1 */; };
+ FCBA165014A146BE00AA698B /* users.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA140D14A141A300AA698B /* users.c */; };
+ FCBA165114A146C100AA698B /* users.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA140C14A141A300AA698B /* users.1 */; };
+ FCE30EA814B5105200CC0294 /* pwd.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA13D814A141A300AA698B /* pwd.1 */; };
+ FCE30EBA14B532D900CC0294 /* com.apple.locate.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA13A414A141A300AA698B /* com.apple.locate.plist */; };
+ FCE30EBD14B533A200CC0294 /* locate.rc in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA13AA14A141A300AA698B /* locate.rc */; };
+ FCE30EBF14B533E200CC0294 /* locate.updatedb.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA13AB14A141A300AA698B /* locate.updatedb.8 */; };
+ FCE30ED414B536A600CC0294 /* locate.bigram.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA139E14A141A300AA698B /* locate.bigram.c */; };
+ FCE30ED514B536B200CC0294 /* locate.bigram.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCE30EC114B5347A00CC0294 /* locate.bigram.8 */; };
+ FCE30EE014B536F200CC0294 /* locate.code.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA13A114A141A300AA698B /* locate.code.c */; };
+ FCE30EE114B536F800CC0294 /* locate.code.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA13B114A141A300AA698B /* locate.code.8 */; };
+ FCED3AF614B4FC1800C313C3 /* libpam.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = FCED3AF514B4FC1800C313C3 /* libpam.dylib */; };
+ FD155C751D6E37E5005A53CA /* legacy_test.sh in CopyFiles */ = {isa = PBXBuildFile; fileRef = FD155C721D6E37B5005A53CA /* legacy_test.sh */; };
+ FD155C891D6E38C0005A53CA /* legacy_test.sh in CopyFiles */ = {isa = PBXBuildFile; fileRef = FD155C771D6E3847005A53CA /* legacy_test.sh */; };
+ FD155C8A1D6E38C0005A53CA /* regress.b.out in CopyFiles */ = {isa = PBXBuildFile; fileRef = FD155C7A1D6E3847005A53CA /* regress.b.out */; };
+ FD155C8B1D6E38C0005A53CA /* regress.d.out in CopyFiles */ = {isa = PBXBuildFile; fileRef = FD155C7B1D6E3847005A53CA /* regress.d.out */; };
+ FD155C8C1D6E38C0005A53CA /* regress.f.out in CopyFiles */ = {isa = PBXBuildFile; fileRef = FD155C7C1D6E3847005A53CA /* regress.f.out */; };
+ FD155C8D1D6E38C0005A53CA /* regress.l1.out in CopyFiles */ = {isa = PBXBuildFile; fileRef = FD155C7D1D6E3847005A53CA /* regress.l1.out */; };
+ FD155C8E1D6E38C0005A53CA /* regress.l2.out in CopyFiles */ = {isa = PBXBuildFile; fileRef = FD155C7E1D6E3847005A53CA /* regress.l2.out */; };
+ FD155C8F1D6E38C0005A53CA /* regress.m1.out in CopyFiles */ = {isa = PBXBuildFile; fileRef = FD155C7F1D6E3847005A53CA /* regress.m1.out */; };
+ FD155C901D6E38C0005A53CA /* regress.m2.out in CopyFiles */ = {isa = PBXBuildFile; fileRef = FD155C801D6E3847005A53CA /* regress.m2.out */; };
+ FD155C911D6E38C0005A53CA /* regress.m3.out in CopyFiles */ = {isa = PBXBuildFile; fileRef = FD155C811D6E3847005A53CA /* regress.m3.out */; };
+ FD155C921D6E38C0005A53CA /* regress.m4.out in CopyFiles */ = {isa = PBXBuildFile; fileRef = FD155C821D6E3847005A53CA /* regress.m4.out */; };
+ FD155C931D6E38C0005A53CA /* regress.m5.out in CopyFiles */ = {isa = PBXBuildFile; fileRef = FD155C831D6E3847005A53CA /* regress.m5.out */; };
+ FD155C941D6E38C0005A53CA /* regress.missingpos1.out in CopyFiles */ = {isa = PBXBuildFile; fileRef = FD155C841D6E3847005A53CA /* regress.missingpos1.out */; };
+ FD155C951D6E38C0005A53CA /* regress.s.out in CopyFiles */ = {isa = PBXBuildFile; fileRef = FD155C851D6E3847005A53CA /* regress.s.out */; };
+ FD155C961D6E38C0005A53CA /* regress.sh in CopyFiles */ = {isa = PBXBuildFile; fileRef = FD155C861D6E3847005A53CA /* regress.sh */; };
+ FD155C971D6E38C0005A53CA /* regress.zero.out in CopyFiles */ = {isa = PBXBuildFile; fileRef = FD155C871D6E3847005A53CA /* regress.zero.out */; };
+ FD6060B51B7C0388004BCA6A /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = FD6060B41B7C0388004BCA6A /* main.c */; };
+ FD6060D21B7C0471004BCA6A /* alias.c in Sources */ = {isa = PBXBuildFile; fileRef = FD6060BC1B7C0471004BCA6A /* alias.c */; };
+ FD6060D31B7C0471004BCA6A /* arith_yacc.c in Sources */ = {isa = PBXBuildFile; fileRef = FD6060BD1B7C0471004BCA6A /* arith_yacc.c */; };
+ FD6060D41B7C0471004BCA6A /* arith_yylex.c in Sources */ = {isa = PBXBuildFile; fileRef = FD6060BE1B7C0471004BCA6A /* arith_yylex.c */; };
+ FD6060D51B7C0471004BCA6A /* cd.c in Sources */ = {isa = PBXBuildFile; fileRef = FD6060BF1B7C0471004BCA6A /* cd.c */; };
+ FD6060D61B7C0471004BCA6A /* error.c in Sources */ = {isa = PBXBuildFile; fileRef = FD6060C01B7C0471004BCA6A /* error.c */; };
+ FD6060D71B7C0471004BCA6A /* eval.c in Sources */ = {isa = PBXBuildFile; fileRef = FD6060C11B7C0471004BCA6A /* eval.c */; };
+ FD6060D81B7C0471004BCA6A /* exec.c in Sources */ = {isa = PBXBuildFile; fileRef = FD6060C21B7C0471004BCA6A /* exec.c */; };
+ FD6060D91B7C0471004BCA6A /* expand.c in Sources */ = {isa = PBXBuildFile; fileRef = FD6060C31B7C0471004BCA6A /* expand.c */; };
+ FD6060DA1B7C0471004BCA6A /* histedit.c in Sources */ = {isa = PBXBuildFile; fileRef = FD6060C41B7C0471004BCA6A /* histedit.c */; };
+ FD6060DB1B7C0471004BCA6A /* input.c in Sources */ = {isa = PBXBuildFile; fileRef = FD6060C51B7C0471004BCA6A /* input.c */; };
+ FD6060DC1B7C0471004BCA6A /* jobs.c in Sources */ = {isa = PBXBuildFile; fileRef = FD6060C61B7C0471004BCA6A /* jobs.c */; };
+ FD6060DD1B7C0471004BCA6A /* mail.c in Sources */ = {isa = PBXBuildFile; fileRef = FD6060C71B7C0471004BCA6A /* mail.c */; };
+ FD6060DE1B7C0471004BCA6A /* memalloc.c in Sources */ = {isa = PBXBuildFile; fileRef = FD6060C81B7C0471004BCA6A /* memalloc.c */; };
+ FD6060DF1B7C0471004BCA6A /* miscbltin.c in Sources */ = {isa = PBXBuildFile; fileRef = FD6060C91B7C0471004BCA6A /* miscbltin.c */; };
+ FD6060E01B7C0471004BCA6A /* mystring.c in Sources */ = {isa = PBXBuildFile; fileRef = FD6060CA1B7C0471004BCA6A /* mystring.c */; };
+ FD6060E11B7C0471004BCA6A /* options.c in Sources */ = {isa = PBXBuildFile; fileRef = FD6060CB1B7C0471004BCA6A /* options.c */; };
+ FD6060E21B7C0471004BCA6A /* output.c in Sources */ = {isa = PBXBuildFile; fileRef = FD6060CC1B7C0471004BCA6A /* output.c */; };
+ FD6060E31B7C0471004BCA6A /* parser.c in Sources */ = {isa = PBXBuildFile; fileRef = FD6060CD1B7C0471004BCA6A /* parser.c */; };
+ FD6060E41B7C0471004BCA6A /* redir.c in Sources */ = {isa = PBXBuildFile; fileRef = FD6060CE1B7C0471004BCA6A /* redir.c */; };
+ FD6060E51B7C0471004BCA6A /* show.c in Sources */ = {isa = PBXBuildFile; fileRef = FD6060CF1B7C0471004BCA6A /* show.c */; };
+ FD6060E61B7C0471004BCA6A /* trap.c in Sources */ = {isa = PBXBuildFile; fileRef = FD6060D01B7C0471004BCA6A /* trap.c */; };
+ FD6060E71B7C0471004BCA6A /* var.c in Sources */ = {isa = PBXBuildFile; fileRef = FD6060D11B7C0471004BCA6A /* var.c */; };
+ FD6060EB1B7C04E4004BCA6A /* echo.c in Sources */ = {isa = PBXBuildFile; fileRef = FD6060EA1B7C04E4004BCA6A /* echo.c */; };
+ FD6060EC1B7C0506004BCA6A /* kill.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA139114A141A300AA698B /* kill.c */; };
+ FD6060ED1B7C0518004BCA6A /* printf.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA13D514A141A300AA698B /* printf.c */; };
+ FD6060EE1B7C0521004BCA6A /* test.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA13FB14A141A300AA698B /* test.c */; };
+ FD6060FD1B7C0CAF004BCA6A /* builtins.c in Sources */ = {isa = PBXBuildFile; fileRef = FD6060FA1B7C0CAF004BCA6A /* builtins.c */; };
+ FD6060FE1B7C0CAF004BCA6A /* nodes.c in Sources */ = {isa = PBXBuildFile; fileRef = FD6060FB1B7C0CAF004BCA6A /* nodes.c */; };
+ FD6060FF1B7C0CAF004BCA6A /* syntax.c in Sources */ = {isa = PBXBuildFile; fileRef = FD6060FC1B7C0CAF004BCA6A /* syntax.c */; };
+ FD88EB03198C5257006B7EFD /* envopts.c in Sources */ = {isa = PBXBuildFile; fileRef = FD88EB01198C5257006B7EFD /* envopts.c */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ C6868580154725990025D623 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = C6868575154725700025D623;
+ remoteInfo = systime;
+ };
+ C6868582154725A30025D623 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = C6868575154725700025D623;
+ remoteInfo = systime;
+ };
+ FC5D63A114B9864400123E48 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC5D638F14B9822D00123E48;
+ remoteInfo = hexdump;
+ };
+ FC5D63A314B9864400123E48 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC5D637F14B9819E00123E48;
+ remoteInfo = what;
+ };
+ FC5D63A514B9866500123E48 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC5D638F14B9822D00123E48;
+ remoteInfo = hexdump;
+ };
+ FC5D63A714B9866500123E48 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC5D637F14B9819E00123E48;
+ remoteInfo = what;
+ };
+ FCBA150014A144F700AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA149814A141FF00AA698B;
+ remoteInfo = apply;
+ };
+ FCBA150214A144F700AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA14AE14A1422D00AA698B;
+ remoteInfo = basename;
+ };
+ FCBA150414A144F700AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA14B714A1423E00AA698B;
+ remoteInfo = chroot;
+ };
+ FCBA150614A144F700AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA14BF14A1426800AA698B;
+ remoteInfo = date;
+ };
+ FCBA150814A144F700AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA14C714A1428000AA698B;
+ remoteInfo = dirname;
+ };
+ FCBA150A14A144F700AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA14CF14A1433F00AA698B;
+ remoteInfo = echo;
+ };
+ FCBA150C14A144F700AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA14D714A1434A00AA698B;
+ remoteInfo = env;
+ };
+ FCBA165414A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA150E14A1453A00AA698B;
+ remoteInfo = expr;
+ };
+ FCBA165614A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA151614A1454D00AA698B;
+ remoteInfo = false;
+ };
+ FCBA165814A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA151E14A1455600AA698B;
+ remoteInfo = find;
+ };
+ FCBA165A14A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA152614A1455900AA698B;
+ remoteInfo = getopt;
+ };
+ FCBA165C14A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA152E14A1455C00AA698B;
+ remoteInfo = hostname;
+ };
+ FCBA165E14A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA153614A1455F00AA698B;
+ remoteInfo = id;
+ };
+ FCBA166014A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA153E14A1456100AA698B;
+ remoteInfo = jot;
+ };
+ FCBA166214A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA154614A1456400AA698B;
+ remoteInfo = kill;
+ };
+ FCBA166414A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA154E14A1456700AA698B;
+ remoteInfo = killall;
+ };
+ FCBA166614A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA155614A1456A00AA698B;
+ remoteInfo = lastcomm;
+ };
+ FCBA166814A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA155E14A1456E00AA698B;
+ remoteInfo = locate;
+ };
+ FCBA166A14A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA156614A1457100AA698B;
+ remoteInfo = logname;
+ };
+ FCBA166E14A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA157614A1457B00AA698B;
+ remoteInfo = mktemp;
+ };
+ FCBA167014A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA157E14A1457F00AA698B;
+ remoteInfo = nice;
+ };
+ FCBA167214A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA158614A1458500AA698B;
+ remoteInfo = nohup;
+ };
+ FCBA167414A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA158E14A1458800AA698B;
+ remoteInfo = path_helper;
+ };
+ FCBA167614A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA159614A1458C00AA698B;
+ remoteInfo = printenv;
+ };
+ FCBA167814A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA159E14A1459000AA698B;
+ remoteInfo = printf;
+ };
+ FCBA167A14A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA15A614A1459500AA698B;
+ remoteInfo = pwd;
+ };
+ FCBA167C14A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA15AE14A1459700AA698B;
+ remoteInfo = renice;
+ };
+ FCBA167E14A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA15B614A1459900AA698B;
+ remoteInfo = script;
+ };
+ FCBA168014A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA15BE14A1459E00AA698B;
+ remoteInfo = seq;
+ };
+ FCBA168214A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA15C614A145A200AA698B;
+ remoteInfo = shlock;
+ };
+ FCBA168414A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA15CE14A145A500AA698B;
+ remoteInfo = sleep;
+ };
+ FCBA168614A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA15D614A145A700AA698B;
+ remoteInfo = su;
+ };
+ FCBA168814A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA15DE14A145A900AA698B;
+ remoteInfo = tee;
+ };
+ FCBA168A14A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA15E614A145AE00AA698B;
+ remoteInfo = test;
+ };
+ FCBA168C14A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA15EE14A145B000AA698B;
+ remoteInfo = time;
+ };
+ FCBA168E14A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA15F614A145B200AA698B;
+ remoteInfo = true;
+ };
+ FCBA169014A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA15FE14A145B500AA698B;
+ remoteInfo = uname;
+ };
+ FCBA169214A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA160614A145B800AA698B;
+ remoteInfo = users;
+ };
+ FCBA169414A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA160E14A145BA00AA698B;
+ remoteInfo = w;
+ };
+ FCBA169614A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA161614A145BC00AA698B;
+ remoteInfo = whereis;
+ };
+ FCBA169814A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA161E14A145C000AA698B;
+ remoteInfo = which;
+ };
+ FCBA169A14A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA162614A145C500AA698B;
+ remoteInfo = who;
+ };
+ FCBA169C14A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA162E14A145C700AA698B;
+ remoteInfo = xargs;
+ };
+ FCBA169E14A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA163614A145CA00AA698B;
+ remoteInfo = yes;
+ };
+ FCE30EE214B539BF00CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCE30EC214B5368A00CC0294;
+ remoteInfo = locate.bigram;
+ };
+ FCE30EE414B539BF00CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCE30ED614B536C900CC0294;
+ remoteInfo = locate.code;
+ };
+ FCE30F4E14B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA149814A141FF00AA698B;
+ remoteInfo = apply;
+ };
+ FCE30F5014B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA14AE14A1422D00AA698B;
+ remoteInfo = basename;
+ };
+ FCE30F5214B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA14B714A1423E00AA698B;
+ remoteInfo = chroot;
+ };
+ FCE30F5414B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA14BF14A1426800AA698B;
+ remoteInfo = date;
+ };
+ FCE30F5614B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA14C714A1428000AA698B;
+ remoteInfo = dirname;
+ };
+ FCE30F5814B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA14CF14A1433F00AA698B;
+ remoteInfo = echo;
+ };
+ FCE30F5A14B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA14D714A1434A00AA698B;
+ remoteInfo = env;
+ };
+ FCE30F5C14B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA150E14A1453A00AA698B;
+ remoteInfo = expr;
+ };
+ FCE30F5E14B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA151614A1454D00AA698B;
+ remoteInfo = false;
+ };
+ FCE30F6014B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA151E14A1455600AA698B;
+ remoteInfo = find;
+ };
+ FCE30F6214B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA152614A1455900AA698B;
+ remoteInfo = getopt;
+ };
+ FCE30F6414B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA152E14A1455C00AA698B;
+ remoteInfo = hostname;
+ };
+ FCE30F6614B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA153614A1455F00AA698B;
+ remoteInfo = id;
+ };
+ FCE30F6814B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA153E14A1456100AA698B;
+ remoteInfo = jot;
+ };
+ FCE30F6A14B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA154614A1456400AA698B;
+ remoteInfo = kill;
+ };
+ FCE30F6C14B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA154E14A1456700AA698B;
+ remoteInfo = killall;
+ };
+ FCE30F6E14B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA155614A1456A00AA698B;
+ remoteInfo = lastcomm;
+ };
+ FCE30F7014B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA156614A1457100AA698B;
+ remoteInfo = logname;
+ };
+ FCE30F7214B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA157614A1457B00AA698B;
+ remoteInfo = mktemp;
+ };
+ FCE30F7414B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA157E14A1457F00AA698B;
+ remoteInfo = nice;
+ };
+ FCE30F7614B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA158614A1458500AA698B;
+ remoteInfo = nohup;
+ };
+ FCE30F7814B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA158E14A1458800AA698B;
+ remoteInfo = path_helper;
+ };
+ FCE30F7A14B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA159614A1458C00AA698B;
+ remoteInfo = printenv;
+ };
+ FCE30F7C14B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA159E14A1459000AA698B;
+ remoteInfo = printf;
+ };
+ FCE30F7E14B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA15A614A1459500AA698B;
+ remoteInfo = pwd;
+ };
+ FCE30F8014B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA15AE14A1459700AA698B;
+ remoteInfo = renice;
+ };
+ FCE30F8214B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA15B614A1459900AA698B;
+ remoteInfo = script;
+ };
+ FCE30F8414B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA15BE14A1459E00AA698B;
+ remoteInfo = seq;
+ };
+ FCE30F8614B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA15C614A145A200AA698B;
+ remoteInfo = shlock;
+ };
+ FCE30F8814B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA15CE14A145A500AA698B;
+ remoteInfo = sleep;
+ };
+ FCE30F8A14B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA15DE14A145A900AA698B;
+ remoteInfo = tee;
+ };
+ FCE30F8C14B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA15E614A145AE00AA698B;
+ remoteInfo = test;
+ };
+ FCE30F8E14B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA15EE14A145B000AA698B;
+ remoteInfo = time;
+ };
+ FCE30F9014B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA15F614A145B200AA698B;
+ remoteInfo = true;
+ };
+ FCE30F9214B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA15FE14A145B500AA698B;
+ remoteInfo = uname;
+ };
+ FCE30F9414B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA160614A145B800AA698B;
+ remoteInfo = users;
+ };
+ FCE30F9614B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA160E14A145BA00AA698B;
+ remoteInfo = w;
+ };
+ FCE30F9814B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA161614A145BC00AA698B;
+ remoteInfo = whereis;
+ };
+ FCE30F9A14B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA161E14A145C000AA698B;
+ remoteInfo = which;
+ };
+ FCE30F9C14B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA162614A145C500AA698B;
+ remoteInfo = who;
+ };
+ FCE30F9E14B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA162E14A145C700AA698B;
+ remoteInfo = xargs;
+ };
+ FCE30FA014B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA163614A145CA00AA698B;
+ remoteInfo = yes;
+ };
+ FD6060B81B7C03B3004BCA6A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FD6060B11B7C0388004BCA6A;
+ remoteInfo = sh;
+ };
+ FD6060BA1B7C03BC004BCA6A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FD6060B11B7C0388004BCA6A;
+ remoteInfo = sh;
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+ C6868574154725700025D623 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/local/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ C686857C154725700025D623 /* systime.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC5D638614B9819E00123E48 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC5D638E14B981D800123E48 /* what.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC5D639314B9822D00123E48 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC5D639914B9825B00123E48 /* hexdump.1 in CopyFiles */,
+ FC5D639A14B9825B00123E48 /* od.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA149B14A141FF00AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA14ED14A1444E00AA698B /* apply.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA14B114A1422D00AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA14EF14A1446B00AA698B /* basename.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA14BA14A1423E00AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA14F214A1448F00AA698B /* chroot.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA14C214A1426800AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA14F314A1449A00AA698B /* date.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA14CA14A1428000AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA14F814A144CB00AA698B /* dirname.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA14D214A1433F00AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA14F914A144D000AA698B /* echo.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA14DA14A1434A00AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA14FB14A144E300AA698B /* env.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA151114A1453A00AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA030014B5071A0030BEB3 /* expr.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA151914A1454D00AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA030214B5072C0030BEB3 /* false.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA152114A1455600AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA030B14B507450030BEB3 /* find.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA152914A1455900AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA030D14B507580030BEB3 /* getopt.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA153114A1455C00AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA030F14B507700030BEB3 /* hostname.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA153914A1455F00AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA031214B507870030BEB3 /* groups.1 in CopyFiles */,
+ FCBA031314B507870030BEB3 /* id.1 in CopyFiles */,
+ FCBA031414B507870030BEB3 /* whoami.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA154114A1456100AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA031614B507950030BEB3 /* jot.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA154914A1456400AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA031814B507A50030BEB3 /* kill.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA155114A1456700AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA031A14B507B60030BEB3 /* killall.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA155914A1456A00AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA031C14B507C40030BEB3 /* lastcomm.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA156114A1456E00AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA032014B507E50030BEB3 /* locate.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA156914A1457100AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA02FE14B506FF0030BEB3 /* logname.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA157914A1457B00AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA02FA14B506DA0030BEB3 /* mktemp.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA158114A1457F00AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA02F714B506B10030BEB3 /* nice.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA158914A1458500AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA02F614B5069C0030BEB3 /* nohup.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA159114A1458800AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA02F414B5068C0030BEB3 /* path_helper.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA159914A1458C00AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA02F214B5067C0030BEB3 /* printenv.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA15A114A1459000AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA02EF14B5065D0030BEB3 /* printf.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA15A914A1459500AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCE30EA814B5105200CC0294 /* pwd.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA15B114A1459700AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA02EB14B5063E0030BEB3 /* renice.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA15B914A1459900AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA02E914B5062E0030BEB3 /* script.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA15C114A1459E00AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA02E714B5061B0030BEB3 /* seq.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA15C914A145A200AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC2B5C0C14B3CD5B00ECF511 /* shlock.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA15D114A145A500AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC2B5C0914B3CD3E00ECF511 /* sleep.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA15D914A145A700AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC2B5C0814B3CD3500ECF511 /* su.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA15E114A145A900AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC2B5C0514B3CD1D00ECF511 /* tee.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA15E914A145AE00AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC2B5C0314B3CD1400ECF511 /* [.1 in CopyFiles */,
+ FC2B5C0414B3CD1400ECF511 /* test.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA15F114A145B000AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC2B5C0114B3CD0300ECF511 /* time.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA15F914A145B200AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC2B5BFF14B3CCEF00ECF511 /* true.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA160114A145B500AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC2B5BFD14B3CCD200ECF511 /* uname.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA160914A145B800AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA165114A146C100AA698B /* users.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA161114A145BA00AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA164F14A146A700AA698B /* w.1 in CopyFiles */,
+ FCBA164E14A146A500AA698B /* uptime.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA161914A145BC00AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA164914A1469300AA698B /* whereis.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA162114A145C000AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA164714A1468900AA698B /* which.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA162914A145C500AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA164514A1468000AA698B /* who.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA163114A145C700AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA164214A1467500AA698B /* xargs.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA163914A145CA00AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA163E14A1466500AA698B /* yes.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCE30EB914B532C700CC0294 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /System/Library/LaunchDaemons/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCE30EBA14B532D900CC0294 /* com.apple.locate.plist in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCE30EBC14B5339000CC0294 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /private/etc/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCE30EBD14B533A200CC0294 /* locate.rc in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCE30EBE14B533B500CC0294 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man8/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCE30EBF14B533E200CC0294 /* locate.updatedb.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCE30EC714B5368A00CC0294 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCE30ED514B536B200CC0294 /* locate.bigram.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCE30EDA14B536C900CC0294 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCE30EE114B536F800CC0294 /* locate.code.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FD155C741D6E37D7005A53CA /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /AppleInternal/Tests/shell_cmds/test;
+ dstSubfolderSpec = 0;
+ files = (
+ FD155C751D6E37E5005A53CA /* legacy_test.sh in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FD155C881D6E38AB005A53CA /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /AppleInternal/Tests/shell_cmds/printf;
+ dstSubfolderSpec = 0;
+ files = (
+ FD155C891D6E38C0005A53CA /* legacy_test.sh in CopyFiles */,
+ FD155C8A1D6E38C0005A53CA /* regress.b.out in CopyFiles */,
+ FD155C8B1D6E38C0005A53CA /* regress.d.out in CopyFiles */,
+ FD155C8C1D6E38C0005A53CA /* regress.f.out in CopyFiles */,
+ FD155C8D1D6E38C0005A53CA /* regress.l1.out in CopyFiles */,
+ FD155C8E1D6E38C0005A53CA /* regress.l2.out in CopyFiles */,
+ FD155C8F1D6E38C0005A53CA /* regress.m1.out in CopyFiles */,
+ FD155C901D6E38C0005A53CA /* regress.m2.out in CopyFiles */,
+ FD155C911D6E38C0005A53CA /* regress.m3.out in CopyFiles */,
+ FD155C921D6E38C0005A53CA /* regress.m4.out in CopyFiles */,
+ FD155C931D6E38C0005A53CA /* regress.m5.out in CopyFiles */,
+ FD155C941D6E38C0005A53CA /* regress.missingpos1.out in CopyFiles */,
+ FD155C951D6E38C0005A53CA /* regress.s.out in CopyFiles */,
+ FD155C961D6E38C0005A53CA /* regress.sh in CopyFiles */,
+ FD155C971D6E38C0005A53CA /* regress.zero.out in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+ 6C1C283E22FB822900E0AC67 /* su_entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = su_entitlements.plist; sourceTree = "<group>"; };
+ C6868576154725700025D623 /* systime */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = systime; sourceTree = BUILT_PRODUCTS_DIR; };
+ C6868579154725700025D623 /* systime.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = systime.c; sourceTree = "<group>"; };
+ C686857B154725700025D623 /* systime.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = systime.1; sourceTree = "<group>"; };
+ CE799E6024AD3B1B00E73238 /* test_time.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = test_time.sh; sourceTree = "<group>"; usesTabs = 1; };
+ CE799E6224B3982200E73238 /* install-files.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = "install-files.sh"; sourceTree = "<group>"; };
+ CE799E6324B3982200E73238 /* builtins.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = builtins.txt; sourceTree = "<group>"; };
+ CE799E6424B3982200E73238 /* builtins-manpages.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "builtins-manpages.txt"; sourceTree = "<group>"; };
+ FC5D636814B9808E00123E48 /* conv.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = conv.c; sourceTree = "<group>"; };
+ FC5D636914B9808E00123E48 /* display.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = display.c; sourceTree = "<group>"; };
+ FC5D636A14B9808E00123E48 /* hexdump.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = hexdump.1; sourceTree = "<group>"; };
+ FC5D636B14B9808E00123E48 /* hexdump.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = hexdump.c; sourceTree = "<group>"; };
+ FC5D636C14B9808E00123E48 /* hexdump.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = hexdump.h; sourceTree = "<group>"; };
+ FC5D636D14B9808E00123E48 /* hexsyntax.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = hexsyntax.c; sourceTree = "<group>"; };
+ FC5D636E14B9808E00123E48 /* od.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = od.1; sourceTree = "<group>"; };
+ FC5D636F14B9808E00123E48 /* odsyntax.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = odsyntax.c; sourceTree = "<group>"; };
+ FC5D637014B9808E00123E48 /* parse.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = parse.c; sourceTree = "<group>"; };
+ FC5D637214B9808E00123E48 /* what.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = what.1; sourceTree = "<group>"; };
+ FC5D637314B9808E00123E48 /* what.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = what.c; sourceTree = "<group>"; };
+ FC5D638B14B9819E00123E48 /* what */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = what; sourceTree = BUILT_PRODUCTS_DIR; };
+ FC5D639714B9822D00123E48 /* hexdump */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = hexdump; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA02E514B505A50030BEB3 /* libresolv.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libresolv.dylib; path = /usr/lib/libresolv.dylib; sourceTree = "<absolute>"; };
+ FCBA134114A141A300AA698B /* alias.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = alias.1; sourceTree = "<group>"; };
+ FCBA134314A141A300AA698B /* generic.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = generic.sh; sourceTree = "<group>"; };
+ FCBA134614A141A300AA698B /* apply.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = apply.1; sourceTree = "<group>"; };
+ FCBA134714A141A300AA698B /* apply.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = apply.c; sourceTree = "<group>"; };
+ FCBA134A14A141A300AA698B /* basename.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = basename.1; sourceTree = "<group>"; };
+ FCBA134B14A141A300AA698B /* basename.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = basename.c; sourceTree = "<group>"; };
+ FCBA134C14A141A300AA698B /* dirname.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; name = dirname.1; path = ../basename/dirname.1; sourceTree = "<group>"; };
+ FCBA134F14A141A300AA698B /* chroot.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = chroot.8; sourceTree = "<group>"; };
+ FCBA135014A141A300AA698B /* chroot.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = chroot.c; sourceTree = "<group>"; };
+ FCBA135314A141A300AA698B /* date.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = date.1; sourceTree = "<group>"; };
+ FCBA135414A141A300AA698B /* date.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = date.c; sourceTree = "<group>"; };
+ FCBA135514A141A300AA698B /* extern.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = extern.h; sourceTree = "<group>"; };
+ FCBA135714A141A300AA698B /* netdate.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = netdate.c; sourceTree = "<group>"; };
+ FCBA135814A141A300AA698B /* vary.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = vary.c; sourceTree = "<group>"; };
+ FCBA135914A141A300AA698B /* vary.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = vary.h; sourceTree = "<group>"; };
+ FCBA135B14A141A300AA698B /* dirname.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = dirname.c; sourceTree = "<group>"; };
+ FCBA135E14A141A300AA698B /* echo.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = echo.1; sourceTree = "<group>"; };
+ FCBA135F14A141A300AA698B /* echo.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = echo.c; sourceTree = "<group>"; };
+ FCBA136214A141A300AA698B /* env.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = env.1; sourceTree = "<group>"; };
+ FCBA136314A141A300AA698B /* env.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = env.c; sourceTree = "<group>"; };
+ FCBA136614A141A300AA698B /* expr.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = expr.1; sourceTree = "<group>"; };
+ FCBA136714A141A300AA698B /* expr.y */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.yacc; path = expr.y; sourceTree = "<group>"; };
+ FCBA136A14A141A300AA698B /* false.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = false.1; sourceTree = "<group>"; };
+ FCBA136B14A141A300AA698B /* false.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = false.c; sourceTree = "<group>"; };
+ FCBA136F14A141A300AA698B /* extern.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = extern.h; sourceTree = "<group>"; };
+ FCBA137014A141A300AA698B /* find.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = find.1; sourceTree = "<group>"; };
+ FCBA137114A141A300AA698B /* find.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = find.c; sourceTree = "<group>"; };
+ FCBA137214A141A300AA698B /* find.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = find.h; sourceTree = "<group>"; };
+ FCBA137314A141A300AA698B /* function.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = function.c; sourceTree = "<group>"; };
+ FCBA137414A141A300AA698B /* getdate.y */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.yacc; path = getdate.y; sourceTree = "<group>"; };
+ FCBA137514A141A300AA698B /* ls.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = ls.c; sourceTree = "<group>"; };
+ FCBA137614A141A300AA698B /* main.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = main.c; sourceTree = "<group>"; };
+ FCBA137814A141A300AA698B /* misc.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = misc.c; sourceTree = "<group>"; };
+ FCBA137914A141A300AA698B /* operator.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = operator.c; sourceTree = "<group>"; };
+ FCBA137A14A141A300AA698B /* option.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = option.c; sourceTree = "<group>"; };
+ FCBA137C14A141A300AA698B /* getopt.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = getopt.1; sourceTree = "<group>"; };
+ FCBA137D14A141A300AA698B /* getopt.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = getopt.c; sourceTree = "<group>"; };
+ FCBA138014A141A300AA698B /* hostname.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = hostname.1; sourceTree = "<group>"; };
+ FCBA138114A141A300AA698B /* hostname.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = hostname.c; sourceTree = "<group>"; };
+ FCBA138414A141A300AA698B /* groups.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = groups.1; sourceTree = "<group>"; };
+ FCBA138514A141A300AA698B /* id.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = id.1; sourceTree = "<group>"; };
+ FCBA138614A141A300AA698B /* id.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = id.c; sourceTree = "<group>"; };
+ FCBA138A14A141A300AA698B /* whoami.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = whoami.1; sourceTree = "<group>"; };
+ FCBA138C14A141A300AA698B /* jot.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = jot.1; sourceTree = "<group>"; };
+ FCBA138D14A141A300AA698B /* jot.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = jot.c; sourceTree = "<group>"; };
+ FCBA139014A141A300AA698B /* kill.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = kill.1; sourceTree = "<group>"; };
+ FCBA139114A141A300AA698B /* kill.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = kill.c; sourceTree = "<group>"; };
+ FCBA139414A141A300AA698B /* killall.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = killall.1; sourceTree = "<group>"; };
+ FCBA139514A141A300AA698B /* killall.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = killall.c; sourceTree = "<group>"; };
+ FCBA139814A141A300AA698B /* lastcomm.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = lastcomm.1; sourceTree = "<group>"; };
+ FCBA139914A141A300AA698B /* lastcomm.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = lastcomm.c; sourceTree = "<group>"; };
+ FCBA139B14A141A300AA698B /* pathnames.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = pathnames.h; sourceTree = "<group>"; };
+ FCBA139E14A141A300AA698B /* locate.bigram.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = locate.bigram.c; sourceTree = "<group>"; };
+ FCBA13A114A141A300AA698B /* locate.code.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = locate.code.c; sourceTree = "<group>"; };
+ FCBA13A414A141A300AA698B /* com.apple.locate.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = com.apple.locate.plist; sourceTree = "<group>"; };
+ FCBA13A514A141A300AA698B /* concatdb.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = concatdb.sh; sourceTree = "<group>"; };
+ FCBA13A714A141A300AA698B /* locate.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = locate.1; sourceTree = "<group>"; };
+ FCBA13A814A141A300AA698B /* locate.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = locate.c; sourceTree = "<group>"; };
+ FCBA13A914A141A300AA698B /* locate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = locate.h; sourceTree = "<group>"; };
+ FCBA13AA14A141A300AA698B /* locate.rc */ = {isa = PBXFileReference; lastKnownFileType = text; path = locate.rc; sourceTree = "<group>"; };
+ FCBA13AB14A141A300AA698B /* locate.updatedb.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = locate.updatedb.8; sourceTree = "<group>"; };
+ FCBA13AD14A141A300AA698B /* mklocatedb.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = mklocatedb.sh; sourceTree = "<group>"; };
+ FCBA13AE14A141A300AA698B /* pathnames.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = pathnames.h; sourceTree = "<group>"; };
+ FCBA13AF14A141A300AA698B /* updatedb.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = updatedb.sh; sourceTree = "<group>"; };
+ FCBA13B014A141A300AA698B /* util.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = util.c; sourceTree = "<group>"; };
+ FCBA13B114A141A300AA698B /* locate.code.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = locate.code.8; sourceTree = "<group>"; };
+ FCBA13B414A141A300AA698B /* logname.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = logname.1; sourceTree = "<group>"; };
+ FCBA13B514A141A300AA698B /* logname.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = logname.c; sourceTree = "<group>"; };
+ FCBA13C014A141A300AA698B /* mktemp.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = mktemp.1; sourceTree = "<group>"; };
+ FCBA13C114A141A300AA698B /* mktemp.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = mktemp.c; sourceTree = "<group>"; };
+ FCBA13C414A141A300AA698B /* nice.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = nice.1; sourceTree = "<group>"; };
+ FCBA13C514A141A300AA698B /* nice.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = nice.c; sourceTree = "<group>"; };
+ FCBA13C814A141A300AA698B /* nohup.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = nohup.1; sourceTree = "<group>"; };
+ FCBA13C914A141A300AA698B /* nohup.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = nohup.c; sourceTree = "<group>"; };
+ FCBA13CC14A141A300AA698B /* path_helper.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = path_helper.8; sourceTree = "<group>"; };
+ FCBA13CD14A141A300AA698B /* path_helper.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = path_helper.c; sourceTree = "<group>"; };
+ FCBA13D014A141A300AA698B /* printenv.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = printenv.1; sourceTree = "<group>"; };
+ FCBA13D114A141A300AA698B /* printenv.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = printenv.c; sourceTree = "<group>"; };
+ FCBA13D414A141A300AA698B /* printf.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = printf.1; sourceTree = "<group>"; };
+ FCBA13D514A141A300AA698B /* printf.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = printf.c; sourceTree = "<group>"; };
+ FCBA13D814A141A300AA698B /* pwd.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = pwd.1; sourceTree = "<group>"; };
+ FCBA13D914A141A300AA698B /* pwd.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = pwd.c; sourceTree = "<group>"; };
+ FCBA13DC14A141A300AA698B /* renice.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = renice.8; sourceTree = "<group>"; };
+ FCBA13DD14A141A300AA698B /* renice.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = renice.c; sourceTree = "<group>"; };
+ FCBA13E014A141A300AA698B /* script.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = script.1; sourceTree = "<group>"; };
+ FCBA13E114A141A300AA698B /* script.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = script.c; sourceTree = "<group>"; };
+ FCBA13E414A141A300AA698B /* seq.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = seq.1; sourceTree = "<group>"; };
+ FCBA13E514A141A300AA698B /* seq.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = seq.c; sourceTree = "<group>"; };
+ FCBA13E814A141A300AA698B /* shlock.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = shlock.1; sourceTree = "<group>"; };
+ FCBA13E914A141A300AA698B /* shlock.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = shlock.c; sourceTree = "<group>"; };
+ FCBA13EC14A141A300AA698B /* sleep.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = sleep.1; sourceTree = "<group>"; };
+ FCBA13ED14A141A300AA698B /* sleep.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = sleep.c; sourceTree = "<group>"; };
+ FCBA13F014A141A300AA698B /* su.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = su.1; sourceTree = "<group>"; };
+ FCBA13F114A141A300AA698B /* su.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = su.c; sourceTree = "<group>"; };
+ FCBA13F214A141A300AA698B /* su.pam */ = {isa = PBXFileReference; lastKnownFileType = text; path = su.pam; sourceTree = "<group>"; };
+ FCBA13F514A141A300AA698B /* tee.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = tee.1; sourceTree = "<group>"; };
+ FCBA13F614A141A300AA698B /* tee.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = tee.c; sourceTree = "<group>"; };
+ FCBA13F814A141A300AA698B /* [.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = "[.1"; sourceTree = "<group>"; };
+ FCBA13FA14A141A300AA698B /* test.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = test.1; sourceTree = "<group>"; };
+ FCBA13FB14A141A300AA698B /* test.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = test.c; sourceTree = "<group>"; };
+ FCBA13FF14A141A300AA698B /* time.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = time.1; sourceTree = "<group>"; };
+ FCBA140014A141A300AA698B /* time.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = time.c; sourceTree = "<group>"; usesTabs = 1; };
+ FCBA140314A141A300AA698B /* true.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = true.1; sourceTree = "<group>"; };
+ FCBA140414A141A300AA698B /* true.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = true.c; sourceTree = "<group>"; };
+ FCBA140814A141A300AA698B /* uname.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = uname.1; sourceTree = "<group>"; };
+ FCBA140914A141A300AA698B /* uname.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = uname.c; sourceTree = "<group>"; };
+ FCBA140C14A141A300AA698B /* users.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = users.1; sourceTree = "<group>"; };
+ FCBA140D14A141A300AA698B /* users.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = users.c; sourceTree = "<group>"; };
+ FCBA140F14A141A300AA698B /* extern.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = extern.h; sourceTree = "<group>"; };
+ FCBA141014A141A300AA698B /* fmt.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = fmt.c; sourceTree = "<group>"; };
+ FCBA141214A141A300AA698B /* pr_time.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = pr_time.c; sourceTree = "<group>"; };
+ FCBA141314A141A300AA698B /* proc_compare.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = proc_compare.c; sourceTree = "<group>"; };
+ FCBA141414A141A300AA698B /* uptime.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = uptime.1; sourceTree = "<group>"; };
+ FCBA141514A141A300AA698B /* w.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = w.1; sourceTree = "<group>"; };
+ FCBA141614A141A300AA698B /* w.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = w.c; sourceTree = "<group>"; };
+ FCBA141914A141A300AA698B /* whereis.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = whereis.1; sourceTree = "<group>"; };
+ FCBA141A14A141A300AA698B /* whereis.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = whereis.c; sourceTree = "<group>"; };
+ FCBA141D14A141A300AA698B /* which.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = which.1; sourceTree = "<group>"; };
+ FCBA141E14A141A300AA698B /* which.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = which.c; sourceTree = "<group>"; };
+ FCBA142114A141A300AA698B /* utmpentry.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = utmpentry.c; sourceTree = "<group>"; };
+ FCBA142214A141A300AA698B /* utmpentry.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = utmpentry.h; sourceTree = "<group>"; };
+ FCBA142314A141A300AA698B /* who.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = who.1; sourceTree = "<group>"; };
+ FCBA142414A141A300AA698B /* who.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = who.c; sourceTree = "<group>"; };
+ FCBA142714A141A300AA698B /* pathnames.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = pathnames.h; sourceTree = "<group>"; };
+ FCBA142814A141A300AA698B /* strnsubst.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = strnsubst.c; sourceTree = "<group>"; };
+ FCBA142914A141A300AA698B /* xargs.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = xargs.1; sourceTree = "<group>"; };
+ FCBA142A14A141A300AA698B /* xargs.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = xargs.c; sourceTree = "<group>"; };
+ FCBA142D14A141A300AA698B /* yes.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = yes.1; sourceTree = "<group>"; };
+ FCBA142E14A141A300AA698B /* yes.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = yes.c; sourceTree = "<group>"; };
+ FCBA149E14A141FF00AA698B /* apply */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = apply; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA14B414A1422D00AA698B /* basename */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = basename; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA14BD14A1423E00AA698B /* chroot */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = chroot; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA14C514A1426800AA698B /* date */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = date; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA14CD14A1428000AA698B /* dirname */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = dirname; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA14D514A1433F00AA698B /* echo */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = echo; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA14DD14A1434A00AA698B /* env */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = env; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA151414A1453A00AA698B /* expr */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = expr; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA151C14A1454D00AA698B /* false */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = false; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA152414A1455600AA698B /* find */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = find; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA152C14A1455900AA698B /* getopt */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = getopt; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA153414A1455C00AA698B /* hostname */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = hostname; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA153C14A1455F00AA698B /* id */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = id; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA154414A1456100AA698B /* jot */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = jot; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA154C14A1456400AA698B /* kill */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = kill; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA155414A1456700AA698B /* killall */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = killall; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA155C14A1456A00AA698B /* lastcomm */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = lastcomm; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA156414A1456E00AA698B /* locate */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = locate; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA156C14A1457100AA698B /* logname */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = logname; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA157C14A1457B00AA698B /* mktemp */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mktemp; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA158414A1457F00AA698B /* nice */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = nice; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA158C14A1458500AA698B /* nohup */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = nohup; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA159414A1458800AA698B /* path_helper */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = path_helper; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA159C14A1458C00AA698B /* printenv */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = printenv; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA15A414A1459000AA698B /* printf */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = printf; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA15AC14A1459500AA698B /* pwd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = pwd; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA15B414A1459700AA698B /* renice */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = renice; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA15BC14A1459900AA698B /* script */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = script; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA15C414A1459E00AA698B /* seq */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = seq; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA15CC14A145A200AA698B /* shlock */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = shlock; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA15D414A145A500AA698B /* sleep */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = sleep; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA15DC14A145A700AA698B /* su */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = su; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA15E414A145A900AA698B /* tee */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = tee; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA15EC14A145AE00AA698B /* test */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = test; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA15F414A145B000AA698B /* time */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = time; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA15FC14A145B200AA698B /* true */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = true; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA160414A145B500AA698B /* uname */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = uname; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA160C14A145B800AA698B /* users */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = users; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA161414A145BA00AA698B /* w */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = w; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA161C14A145BC00AA698B /* whereis */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = whereis; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA162414A145C000AA698B /* which */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = which; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA162C14A145C500AA698B /* who */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = who; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA163414A145C700AA698B /* xargs */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = xargs; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA163C14A145CA00AA698B /* yes */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = yes; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCE30EC114B5347A00CC0294 /* locate.bigram.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = locate.bigram.8; sourceTree = "<group>"; };
+ FCE30ED214B5368A00CC0294 /* locate.bigram */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = locate.bigram; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCE30EDE14B536C900CC0294 /* locate.code */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = locate.code; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCED3AF514B4FC1800C313C3 /* libpam.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libpam.dylib; path = /usr/lib/libpam.dylib; sourceTree = "<absolute>"; };
+ FD155C721D6E37B5005A53CA /* legacy_test.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = legacy_test.sh; sourceTree = "<group>"; };
+ FD155C771D6E3847005A53CA /* legacy_test.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = legacy_test.sh; sourceTree = "<group>"; };
+ FD155C7A1D6E3847005A53CA /* regress.b.out */ = {isa = PBXFileReference; lastKnownFileType = text; path = regress.b.out; sourceTree = "<group>"; };
+ FD155C7B1D6E3847005A53CA /* regress.d.out */ = {isa = PBXFileReference; lastKnownFileType = text; path = regress.d.out; sourceTree = "<group>"; };
+ FD155C7C1D6E3847005A53CA /* regress.f.out */ = {isa = PBXFileReference; lastKnownFileType = text; path = regress.f.out; sourceTree = "<group>"; };
+ FD155C7D1D6E3847005A53CA /* regress.l1.out */ = {isa = PBXFileReference; lastKnownFileType = text; path = regress.l1.out; sourceTree = "<group>"; };
+ FD155C7E1D6E3847005A53CA /* regress.l2.out */ = {isa = PBXFileReference; lastKnownFileType = text; path = regress.l2.out; sourceTree = "<group>"; };
+ FD155C7F1D6E3847005A53CA /* regress.m1.out */ = {isa = PBXFileReference; lastKnownFileType = file; path = regress.m1.out; sourceTree = "<group>"; };
+ FD155C801D6E3847005A53CA /* regress.m2.out */ = {isa = PBXFileReference; lastKnownFileType = text; path = regress.m2.out; sourceTree = "<group>"; };
+ FD155C811D6E3847005A53CA /* regress.m3.out */ = {isa = PBXFileReference; lastKnownFileType = text; path = regress.m3.out; sourceTree = "<group>"; };
+ FD155C821D6E3847005A53CA /* regress.m4.out */ = {isa = PBXFileReference; lastKnownFileType = text; path = regress.m4.out; sourceTree = "<group>"; };
+ FD155C831D6E3847005A53CA /* regress.m5.out */ = {isa = PBXFileReference; lastKnownFileType = text; path = regress.m5.out; sourceTree = "<group>"; };
+ FD155C841D6E3847005A53CA /* regress.missingpos1.out */ = {isa = PBXFileReference; lastKnownFileType = text; path = regress.missingpos1.out; sourceTree = "<group>"; };
+ FD155C851D6E3847005A53CA /* regress.s.out */ = {isa = PBXFileReference; lastKnownFileType = text; path = regress.s.out; sourceTree = "<group>"; };
+ FD155C861D6E3847005A53CA /* regress.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = regress.sh; sourceTree = "<group>"; };
+ FD155C871D6E3847005A53CA /* regress.zero.out */ = {isa = PBXFileReference; lastKnownFileType = text; path = regress.zero.out; sourceTree = "<group>"; };
+ FD6060B21B7C0388004BCA6A /* ash */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ash; sourceTree = BUILT_PRODUCTS_DIR; };
+ FD6060B41B7C0388004BCA6A /* main.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = main.c; sourceTree = "<group>"; };
+ FD6060BC1B7C0471004BCA6A /* alias.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = alias.c; sourceTree = "<group>"; };
+ FD6060BD1B7C0471004BCA6A /* arith_yacc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = arith_yacc.c; sourceTree = "<group>"; };
+ FD6060BE1B7C0471004BCA6A /* arith_yylex.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = arith_yylex.c; sourceTree = "<group>"; };
+ FD6060BF1B7C0471004BCA6A /* cd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cd.c; sourceTree = "<group>"; };
+ FD6060C01B7C0471004BCA6A /* error.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = error.c; sourceTree = "<group>"; };
+ FD6060C11B7C0471004BCA6A /* eval.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = eval.c; sourceTree = "<group>"; };
+ FD6060C21B7C0471004BCA6A /* exec.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = exec.c; sourceTree = "<group>"; };
+ FD6060C31B7C0471004BCA6A /* expand.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = expand.c; sourceTree = "<group>"; };
+ FD6060C41B7C0471004BCA6A /* histedit.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = histedit.c; sourceTree = "<group>"; };
+ FD6060C51B7C0471004BCA6A /* input.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = input.c; sourceTree = "<group>"; };
+ FD6060C61B7C0471004BCA6A /* jobs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = jobs.c; sourceTree = "<group>"; };
+ FD6060C71B7C0471004BCA6A /* mail.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mail.c; sourceTree = "<group>"; };
+ FD6060C81B7C0471004BCA6A /* memalloc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = memalloc.c; sourceTree = "<group>"; };
+ FD6060C91B7C0471004BCA6A /* miscbltin.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = miscbltin.c; sourceTree = "<group>"; };
+ FD6060CA1B7C0471004BCA6A /* mystring.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mystring.c; sourceTree = "<group>"; };
+ FD6060CB1B7C0471004BCA6A /* options.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = options.c; sourceTree = "<group>"; };
+ FD6060CC1B7C0471004BCA6A /* output.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = output.c; sourceTree = "<group>"; };
+ FD6060CD1B7C0471004BCA6A /* parser.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = parser.c; sourceTree = "<group>"; };
+ FD6060CE1B7C0471004BCA6A /* redir.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = redir.c; sourceTree = "<group>"; };
+ FD6060CF1B7C0471004BCA6A /* show.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = show.c; sourceTree = "<group>"; };
+ FD6060D01B7C0471004BCA6A /* trap.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = trap.c; sourceTree = "<group>"; };
+ FD6060D11B7C0471004BCA6A /* var.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = var.c; sourceTree = "<group>"; };
+ FD6060EA1B7C04E4004BCA6A /* echo.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = echo.c; sourceTree = "<group>"; };
+ FD6060FA1B7C0CAF004BCA6A /* builtins.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = builtins.c; sourceTree = "<group>"; };
+ FD6060FB1B7C0CAF004BCA6A /* nodes.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = nodes.c; sourceTree = "<group>"; };
+ FD6060FC1B7C0CAF004BCA6A /* syntax.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = syntax.c; sourceTree = "<group>"; };
+ FD6061011B7D2B6D004BCA6A /* builtins.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = builtins.h; sourceTree = "<group>"; };
+ FD6061021B7D2B6D004BCA6A /* nodes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = nodes.h; sourceTree = "<group>"; };
+ FD6061031B7D2B6D004BCA6A /* syntax.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = syntax.h; sourceTree = "<group>"; };
+ FD6061041B7D2B6D004BCA6A /* token.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = token.h; sourceTree = "<group>"; };
+ FD6061051B7D2BF8004BCA6A /* bltin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bltin.h; sourceTree = "<group>"; };
+ FD6061061B7D2C8C004BCA6A /* alias.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = alias.h; sourceTree = "<group>"; };
+ FD6061071B7D2C8C004BCA6A /* arith_yacc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = arith_yacc.h; sourceTree = "<group>"; };
+ FD6061081B7D2C8C004BCA6A /* arith.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = arith.h; sourceTree = "<group>"; };
+ FD6061091B7D2C8C004BCA6A /* builtins.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = builtins.def; sourceTree = "<group>"; };
+ FD60610A1B7D2C8C004BCA6A /* cd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cd.h; sourceTree = "<group>"; };
+ FD60610B1B7D2C8C004BCA6A /* error.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = error.h; sourceTree = "<group>"; };
+ FD60610C1B7D2C8C004BCA6A /* eval.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eval.h; sourceTree = "<group>"; };
+ FD60610D1B7D2C8C004BCA6A /* exec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = exec.h; sourceTree = "<group>"; };
+ FD60610E1B7D2C8C004BCA6A /* expand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = expand.h; sourceTree = "<group>"; };
+ FD60610F1B7D2C8C004BCA6A /* input.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = input.h; sourceTree = "<group>"; };
+ FD6061101B7D2C8C004BCA6A /* jobs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jobs.h; sourceTree = "<group>"; };
+ FD6061111B7D2C8C004BCA6A /* mail.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mail.h; sourceTree = "<group>"; };
+ FD6061121B7D2C8C004BCA6A /* main.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = main.h; sourceTree = "<group>"; };
+ FD6061131B7D2C8C004BCA6A /* memalloc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = memalloc.h; sourceTree = "<group>"; };
+ FD6061141B7D2C8C004BCA6A /* mkbuiltins */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = mkbuiltins; sourceTree = "<group>"; };
+ FD6061151B7D2C8C004BCA6A /* mknodes.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mknodes.c; sourceTree = "<group>"; };
+ FD6061161B7D2C8C004BCA6A /* mksyntax.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mksyntax.c; sourceTree = "<group>"; };
+ FD6061171B7D2C8C004BCA6A /* mktokens */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = mktokens; sourceTree = "<group>"; };
+ FD6061181B7D2C8C004BCA6A /* myhistedit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = myhistedit.h; sourceTree = "<group>"; };
+ FD6061191B7D2C8C004BCA6A /* mystring.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mystring.h; sourceTree = "<group>"; };
+ FD60611A1B7D2C8C004BCA6A /* nodes.c.pat */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = nodes.c.pat; sourceTree = "<group>"; };
+ FD60611B1B7D2C8C004BCA6A /* nodetypes */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = nodetypes; sourceTree = "<group>"; };
+ FD60611C1B7D2C8C004BCA6A /* options.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = options.h; sourceTree = "<group>"; };
+ FD60611D1B7D2C8C004BCA6A /* output.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = output.h; sourceTree = "<group>"; };
+ FD60611E1B7D2C8C004BCA6A /* parser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = parser.h; sourceTree = "<group>"; };
+ FD60611F1B7D2C8C004BCA6A /* redir.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = redir.h; sourceTree = "<group>"; };
+ FD6061201B7D2C8C004BCA6A /* sh.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = sh.1; sourceTree = "<group>"; };
+ FD6061211B7D2C8C004BCA6A /* shell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = shell.h; sourceTree = "<group>"; };
+ FD6061221B7D2C8C004BCA6A /* show.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = show.h; sourceTree = "<group>"; };
+ FD6061231B7D2C8C004BCA6A /* trap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = trap.h; sourceTree = "<group>"; };
+ FD6061241B7D2C8C004BCA6A /* var.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = var.h; sourceTree = "<group>"; };
+ FD6061281B7D2D1D004BCA6A /* cmv */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = cmv; sourceTree = "<group>"; };
+ FD6061291B7D2D1D004BCA6A /* dirs */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = dirs; sourceTree = "<group>"; };
+ FD60612A1B7D2D1D004BCA6A /* login */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = login; sourceTree = "<group>"; };
+ FD60612B1B7D2D1D004BCA6A /* newgrp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = newgrp; sourceTree = "<group>"; };
+ FD60612C1B7D2D1D004BCA6A /* popd */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = popd; sourceTree = "<group>"; };
+ FD60612D1B7D2D1D004BCA6A /* pushd */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = pushd; sourceTree = "<group>"; };
+ FD60612E1B7D2D1D004BCA6A /* suspend */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = suspend; sourceTree = "<group>"; };
+ FD6061301B7D2DDE004BCA6A /* base.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = base.xcconfig; sourceTree = "<group>"; };
+ FD6061311B7D2DDE004BCA6A /* sh.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = sh.xcconfig; sourceTree = "<group>"; };
+ FD88EB01198C5257006B7EFD /* envopts.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = envopts.c; sourceTree = "<group>"; };
+ FD88EB02198C5257006B7EFD /* envopts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = envopts.h; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ C6868573154725700025D623 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC5D638514B9819E00123E48 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC5D639214B9822D00123E48 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA149A14A141FF00AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA14B014A1422D00AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA14B914A1423E00AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA14C114A1426800AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA14C914A1428000AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA14D114A1433F00AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA14D914A1434A00AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA151014A1453A00AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA151814A1454D00AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA152014A1455600AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA152814A1455900AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA153014A1455C00AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA153814A1455F00AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA154014A1456100AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA154814A1456400AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA155014A1456700AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA155814A1456A00AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA156014A1456E00AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA156814A1457100AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA157814A1457B00AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA158014A1457F00AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA158814A1458500AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA159014A1458800AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA159814A1458C00AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA15A014A1459000AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA15A814A1459500AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA15B014A1459700AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA15B814A1459900AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA15C014A1459E00AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA15C814A145A200AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA15D014A145A500AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA15D814A145A700AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCED3AF614B4FC1800C313C3 /* libpam.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA15E014A145A900AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA15E814A145AE00AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA15F014A145B000AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA15F814A145B200AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA160014A145B500AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA160814A145B800AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA161014A145BA00AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA161814A145BC00AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA162014A145C000AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA162814A145C500AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA163014A145C700AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA163814A145CA00AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCE30EC614B5368A00CC0294 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCE30ED914B536C900CC0294 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FD6060AF1B7C0388004BCA6A /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ C6868578154725700025D623 /* systime */ = {
+ isa = PBXGroup;
+ children = (
+ C6868579154725700025D623 /* systime.c */,
+ C686857B154725700025D623 /* systime.1 */,
+ );
+ path = systime;
+ sourceTree = "<group>";
+ };
+ CE799E5F24AD3B1B00E73238 /* tests */ = {
+ isa = PBXGroup;
+ children = (
+ CE799E6024AD3B1B00E73238 /* test_time.sh */,
+ );
+ path = tests;
+ sourceTree = "<group>";
+ };
+ CE799E6124B3982200E73238 /* xcodescripts */ = {
+ isa = PBXGroup;
+ children = (
+ CE799E6224B3982200E73238 /* install-files.sh */,
+ CE799E6324B3982200E73238 /* builtins.txt */,
+ CE799E6424B3982200E73238 /* builtins-manpages.txt */,
+ );
+ path = xcodescripts;
+ sourceTree = "<group>";
+ };
+ FC5D636714B9808E00123E48 /* hexdump */ = {
+ isa = PBXGroup;
+ children = (
+ FC5D636814B9808E00123E48 /* conv.c */,
+ FC5D636914B9808E00123E48 /* display.c */,
+ FC5D636A14B9808E00123E48 /* hexdump.1 */,
+ FC5D636B14B9808E00123E48 /* hexdump.c */,
+ FC5D636C14B9808E00123E48 /* hexdump.h */,
+ FC5D636D14B9808E00123E48 /* hexsyntax.c */,
+ FC5D636E14B9808E00123E48 /* od.1 */,
+ FC5D636F14B9808E00123E48 /* odsyntax.c */,
+ FC5D637014B9808E00123E48 /* parse.c */,
+ );
+ path = hexdump;
+ sourceTree = "<group>";
+ };
+ FC5D637114B9808E00123E48 /* what */ = {
+ isa = PBXGroup;
+ children = (
+ FC5D637214B9808E00123E48 /* what.1 */,
+ FC5D637314B9808E00123E48 /* what.c */,
+ );
+ path = what;
+ sourceTree = "<group>";
+ };
+ FC80BF5514A05A2F00C6F7F5 = {
+ isa = PBXGroup;
+ children = (
+ CE799E6124B3982200E73238 /* xcodescripts */,
+ FD60612F1B7D2DDE004BCA6A /* xcconfigs */,
+ FCBA134014A141A300AA698B /* alias */,
+ FCBA134514A141A300AA698B /* apply */,
+ FCBA134914A141A300AA698B /* basename */,
+ FCBA134E14A141A300AA698B /* chroot */,
+ FCBA135214A141A300AA698B /* date */,
+ FCBA135A14A141A300AA698B /* dirname */,
+ FCBA135D14A141A300AA698B /* echo */,
+ FCBA136114A141A300AA698B /* env */,
+ FCBA136514A141A300AA698B /* expr */,
+ FCBA136914A141A300AA698B /* false */,
+ FCBA136E14A141A300AA698B /* find */,
+ FCBA137B14A141A300AA698B /* getopt */,
+ FC5D636714B9808E00123E48 /* hexdump */,
+ FCBA137F14A141A300AA698B /* hostname */,
+ FCBA138314A141A300AA698B /* id */,
+ FCBA138B14A141A300AA698B /* jot */,
+ FCBA138F14A141A300AA698B /* kill */,
+ FCBA139314A141A300AA698B /* killall */,
+ FCBA139714A141A300AA698B /* lastcomm */,
+ FCBA139C14A141A300AA698B /* locate */,
+ FCBA13B314A141A300AA698B /* logname */,
+ FCBA13BE14A141A300AA698B /* mktemp */,
+ FCBA13C214A141A300AA698B /* nice */,
+ FCBA13C614A141A300AA698B /* nohup */,
+ FCBA13CA14A141A300AA698B /* path_helper */,
+ FCBA13CE14A141A300AA698B /* printenv */,
+ FCBA13D214A141A300AA698B /* printf */,
+ FCBA13D614A141A300AA698B /* pwd */,
+ FCBA13DA14A141A300AA698B /* renice */,
+ FCBA13DE14A141A300AA698B /* script */,
+ FCBA13E214A141A300AA698B /* seq */,
+ FD6060B31B7C0388004BCA6A /* sh */,
+ FCBA13E614A141A300AA698B /* shlock */,
+ FCBA13EA14A141A300AA698B /* sleep */,
+ FCBA13EE14A141A300AA698B /* su */,
+ C6868578154725700025D623 /* systime */,
+ FCBA13F314A141A300AA698B /* tee */,
+ FCBA13F714A141A300AA698B /* test */,
+ FCBA13FD14A141A300AA698B /* time */,
+ FCBA140114A141A300AA698B /* true */,
+ FCBA140614A141A300AA698B /* uname */,
+ FCBA140A14A141A300AA698B /* users */,
+ FCBA140E14A141A300AA698B /* w */,
+ FC5D637114B9808E00123E48 /* what */,
+ FCBA141714A141A300AA698B /* whereis */,
+ FCBA141B14A141A300AA698B /* which */,
+ FCBA141F14A141A300AA698B /* who */,
+ FCBA142514A141A300AA698B /* xargs */,
+ FCBA142B14A141A300AA698B /* yes */,
+ FC80BF6114A05A2F00C6F7F5 /* Products */,
+ );
+ sourceTree = "<group>";
+ };
+ FC80BF6114A05A2F00C6F7F5 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA149E14A141FF00AA698B /* apply */,
+ FCBA14B414A1422D00AA698B /* basename */,
+ FCBA14BD14A1423E00AA698B /* chroot */,
+ FCBA14C514A1426800AA698B /* date */,
+ FCBA14CD14A1428000AA698B /* dirname */,
+ FCBA14D514A1433F00AA698B /* echo */,
+ FCBA14DD14A1434A00AA698B /* env */,
+ FCBA151414A1453A00AA698B /* expr */,
+ FCBA151C14A1454D00AA698B /* false */,
+ FCBA152414A1455600AA698B /* find */,
+ FCBA152C14A1455900AA698B /* getopt */,
+ FCBA153414A1455C00AA698B /* hostname */,
+ FCBA153C14A1455F00AA698B /* id */,
+ FCBA154414A1456100AA698B /* jot */,
+ FCBA154C14A1456400AA698B /* kill */,
+ FCBA155414A1456700AA698B /* killall */,
+ FCBA155C14A1456A00AA698B /* lastcomm */,
+ FCBA156414A1456E00AA698B /* locate */,
+ FCBA156C14A1457100AA698B /* logname */,
+ FCBA157C14A1457B00AA698B /* mktemp */,
+ FCBA158414A1457F00AA698B /* nice */,
+ FCBA158C14A1458500AA698B /* nohup */,
+ FCBA159414A1458800AA698B /* path_helper */,
+ FCBA159C14A1458C00AA698B /* printenv */,
+ FCBA15A414A1459000AA698B /* printf */,
+ FCBA15AC14A1459500AA698B /* pwd */,
+ FCBA15B414A1459700AA698B /* renice */,
+ FCBA15BC14A1459900AA698B /* script */,
+ FCBA15C414A1459E00AA698B /* seq */,
+ FD6060B21B7C0388004BCA6A /* ash */,
+ FCBA15CC14A145A200AA698B /* shlock */,
+ FCBA15D414A145A500AA698B /* sleep */,
+ FCBA15DC14A145A700AA698B /* su */,
+ FCBA15E414A145A900AA698B /* tee */,
+ FCBA15EC14A145AE00AA698B /* test */,
+ FCBA15F414A145B000AA698B /* time */,
+ FCBA15FC14A145B200AA698B /* true */,
+ FCBA160414A145B500AA698B /* uname */,
+ FCBA160C14A145B800AA698B /* users */,
+ FCBA161414A145BA00AA698B /* w */,
+ FCBA161C14A145BC00AA698B /* whereis */,
+ FCBA162414A145C000AA698B /* which */,
+ FCBA162C14A145C500AA698B /* who */,
+ FCBA163414A145C700AA698B /* xargs */,
+ FCBA163C14A145CA00AA698B /* yes */,
+ FCE30ED214B5368A00CC0294 /* locate.bigram */,
+ FCE30EDE14B536C900CC0294 /* locate.code */,
+ FC5D638B14B9819E00123E48 /* what */,
+ FC5D639714B9822D00123E48 /* hexdump */,
+ C6868576154725700025D623 /* systime */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ FCBA134014A141A300AA698B /* alias */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA134114A141A300AA698B /* alias.1 */,
+ FCBA134314A141A300AA698B /* generic.sh */,
+ );
+ path = alias;
+ sourceTree = "<group>";
+ };
+ FCBA134514A141A300AA698B /* apply */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA134614A141A300AA698B /* apply.1 */,
+ FCBA134714A141A300AA698B /* apply.c */,
+ );
+ path = apply;
+ sourceTree = "<group>";
+ };
+ FCBA134914A141A300AA698B /* basename */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA134A14A141A300AA698B /* basename.1 */,
+ FCBA134B14A141A300AA698B /* basename.c */,
+ );
+ path = basename;
+ sourceTree = "<group>";
+ };
+ FCBA134E14A141A300AA698B /* chroot */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA134F14A141A300AA698B /* chroot.8 */,
+ FCBA135014A141A300AA698B /* chroot.c */,
+ );
+ path = chroot;
+ sourceTree = "<group>";
+ };
+ FCBA135214A141A300AA698B /* date */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA135314A141A300AA698B /* date.1 */,
+ FCBA135414A141A300AA698B /* date.c */,
+ FCBA135514A141A300AA698B /* extern.h */,
+ FCBA135714A141A300AA698B /* netdate.c */,
+ FCBA135814A141A300AA698B /* vary.c */,
+ FCBA135914A141A300AA698B /* vary.h */,
+ );
+ path = date;
+ sourceTree = "<group>";
+ };
+ FCBA135A14A141A300AA698B /* dirname */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA135B14A141A300AA698B /* dirname.c */,
+ FCBA134C14A141A300AA698B /* dirname.1 */,
+ );
+ path = dirname;
+ sourceTree = "<group>";
+ };
+ FCBA135D14A141A300AA698B /* echo */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA135E14A141A300AA698B /* echo.1 */,
+ FCBA135F14A141A300AA698B /* echo.c */,
+ );
+ path = echo;
+ sourceTree = "<group>";
+ };
+ FCBA136114A141A300AA698B /* env */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA136214A141A300AA698B /* env.1 */,
+ FCBA136314A141A300AA698B /* env.c */,
+ FD88EB01198C5257006B7EFD /* envopts.c */,
+ FD88EB02198C5257006B7EFD /* envopts.h */,
+ );
+ path = env;
+ sourceTree = "<group>";
+ };
+ FCBA136514A141A300AA698B /* expr */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA136614A141A300AA698B /* expr.1 */,
+ FCBA136714A141A300AA698B /* expr.y */,
+ );
+ path = expr;
+ sourceTree = "<group>";
+ };
+ FCBA136914A141A300AA698B /* false */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA136A14A141A300AA698B /* false.1 */,
+ FCBA136B14A141A300AA698B /* false.c */,
+ );
+ path = false;
+ sourceTree = "<group>";
+ };
+ FCBA136E14A141A300AA698B /* find */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA136F14A141A300AA698B /* extern.h */,
+ FCBA137014A141A300AA698B /* find.1 */,
+ FCBA137114A141A300AA698B /* find.c */,
+ FCBA137214A141A300AA698B /* find.h */,
+ FCBA137314A141A300AA698B /* function.c */,
+ FCBA137414A141A300AA698B /* getdate.y */,
+ FCBA137514A141A300AA698B /* ls.c */,
+ FCBA137614A141A300AA698B /* main.c */,
+ FCBA137814A141A300AA698B /* misc.c */,
+ FCBA137914A141A300AA698B /* operator.c */,
+ FCBA137A14A141A300AA698B /* option.c */,
+ );
+ path = find;
+ sourceTree = "<group>";
+ };
+ FCBA137B14A141A300AA698B /* getopt */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA137C14A141A300AA698B /* getopt.1 */,
+ FCBA137D14A141A300AA698B /* getopt.c */,
+ );
+ path = getopt;
+ sourceTree = "<group>";
+ };
+ FCBA137F14A141A300AA698B /* hostname */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA138014A141A300AA698B /* hostname.1 */,
+ FCBA138114A141A300AA698B /* hostname.c */,
+ );
+ path = hostname;
+ sourceTree = "<group>";
+ };
+ FCBA138314A141A300AA698B /* id */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA138414A141A300AA698B /* groups.1 */,
+ FCBA138514A141A300AA698B /* id.1 */,
+ FCBA138614A141A300AA698B /* id.c */,
+ FCBA138A14A141A300AA698B /* whoami.1 */,
+ );
+ path = id;
+ sourceTree = "<group>";
+ };
+ FCBA138B14A141A300AA698B /* jot */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA138C14A141A300AA698B /* jot.1 */,
+ FCBA138D14A141A300AA698B /* jot.c */,
+ );
+ path = jot;
+ sourceTree = "<group>";
+ };
+ FCBA138F14A141A300AA698B /* kill */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA139014A141A300AA698B /* kill.1 */,
+ FCBA139114A141A300AA698B /* kill.c */,
+ );
+ path = kill;
+ sourceTree = "<group>";
+ };
+ FCBA139314A141A300AA698B /* killall */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA139414A141A300AA698B /* killall.1 */,
+ FCBA139514A141A300AA698B /* killall.c */,
+ );
+ path = killall;
+ sourceTree = "<group>";
+ };
+ FCBA139714A141A300AA698B /* lastcomm */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA139814A141A300AA698B /* lastcomm.1 */,
+ FCBA139914A141A300AA698B /* lastcomm.c */,
+ FCBA139B14A141A300AA698B /* pathnames.h */,
+ );
+ path = lastcomm;
+ sourceTree = "<group>";
+ };
+ FCBA139C14A141A300AA698B /* locate */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA139D14A141A300AA698B /* bigram */,
+ FCBA13A014A141A300AA698B /* code */,
+ FCBA13A314A141A300AA698B /* locate */,
+ );
+ path = locate;
+ sourceTree = "<group>";
+ };
+ FCBA139D14A141A300AA698B /* bigram */ = {
+ isa = PBXGroup;
+ children = (
+ FCE30EC114B5347A00CC0294 /* locate.bigram.8 */,
+ FCBA139E14A141A300AA698B /* locate.bigram.c */,
+ );
+ path = bigram;
+ sourceTree = "<group>";
+ };
+ FCBA13A014A141A300AA698B /* code */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA13B114A141A300AA698B /* locate.code.8 */,
+ FCBA13A114A141A300AA698B /* locate.code.c */,
+ );
+ path = code;
+ sourceTree = "<group>";
+ };
+ FCBA13A314A141A300AA698B /* locate */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA13A414A141A300AA698B /* com.apple.locate.plist */,
+ FCBA13A514A141A300AA698B /* concatdb.sh */,
+ FCBA13A714A141A300AA698B /* locate.1 */,
+ FCBA13A814A141A300AA698B /* locate.c */,
+ FCBA13A914A141A300AA698B /* locate.h */,
+ FCBA13AA14A141A300AA698B /* locate.rc */,
+ FCBA13AB14A141A300AA698B /* locate.updatedb.8 */,
+ FCBA13AD14A141A300AA698B /* mklocatedb.sh */,
+ FCBA13AE14A141A300AA698B /* pathnames.h */,
+ FCBA13AF14A141A300AA698B /* updatedb.sh */,
+ FCBA13B014A141A300AA698B /* util.c */,
+ );
+ path = locate;
+ sourceTree = "<group>";
+ };
+ FCBA13B314A141A300AA698B /* logname */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA13B414A141A300AA698B /* logname.1 */,
+ FCBA13B514A141A300AA698B /* logname.c */,
+ );
+ path = logname;
+ sourceTree = "<group>";
+ };
+ FCBA13BE14A141A300AA698B /* mktemp */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA13C014A141A300AA698B /* mktemp.1 */,
+ FCBA13C114A141A300AA698B /* mktemp.c */,
+ );
+ path = mktemp;
+ sourceTree = "<group>";
+ };
+ FCBA13C214A141A300AA698B /* nice */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA13C414A141A300AA698B /* nice.1 */,
+ FCBA13C514A141A300AA698B /* nice.c */,
+ );
+ path = nice;
+ sourceTree = "<group>";
+ };
+ FCBA13C614A141A300AA698B /* nohup */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA13C814A141A300AA698B /* nohup.1 */,
+ FCBA13C914A141A300AA698B /* nohup.c */,
+ );
+ path = nohup;
+ sourceTree = "<group>";
+ };
+ FCBA13CA14A141A300AA698B /* path_helper */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA13CC14A141A300AA698B /* path_helper.8 */,
+ FCBA13CD14A141A300AA698B /* path_helper.c */,
+ );
+ path = path_helper;
+ sourceTree = "<group>";
+ };
+ FCBA13CE14A141A300AA698B /* printenv */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA13D014A141A300AA698B /* printenv.1 */,
+ FCBA13D114A141A300AA698B /* printenv.c */,
+ );
+ path = printenv;
+ sourceTree = "<group>";
+ };
+ FCBA13D214A141A300AA698B /* printf */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA13D414A141A300AA698B /* printf.1 */,
+ FCBA13D514A141A300AA698B /* printf.c */,
+ FD155C761D6E3847005A53CA /* tests */,
+ );
+ path = printf;
+ sourceTree = "<group>";
+ };
+ FCBA13D614A141A300AA698B /* pwd */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA13D814A141A300AA698B /* pwd.1 */,
+ FCBA13D914A141A300AA698B /* pwd.c */,
+ );
+ path = pwd;
+ sourceTree = "<group>";
+ };
+ FCBA13DA14A141A300AA698B /* renice */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA13DC14A141A300AA698B /* renice.8 */,
+ FCBA13DD14A141A300AA698B /* renice.c */,
+ );
+ path = renice;
+ sourceTree = "<group>";
+ };
+ FCBA13DE14A141A300AA698B /* script */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA13E014A141A300AA698B /* script.1 */,
+ FCBA13E114A141A300AA698B /* script.c */,
+ );
+ path = script;
+ sourceTree = "<group>";
+ };
+ FCBA13E214A141A300AA698B /* seq */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA13E414A141A300AA698B /* seq.1 */,
+ FCBA13E514A141A300AA698B /* seq.c */,
+ );
+ path = seq;
+ sourceTree = "<group>";
+ };
+ FCBA13E614A141A300AA698B /* shlock */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA13E814A141A300AA698B /* shlock.1 */,
+ FCBA13E914A141A300AA698B /* shlock.c */,
+ );
+ path = shlock;
+ sourceTree = "<group>";
+ };
+ FCBA13EA14A141A300AA698B /* sleep */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA13EC14A141A300AA698B /* sleep.1 */,
+ FCBA13ED14A141A300AA698B /* sleep.c */,
+ );
+ path = sleep;
+ sourceTree = "<group>";
+ };
+ FCBA13EE14A141A300AA698B /* su */ = {
+ isa = PBXGroup;
+ children = (
+ 6C1C283E22FB822900E0AC67 /* su_entitlements.plist */,
+ FCBA13F014A141A300AA698B /* su.1 */,
+ FCBA13F114A141A300AA698B /* su.c */,
+ FCBA13F214A141A300AA698B /* su.pam */,
+ FCED3AF514B4FC1800C313C3 /* libpam.dylib */,
+ );
+ path = su;
+ sourceTree = "<group>";
+ };
+ FCBA13F314A141A300AA698B /* tee */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA13F514A141A300AA698B /* tee.1 */,
+ FCBA13F614A141A300AA698B /* tee.c */,
+ );
+ path = tee;
+ sourceTree = "<group>";
+ };
+ FCBA13F714A141A300AA698B /* test */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA13F814A141A300AA698B /* [.1 */,
+ FCBA13FA14A141A300AA698B /* test.1 */,
+ FCBA13FB14A141A300AA698B /* test.c */,
+ FD155C711D6E37B5005A53CA /* tests */,
+ );
+ path = test;
+ sourceTree = "<group>";
+ };
+ FCBA13FD14A141A300AA698B /* time */ = {
+ isa = PBXGroup;
+ children = (
+ CE799E5F24AD3B1B00E73238 /* tests */,
+ FCBA13FF14A141A300AA698B /* time.1 */,
+ FCBA140014A141A300AA698B /* time.c */,
+ );
+ path = time;
+ sourceTree = "<group>";
+ };
+ FCBA140114A141A300AA698B /* true */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA140314A141A300AA698B /* true.1 */,
+ FCBA140414A141A300AA698B /* true.c */,
+ );
+ path = true;
+ sourceTree = "<group>";
+ };
+ FCBA140614A141A300AA698B /* uname */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA140814A141A300AA698B /* uname.1 */,
+ FCBA140914A141A300AA698B /* uname.c */,
+ );
+ path = uname;
+ sourceTree = "<group>";
+ };
+ FCBA140A14A141A300AA698B /* users */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA140C14A141A300AA698B /* users.1 */,
+ FCBA140D14A141A300AA698B /* users.c */,
+ );
+ path = users;
+ sourceTree = "<group>";
+ };
+ FCBA140E14A141A300AA698B /* w */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA140F14A141A300AA698B /* extern.h */,
+ FCBA141014A141A300AA698B /* fmt.c */,
+ FCBA141214A141A300AA698B /* pr_time.c */,
+ FCBA141314A141A300AA698B /* proc_compare.c */,
+ FCBA141414A141A300AA698B /* uptime.1 */,
+ FCBA141514A141A300AA698B /* w.1 */,
+ FCBA141614A141A300AA698B /* w.c */,
+ );
+ path = w;
+ sourceTree = "<group>";
+ };
+ FCBA141714A141A300AA698B /* whereis */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA141914A141A300AA698B /* whereis.1 */,
+ FCBA141A14A141A300AA698B /* whereis.c */,
+ );
+ path = whereis;
+ sourceTree = "<group>";
+ };
+ FCBA141B14A141A300AA698B /* which */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA141D14A141A300AA698B /* which.1 */,
+ FCBA141E14A141A300AA698B /* which.c */,
+ );
+ path = which;
+ sourceTree = "<group>";
+ };
+ FCBA141F14A141A300AA698B /* who */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA142114A141A300AA698B /* utmpentry.c */,
+ FCBA142214A141A300AA698B /* utmpentry.h */,
+ FCBA142314A141A300AA698B /* who.1 */,
+ FCBA142414A141A300AA698B /* who.c */,
+ FCBA02E514B505A50030BEB3 /* libresolv.dylib */,
+ );
+ path = who;
+ sourceTree = "<group>";
+ };
+ FCBA142514A141A300AA698B /* xargs */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA142714A141A300AA698B /* pathnames.h */,
+ FCBA142814A141A300AA698B /* strnsubst.c */,
+ FCBA142914A141A300AA698B /* xargs.1 */,
+ FCBA142A14A141A300AA698B /* xargs.c */,
+ );
+ path = xargs;
+ sourceTree = "<group>";
+ };
+ FCBA142B14A141A300AA698B /* yes */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA142D14A141A300AA698B /* yes.1 */,
+ FCBA142E14A141A300AA698B /* yes.c */,
+ );
+ path = yes;
+ sourceTree = "<group>";
+ };
+ FD155C711D6E37B5005A53CA /* tests */ = {
+ isa = PBXGroup;
+ children = (
+ FD155C721D6E37B5005A53CA /* legacy_test.sh */,
+ );
+ path = tests;
+ sourceTree = "<group>";
+ };
+ FD155C761D6E3847005A53CA /* tests */ = {
+ isa = PBXGroup;
+ children = (
+ FD155C771D6E3847005A53CA /* legacy_test.sh */,
+ FD155C7A1D6E3847005A53CA /* regress.b.out */,
+ FD155C7B1D6E3847005A53CA /* regress.d.out */,
+ FD155C7C1D6E3847005A53CA /* regress.f.out */,
+ FD155C7D1D6E3847005A53CA /* regress.l1.out */,
+ FD155C7E1D6E3847005A53CA /* regress.l2.out */,
+ FD155C7F1D6E3847005A53CA /* regress.m1.out */,
+ FD155C801D6E3847005A53CA /* regress.m2.out */,
+ FD155C811D6E3847005A53CA /* regress.m3.out */,
+ FD155C821D6E3847005A53CA /* regress.m4.out */,
+ FD155C831D6E3847005A53CA /* regress.m5.out */,
+ FD155C841D6E3847005A53CA /* regress.missingpos1.out */,
+ FD155C851D6E3847005A53CA /* regress.s.out */,
+ FD155C861D6E3847005A53CA /* regress.sh */,
+ FD155C871D6E3847005A53CA /* regress.zero.out */,
+ );
+ path = tests;
+ sourceTree = "<group>";
+ };
+ FD6060B31B7C0388004BCA6A /* sh */ = {
+ isa = PBXGroup;
+ children = (
+ FD6061001B7C0D01004BCA6A /* BUILT */,
+ FD6060BC1B7C0471004BCA6A /* alias.c */,
+ FD6061061B7D2C8C004BCA6A /* alias.h */,
+ FD6061081B7D2C8C004BCA6A /* arith.h */,
+ FD6060BD1B7C0471004BCA6A /* arith_yacc.c */,
+ FD6061071B7D2C8C004BCA6A /* arith_yacc.h */,
+ FD6060BE1B7C0471004BCA6A /* arith_yylex.c */,
+ FD6060E81B7C04E4004BCA6A /* bltin */,
+ FD6061091B7D2C8C004BCA6A /* builtins.def */,
+ FD6060BF1B7C0471004BCA6A /* cd.c */,
+ FD60610A1B7D2C8C004BCA6A /* cd.h */,
+ FD6060C01B7C0471004BCA6A /* error.c */,
+ FD60610B1B7D2C8C004BCA6A /* error.h */,
+ FD6060C11B7C0471004BCA6A /* eval.c */,
+ FD60610C1B7D2C8C004BCA6A /* eval.h */,
+ FD6060C21B7C0471004BCA6A /* exec.c */,
+ FD60610D1B7D2C8C004BCA6A /* exec.h */,
+ FD6060C31B7C0471004BCA6A /* expand.c */,
+ FD60610E1B7D2C8C004BCA6A /* expand.h */,
+ FD6061271B7D2D1D004BCA6A /* funcs */,
+ FD6060C41B7C0471004BCA6A /* histedit.c */,
+ FD6060C51B7C0471004BCA6A /* input.c */,
+ FD60610F1B7D2C8C004BCA6A /* input.h */,
+ FD6060C61B7C0471004BCA6A /* jobs.c */,
+ FD6061101B7D2C8C004BCA6A /* jobs.h */,
+ FD6060C71B7C0471004BCA6A /* mail.c */,
+ FD6061111B7D2C8C004BCA6A /* mail.h */,
+ FD6060B41B7C0388004BCA6A /* main.c */,
+ FD6061121B7D2C8C004BCA6A /* main.h */,
+ FD6060C81B7C0471004BCA6A /* memalloc.c */,
+ FD6061131B7D2C8C004BCA6A /* memalloc.h */,
+ FD6060C91B7C0471004BCA6A /* miscbltin.c */,
+ FD6061141B7D2C8C004BCA6A /* mkbuiltins */,
+ FD6061151B7D2C8C004BCA6A /* mknodes.c */,
+ FD6061161B7D2C8C004BCA6A /* mksyntax.c */,
+ FD6061171B7D2C8C004BCA6A /* mktokens */,
+ FD6061181B7D2C8C004BCA6A /* myhistedit.h */,
+ FD6060CA1B7C0471004BCA6A /* mystring.c */,
+ FD6061191B7D2C8C004BCA6A /* mystring.h */,
+ FD60611A1B7D2C8C004BCA6A /* nodes.c.pat */,
+ FD60611B1B7D2C8C004BCA6A /* nodetypes */,
+ FD6060CB1B7C0471004BCA6A /* options.c */,
+ FD60611C1B7D2C8C004BCA6A /* options.h */,
+ FD6060CC1B7C0471004BCA6A /* output.c */,
+ FD60611D1B7D2C8C004BCA6A /* output.h */,
+ FD6060CD1B7C0471004BCA6A /* parser.c */,
+ FD60611E1B7D2C8C004BCA6A /* parser.h */,
+ FD6060CE1B7C0471004BCA6A /* redir.c */,
+ FD60611F1B7D2C8C004BCA6A /* redir.h */,
+ FD6061201B7D2C8C004BCA6A /* sh.1 */,
+ FD6061211B7D2C8C004BCA6A /* shell.h */,
+ FD6060CF1B7C0471004BCA6A /* show.c */,
+ FD6061221B7D2C8C004BCA6A /* show.h */,
+ FD6060D01B7C0471004BCA6A /* trap.c */,
+ FD6061231B7D2C8C004BCA6A /* trap.h */,
+ FD6060D11B7C0471004BCA6A /* var.c */,
+ FD6061241B7D2C8C004BCA6A /* var.h */,
+ );
+ path = sh;
+ sourceTree = "<group>";
+ };
+ FD6060E81B7C04E4004BCA6A /* bltin */ = {
+ isa = PBXGroup;
+ children = (
+ FD6061051B7D2BF8004BCA6A /* bltin.h */,
+ FD6060EA1B7C04E4004BCA6A /* echo.c */,
+ );
+ path = bltin;
+ sourceTree = "<group>";
+ };
+ FD6061001B7C0D01004BCA6A /* BUILT */ = {
+ isa = PBXGroup;
+ children = (
+ FD6060FA1B7C0CAF004BCA6A /* builtins.c */,
+ FD6061011B7D2B6D004BCA6A /* builtins.h */,
+ FD6060FB1B7C0CAF004BCA6A /* nodes.c */,
+ FD6061021B7D2B6D004BCA6A /* nodes.h */,
+ FD6060FC1B7C0CAF004BCA6A /* syntax.c */,
+ FD6061031B7D2B6D004BCA6A /* syntax.h */,
+ FD6061041B7D2B6D004BCA6A /* token.h */,
+ );
+ name = BUILT;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+ FD6061271B7D2D1D004BCA6A /* funcs */ = {
+ isa = PBXGroup;
+ children = (
+ FD6061281B7D2D1D004BCA6A /* cmv */,
+ FD6061291B7D2D1D004BCA6A /* dirs */,
+ FD60612A1B7D2D1D004BCA6A /* login */,
+ FD60612B1B7D2D1D004BCA6A /* newgrp */,
+ FD60612C1B7D2D1D004BCA6A /* popd */,
+ FD60612D1B7D2D1D004BCA6A /* pushd */,
+ FD60612E1B7D2D1D004BCA6A /* suspend */,
+ );
+ path = funcs;
+ sourceTree = "<group>";
+ };
+ FD60612F1B7D2DDE004BCA6A /* xcconfigs */ = {
+ isa = PBXGroup;
+ children = (
+ FD6061301B7D2DDE004BCA6A /* base.xcconfig */,
+ FD6061311B7D2DDE004BCA6A /* sh.xcconfig */,
+ );
+ path = xcconfigs;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ C6868575154725700025D623 /* systime */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = C686857E154725700025D623 /* Build configuration list for PBXNativeTarget "systime" */;
+ buildPhases = (
+ C6868572154725700025D623 /* Sources */,
+ C6868573154725700025D623 /* Frameworks */,
+ C6868574154725700025D623 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = systime;
+ productName = systime;
+ productReference = C6868576154725700025D623 /* systime */;
+ productType = "com.apple.product-type.tool";
+ };
+ FC5D637F14B9819E00123E48 /* what */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FC5D638914B9819E00123E48 /* Build configuration list for PBXNativeTarget "what" */;
+ buildPhases = (
+ FC5D638014B9819E00123E48 /* Sources */,
+ FC5D638514B9819E00123E48 /* Frameworks */,
+ FC5D638614B9819E00123E48 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = what;
+ productName = shell_cmds;
+ productReference = FC5D638B14B9819E00123E48 /* what */;
+ productType = "com.apple.product-type.tool";
+ };
+ FC5D638F14B9822D00123E48 /* hexdump */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FC5D639514B9822D00123E48 /* Build configuration list for PBXNativeTarget "hexdump" */;
+ buildPhases = (
+ FC5D639014B9822D00123E48 /* Sources */,
+ FC5D639214B9822D00123E48 /* Frameworks */,
+ FC5D639314B9822D00123E48 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = hexdump;
+ productName = shell_cmds;
+ productReference = FC5D639714B9822D00123E48 /* hexdump */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA149814A141FF00AA698B /* apply */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA149C14A141FF00AA698B /* Build configuration list for PBXNativeTarget "apply" */;
+ buildPhases = (
+ FCBA149914A141FF00AA698B /* Sources */,
+ FCBA149A14A141FF00AA698B /* Frameworks */,
+ FCBA149B14A141FF00AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = apply;
+ productName = shell_cmds;
+ productReference = FCBA149E14A141FF00AA698B /* apply */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA14AE14A1422D00AA698B /* basename */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA14B214A1422D00AA698B /* Build configuration list for PBXNativeTarget "basename" */;
+ buildPhases = (
+ FCBA14AF14A1422D00AA698B /* Sources */,
+ FCBA14B014A1422D00AA698B /* Frameworks */,
+ FCBA14B114A1422D00AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = basename;
+ productName = shell_cmds;
+ productReference = FCBA14B414A1422D00AA698B /* basename */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA14B714A1423E00AA698B /* chroot */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA14BB14A1423E00AA698B /* Build configuration list for PBXNativeTarget "chroot" */;
+ buildPhases = (
+ FCBA14B814A1423E00AA698B /* Sources */,
+ FCBA14B914A1423E00AA698B /* Frameworks */,
+ FCBA14BA14A1423E00AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = chroot;
+ productName = shell_cmds;
+ productReference = FCBA14BD14A1423E00AA698B /* chroot */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA14BF14A1426800AA698B /* date */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA14C314A1426800AA698B /* Build configuration list for PBXNativeTarget "date" */;
+ buildPhases = (
+ FCBA14C014A1426800AA698B /* Sources */,
+ FCBA14C114A1426800AA698B /* Frameworks */,
+ FCBA14C214A1426800AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = date;
+ productName = shell_cmds;
+ productReference = FCBA14C514A1426800AA698B /* date */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA14C714A1428000AA698B /* dirname */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA14CB14A1428000AA698B /* Build configuration list for PBXNativeTarget "dirname" */;
+ buildPhases = (
+ FCBA14C814A1428000AA698B /* Sources */,
+ FCBA14C914A1428000AA698B /* Frameworks */,
+ FCBA14CA14A1428000AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = dirname;
+ productName = shell_cmds;
+ productReference = FCBA14CD14A1428000AA698B /* dirname */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA14CF14A1433F00AA698B /* echo */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA14D314A1433F00AA698B /* Build configuration list for PBXNativeTarget "echo" */;
+ buildPhases = (
+ FCBA14D014A1433F00AA698B /* Sources */,
+ FCBA14D114A1433F00AA698B /* Frameworks */,
+ FCBA14D214A1433F00AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = echo;
+ productName = shell_cmds;
+ productReference = FCBA14D514A1433F00AA698B /* echo */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA14D714A1434A00AA698B /* env */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA14DB14A1434A00AA698B /* Build configuration list for PBXNativeTarget "env" */;
+ buildPhases = (
+ FCBA14D814A1434A00AA698B /* Sources */,
+ FCBA14D914A1434A00AA698B /* Frameworks */,
+ FCBA14DA14A1434A00AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = env;
+ productName = shell_cmds;
+ productReference = FCBA14DD14A1434A00AA698B /* env */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA150E14A1453A00AA698B /* expr */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA151214A1453A00AA698B /* Build configuration list for PBXNativeTarget "expr" */;
+ buildPhases = (
+ FCBA150F14A1453A00AA698B /* Sources */,
+ FCBA151014A1453A00AA698B /* Frameworks */,
+ FCBA151114A1453A00AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = expr;
+ productName = shell_cmds;
+ productReference = FCBA151414A1453A00AA698B /* expr */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA151614A1454D00AA698B /* false */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA151A14A1454D00AA698B /* Build configuration list for PBXNativeTarget "false" */;
+ buildPhases = (
+ FCBA151714A1454D00AA698B /* Sources */,
+ FCBA151814A1454D00AA698B /* Frameworks */,
+ FCBA151914A1454D00AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = false;
+ productName = shell_cmds;
+ productReference = FCBA151C14A1454D00AA698B /* false */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA151E14A1455600AA698B /* find */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA152214A1455600AA698B /* Build configuration list for PBXNativeTarget "find" */;
+ buildPhases = (
+ FCBA151F14A1455600AA698B /* Sources */,
+ FCBA152014A1455600AA698B /* Frameworks */,
+ FCBA152114A1455600AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = find;
+ productName = shell_cmds;
+ productReference = FCBA152414A1455600AA698B /* find */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA152614A1455900AA698B /* getopt */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA152A14A1455900AA698B /* Build configuration list for PBXNativeTarget "getopt" */;
+ buildPhases = (
+ FCBA152714A1455900AA698B /* Sources */,
+ FCBA152814A1455900AA698B /* Frameworks */,
+ FCBA152914A1455900AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = getopt;
+ productName = shell_cmds;
+ productReference = FCBA152C14A1455900AA698B /* getopt */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA152E14A1455C00AA698B /* hostname */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA153214A1455C00AA698B /* Build configuration list for PBXNativeTarget "hostname" */;
+ buildPhases = (
+ FCBA152F14A1455C00AA698B /* Sources */,
+ FCBA153014A1455C00AA698B /* Frameworks */,
+ FCBA153114A1455C00AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = hostname;
+ productName = shell_cmds;
+ productReference = FCBA153414A1455C00AA698B /* hostname */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA153614A1455F00AA698B /* id */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA153A14A1455F00AA698B /* Build configuration list for PBXNativeTarget "id" */;
+ buildPhases = (
+ FCBA153714A1455F00AA698B /* Sources */,
+ FCBA153814A1455F00AA698B /* Frameworks */,
+ FCBA153914A1455F00AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = id;
+ productName = shell_cmds;
+ productReference = FCBA153C14A1455F00AA698B /* id */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA153E14A1456100AA698B /* jot */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA154214A1456100AA698B /* Build configuration list for PBXNativeTarget "jot" */;
+ buildPhases = (
+ FCBA153F14A1456100AA698B /* Sources */,
+ FCBA154014A1456100AA698B /* Frameworks */,
+ FCBA154114A1456100AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = jot;
+ productName = shell_cmds;
+ productReference = FCBA154414A1456100AA698B /* jot */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA154614A1456400AA698B /* kill */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA154A14A1456400AA698B /* Build configuration list for PBXNativeTarget "kill" */;
+ buildPhases = (
+ FCBA154714A1456400AA698B /* Sources */,
+ FCBA154814A1456400AA698B /* Frameworks */,
+ FCBA154914A1456400AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = kill;
+ productName = shell_cmds;
+ productReference = FCBA154C14A1456400AA698B /* kill */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA154E14A1456700AA698B /* killall */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA155214A1456700AA698B /* Build configuration list for PBXNativeTarget "killall" */;
+ buildPhases = (
+ FCBA154F14A1456700AA698B /* Sources */,
+ FCBA155014A1456700AA698B /* Frameworks */,
+ FCBA155114A1456700AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = killall;
+ productName = shell_cmds;
+ productReference = FCBA155414A1456700AA698B /* killall */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA155614A1456A00AA698B /* lastcomm */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA155A14A1456A00AA698B /* Build configuration list for PBXNativeTarget "lastcomm" */;
+ buildPhases = (
+ FCBA155714A1456A00AA698B /* Sources */,
+ FCBA155814A1456A00AA698B /* Frameworks */,
+ FCBA155914A1456A00AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = lastcomm;
+ productName = shell_cmds;
+ productReference = FCBA155C14A1456A00AA698B /* lastcomm */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA155E14A1456E00AA698B /* locate */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA156214A1456E00AA698B /* Build configuration list for PBXNativeTarget "locate" */;
+ buildPhases = (
+ FCBA155F14A1456E00AA698B /* Sources */,
+ FCBA156014A1456E00AA698B /* Frameworks */,
+ FCBA156114A1456E00AA698B /* CopyFiles */,
+ FCE30EBE14B533B500CC0294 /* CopyFiles */,
+ FCE30EB914B532C700CC0294 /* CopyFiles */,
+ FCE30EBC14B5339000CC0294 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = locate;
+ productName = shell_cmds;
+ productReference = FCBA156414A1456E00AA698B /* locate */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA156614A1457100AA698B /* logname */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA156A14A1457100AA698B /* Build configuration list for PBXNativeTarget "logname" */;
+ buildPhases = (
+ FCBA156714A1457100AA698B /* Sources */,
+ FCBA156814A1457100AA698B /* Frameworks */,
+ FCBA156914A1457100AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = logname;
+ productName = shell_cmds;
+ productReference = FCBA156C14A1457100AA698B /* logname */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA157614A1457B00AA698B /* mktemp */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA157A14A1457B00AA698B /* Build configuration list for PBXNativeTarget "mktemp" */;
+ buildPhases = (
+ FCBA157714A1457B00AA698B /* Sources */,
+ FCBA157814A1457B00AA698B /* Frameworks */,
+ FCBA157914A1457B00AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = mktemp;
+ productName = shell_cmds;
+ productReference = FCBA157C14A1457B00AA698B /* mktemp */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA157E14A1457F00AA698B /* nice */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA158214A1457F00AA698B /* Build configuration list for PBXNativeTarget "nice" */;
+ buildPhases = (
+ FCBA157F14A1457F00AA698B /* Sources */,
+ FCBA158014A1457F00AA698B /* Frameworks */,
+ FCBA158114A1457F00AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = nice;
+ productName = shell_cmds;
+ productReference = FCBA158414A1457F00AA698B /* nice */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA158614A1458500AA698B /* nohup */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA158A14A1458500AA698B /* Build configuration list for PBXNativeTarget "nohup" */;
+ buildPhases = (
+ FCBA158714A1458500AA698B /* Sources */,
+ FCBA158814A1458500AA698B /* Frameworks */,
+ FCBA158914A1458500AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = nohup;
+ productName = shell_cmds;
+ productReference = FCBA158C14A1458500AA698B /* nohup */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA158E14A1458800AA698B /* path_helper */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA159214A1458800AA698B /* Build configuration list for PBXNativeTarget "path_helper" */;
+ buildPhases = (
+ FCBA158F14A1458800AA698B /* Sources */,
+ FCBA159014A1458800AA698B /* Frameworks */,
+ FCBA159114A1458800AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = path_helper;
+ productName = shell_cmds;
+ productReference = FCBA159414A1458800AA698B /* path_helper */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA159614A1458C00AA698B /* printenv */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA159A14A1458C00AA698B /* Build configuration list for PBXNativeTarget "printenv" */;
+ buildPhases = (
+ FCBA159714A1458C00AA698B /* Sources */,
+ FCBA159814A1458C00AA698B /* Frameworks */,
+ FCBA159914A1458C00AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = printenv;
+ productName = shell_cmds;
+ productReference = FCBA159C14A1458C00AA698B /* printenv */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA159E14A1459000AA698B /* printf */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA15A214A1459000AA698B /* Build configuration list for PBXNativeTarget "printf" */;
+ buildPhases = (
+ FCBA159F14A1459000AA698B /* Sources */,
+ FCBA15A014A1459000AA698B /* Frameworks */,
+ FCBA15A114A1459000AA698B /* CopyFiles */,
+ FD155C881D6E38AB005A53CA /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = printf;
+ productName = shell_cmds;
+ productReference = FCBA15A414A1459000AA698B /* printf */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA15A614A1459500AA698B /* pwd */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA15AA14A1459500AA698B /* Build configuration list for PBXNativeTarget "pwd" */;
+ buildPhases = (
+ FCBA15A714A1459500AA698B /* Sources */,
+ FCBA15A814A1459500AA698B /* Frameworks */,
+ FCBA15A914A1459500AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = pwd;
+ productName = shell_cmds;
+ productReference = FCBA15AC14A1459500AA698B /* pwd */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA15AE14A1459700AA698B /* renice */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA15B214A1459700AA698B /* Build configuration list for PBXNativeTarget "renice" */;
+ buildPhases = (
+ FCBA15AF14A1459700AA698B /* Sources */,
+ FCBA15B014A1459700AA698B /* Frameworks */,
+ FCBA15B114A1459700AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = renice;
+ productName = shell_cmds;
+ productReference = FCBA15B414A1459700AA698B /* renice */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA15B614A1459900AA698B /* script */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA15BA14A1459900AA698B /* Build configuration list for PBXNativeTarget "script" */;
+ buildPhases = (
+ FCBA15B714A1459900AA698B /* Sources */,
+ FCBA15B814A1459900AA698B /* Frameworks */,
+ FCBA15B914A1459900AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = script;
+ productName = shell_cmds;
+ productReference = FCBA15BC14A1459900AA698B /* script */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA15BE14A1459E00AA698B /* seq */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA15C214A1459E00AA698B /* Build configuration list for PBXNativeTarget "seq" */;
+ buildPhases = (
+ FCBA15BF14A1459E00AA698B /* Sources */,
+ FCBA15C014A1459E00AA698B /* Frameworks */,
+ FCBA15C114A1459E00AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = seq;
+ productName = shell_cmds;
+ productReference = FCBA15C414A1459E00AA698B /* seq */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA15C614A145A200AA698B /* shlock */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA15CA14A145A200AA698B /* Build configuration list for PBXNativeTarget "shlock" */;
+ buildPhases = (
+ FCBA15C714A145A200AA698B /* Sources */,
+ FCBA15C814A145A200AA698B /* Frameworks */,
+ FCBA15C914A145A200AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = shlock;
+ productName = shell_cmds;
+ productReference = FCBA15CC14A145A200AA698B /* shlock */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA15CE14A145A500AA698B /* sleep */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA15D214A145A500AA698B /* Build configuration list for PBXNativeTarget "sleep" */;
+ buildPhases = (
+ FCBA15CF14A145A500AA698B /* Sources */,
+ FCBA15D014A145A500AA698B /* Frameworks */,
+ FCBA15D114A145A500AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = sleep;
+ productName = shell_cmds;
+ productReference = FCBA15D414A145A500AA698B /* sleep */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA15D614A145A700AA698B /* su */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA15DA14A145A700AA698B /* Build configuration list for PBXNativeTarget "su" */;
+ buildPhases = (
+ FCBA15D714A145A700AA698B /* Sources */,
+ FCBA15D814A145A700AA698B /* Frameworks */,
+ FCBA15D914A145A700AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = su;
+ productName = shell_cmds;
+ productReference = FCBA15DC14A145A700AA698B /* su */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA15DE14A145A900AA698B /* tee */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA15E214A145A900AA698B /* Build configuration list for PBXNativeTarget "tee" */;
+ buildPhases = (
+ FCBA15DF14A145A900AA698B /* Sources */,
+ FCBA15E014A145A900AA698B /* Frameworks */,
+ FCBA15E114A145A900AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = tee;
+ productName = shell_cmds;
+ productReference = FCBA15E414A145A900AA698B /* tee */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA15E614A145AE00AA698B /* test */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA15EA14A145AE00AA698B /* Build configuration list for PBXNativeTarget "test" */;
+ buildPhases = (
+ FCBA15E714A145AE00AA698B /* Sources */,
+ FCBA15E814A145AE00AA698B /* Frameworks */,
+ FCBA15E914A145AE00AA698B /* CopyFiles */,
+ FD155C741D6E37D7005A53CA /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = test;
+ productName = shell_cmds;
+ productReference = FCBA15EC14A145AE00AA698B /* test */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA15EE14A145B000AA698B /* time */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA15F214A145B000AA698B /* Build configuration list for PBXNativeTarget "time" */;
+ buildPhases = (
+ FCBA15EF14A145B000AA698B /* Sources */,
+ FCBA15F014A145B000AA698B /* Frameworks */,
+ FCBA15F114A145B000AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = time;
+ productName = shell_cmds;
+ productReference = FCBA15F414A145B000AA698B /* time */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA15F614A145B200AA698B /* true */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA15FA14A145B200AA698B /* Build configuration list for PBXNativeTarget "true" */;
+ buildPhases = (
+ FCBA15F714A145B200AA698B /* Sources */,
+ FCBA15F814A145B200AA698B /* Frameworks */,
+ FCBA15F914A145B200AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = true;
+ productName = shell_cmds;
+ productReference = FCBA15FC14A145B200AA698B /* true */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA15FE14A145B500AA698B /* uname */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA160214A145B500AA698B /* Build configuration list for PBXNativeTarget "uname" */;
+ buildPhases = (
+ FCBA15FF14A145B500AA698B /* Sources */,
+ FCBA160014A145B500AA698B /* Frameworks */,
+ FCBA160114A145B500AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = uname;
+ productName = shell_cmds;
+ productReference = FCBA160414A145B500AA698B /* uname */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA160614A145B800AA698B /* users */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA160A14A145B800AA698B /* Build configuration list for PBXNativeTarget "users" */;
+ buildPhases = (
+ FCBA160714A145B800AA698B /* Sources */,
+ FCBA160814A145B800AA698B /* Frameworks */,
+ FCBA160914A145B800AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = users;
+ productName = shell_cmds;
+ productReference = FCBA160C14A145B800AA698B /* users */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA160E14A145BA00AA698B /* w */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA161214A145BA00AA698B /* Build configuration list for PBXNativeTarget "w" */;
+ buildPhases = (
+ FCBA160F14A145BA00AA698B /* Sources */,
+ FCBA161014A145BA00AA698B /* Frameworks */,
+ FCBA161114A145BA00AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = w;
+ productName = shell_cmds;
+ productReference = FCBA161414A145BA00AA698B /* w */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA161614A145BC00AA698B /* whereis */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA161A14A145BC00AA698B /* Build configuration list for PBXNativeTarget "whereis" */;
+ buildPhases = (
+ FCBA161714A145BC00AA698B /* Sources */,
+ FCBA161814A145BC00AA698B /* Frameworks */,
+ FCBA161914A145BC00AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = whereis;
+ productName = shell_cmds;
+ productReference = FCBA161C14A145BC00AA698B /* whereis */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA161E14A145C000AA698B /* which */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA162214A145C000AA698B /* Build configuration list for PBXNativeTarget "which" */;
+ buildPhases = (
+ FCBA161F14A145C000AA698B /* Sources */,
+ FCBA162014A145C000AA698B /* Frameworks */,
+ FCBA162114A145C000AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = which;
+ productName = shell_cmds;
+ productReference = FCBA162414A145C000AA698B /* which */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA162614A145C500AA698B /* who */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA162A14A145C500AA698B /* Build configuration list for PBXNativeTarget "who" */;
+ buildPhases = (
+ FCBA162714A145C500AA698B /* Sources */,
+ FCBA162814A145C500AA698B /* Frameworks */,
+ FCBA162914A145C500AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = who;
+ productName = shell_cmds;
+ productReference = FCBA162C14A145C500AA698B /* who */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA162E14A145C700AA698B /* xargs */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA163214A145C700AA698B /* Build configuration list for PBXNativeTarget "xargs" */;
+ buildPhases = (
+ FCBA162F14A145C700AA698B /* Sources */,
+ FCBA163014A145C700AA698B /* Frameworks */,
+ FCBA163114A145C700AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = xargs;
+ productName = shell_cmds;
+ productReference = FCBA163414A145C700AA698B /* xargs */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA163614A145CA00AA698B /* yes */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA163A14A145CA00AA698B /* Build configuration list for PBXNativeTarget "yes" */;
+ buildPhases = (
+ FCBA163714A145CA00AA698B /* Sources */,
+ FCBA163814A145CA00AA698B /* Frameworks */,
+ FCBA163914A145CA00AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = yes;
+ productName = shell_cmds;
+ productReference = FCBA163C14A145CA00AA698B /* yes */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCE30EC214B5368A00CC0294 /* locate.bigram */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCE30ED014B5368A00CC0294 /* Build configuration list for PBXNativeTarget "locate.bigram" */;
+ buildPhases = (
+ FCE30EC314B5368A00CC0294 /* Sources */,
+ FCE30EC614B5368A00CC0294 /* Frameworks */,
+ FCE30EC714B5368A00CC0294 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = locate.bigram;
+ productName = shell_cmds;
+ productReference = FCE30ED214B5368A00CC0294 /* locate.bigram */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCE30ED614B536C900CC0294 /* locate.code */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCE30EDC14B536C900CC0294 /* Build configuration list for PBXNativeTarget "locate.code" */;
+ buildPhases = (
+ FCE30ED714B536C900CC0294 /* Sources */,
+ FCE30ED914B536C900CC0294 /* Frameworks */,
+ FCE30EDA14B536C900CC0294 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = locate.code;
+ productName = shell_cmds;
+ productReference = FCE30EDE14B536C900CC0294 /* locate.code */;
+ productType = "com.apple.product-type.tool";
+ };
+ FD6060B11B7C0388004BCA6A /* sh */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FD6060B71B7C0388004BCA6A /* Build configuration list for PBXNativeTarget "sh" */;
+ buildPhases = (
+ FD6060EF1B7C0590004BCA6A /* mkbuiltins */,
+ FD6060F11B7C0742004BCA6A /* mknodes */,
+ FD6060F21B7C0744004BCA6A /* mksyntax */,
+ FD6060F31B7C0964004BCA6A /* mktokens */,
+ FD6060AE1B7C0388004BCA6A /* Sources */,
+ FD6060AF1B7C0388004BCA6A /* Frameworks */,
+ FD6061321B7D32AD004BCA6A /* sh.1 */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = sh;
+ productName = sh;
+ productReference = FD6060B21B7C0388004BCA6A /* ash */;
+ productType = "com.apple.product-type.tool";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ FC80BF5714A05A2F00C6F7F5 /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastUpgradeCheck = 1100;
+ ORGANIZATIONNAME = "Apple Inc.";
+ TargetAttributes = {
+ FD6060B11B7C0388004BCA6A = {
+ CreatedOnToolsVersion = 7.0;
+ };
+ };
+ };
+ buildConfigurationList = FC80BF5A14A05A2F00C6F7F5 /* Build configuration list for PBXProject "shell_cmds" */;
+ compatibilityVersion = "Xcode 3.2";
+ developmentRegion = en;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ Base,
+ );
+ mainGroup = FC80BF5514A05A2F00C6F7F5;
+ productRefGroup = FC80BF6114A05A2F00C6F7F5 /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ FCBA14FD14A144EC00AA698B /* All_OSX */,
+ FCE30F4A14B619B000CC0294 /* All_iOS */,
+ FCBA149814A141FF00AA698B /* apply */,
+ FCBA14AE14A1422D00AA698B /* basename */,
+ FCBA14B714A1423E00AA698B /* chroot */,
+ FCBA14BF14A1426800AA698B /* date */,
+ FCBA14C714A1428000AA698B /* dirname */,
+ FCBA14CF14A1433F00AA698B /* echo */,
+ FCBA14D714A1434A00AA698B /* env */,
+ FCBA150E14A1453A00AA698B /* expr */,
+ FCBA151614A1454D00AA698B /* false */,
+ FCBA151E14A1455600AA698B /* find */,
+ FCBA152614A1455900AA698B /* getopt */,
+ FC5D638F14B9822D00123E48 /* hexdump */,
+ FCBA152E14A1455C00AA698B /* hostname */,
+ FCBA153614A1455F00AA698B /* id */,
+ FCBA153E14A1456100AA698B /* jot */,
+ FCBA154614A1456400AA698B /* kill */,
+ FCBA154E14A1456700AA698B /* killall */,
+ FCBA155614A1456A00AA698B /* lastcomm */,
+ FCBA155E14A1456E00AA698B /* locate */,
+ FCE30EC214B5368A00CC0294 /* locate.bigram */,
+ FCE30ED614B536C900CC0294 /* locate.code */,
+ FCBA156614A1457100AA698B /* logname */,
+ FCBA157614A1457B00AA698B /* mktemp */,
+ FCBA157E14A1457F00AA698B /* nice */,
+ FCBA158614A1458500AA698B /* nohup */,
+ FCBA158E14A1458800AA698B /* path_helper */,
+ FCBA159614A1458C00AA698B /* printenv */,
+ FCBA159E14A1459000AA698B /* printf */,
+ FCBA15A614A1459500AA698B /* pwd */,
+ FCBA15AE14A1459700AA698B /* renice */,
+ FCBA15B614A1459900AA698B /* script */,
+ FCBA15BE14A1459E00AA698B /* seq */,
+ FD6060B11B7C0388004BCA6A /* sh */,
+ FCBA15C614A145A200AA698B /* shlock */,
+ FCBA15CE14A145A500AA698B /* sleep */,
+ FCBA15D614A145A700AA698B /* su */,
+ C6868575154725700025D623 /* systime */,
+ FCBA15DE14A145A900AA698B /* tee */,
+ FCBA15E614A145AE00AA698B /* test */,
+ FCBA15EE14A145B000AA698B /* time */,
+ FCBA15F614A145B200AA698B /* true */,
+ FCBA15FE14A145B500AA698B /* uname */,
+ FCBA160614A145B800AA698B /* users */,
+ FCBA160E14A145BA00AA698B /* w */,
+ FC5D637F14B9819E00123E48 /* what */,
+ FCBA161614A145BC00AA698B /* whereis */,
+ FCBA161E14A145C000AA698B /* which */,
+ FCBA162614A145C500AA698B /* who */,
+ FCBA162E14A145C700AA698B /* xargs */,
+ FCBA163614A145CA00AA698B /* yes */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ FCE30EB814B531EC00CC0294 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = ". \"$PROJECT_DIR\"/xcodescripts/install-files.sh\n";
+ showEnvVarsInLog = 0;
+ };
+ FCE30F4D14B619C900CC0294 /* Run Script */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "Run Script";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = ". \"$PROJECT_DIR\"/xcodescripts/install-files.sh\n";
+ showEnvVarsInLog = 0;
+ };
+ FD6060EF1B7C0590004BCA6A /* mkbuiltins */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "$(SRCROOT)/sh/mkbuiltins",
+ "$(SRCROOT)/sh/builtins.def",
+ );
+ name = mkbuiltins;
+ outputPaths = (
+ "$(BUILT_PRODUCTS_DIR)/builtins.c",
+ "$(BUILT_PRODUCTS_DIR)/builtins.h",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "cd ${BUILT_PRODUCTS_DIR} && sh ${SRCROOT}/sh/mkbuiltins ${SRCROOT}/sh";
+ };
+ FD6060F11B7C0742004BCA6A /* mknodes */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "$(SRCROOT)/sh/mknodes.c",
+ "$(SRCROOT)/sh/nodetypes",
+ "$(SRCROOT)/sh/nodes.c.get",
+ );
+ name = mknodes;
+ outputPaths = (
+ "$(BUILT_PRODUCTS_DIR)/nodes.c",
+ "$(BUILT_PRODUCTS_DIR)/nodes.h",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "mkdir -p ${DERIVED_FILE_DIR}\nenv -i xcrun -sdk macosx cc ${SRCROOT}/sh/mknodes.c -o ${DERIVED_FILE_DIR}/mknodes\ncd ${BUILT_PRODUCTS_DIR} && ${DERIVED_FILE_DIR}/mknodes ${SRCROOT}/sh/nodetypes ${SRCROOT}/sh/nodes.c.pat\n";
+ };
+ FD6060F21B7C0744004BCA6A /* mksyntax */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "$(SRCROOT)/sh/mksyntax.c",
+ );
+ name = mksyntax;
+ outputPaths = (
+ "$(BUILT_PRODUCTS_DIR)/syntax.c",
+ "$(BUILT_PRODUCTS_DIR)/syntax.h",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "env -i xcrun -sdk macosx cc ${SRCROOT}/sh/mksyntax.c -o ${DERIVED_FILE_DIR}/mksyntax\ncd ${BUILT_PRODUCTS_DIR} && ${DERIVED_FILE_DIR}/mksyntax";
+ };
+ FD6060F31B7C0964004BCA6A /* mktokens */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "$(SRCROOT)/sh/mktokens",
+ );
+ name = mktokens;
+ outputPaths = (
+ "$(BUILT_PRODUCTS_DIR)/token.h",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "cd ${BUILT_PRODUCTS_DIR} && sh ${SRCROOT}/sh/mktokens";
+ };
+ FD6061321B7D32AD004BCA6A /* sh.1 */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "$(SRCROOT)/sh/sh.1",
+ );
+ name = sh.1;
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "install -d -m 0755 ${DSTROOT}${SH_MAN_PREFIX}/share/man/man1\ninstall -m 0644 ${SRCROOT}/sh/sh.1 ${DSTROOT}${SH_MAN_PREFIX}/share/man/man1/${PRODUCT_NAME}.1";
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ C6868572154725700025D623 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ C686857A154725700025D623 /* systime.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC5D638014B9819E00123E48 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC5D638D14B981D200123E48 /* what.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC5D639014B9822D00123E48 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC5D639B14B9826500123E48 /* conv.c in Sources */,
+ FC5D639C14B9826500123E48 /* display.c in Sources */,
+ FC5D639D14B9826500123E48 /* hexdump.c in Sources */,
+ FC5D639E14B9826500123E48 /* hexsyntax.c in Sources */,
+ FC5D639F14B9826500123E48 /* odsyntax.c in Sources */,
+ FC5D63A014B9826500123E48 /* parse.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA149914A141FF00AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA14EB14A1444900AA698B /* apply.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA14AF14A1422D00AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA14EE14A1446700AA698B /* basename.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA14B814A1423E00AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA14F114A1448C00AA698B /* chroot.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA14C014A1426800AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA14F614A144B200AA698B /* vary.c in Sources */,
+ FCBA14F514A144AF00AA698B /* netdate.c in Sources */,
+ FCBA14F414A1449C00AA698B /* date.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA14C814A1428000AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA14F714A144C700AA698B /* dirname.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA14D014A1433F00AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA14FA14A144D300AA698B /* echo.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA14D814A1434A00AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA14FC14A144E500AA698B /* env.c in Sources */,
+ FD88EB03198C5257006B7EFD /* envopts.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA150F14A1453A00AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA02FF14B507130030BEB3 /* expr.y in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA151714A1454D00AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA030114B507220030BEB3 /* false.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA151F14A1455600AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA030314B5073F0030BEB3 /* find.c in Sources */,
+ FCBA030414B5073F0030BEB3 /* function.c in Sources */,
+ FCBA030514B5073F0030BEB3 /* getdate.y in Sources */,
+ FCBA030614B5073F0030BEB3 /* ls.c in Sources */,
+ FCBA030714B5073F0030BEB3 /* main.c in Sources */,
+ FCBA030814B5073F0030BEB3 /* misc.c in Sources */,
+ FCBA030914B5073F0030BEB3 /* operator.c in Sources */,
+ FCBA030A14B5073F0030BEB3 /* option.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA152714A1455900AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA030C14B5074D0030BEB3 /* getopt.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA152F14A1455C00AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA030E14B5076A0030BEB3 /* hostname.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA153714A1455F00AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA031014B507790030BEB3 /* id.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA153F14A1456100AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA031514B507900030BEB3 /* jot.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA154714A1456400AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA031714B507A10030BEB3 /* kill.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA154F14A1456700AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA031914B507B00030BEB3 /* killall.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA155714A1456A00AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA031B14B507BD0030BEB3 /* lastcomm.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA155F14A1456E00AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA031E14B507D10030BEB3 /* locate.c in Sources */,
+ FCBA031F14B507D10030BEB3 /* util.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA156714A1457100AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA02FD14B506FA0030BEB3 /* logname.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA157714A1457B00AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA02F914B506CB0030BEB3 /* mktemp.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA157F14A1457F00AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA02F814B506BB0030BEB3 /* nice.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA158714A1458500AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA02F514B506940030BEB3 /* nohup.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA158F14A1458800AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA02F314B506840030BEB3 /* path_helper.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA159714A1458C00AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA02F114B506720030BEB3 /* printenv.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA159F14A1459000AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA02F014B506660030BEB3 /* printf.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA15A714A1459500AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA02ED14B506530030BEB3 /* pwd.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA15AF14A1459700AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA02EC14B5064C0030BEB3 /* renice.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA15B714A1459900AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA02EA14B506340030BEB3 /* script.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA15BF14A1459E00AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA02E814B506230030BEB3 /* seq.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA15C714A145A200AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC2B5C0B14B3CD4F00ECF511 /* shlock.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA15CF14A145A500AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC2B5C0A14B3CD4400ECF511 /* sleep.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA15D714A145A700AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC2B5C0714B3CD2F00ECF511 /* su.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA15DF14A145A900AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC2B5C0614B3CD2800ECF511 /* tee.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA15E714A145AE00AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC2B5C0214B3CD0C00ECF511 /* test.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA15EF14A145B000AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC2B5C0014B3CCF800ECF511 /* time.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA15F714A145B200AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC2B5BFE14B3CCD700ECF511 /* true.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA15FF14A145B500AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC2B5BFB14B3CCC600ECF511 /* uname.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA160714A145B800AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA165014A146BE00AA698B /* users.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA160F14A145BA00AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA164D14A146A200AA698B /* w.c in Sources */,
+ FCBA164C14A1469F00AA698B /* proc_compare.c in Sources */,
+ FCBA164B14A1469D00AA698B /* pr_time.c in Sources */,
+ FCBA164A14A1469A00AA698B /* fmt.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA161714A145BC00AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA164814A1469000AA698B /* whereis.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA161F14A145C000AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA164614A1468600AA698B /* which.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA162714A145C500AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA164414A1467D00AA698B /* who.c in Sources */,
+ FCBA164314A1467A00AA698B /* utmpentry.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA162F14A145C700AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA164114A1467200AA698B /* strnsubst.c in Sources */,
+ FCBA164014A1466F00AA698B /* xargs.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA163714A145CA00AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA163F14A1466900AA698B /* yes.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCE30EC314B5368A00CC0294 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCE30ED414B536A600CC0294 /* locate.bigram.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCE30ED714B536C900CC0294 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCE30EE014B536F200CC0294 /* locate.code.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FD6060AE1B7C0388004BCA6A /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FD6060D21B7C0471004BCA6A /* alias.c in Sources */,
+ FD6060D31B7C0471004BCA6A /* arith_yacc.c in Sources */,
+ FD6060D41B7C0471004BCA6A /* arith_yylex.c in Sources */,
+ FD6060D51B7C0471004BCA6A /* cd.c in Sources */,
+ FD6060EB1B7C04E4004BCA6A /* echo.c in Sources */,
+ FD6060D61B7C0471004BCA6A /* error.c in Sources */,
+ FD6060D71B7C0471004BCA6A /* eval.c in Sources */,
+ FD6060D81B7C0471004BCA6A /* exec.c in Sources */,
+ FD6060D91B7C0471004BCA6A /* expand.c in Sources */,
+ FD6060DA1B7C0471004BCA6A /* histedit.c in Sources */,
+ FD6060DB1B7C0471004BCA6A /* input.c in Sources */,
+ FD6060DC1B7C0471004BCA6A /* jobs.c in Sources */,
+ FD6060EC1B7C0506004BCA6A /* kill.c in Sources */,
+ FD6060DD1B7C0471004BCA6A /* mail.c in Sources */,
+ FD6060B51B7C0388004BCA6A /* main.c in Sources */,
+ FD6060DE1B7C0471004BCA6A /* memalloc.c in Sources */,
+ FD6060DF1B7C0471004BCA6A /* miscbltin.c in Sources */,
+ FD6060E01B7C0471004BCA6A /* mystring.c in Sources */,
+ FD6060E11B7C0471004BCA6A /* options.c in Sources */,
+ FD6060E21B7C0471004BCA6A /* output.c in Sources */,
+ FD6060E31B7C0471004BCA6A /* parser.c in Sources */,
+ FD6060ED1B7C0518004BCA6A /* printf.c in Sources */,
+ FD6060E41B7C0471004BCA6A /* redir.c in Sources */,
+ FD6060E51B7C0471004BCA6A /* show.c in Sources */,
+ FD6060EE1B7C0521004BCA6A /* test.c in Sources */,
+ FD6060E61B7C0471004BCA6A /* trap.c in Sources */,
+ FD6060E71B7C0471004BCA6A /* var.c in Sources */,
+ FD6060FD1B7C0CAF004BCA6A /* builtins.c in Sources */,
+ FD6060FE1B7C0CAF004BCA6A /* nodes.c in Sources */,
+ FD6060FF1B7C0CAF004BCA6A /* syntax.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ C6868581154725990025D623 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = C6868575154725700025D623 /* systime */;
+ targetProxy = C6868580154725990025D623 /* PBXContainerItemProxy */;
+ };
+ C6868583154725A30025D623 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = C6868575154725700025D623 /* systime */;
+ targetProxy = C6868582154725A30025D623 /* PBXContainerItemProxy */;
+ };
+ FC5D63A214B9864400123E48 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC5D638F14B9822D00123E48 /* hexdump */;
+ targetProxy = FC5D63A114B9864400123E48 /* PBXContainerItemProxy */;
+ };
+ FC5D63A414B9864400123E48 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC5D637F14B9819E00123E48 /* what */;
+ targetProxy = FC5D63A314B9864400123E48 /* PBXContainerItemProxy */;
+ };
+ FC5D63A614B9866500123E48 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC5D638F14B9822D00123E48 /* hexdump */;
+ targetProxy = FC5D63A514B9866500123E48 /* PBXContainerItemProxy */;
+ };
+ FC5D63A814B9866500123E48 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC5D637F14B9819E00123E48 /* what */;
+ targetProxy = FC5D63A714B9866500123E48 /* PBXContainerItemProxy */;
+ };
+ FCBA150114A144F700AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA149814A141FF00AA698B /* apply */;
+ targetProxy = FCBA150014A144F700AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA150314A144F700AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA14AE14A1422D00AA698B /* basename */;
+ targetProxy = FCBA150214A144F700AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA150514A144F700AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA14B714A1423E00AA698B /* chroot */;
+ targetProxy = FCBA150414A144F700AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA150714A144F700AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA14BF14A1426800AA698B /* date */;
+ targetProxy = FCBA150614A144F700AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA150914A144F700AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA14C714A1428000AA698B /* dirname */;
+ targetProxy = FCBA150814A144F700AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA150B14A144F700AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA14CF14A1433F00AA698B /* echo */;
+ targetProxy = FCBA150A14A144F700AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA150D14A144F700AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA14D714A1434A00AA698B /* env */;
+ targetProxy = FCBA150C14A144F700AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA165514A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA150E14A1453A00AA698B /* expr */;
+ targetProxy = FCBA165414A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA165714A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA151614A1454D00AA698B /* false */;
+ targetProxy = FCBA165614A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA165914A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA151E14A1455600AA698B /* find */;
+ targetProxy = FCBA165814A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA165B14A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA152614A1455900AA698B /* getopt */;
+ targetProxy = FCBA165A14A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA165D14A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA152E14A1455C00AA698B /* hostname */;
+ targetProxy = FCBA165C14A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA165F14A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA153614A1455F00AA698B /* id */;
+ targetProxy = FCBA165E14A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA166114A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA153E14A1456100AA698B /* jot */;
+ targetProxy = FCBA166014A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA166314A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA154614A1456400AA698B /* kill */;
+ targetProxy = FCBA166214A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA166514A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA154E14A1456700AA698B /* killall */;
+ targetProxy = FCBA166414A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA166714A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA155614A1456A00AA698B /* lastcomm */;
+ targetProxy = FCBA166614A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA166914A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA155E14A1456E00AA698B /* locate */;
+ targetProxy = FCBA166814A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA166B14A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA156614A1457100AA698B /* logname */;
+ targetProxy = FCBA166A14A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA166F14A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA157614A1457B00AA698B /* mktemp */;
+ targetProxy = FCBA166E14A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA167114A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA157E14A1457F00AA698B /* nice */;
+ targetProxy = FCBA167014A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA167314A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA158614A1458500AA698B /* nohup */;
+ targetProxy = FCBA167214A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA167514A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA158E14A1458800AA698B /* path_helper */;
+ targetProxy = FCBA167414A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA167714A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA159614A1458C00AA698B /* printenv */;
+ targetProxy = FCBA167614A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA167914A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA159E14A1459000AA698B /* printf */;
+ targetProxy = FCBA167814A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA167B14A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA15A614A1459500AA698B /* pwd */;
+ targetProxy = FCBA167A14A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA167D14A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA15AE14A1459700AA698B /* renice */;
+ targetProxy = FCBA167C14A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA167F14A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA15B614A1459900AA698B /* script */;
+ targetProxy = FCBA167E14A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA168114A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA15BE14A1459E00AA698B /* seq */;
+ targetProxy = FCBA168014A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA168314A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA15C614A145A200AA698B /* shlock */;
+ targetProxy = FCBA168214A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA168514A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA15CE14A145A500AA698B /* sleep */;
+ targetProxy = FCBA168414A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA168714A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA15D614A145A700AA698B /* su */;
+ targetProxy = FCBA168614A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA168914A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA15DE14A145A900AA698B /* tee */;
+ targetProxy = FCBA168814A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA168B14A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA15E614A145AE00AA698B /* test */;
+ targetProxy = FCBA168A14A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA168D14A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA15EE14A145B000AA698B /* time */;
+ targetProxy = FCBA168C14A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA168F14A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA15F614A145B200AA698B /* true */;
+ targetProxy = FCBA168E14A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA169114A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA15FE14A145B500AA698B /* uname */;
+ targetProxy = FCBA169014A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA169314A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA160614A145B800AA698B /* users */;
+ targetProxy = FCBA169214A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA169514A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA160E14A145BA00AA698B /* w */;
+ targetProxy = FCBA169414A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA169714A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA161614A145BC00AA698B /* whereis */;
+ targetProxy = FCBA169614A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA169914A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA161E14A145C000AA698B /* which */;
+ targetProxy = FCBA169814A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA169B14A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA162614A145C500AA698B /* who */;
+ targetProxy = FCBA169A14A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA169D14A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA162E14A145C700AA698B /* xargs */;
+ targetProxy = FCBA169C14A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA169F14A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA163614A145CA00AA698B /* yes */;
+ targetProxy = FCBA169E14A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCE30EE314B539BF00CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCE30EC214B5368A00CC0294 /* locate.bigram */;
+ targetProxy = FCE30EE214B539BF00CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30EE514B539BF00CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCE30ED614B536C900CC0294 /* locate.code */;
+ targetProxy = FCE30EE414B539BF00CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F4F14B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA149814A141FF00AA698B /* apply */;
+ targetProxy = FCE30F4E14B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F5114B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA14AE14A1422D00AA698B /* basename */;
+ targetProxy = FCE30F5014B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F5314B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA14B714A1423E00AA698B /* chroot */;
+ targetProxy = FCE30F5214B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F5514B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA14BF14A1426800AA698B /* date */;
+ targetProxy = FCE30F5414B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F5714B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA14C714A1428000AA698B /* dirname */;
+ targetProxy = FCE30F5614B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F5914B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA14CF14A1433F00AA698B /* echo */;
+ targetProxy = FCE30F5814B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F5B14B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA14D714A1434A00AA698B /* env */;
+ targetProxy = FCE30F5A14B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F5D14B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA150E14A1453A00AA698B /* expr */;
+ targetProxy = FCE30F5C14B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F5F14B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA151614A1454D00AA698B /* false */;
+ targetProxy = FCE30F5E14B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F6114B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA151E14A1455600AA698B /* find */;
+ targetProxy = FCE30F6014B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F6314B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA152614A1455900AA698B /* getopt */;
+ targetProxy = FCE30F6214B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F6514B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA152E14A1455C00AA698B /* hostname */;
+ targetProxy = FCE30F6414B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F6714B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA153614A1455F00AA698B /* id */;
+ targetProxy = FCE30F6614B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F6914B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA153E14A1456100AA698B /* jot */;
+ targetProxy = FCE30F6814B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F6B14B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA154614A1456400AA698B /* kill */;
+ targetProxy = FCE30F6A14B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F6D14B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA154E14A1456700AA698B /* killall */;
+ targetProxy = FCE30F6C14B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F6F14B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA155614A1456A00AA698B /* lastcomm */;
+ targetProxy = FCE30F6E14B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F7114B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA156614A1457100AA698B /* logname */;
+ targetProxy = FCE30F7014B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F7314B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA157614A1457B00AA698B /* mktemp */;
+ targetProxy = FCE30F7214B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F7514B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA157E14A1457F00AA698B /* nice */;
+ targetProxy = FCE30F7414B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F7714B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA158614A1458500AA698B /* nohup */;
+ targetProxy = FCE30F7614B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F7914B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA158E14A1458800AA698B /* path_helper */;
+ targetProxy = FCE30F7814B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F7B14B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA159614A1458C00AA698B /* printenv */;
+ targetProxy = FCE30F7A14B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F7D14B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA159E14A1459000AA698B /* printf */;
+ targetProxy = FCE30F7C14B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F7F14B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA15A614A1459500AA698B /* pwd */;
+ targetProxy = FCE30F7E14B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F8114B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA15AE14A1459700AA698B /* renice */;
+ targetProxy = FCE30F8014B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F8314B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA15B614A1459900AA698B /* script */;
+ targetProxy = FCE30F8214B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F8514B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA15BE14A1459E00AA698B /* seq */;
+ targetProxy = FCE30F8414B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F8714B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA15C614A145A200AA698B /* shlock */;
+ targetProxy = FCE30F8614B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F8914B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA15CE14A145A500AA698B /* sleep */;
+ targetProxy = FCE30F8814B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F8B14B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA15DE14A145A900AA698B /* tee */;
+ targetProxy = FCE30F8A14B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F8D14B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA15E614A145AE00AA698B /* test */;
+ targetProxy = FCE30F8C14B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F8F14B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA15EE14A145B000AA698B /* time */;
+ targetProxy = FCE30F8E14B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F9114B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA15F614A145B200AA698B /* true */;
+ targetProxy = FCE30F9014B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F9314B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA15FE14A145B500AA698B /* uname */;
+ targetProxy = FCE30F9214B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F9514B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA160614A145B800AA698B /* users */;
+ targetProxy = FCE30F9414B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F9714B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA160E14A145BA00AA698B /* w */;
+ targetProxy = FCE30F9614B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F9914B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA161614A145BC00AA698B /* whereis */;
+ targetProxy = FCE30F9814B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F9B14B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA161E14A145C000AA698B /* which */;
+ targetProxy = FCE30F9A14B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F9D14B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA162614A145C500AA698B /* who */;
+ targetProxy = FCE30F9C14B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F9F14B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA162E14A145C700AA698B /* xargs */;
+ targetProxy = FCE30F9E14B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30FA114B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA163614A145CA00AA698B /* yes */;
+ targetProxy = FCE30FA014B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FD6060B91B7C03B3004BCA6A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FD6060B11B7C0388004BCA6A /* sh */;
+ targetProxy = FD6060B81B7C03B3004BCA6A /* PBXContainerItemProxy */;
+ };
+ FD6060BB1B7C03BC004BCA6A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FD6060B11B7C0388004BCA6A /* sh */;
+ targetProxy = FD6060BA1B7C03BC004BCA6A /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin XCBuildConfiguration section */
+ C686857D154725700025D623 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ INSTALL_PATH = /usr/local/bin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FC5D638A14B9819E00123E48 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FC5D639614B9822D00123E48 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FC80BF6914A05A2F00C6F7F5 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ APPLY_RULES_IN_COPY_FILES = YES;
+ CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGN_IDENTITY = "-";
+ COPY_PHASE_STRIP = YES;
+ CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)";
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_ENABLE_OBJC_EXCEPTIONS = YES;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_PREPROCESSOR_DEFINITIONS = "__FBSDID=__RCSID";
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ INSTALL_PATH = /usr/bin;
+ SDKROOT = macosx.internal;
+ VERSIONING_SYSTEM = "apple-generic";
+ };
+ name = Release;
+ };
+ FCBA149D14A141FF00AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA14B314A1422D00AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA14BC14A1423E00AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA14C414A1426800AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
+ INSTALL_PATH = /bin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA14CC14A1428000AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA14D414A1433F00AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ INSTALL_PATH = /bin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA14DC14A1434A00AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA14FF14A144EC00AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA151314A1453A00AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ INSTALL_PATH = /bin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA151B14A1454D00AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA152314A1455600AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "__FBSDID=__RCSID",
+ _DARWIN_USE_64_BIT_INODE,
+ );
+ GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA152B14A1455900AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA153314A1455C00AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ INSTALL_PATH = /bin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA153B14A1455F00AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "__FBSDID=__RCSID",
+ USE_BSM_AUDIT,
+ );
+ GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA154314A1456100AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA154B14A1456400AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ INSTALL_PATH = /bin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA155314A1456700AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA155B14A1456A00AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA156314A1456E00AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA156B14A1457100AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA157B14A1457B00AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA158314A1457F00AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA158B14A1458500AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA159314A1458800AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ INSTALL_PATH = /usr/libexec;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA159B14A1458C00AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA15A314A1459000AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA15AB14A1459500AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ INSTALL_PATH = /bin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA15B314A1459700AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA15BB14A1459900AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA15C314A1459E00AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA15CB14A145A200AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA15D314A145A500AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ INSTALL_PATH = /bin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA15DB14A145A700AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CODE_SIGN_ENTITLEMENTS = su/su_entitlements.plist;
+ INSTALL_MODE_FLAG = "u+s,u+w,go-w,a+rX";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA15E314A145A900AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA15EB14A145AE00AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ INSTALL_PATH = /bin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA15F314A145B000AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA15FB14A145B200AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA160314A145B500AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA160B14A145B800AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA161314A145BA00AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "__FBSDID=__RCSID",
+ "HAVE_KVM=0",
+ "HAVE_UTMPX=1",
+ );
+ "OTHER_LDFLAGS[sdk=macosx*][arch=*]" = "-lresolv";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA161B14A145BC00AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA162314A145C000AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA162B14A145C500AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "__FBSDID=__RCSID",
+ _UTMPX_COMPAT,
+ SUPPORT_UTMPX,
+ );
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA163314A145C700AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA163B14A145CA00AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCE30ED114B5368A00CC0294 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ INSTALL_PATH = /usr/libexec;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCE30EDD14B536C900CC0294 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ INSTALL_PATH = /usr/libexec;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCE30F4C14B619B000CC0294 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FD6060B61B7C0388004BCA6A /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = FD6061311B7D2DDE004BCA6A /* sh.xcconfig */;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ C686857E154725700025D623 /* Build configuration list for PBXNativeTarget "systime" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ C686857D154725700025D623 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC5D638914B9819E00123E48 /* Build configuration list for PBXNativeTarget "what" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC5D638A14B9819E00123E48 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC5D639514B9822D00123E48 /* Build configuration list for PBXNativeTarget "hexdump" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC5D639614B9822D00123E48 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC80BF5A14A05A2F00C6F7F5 /* Build configuration list for PBXProject "shell_cmds" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC80BF6914A05A2F00C6F7F5 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA149C14A141FF00AA698B /* Build configuration list for PBXNativeTarget "apply" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA149D14A141FF00AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA14B214A1422D00AA698B /* Build configuration list for PBXNativeTarget "basename" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA14B314A1422D00AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA14BB14A1423E00AA698B /* Build configuration list for PBXNativeTarget "chroot" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA14BC14A1423E00AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA14C314A1426800AA698B /* Build configuration list for PBXNativeTarget "date" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA14C414A1426800AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA14CB14A1428000AA698B /* Build configuration list for PBXNativeTarget "dirname" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA14CC14A1428000AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA14D314A1433F00AA698B /* Build configuration list for PBXNativeTarget "echo" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA14D414A1433F00AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA14DB14A1434A00AA698B /* Build configuration list for PBXNativeTarget "env" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA14DC14A1434A00AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA14FE14A144EC00AA698B /* Build configuration list for PBXAggregateTarget "All_OSX" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA14FF14A144EC00AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA151214A1453A00AA698B /* Build configuration list for PBXNativeTarget "expr" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA151314A1453A00AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA151A14A1454D00AA698B /* Build configuration list for PBXNativeTarget "false" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA151B14A1454D00AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA152214A1455600AA698B /* Build configuration list for PBXNativeTarget "find" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA152314A1455600AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA152A14A1455900AA698B /* Build configuration list for PBXNativeTarget "getopt" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA152B14A1455900AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA153214A1455C00AA698B /* Build configuration list for PBXNativeTarget "hostname" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA153314A1455C00AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA153A14A1455F00AA698B /* Build configuration list for PBXNativeTarget "id" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA153B14A1455F00AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA154214A1456100AA698B /* Build configuration list for PBXNativeTarget "jot" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA154314A1456100AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA154A14A1456400AA698B /* Build configuration list for PBXNativeTarget "kill" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA154B14A1456400AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA155214A1456700AA698B /* Build configuration list for PBXNativeTarget "killall" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA155314A1456700AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA155A14A1456A00AA698B /* Build configuration list for PBXNativeTarget "lastcomm" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA155B14A1456A00AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA156214A1456E00AA698B /* Build configuration list for PBXNativeTarget "locate" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA156314A1456E00AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA156A14A1457100AA698B /* Build configuration list for PBXNativeTarget "logname" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA156B14A1457100AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA157A14A1457B00AA698B /* Build configuration list for PBXNativeTarget "mktemp" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA157B14A1457B00AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA158214A1457F00AA698B /* Build configuration list for PBXNativeTarget "nice" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA158314A1457F00AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA158A14A1458500AA698B /* Build configuration list for PBXNativeTarget "nohup" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA158B14A1458500AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA159214A1458800AA698B /* Build configuration list for PBXNativeTarget "path_helper" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA159314A1458800AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA159A14A1458C00AA698B /* Build configuration list for PBXNativeTarget "printenv" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA159B14A1458C00AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA15A214A1459000AA698B /* Build configuration list for PBXNativeTarget "printf" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA15A314A1459000AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA15AA14A1459500AA698B /* Build configuration list for PBXNativeTarget "pwd" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA15AB14A1459500AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA15B214A1459700AA698B /* Build configuration list for PBXNativeTarget "renice" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA15B314A1459700AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA15BA14A1459900AA698B /* Build configuration list for PBXNativeTarget "script" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA15BB14A1459900AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA15C214A1459E00AA698B /* Build configuration list for PBXNativeTarget "seq" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA15C314A1459E00AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA15CA14A145A200AA698B /* Build configuration list for PBXNativeTarget "shlock" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA15CB14A145A200AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA15D214A145A500AA698B /* Build configuration list for PBXNativeTarget "sleep" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA15D314A145A500AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA15DA14A145A700AA698B /* Build configuration list for PBXNativeTarget "su" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA15DB14A145A700AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA15E214A145A900AA698B /* Build configuration list for PBXNativeTarget "tee" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA15E314A145A900AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA15EA14A145AE00AA698B /* Build configuration list for PBXNativeTarget "test" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA15EB14A145AE00AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA15F214A145B000AA698B /* Build configuration list for PBXNativeTarget "time" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA15F314A145B000AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA15FA14A145B200AA698B /* Build configuration list for PBXNativeTarget "true" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA15FB14A145B200AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA160214A145B500AA698B /* Build configuration list for PBXNativeTarget "uname" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA160314A145B500AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA160A14A145B800AA698B /* Build configuration list for PBXNativeTarget "users" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA160B14A145B800AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA161214A145BA00AA698B /* Build configuration list for PBXNativeTarget "w" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA161314A145BA00AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA161A14A145BC00AA698B /* Build configuration list for PBXNativeTarget "whereis" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA161B14A145BC00AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA162214A145C000AA698B /* Build configuration list for PBXNativeTarget "which" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA162314A145C000AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA162A14A145C500AA698B /* Build configuration list for PBXNativeTarget "who" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA162B14A145C500AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA163214A145C700AA698B /* Build configuration list for PBXNativeTarget "xargs" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA163314A145C700AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA163A14A145CA00AA698B /* Build configuration list for PBXNativeTarget "yes" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA163B14A145CA00AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCE30ED014B5368A00CC0294 /* Build configuration list for PBXNativeTarget "locate.bigram" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCE30ED114B5368A00CC0294 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCE30EDC14B536C900CC0294 /* Build configuration list for PBXNativeTarget "locate.code" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCE30EDD14B536C900CC0294 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCE30F4B14B619B000CC0294 /* Build configuration list for PBXAggregateTarget "All_iOS" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCE30F4C14B619B000CC0294 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FD6060B71B7C0388004BCA6A /* Build configuration list for PBXNativeTarget "sh" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FD6060B61B7C0388004BCA6A /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+}
diff --git a/shell_cmds/shell_cmds.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/shell_cmds/shell_cmds.xcodeproj/project.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..919434a
--- /dev/null
+++ b/shell_cmds/shell_cmds.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Workspace
+ version = "1.0">
+ <FileRef
+ location = "self:">
+ </FileRef>
+</Workspace>
diff --git a/shell_cmds/shlock/shlock.1 b/shell_cmds/shlock/shlock.1
new file mode 100644
index 0000000..9b1667d
--- /dev/null
+++ b/shell_cmds/shlock/shlock.1
@@ -0,0 +1,147 @@
+.\" $NetBSD: shlock.1,v 1.11 2008/04/30 13:11:01 martin Exp $
+.\"
+.\" Copyright (c) 2006 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Erik E. Fair.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd June 29, 1997
+.Dt SHLOCK 1
+.Os
+.Sh NAME
+.Nm shlock
+.Nd create or verify a lock file for shell scripts
+.Sh SYNOPSIS
+.Nm
+.Op Fl du
+.Op Fl p Ar PID
+.Fl f
+.Ar lockfile
+.Sh DESCRIPTION
+The
+.Nm
+command can create or verify a lock file on behalf of a shell or
+other script program.
+When it attempts to create a lock file, if one already exists,
+.Nm
+verifies that it is or is not valid.
+If valid,
+.Nm
+will exit with a non-zero exit code.
+If invalid,
+.Nm
+will remove the lock file, and
+create a new one.
+.Pp
+.Nm
+uses the
+.Xr link 2
+system call to make the final target lock file, which is an atomic
+operation (i.e. "dot locking", so named for this mechanism's original
+use for locking system mailboxes).
+It puts the process ID ("PID") from the command line into the
+requested lock file.
+.Pp
+.Nm
+verifies that an extant lock file is still valid by
+using
+.Xr kill 2
+with a zero signal to check for the existence of the process that
+holds the lock.
+.Pp
+The
+.Fl d
+option causes
+.Nm
+to be verbose about what it is doing.
+.Pp
+The
+.Fl f
+argument with
+.Ar lockfile
+is always required.
+.Pp
+The
+.Fl p
+option with
+.Ar PID
+is given when the program is to create a lock file; when absent,
+.Nm
+will simply check for the validity of the lock file.
+.Pp
+The
+.Fl u
+option causes
+.Nm
+to read and write the PID as a binary pid_t, instead of as ASCII,
+to be compatible with the locks created by UUCP.
+.Sh EXIT STATUS
+A zero exit code indicates a valid lock file.
+.Sh EXAMPLES
+.Ss BOURNE SHELL
+.Bd -literal
+#!/bin/sh
+lckfile=/tmp/foo.lock
+if shlock -f ${lckfile} -p $$
+then
+# do what required the lock
+ rm ${lckfile}
+else
+ echo Lock ${lckfile} already held by `cat ${lckfile}`
+fi
+.Ed
+.Ss C SHELL
+.Bd -literal
+#!/bin/csh -f
+set lckfile=/tmp/foo.lock
+shlock -f ${lckfile} -p $$
+if ($status == 0) then
+# do what required the lock
+ rm ${lckfile}
+else
+ echo Lock ${lckfile} already held by `cat ${lckfile}`
+endif
+.Ed
+.Pp
+The examples assume that the file system where the lock file is to
+be created is writable by the user, and has space available.
+.Sh HISTORY
+.Nm
+was written for the first Network News Transfer Protocol (NNTP)
+software distribution, released in March 1986.
+The algorithm was suggested by Peter Honeyman,
+from work he did on HoneyDanBer UUCP.
+.Sh AUTHORS
+.An Erik E. Fair Aq fair@clock.org
+.Sh BUGS
+Does not work on NFS or other network file system on different
+systems because the disparate systems have disjoint PID spaces.
+.Pp
+Cannot handle the case where a lock file was not deleted, the
+process that created it has exited, and the system has created a
+new process with the same PID as in the dead lock file.
+The lock file will appear to be valid even though the process is
+unrelated to the one that created the lock in the first place.
+Always remove your lock files after you're done.
diff --git a/shell_cmds/shlock/shlock.c b/shell_cmds/shlock/shlock.c
new file mode 100644
index 0000000..9dcb645
--- /dev/null
+++ b/shell_cmds/shlock/shlock.c
@@ -0,0 +1,364 @@
+/* $NetBSD: shlock.c,v 1.10 2008/04/28 20:24:14 martin Exp $ */
+
+/*-
+ * Copyright (c) 2006 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Erik E. Fair.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+** Program to produce reliable locks for shell scripts.
+** Algorithm suggested by Peter Honeyman, January 1984,
+** in connection with HoneyDanBer UUCP.
+**
+** I tried extending this to handle shared locks in November 1987,
+** and ran into to some fundamental problems:
+**
+** Neither 4.3 BSD nor System V have an open(2) with locking,
+** so that you can open a file and have it locked as soon as
+** it's real; you have to make two system calls, and there's
+** a race...
+**
+** When removing dead process id's from a list in a file,
+** you need to truncate the file (you don't want to create a
+** new one; see above); unfortunately for the portability of
+** this program, only 4.3 BSD has ftruncate(2).
+**
+** Erik E. Fair <fair@ucbarpa.berkeley.edu>, November 8, 1987
+**
+** Extensions for UUCP style locks (i.e. pid is an int in the file,
+** rather than an ASCII string). Also fix long standing bug with
+** full file systems and temporary files.
+**
+** Erik E. Fair <fair@apple.com>, November 12, 1989
+**
+** ANSIfy the code somewhat to make gcc -Wall happy with the code.
+** Submit to NetBSD
+**
+** Erik E. Fair <fair@clock.org>, May 20, 1997
+*/
+
+#include <sys/cdefs.h>
+
+#ifndef lint
+__RCSID("$NetBSD: shlock.c,v 1.10 2008/04/28 20:24:14 martin Exp $");
+#endif
+
+#include <sys/types.h>
+#include <sys/file.h>
+#include <fcntl.h> /* Needed on hpux */
+#include <stdio.h>
+#include <signal.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#define LOCK_SET 0
+#define LOCK_FAIL 1
+
+#define LOCK_GOOD 0
+#define LOCK_BAD 1
+
+#define FAIL (-1)
+
+#define TRUE 1
+#define FALSE 0
+
+int Debug = FALSE;
+char *Pname;
+const char USAGE[] = "%s: USAGE: %s [-du] [-p PID] -f file\n";
+const char E_unlk[] = "%s: unlink(%s): %s\n";
+const char E_open[] = "%s: open(%s): %s\n";
+
+#define dprintf if (Debug) printf
+
+/*
+** Prototypes to make the ANSI compilers happy
+** Didn't lint used to do type and argument checking?
+** (and wasn't that sufficient?)
+*/
+
+/* the following is in case you need to make the prototypes go away. */
+char *xtmpfile(char *, pid_t, int);
+int p_exists(pid_t);
+int cklock(char *, int);
+int mklock(char *, pid_t, int);
+void bad_usage(void);
+int main(int, char **);
+
+/*
+** Create a temporary file, all ready to lock with.
+** The file arg is so we get the filename right, if he
+** gave us a full path, instead of using the current directory
+** which might not be in the same filesystem.
+*/
+char *
+xtmpfile(char *file, pid_t pid, int uucpstyle)
+{
+ int fd;
+ int len;
+ char *cp, buf[BUFSIZ];
+ static char tempname[BUFSIZ];
+
+ sprintf(buf, "shlock%ld", (u_long)getpid());
+ if ((cp = strrchr(strcpy(tempname, file), '/')) != (char *)NULL) {
+ *++cp = '\0';
+ (void) strcat(tempname, buf);
+ } else
+ (void) strcpy(tempname, buf);
+ dprintf("%s: temporary filename: %s\n", Pname, tempname);
+
+ sprintf(buf, "%ld\n", (u_long)pid);
+ len = strlen(buf);
+openloop:
+ if ((fd = open(tempname, O_RDWR|O_CREAT|O_EXCL, 0644)) < 0) {
+ switch(errno) {
+ case EEXIST:
+ dprintf("%s: file %s exists already.\n",
+ Pname, tempname);
+ if (unlink(tempname) < 0) {
+ fprintf(stderr, E_unlk,
+ Pname, tempname, strerror(errno));
+ return((char *)NULL);
+ }
+ /*
+ ** Further profanity
+ */
+ goto openloop;
+ default:
+ fprintf(stderr, E_open,
+ Pname, tempname, strerror(errno));
+ return((char *)NULL);
+ }
+ }
+
+ /*
+ ** Write the PID into the temporary file before attempting to link
+ ** to the actual lock file. That way we have a valid lock the instant
+ ** the link succeeds.
+ */
+ if (uucpstyle ?
+ (write(fd, &pid, sizeof(pid)) != sizeof(pid)) :
+ (write(fd, buf, len) < 0))
+ {
+ fprintf(stderr, "%s: write(%s,%ld): %s\n",
+ Pname, tempname, (u_long)pid, strerror(errno));
+ (void) close(fd);
+ if (unlink(tempname) < 0) {
+ fprintf(stderr, E_unlk,
+ Pname, tempname, strerror(errno));
+ }
+ return((char *)NULL);
+ }
+ (void) close(fd);
+ return(tempname);
+}
+
+/*
+** Does the PID exist?
+** Send null signal to find out.
+*/
+int
+p_exists(pid_t pid)
+{
+ dprintf("%s: process %ld is ", Pname, (u_long)pid);
+ if (pid <= 0) {
+ dprintf("invalid\n");
+ return(FALSE);
+ }
+ if (kill(pid, 0) < 0) {
+ switch(errno) {
+ case ESRCH:
+ dprintf("dead\n");
+ return(FALSE); /* pid does not exist */
+ case EPERM:
+ dprintf("alive\n");
+ return(TRUE); /* pid exists */
+ default:
+ dprintf("state unknown: %s\n", strerror(errno));
+ return(TRUE); /* be conservative */
+ }
+ }
+ dprintf("alive\n");
+ return(TRUE); /* pid exists */
+}
+
+/*
+** Check the validity of an existing lock file.
+**
+** Read the PID out of the lock
+** Send a null signal to determine whether that PID still exists
+** Existence (or not) determines the validity of the lock.
+**
+** Two bigs wins to this algorithm:
+**
+** o Locks do not survive crashes of either the system or the
+** application by any appreciable period of time.
+**
+** o No clean up to do if the system or application crashes.
+**
+*/
+int
+cklock(char *file, int uucpstyle)
+{
+ int fd = open(file, O_RDONLY);
+ ssize_t len;
+ pid_t pid;
+ char buf[BUFSIZ];
+
+ dprintf("%s: checking extant lock <%s>\n", Pname, file);
+ if (fd < 0) {
+ if (errno != ENOENT)
+ fprintf(stderr, E_open, Pname, file, strerror(errno));
+ return(TRUE); /* might or might not; conservatism */
+ }
+
+ if (uucpstyle ?
+ ((len = read(fd, &pid, sizeof(pid))) != sizeof(pid)) :
+ ((len = read(fd, buf, sizeof(buf))) <= 0))
+ {
+ close(fd);
+ dprintf("%s: lock file format error\n", Pname);
+ return(FALSE);
+ }
+ close(fd);
+ buf[len + 1] = '\0';
+ return(p_exists(uucpstyle ? pid : atoi(buf)));
+}
+
+int
+mklock(char *file, pid_t pid, int uucpstyle)
+{
+ char *tmp;
+ int retcode = FALSE;
+
+ dprintf("%s: trying lock <%s> for process %ld\n", Pname, file,
+ (u_long)pid);
+ if ((tmp = xtmpfile(file, pid, uucpstyle)) == (char *)NULL)
+ return(FALSE);
+
+linkloop:
+ if (link(tmp, file) < 0) {
+ switch(errno) {
+ case EEXIST:
+ dprintf("%s: lock <%s> already exists\n", Pname, file);
+ if (cklock(file, uucpstyle)) {
+ dprintf("%s: extant lock is valid\n", Pname);
+ break;
+ } else {
+ dprintf("%s: lock is invalid, removing\n",
+ Pname);
+ if (unlink(file) < 0) {
+ fprintf(stderr, E_unlk,
+ Pname, file, strerror(errno));
+ break;
+ }
+ }
+ /*
+ ** I hereby profane the god of structured programming,
+ ** Edsgar Dijkstra
+ */
+ goto linkloop;
+ default:
+ fprintf(stderr, "%s: link(%s, %s): %s\n",
+ Pname, tmp, file, strerror(errno));
+ break;
+ }
+ } else {
+ dprintf("%s: got lock <%s>\n", Pname, file);
+ retcode = TRUE;
+ }
+ if (unlink(tmp) < 0) {
+ fprintf(stderr, E_unlk, Pname, tmp, strerror(errno));
+ }
+ return(retcode);
+}
+
+void
+bad_usage(void)
+{
+ fprintf(stderr, USAGE, Pname, Pname);
+ exit(LOCK_FAIL);
+}
+
+int
+main(int ac, char **av)
+{
+ int x;
+ char *file = (char *)NULL;
+ pid_t pid = 0;
+ int uucpstyle = FALSE; /* indicating UUCP style locks */
+ int only_check = TRUE; /* don't make a lock */
+
+ Pname = ((Pname = strrchr(av[0], '/')) ? Pname + 1 : av[0]);
+
+ for(x = 1; x < ac; x++) {
+ if (av[x][0] == '-') {
+ switch(av[x][1]) {
+ case 'u':
+ uucpstyle = TRUE;
+ break;
+ case 'd':
+ Debug = TRUE;
+ break;
+ case 'p':
+ if (strlen(av[x]) > 2) {
+ pid = atoi(&av[x][2]);
+ } else {
+ if (++x >= ac) {
+ bad_usage();
+ }
+ pid = atoi(av[x]);
+ }
+ only_check = FALSE; /* wants one */
+ break;
+ case 'f':
+ if (strlen(av[x]) > 2) {
+ file = &av[x][2];
+ } else {
+ if (++x >= ac) {
+ bad_usage();
+ }
+ file = av[x];
+ }
+ break;
+ default:
+ bad_usage();
+ }
+ }
+ }
+
+ if (file == (char *)NULL || (!only_check && pid <= 0)) {
+ bad_usage();
+ }
+
+ if (only_check) {
+ exit(cklock(file, uucpstyle) ? LOCK_GOOD : LOCK_BAD);
+ }
+
+ exit(mklock(file, pid, uucpstyle) ? LOCK_SET : LOCK_FAIL);
+}
diff --git a/shell_cmds/sleep/sleep.1 b/shell_cmds/sleep/sleep.1
new file mode 100644
index 0000000..f5215be
--- /dev/null
+++ b/shell_cmds/sleep/sleep.1
@@ -0,0 +1,124 @@
+.\"-
+.\" Copyright (c) 1990, 1993, 1994
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)sleep.1 8.3 (Berkeley) 4/18/94
+.\" $FreeBSD: src/bin/sleep/sleep.1,v 1.22 2005/01/16 16:41:59 ru Exp $
+.\"
+.Dd April 18, 1994
+.Dt SLEEP 1
+.Os
+.Sh NAME
+.Nm sleep
+.Nd suspend execution for an interval of time
+.Sh SYNOPSIS
+.Nm
+.Ar seconds
+.Sh DESCRIPTION
+The
+.Nm
+command
+suspends execution for a minimum of
+.Ar seconds .
+.Pp
+If the
+.Nm
+command receives a signal, it takes the standard action.
+.Sh IMPLEMENTATION NOTES
+The
+.Dv SIGALRM
+signal is not handled specially by this implementation.
+.Pp
+The
+.Nm
+command will accept and honor a non-integer number of specified seconds
+(with a
+.Ql .\&
+character as a decimal point).
+.Bf Sy
+This is a non-portable extension, and its use will nearly guarantee that
+a shell script will not execute properly on another system.
+.Ef
+.Sh EXIT STATUS
+.Ex -std
+.Sh EXAMPLES
+To schedule the execution of a command for
+.Va x
+number seconds later (with
+.Xr csh 1 ) :
+.Pp
+.Dl (sleep 1800; sh command_file >& errors)&
+.Pp
+This incantation would wait a half hour before
+running the script command_file.
+(See the
+.Xr at 1
+utility.)
+.Pp
+To reiteratively run a command (with the
+.Xr csh 1 ) :
+.Pp
+.Bd -literal -offset indent -compact
+while (1)
+ if (! -r zzz.rawdata) then
+ sleep 300
+ else
+ foreach i (`ls *.rawdata`)
+ sleep 70
+ awk -f collapse_data $i >> results
+ end
+ break
+ endif
+end
+.Ed
+.Pp
+The scenario for a script such as this might be: a program currently
+running is taking longer than expected to process a series of
+files, and it would be nice to have
+another program start processing the files created by the first
+program as soon as it is finished (when zzz.rawdata is created).
+The script checks every five minutes for the file zzz.rawdata,
+when the file is found, then another portion processing
+is done courteously by sleeping for 70 seconds in between each
+awk job.
+.Sh SEE ALSO
+.Xr nanosleep 2 ,
+.Xr sleep 3
+.Sh STANDARDS
+The
+.Nm
+command is expected to be
+.St -p1003.2
+compatible.
+.Sh HISTORY
+A
+.Nm
+command appeared in
+.At v4 .
diff --git a/shell_cmds/sleep/sleep.c b/shell_cmds/sleep/sleep.c
new file mode 100644
index 0000000..d41556c
--- /dev/null
+++ b/shell_cmds/sleep/sleep.c
@@ -0,0 +1,131 @@
+/*-
+ * Copyright (c) 1988, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static char const copyright[] =
+"@(#) Copyright (c) 1988, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)sleep.c 8.3 (Berkeley) 4/2/94";
+#endif /* not lint */
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/bin/sleep/sleep.c,v 1.20 2005/08/07 09:11:38 stefanf Exp $");
+
+#include <ctype.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+#include <string.h>
+
+void usage(void);
+
+int
+main(int argc, char *argv[])
+{
+ struct timespec time_to_sleep;
+ long l;
+ int neg;
+ char *p;
+
+ if (argc == 2) {
+ p = argv[1];
+ } else if (argc == 3 && !strcmp("--", argv[1])) {
+ // POSIX issue: "sleep -- 3" should be the same as "sleep 3",
+ // normally getopt makes this kind of thing work, but sleep has
+ // no options, so we do it "the easy way"
+ p = argv[2];
+ } else {
+ usage();
+ return(1);
+ }
+
+ /* Skip over leading whitespaces. */
+ while (isspace((unsigned char)*p))
+ ++p;
+
+ /* Check for optional `+' or `-' sign. */
+ neg = 0;
+ if (*p == '-') {
+ neg = 1;
+ ++p;
+ if (!isdigit((unsigned char)*p) && *p != '.') {
+ usage();
+ return(1);
+ }
+ }
+ else if (*p == '+')
+ ++p;
+
+ /* Calculate seconds. */
+ if (isdigit((unsigned char)*p)) {
+ l = strtol(p, &p, 10);
+ if (l > INT_MAX) {
+ /*
+ * Avoid overflow when `seconds' is huge. This assumes
+ * that the maximum value for a time_t is <= INT_MAX.
+ */
+ l = INT_MAX;
+ }
+ } else
+ l = 0;
+ time_to_sleep.tv_sec = (time_t)l;
+
+ /* Calculate nanoseconds. */
+ time_to_sleep.tv_nsec = 0;
+
+ if (*p == '.') { /* Decimal point. */
+ l = 100000000L;
+ do {
+ if (isdigit((unsigned char)*++p))
+ time_to_sleep.tv_nsec += (*p - '0') * l;
+ else
+ break;
+ l /= 10;
+ } while (l);
+ }
+
+ if (!neg && (time_to_sleep.tv_sec > 0 || time_to_sleep.tv_nsec > 0))
+ (void)nanosleep(&time_to_sleep, (struct timespec *)NULL);
+
+ return(0);
+}
+
+void
+usage(void)
+{
+ const char msg[] = "usage: sleep seconds\n";
+
+ write(STDERR_FILENO, msg, sizeof(msg) - 1);
+}
diff --git a/shell_cmds/su/su.1 b/shell_cmds/su/su.1
new file mode 100644
index 0000000..014a567
--- /dev/null
+++ b/shell_cmds/su/su.1
@@ -0,0 +1,213 @@
+.\" Copyright (c) 1988, 1990, 1993, 1994
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)su.1 8.2 (Berkeley) 4/18/94
+.\" $FreeBSD: src/usr.bin/su/su.1,v 1.40 2007/07/24 06:41:07 delphij Exp $
+.\"
+.Dd September 13, 2006
+.Dt SU 1
+.Os
+.Sh NAME
+.Nm su
+.Nd substitute user identity
+.Sh SYNOPSIS
+.Nm
+.Op Fl
+.Op Fl flm
+.Op Ar login Op Ar args
+.Sh DESCRIPTION
+The
+.Nm
+utility requests appropriate user credentials via PAM
+and switches to that user ID
+(the default user is the superuser).
+A shell is then executed.
+.Pp
+PAM is used to set the policy
+.Xr su 1
+will use.
+In particular, by default only users in the
+.Dq Li admin
+or
+.Dq Li wheel
+groups can switch to UID 0
+.Pq Dq Li root .
+This group requirement may be changed by modifying the
+.Dq Li pam_group
+section of
+.Pa /etc/pam.d/su .
+See
+.Xr pam_group 8
+for details on how to modify this setting.
+.Pp
+By default, the environment is unmodified with the exception of
+.Ev USER ,
+.Ev HOME ,
+and
+.Ev SHELL .
+.Ev HOME
+and
+.Ev SHELL
+are set to the target login's default values.
+.Ev USER
+is set to the target login, unless the target login has a user ID of 0,
+in which case it is unmodified.
+The invoked shell is the one belonging to the target login.
+This is the traditional behavior of
+.Nm .
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl f
+If the invoked shell is
+.Xr csh 1 ,
+this option prevents it from reading the
+.Dq Pa .cshrc
+file.
+.It Fl l
+Simulate a full login.
+The environment is discarded except for
+.Ev HOME ,
+.Ev SHELL ,
+.Ev PATH ,
+.Ev TERM ,
+and
+.Ev USER .
+.Ev HOME
+and
+.Ev SHELL
+are modified as above.
+.Ev USER
+is set to the target login.
+.Ev PATH
+is set to
+.Dq Pa /bin:/usr/bin .
+.Ev TERM
+is imported from your current environment.
+The invoked shell is the target login's, and
+.Nm
+will change directory to the target login's home directory.
+.It Fl
+(no letter) The same as
+.Fl l .
+.It Fl m
+Leave the environment unmodified.
+The invoked shell is your login shell, and no directory changes are made.
+As a security precaution, if the target user's shell is a non-standard
+shell (as defined by
+.Xr getusershell 3 )
+and the caller's real uid is
+non-zero,
+.Nm
+will fail.
+.El
+.Pp
+The
+.Fl l
+(or
+.Fl )
+and
+.Fl m
+options are mutually exclusive; the last one specified
+overrides any previous ones.
+.Pp
+If the optional
+.Ar args
+are provided on the command line, they are passed to the login shell of
+the target login.
+Note that all command line arguments before the target login name are
+processed by
+.Nm
+itself, everything after the target login name gets passed to the login
+shell.
+.Pp
+By default (unless the prompt is reset by a startup file) the super-user
+prompt is set to
+.Dq Sy \&#
+to remind one of its awesome power.
+.Sh ENVIRONMENT
+Environment variables used by
+.Nm :
+.Bl -tag -width HOME
+.It Ev HOME
+Default home directory of real user ID unless modified as
+specified above.
+.It Ev PATH
+Default search path of real user ID unless modified as specified above.
+.It Ev TERM
+Provides terminal type which may be retained for the substituted
+user ID.
+.It Ev USER
+The user ID is always the effective ID (the target user ID) after an
+.Nm
+unless the user ID is 0 (root).
+.El
+.Sh FILES
+.Bl -tag -width ".Pa /etc/pam.d/su" -compact
+.It Pa /etc/pam.d/su
+PAM configuration for
+.Nm .
+.El
+.Sh EXAMPLES
+.Bl -tag -width 5n -compact
+.It Li "su man -c catman"
+Runs the command
+.Li catman
+as user
+.Li man .
+You will be asked for man's password unless your real UID is 0.
+.It Li "su man -c 'catman /usr/share/man /usr/local/man'"
+Same as above, but the target command consists of more than a
+single word and hence is quoted for use with the
+.Fl c
+option being passed to the shell.
+(Most shells expect the argument to
+.Fl c
+to be a single word).
+.It Li "su -l foo"
+Simulate a login for user foo.
+.It Li "su - foo"
+Same as above.
+.It Li "su -"
+Simulate a login for root.
+.El
+.Sh SEE ALSO
+.Xr csh 1 ,
+.Xr sh 1 ,
+.Xr group 5 ,
+.Xr passwd 5 ,
+.Xr environ 7 ,
+.Xr pam_group 8
+.Sh HISTORY
+A
+.Nm
+command appeared in
+.At v1 .
diff --git a/shell_cmds/su/su.c b/shell_cmds/su/su.c
new file mode 100644
index 0000000..8ad7434
--- /dev/null
+++ b/shell_cmds/su/su.c
@@ -0,0 +1,737 @@
+/*
+ * Copyright (c) 2002, 2005 Networks Associates Technologies, Inc.
+ * All rights reserved.
+ *
+ * Portions of this software were developed for the FreeBSD Project by
+ * ThinkSec AS and NAI Labs, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+ * ("CBOSS"), as part of the DARPA CHATS research program.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*-
+ * Copyright (c) 1988, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1988, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)su.c 8.3 (Berkeley) 4/2/94";
+#endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/su/su.c,v 1.91 2009/12/13 03:14:06 delphij Exp $");
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+
+#ifdef USE_BSM_AUDIT
+#include <bsm/libbsm.h>
+#include <bsm/audit_uevents.h>
+#endif
+
+#include <err.h>
+#include <errno.h>
+#include <grp.h>
+#ifndef __APPLE__
+#include <login_cap.h>
+#endif /* !__APPLE__ */
+#include <paths.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <stdarg.h>
+
+#include <security/pam_appl.h>
+#include <security/openpam.h>
+
+#ifdef __APPLE__
+#include <bsm/audit_session.h>
+#endif /* __APPLE__ */
+
+#define PAM_END() do { \
+ int local_ret; \
+ if (pamh != NULL) { \
+ local_ret = pam_setcred(pamh, PAM_DELETE_CRED); \
+ if (local_ret != PAM_SUCCESS) \
+ syslog(LOG_ERR, "pam_setcred: %s", \
+ pam_strerror(pamh, local_ret)); \
+ if (asthem) { \
+ local_ret = pam_close_session(pamh, 0); \
+ if (local_ret != PAM_SUCCESS) \
+ syslog(LOG_ERR, "pam_close_session: %s",\
+ pam_strerror(pamh, local_ret)); \
+ } \
+ local_ret = pam_end(pamh, local_ret); \
+ if (local_ret != PAM_SUCCESS) \
+ syslog(LOG_ERR, "pam_end: %s", \
+ pam_strerror(pamh, local_ret)); \
+ } \
+} while (0)
+
+
+#define PAM_SET_ITEM(what, item) do { \
+ int local_ret; \
+ local_ret = pam_set_item(pamh, what, item); \
+ if (local_ret != PAM_SUCCESS) { \
+ syslog(LOG_ERR, "pam_set_item(" #what "): %s", \
+ pam_strerror(pamh, local_ret)); \
+ errx(1, "pam_set_item(" #what "): %s", \
+ pam_strerror(pamh, local_ret)); \
+ /* NOTREACHED */ \
+ } \
+} while (0)
+
+enum tristate { UNSET, YES, NO };
+
+static pam_handle_t *pamh = NULL;
+static char **environ_pam;
+
+static char *ontty(void);
+static int chshell(const char *);
+static void usage(void) __dead2;
+static void export_pam_environment(void);
+static int ok_to_export(const char *);
+
+extern char **environ;
+
+int
+main(int argc, char *argv[])
+{
+ static char *cleanenv;
+ struct passwd *pwd;
+ struct pam_conv conv = { openpam_ttyconv, NULL };
+ enum tristate iscsh;
+#ifndef __APPLE__
+ login_cap_t *lc;
+#endif /* !__APPLE__ */
+ union {
+ const char **a;
+ char * const *b;
+ } np;
+ uid_t ruid;
+ pid_t child_pid, child_pgrp, pid;
+ int asme, ch, asthem, fastlogin, prio, i, retcode,
+ statusp, setmaclabel;
+#ifndef __APPLE__
+ u_int setwhat;
+#endif /* !__APPLE__ */
+ char *username, *class, shellbuf[MAXPATHLEN];
+ const char *p, *user, *shell, *mytty, **nargv;
+ const void *v;
+ struct sigaction sa, sa_int, sa_quit, sa_pipe;
+ int temp, fds[2];
+#ifdef USE_BSM_AUDIT
+ const char *aerr;
+ au_id_t auid;
+#endif
+#ifdef __APPLE__
+ /* 4043304 */
+ const char *avshell;
+ char avshellbuf[MAXPATHLEN];
+#endif /* __APPLE__ */
+
+ shell = class = cleanenv = NULL;
+ asme = asthem = fastlogin = statusp = 0;
+ user = "root";
+ iscsh = UNSET;
+ setmaclabel = 0;
+
+#ifdef __APPLE__
+ while ((ch = getopt(argc, argv, "-flm")) != -1)
+#else
+ while ((ch = getopt(argc, argv, "-flmsc:")) != -1)
+#endif /* __APPLE__ */
+ switch ((char)ch) {
+ case 'f':
+ fastlogin = 1;
+ break;
+ case '-':
+ case 'l':
+ asme = 0;
+ asthem = 1;
+ break;
+ case 'm':
+ asme = 1;
+ asthem = 0;
+ break;
+#ifndef __APPLE__
+ case 's':
+ setmaclabel = 1;
+ break;
+ case 'c':
+ class = optarg;
+ break;
+#endif /* !__APPLE__ */
+ case '?':
+ default:
+ usage();
+ /* NOTREACHED */
+ }
+
+ if (optind < argc)
+ user = argv[optind++];
+
+ if (user == NULL)
+ usage();
+ /* NOTREACHED */
+
+ /*
+ * Try to provide more helpful debugging output if su(1) is running
+ * non-setuid, or was run from a file system not mounted setuid.
+ */
+ if (geteuid() != 0)
+ errx(1, "not running setuid");
+
+#ifdef USE_BSM_AUDIT
+ if (getauid(&auid) < 0 && errno != ENOSYS) {
+ syslog(LOG_AUTH | LOG_ERR, "getauid: %s", strerror(errno));
+ errx(1, "Permission denied");
+ }
+#endif
+ if (strlen(user) > MAXLOGNAME - 1) {
+#ifdef USE_BSM_AUDIT
+ if (audit_submit(AUE_su, auid,
+ EPERM, 1, "username too long: '%s'", user))
+ errx(1, "Permission denied");
+#endif
+ errx(1, "username too long");
+ }
+
+ nargv = malloc(sizeof(char *) * (size_t)(argc + 4));
+ if (nargv == NULL)
+ errx(1, "malloc failure");
+
+ nargv[argc + 3] = NULL;
+ for (i = argc; i >= optind; i--)
+ nargv[i + 3] = argv[i];
+ np.a = &nargv[i + 3];
+
+ argv += optind;
+
+ errno = 0;
+ prio = getpriority(PRIO_PROCESS, 0);
+ if (errno)
+ prio = 0;
+
+ setpriority(PRIO_PROCESS, 0, -2);
+ openlog("su", LOG_CONS, LOG_AUTH);
+
+ /* get current login name, real uid and shell */
+ ruid = getuid();
+ username = getlogin();
+ pwd = getpwnam(username);
+ if (username == NULL || pwd == NULL || pwd->pw_uid != ruid)
+ pwd = getpwuid(ruid);
+ if (pwd == NULL) {
+#ifdef USE_BSM_AUDIT
+ if (audit_submit(AUE_su, auid, EPERM, 1,
+ "unable to determine invoking subject: '%s'", username))
+ errx(1, "Permission denied");
+#endif
+ errx(1, "who are you?");
+ }
+
+ username = strdup(pwd->pw_name);
+ if (username == NULL)
+ err(1, "strdup failure");
+
+ if (asme) {
+ if (pwd->pw_shell != NULL && *pwd->pw_shell != '\0') {
+ /* must copy - pwd memory is recycled */
+ shell = strncpy(shellbuf, pwd->pw_shell,
+ sizeof(shellbuf));
+ shellbuf[sizeof(shellbuf) - 1] = '\0';
+ }
+ else {
+ shell = _PATH_BSHELL;
+ iscsh = NO;
+ }
+ }
+
+ /* Do the whole PAM startup thing */
+ retcode = pam_start("su", user, &conv, &pamh);
+ if (retcode != PAM_SUCCESS) {
+ syslog(LOG_ERR, "pam_start: %s", pam_strerror(pamh, retcode));
+ errx(1, "pam_start: %s", pam_strerror(pamh, retcode));
+ }
+
+ PAM_SET_ITEM(PAM_RUSER, username);
+
+ mytty = ttyname(STDERR_FILENO);
+ if (!mytty)
+ mytty = "tty";
+ PAM_SET_ITEM(PAM_TTY, mytty);
+
+ retcode = pam_authenticate(pamh, 0);
+ if (retcode != PAM_SUCCESS) {
+#ifdef USE_BSM_AUDIT
+ if (audit_submit(AUE_su, auid, EPERM, 1, "bad su %s to %s on %s",
+ username, user, mytty))
+ errx(1, "Permission denied");
+#endif
+ syslog(LOG_AUTH|LOG_WARNING, "BAD SU %s to %s on %s",
+ username, user, mytty);
+ errx(1, "Sorry");
+ }
+#ifdef USE_BSM_AUDIT
+ if (audit_submit(AUE_su, auid, 0, 0, "successful authentication"))
+ errx(1, "Permission denied");
+#endif
+ retcode = pam_get_item(pamh, PAM_USER, &v);
+ if (retcode == PAM_SUCCESS)
+ user = v;
+ else
+ syslog(LOG_ERR, "pam_get_item(PAM_USER): %s",
+ pam_strerror(pamh, retcode));
+ pwd = getpwnam(user);
+ if (pwd == NULL) {
+#ifdef USE_BSM_AUDIT
+ if (audit_submit(AUE_su, auid, EPERM, 1,
+ "unknown subject: %s", user))
+ errx(1, "Permission denied");
+#endif
+ errx(1, "unknown login: %s", user);
+ }
+
+ retcode = pam_acct_mgmt(pamh, 0);
+ if (retcode == PAM_NEW_AUTHTOK_REQD) {
+ retcode = pam_chauthtok(pamh,
+ PAM_CHANGE_EXPIRED_AUTHTOK);
+ if (retcode != PAM_SUCCESS) {
+#ifdef USE_BSM_AUDIT
+ aerr = pam_strerror(pamh, retcode);
+ if (aerr == NULL)
+ aerr = "Unknown PAM error";
+ if (audit_submit(AUE_su, auid, EPERM, 1,
+ "pam_chauthtok: %s", aerr))
+ errx(1, "Permission denied");
+#endif
+ syslog(LOG_ERR, "pam_chauthtok: %s",
+ pam_strerror(pamh, retcode));
+ errx(1, "Sorry");
+ }
+ }
+ if (retcode != PAM_SUCCESS) {
+#ifdef USE_BSM_AUDIT
+ if (audit_submit(AUE_su, auid, EPERM, 1, "pam_acct_mgmt: %s",
+ pam_strerror(pamh, retcode)))
+ errx(1, "Permission denied");
+#endif
+ syslog(LOG_ERR, "pam_acct_mgmt: %s",
+ pam_strerror(pamh, retcode));
+ errx(1, "Sorry");
+ }
+
+#ifndef __APPLE__
+ /* get target login information */
+ if (class == NULL)
+ lc = login_getpwclass(pwd);
+ else {
+ if (ruid != 0) {
+#ifdef USE_BSM_AUDIT
+ if (audit_submit(AUE_su, auid, EPERM, 1,
+ "only root may use -c"))
+ errx(1, "Permission denied");
+#endif
+ errx(1, "only root may use -c");
+ }
+ lc = login_getclass(class);
+ if (lc == NULL)
+ errx(1, "unknown class: %s", class);
+ }
+#endif /* !__APPLE__ */
+
+ /* if asme and non-standard target shell, must be root */
+ if (asme) {
+ if (ruid != 0 && !chshell(pwd->pw_shell))
+ errx(1, "permission denied (shell)");
+ }
+ else if (pwd->pw_shell && *pwd->pw_shell) {
+#ifdef __APPLE__
+ /* 3825554 */
+ shell = strncpy(shellbuf, pwd->pw_shell, sizeof(shellbuf));
+ shellbuf[sizeof(shellbuf) - 1] = '\0';
+#else
+ shell = pwd->pw_shell;
+#endif /* __APPLE__ */
+ iscsh = UNSET;
+ }
+ else {
+ shell = _PATH_BSHELL;
+ iscsh = NO;
+ }
+
+ /* if we're forking a csh, we want to slightly muck the args */
+ if (iscsh == UNSET) {
+ p = strrchr(shell, '/');
+ if (p)
+ ++p;
+ else
+ p = shell;
+ iscsh = strcmp(p, "csh") ? (strcmp(p, "tcsh") ? NO : YES) : YES;
+ }
+ setpriority(PRIO_PROCESS, 0, prio);
+
+ /*
+ * PAM modules might add supplementary groups in pam_setcred(), so
+ * initialize them first.
+ */
+#ifdef __APPLE__
+ if (initgroups(user, pwd->pw_gid))
+ err(1, "initgroups");
+#else
+ if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETGROUP) < 0)
+ err(1, "setusercontext");
+#endif /* __APPLE__ */
+
+#ifdef __APPLE__
+ /* 8530846 */
+ if (asthem) {
+ auditinfo_addr_t auinfo = {
+ .ai_termid = { .at_type = AU_IPv4 },
+ .ai_asid = AU_ASSIGN_ASID,
+ .ai_auid = getuid(),
+ .ai_flags = 0,
+ };
+ if (setaudit_addr(&auinfo, sizeof(auinfo)) == 0) {
+ char session[16];
+ snprintf(session, sizeof(session), "%x", auinfo.ai_asid);
+ setenv("SECURITYSESSIONID", session, 1);
+ } else {
+ errx(1, "failed to create session.");
+ }
+ }
+#endif /* __APPLE__ */
+
+ retcode = pam_setcred(pamh, PAM_ESTABLISH_CRED);
+ if (retcode != PAM_SUCCESS) {
+ syslog(LOG_ERR, "pam_setcred: %s",
+ pam_strerror(pamh, retcode));
+ errx(1, "failed to establish credentials.");
+ }
+ if (asthem) {
+ retcode = pam_open_session(pamh, 0);
+ if (retcode != PAM_SUCCESS) {
+ syslog(LOG_ERR, "pam_open_session: %s",
+ pam_strerror(pamh, retcode));
+ errx(1, "failed to open session.");
+ }
+ }
+
+ /*
+ * We must fork() before setuid() because we need to call
+ * pam_setcred(pamh, PAM_DELETE_CRED) as root.
+ */
+ sa.sa_flags = SA_RESTART;
+ sa.sa_handler = SIG_IGN;
+ sigemptyset(&sa.sa_mask);
+ sigaction(SIGINT, &sa, &sa_int);
+ sigaction(SIGQUIT, &sa, &sa_quit);
+ sigaction(SIGPIPE, &sa, &sa_pipe);
+ sa.sa_handler = SIG_DFL;
+ sigaction(SIGTSTP, &sa, NULL);
+ statusp = 1;
+ if (pipe(fds) == -1) {
+ PAM_END();
+ err(1, "pipe");
+ }
+ child_pid = fork();
+ switch (child_pid) {
+ default:
+ sa.sa_handler = SIG_IGN;
+ sigaction(SIGTTOU, &sa, NULL);
+ close(fds[0]);
+ setpgid(child_pid, child_pid);
+ if (tcgetpgrp(STDERR_FILENO) == getpgrp())
+ tcsetpgrp(STDERR_FILENO, child_pid);
+ close(fds[1]);
+ sigaction(SIGPIPE, &sa_pipe, NULL);
+ while ((pid = waitpid(child_pid, &statusp, WUNTRACED)) != -1) {
+ if (WIFSTOPPED(statusp)) {
+ child_pgrp = getpgid(child_pid);
+ if (tcgetpgrp(STDERR_FILENO) == child_pgrp)
+ tcsetpgrp(STDERR_FILENO, getpgrp());
+ kill(getpid(), SIGSTOP);
+ if (tcgetpgrp(STDERR_FILENO) == getpgrp()) {
+ child_pgrp = getpgid(child_pid);
+ tcsetpgrp(STDERR_FILENO, child_pgrp);
+ }
+ kill(child_pid, SIGCONT);
+ statusp = 1;
+ continue;
+ }
+ break;
+ }
+ tcsetpgrp(STDERR_FILENO, getpgrp());
+ if (pid == -1)
+ err(1, "waitpid");
+ PAM_END();
+ exit(WEXITSTATUS(statusp));
+ case -1:
+ PAM_END();
+ err(1, "fork");
+ case 0:
+ close(fds[1]);
+ read(fds[0], &temp, 1);
+ close(fds[0]);
+ sigaction(SIGPIPE, &sa_pipe, NULL);
+ sigaction(SIGINT, &sa_int, NULL);
+ sigaction(SIGQUIT, &sa_quit, NULL);
+
+#ifdef __APPLE__
+ if (setgid(pwd->pw_gid))
+ err(1, "setgid");
+ /* Call initgroups(2) after setgid(2) to re-establish memberd */
+ if (initgroups(user, pwd->pw_gid))
+ err(1, "initgroups");
+ if (setuid(pwd->pw_uid))
+ err(1, "setuid");
+#else
+ /*
+ * Set all user context except for: Environmental variables
+ * Umask Login records (wtmp, etc) Path
+ */
+ setwhat = LOGIN_SETALL & ~(LOGIN_SETENV | LOGIN_SETUMASK |
+ LOGIN_SETLOGIN | LOGIN_SETPATH | LOGIN_SETGROUP |
+ LOGIN_SETMAC);
+ /*
+ * If -s is present, also set the MAC label.
+ */
+ if (setmaclabel)
+ setwhat |= LOGIN_SETMAC;
+ /*
+ * Don't touch resource/priority settings if -m has been used
+ * or -l and -c hasn't, and we're not su'ing to root.
+ */
+ if ((asme || (!asthem && class == NULL)) && pwd->pw_uid)
+ setwhat &= ~(LOGIN_SETPRIORITY | LOGIN_SETRESOURCES);
+ if (setusercontext(lc, pwd, pwd->pw_uid, setwhat) < 0)
+ err(1, "setusercontext");
+#endif /* __APPLE__ */
+
+ if (!asme) {
+ if (asthem) {
+ p = getenv("TERM");
+ environ = &cleanenv;
+ }
+
+ if (asthem || pwd->pw_uid)
+ setenv("USER", pwd->pw_name, 1);
+ setenv("HOME", pwd->pw_dir, 1);
+ setenv("SHELL", shell, 1);
+#ifdef __APPLE__
+ unsetenv("TMPDIR");
+#endif /* __APPLE__ */
+
+ if (asthem) {
+ /*
+ * Add any environmental variables that the
+ * PAM modules may have set.
+ */
+ environ_pam = pam_getenvlist(pamh);
+ if (environ_pam)
+ export_pam_environment();
+
+#ifdef __APPLE__
+ /* 5276965: As documented, set $PATH. */
+ setenv("PATH", "/bin:/usr/bin", 1);
+#else
+ /* set the su'd user's environment & umask */
+ setusercontext(lc, pwd, pwd->pw_uid,
+ LOGIN_SETPATH | LOGIN_SETUMASK |
+ LOGIN_SETENV);
+#endif /* __APPLE__ */
+ if (p)
+ setenv("TERM", p, 1);
+
+ p = pam_getenv(pamh, "HOME");
+ if (chdir(p ? p : pwd->pw_dir) < 0)
+ errx(1, "no directory");
+ }
+ }
+#ifndef __APPLE__
+ login_close(lc);
+#endif /* !__APPLE__ */
+
+ if (iscsh == YES) {
+ if (fastlogin)
+ *np.a-- = "-f";
+ if (asme)
+ *np.a-- = "-m";
+ }
+#ifdef __APPLE__
+ /* 4043304 */
+ if ((p = strrchr(shell, '/')) != NULL)
+ avshell = p + 1;
+ else
+ avshell = shell;
+
+ if (asthem) {
+ avshellbuf[0] = '-';
+ strlcpy(avshellbuf+1, avshell, sizeof(avshellbuf) - 1);
+ avshell = avshellbuf;
+ }
+
+ /* csh *no longer* strips the first character... */
+ *np.a = avshell;
+#else
+ /* csh strips the first character... */
+ *np.a = asthem ? "-su" : iscsh == YES ? "_su" : "su";
+#endif /* __APPLE__ */
+
+ if (ruid != 0)
+ syslog(LOG_NOTICE, "%s to %s%s", username, user,
+ ontty());
+
+ execv(shell, np.b);
+ err(1, "%s", shell);
+ }
+}
+
+static void
+export_pam_environment(void)
+{
+ char **pp;
+ char *p;
+
+ for (pp = environ_pam; *pp != NULL; pp++) {
+ if (ok_to_export(*pp)) {
+ p = strchr(*pp, '=');
+ *p = '\0';
+ setenv(*pp, p + 1, 1);
+ }
+ free(*pp);
+ }
+}
+
+/*
+ * Sanity checks on PAM environmental variables:
+ * - Make sure there is an '=' in the string.
+ * - Make sure the string doesn't run on too long.
+ * - Do not export certain variables. This list was taken from the
+ * Solaris pam_putenv(3) man page.
+ * Note that if the user is chrooted, PAM may have a better idea than we
+ * do of where her home directory is.
+ */
+static int
+ok_to_export(const char *s)
+{
+ static const char *noexport[] = {
+ "SHELL", /* "HOME", */ "LOGNAME", "MAIL", "CDPATH",
+ "IFS", "PATH", NULL
+ };
+ const char **pp;
+ size_t n;
+
+ if (strlen(s) > 1024 || strchr(s, '=') == NULL)
+ return 0;
+ if (strncmp(s, "LD_", 3) == 0)
+ return 0;
+ for (pp = noexport; *pp != NULL; pp++) {
+ n = strlen(*pp);
+ if (s[n] == '=' && strncmp(s, *pp, n) == 0)
+ return 0;
+ }
+ return 1;
+}
+
+static void
+usage(void)
+{
+
+#ifdef __APPLE__
+ fprintf(stderr, "usage: su [-] [-flm] [login [args]]\n");
+#else
+ fprintf(stderr, "usage: su [-] [-flms] [-c class] [login [args]]\n");
+#endif /* __APPLE__ */
+ exit(1);
+ /* NOTREACHED */
+}
+
+static int
+chshell(const char *sh)
+{
+ int r;
+ char *cp;
+
+ r = 0;
+ setusershell();
+ while ((cp = getusershell()) != NULL && !r)
+ r = (strcmp(cp, sh) == 0);
+ endusershell();
+ return r;
+}
+
+static char *
+ontty(void)
+{
+ char *p;
+ static char buf[MAXPATHLEN + 4];
+
+ buf[0] = 0;
+ p = ttyname(STDERR_FILENO);
+ if (p)
+ snprintf(buf, sizeof(buf), " on %s", p);
+ return buf;
+}
diff --git a/shell_cmds/su/su.pam b/shell_cmds/su/su.pam
new file mode 100644
index 0000000..fd8a789
--- /dev/null
+++ b/shell_cmds/su/su.pam
@@ -0,0 +1,7 @@
+# su: auth account session
+auth sufficient pam_rootok.so
+auth required pam_opendirectory.so
+account required pam_group.so no_warn group=admin,wheel ruser root_only fail_safe
+account required pam_opendirectory.so no_check_shell
+password required pam_opendirectory.so
+session required pam_launchd.so
diff --git a/shell_cmds/su/su_entitlements.plist b/shell_cmds/su/su_entitlements.plist
new file mode 100644
index 0000000..a96cb44
--- /dev/null
+++ b/shell_cmds/su/su_entitlements.plist
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>com.apple.keystore.console</key>
+ <true/>
+ <key>com.apple.private.security.clear-library-validation</key>
+ <true/>
+</dict>
+</plist>
diff --git a/shell_cmds/systime/systime.1 b/shell_cmds/systime/systime.1
new file mode 100644
index 0000000..ce296b6
--- /dev/null
+++ b/shell_cmds/systime/systime.1
@@ -0,0 +1,76 @@
+.Dd April 24, 2012
+.Dt systime 1
+.Os Darwin
+.Sh NAME
+.Nm systime
+.Nd gather system-wide time during program execution
+.Sh SYNOPSIS
+.Nm
+.Op Fl P
+.Op Fl r
+.Op Fl t Ar sleep_time
+.Ar utility Op Ar argument ...
+.Nm
+.Fl p
+.Op Fl r
+.Op Fl t Ar sleep_time
+.Nm
+.Op Fl P
+.Fl u Ar user
+.Fl s Ar sys
+.Fl i Ar idle
+.Nm
+.Op Fl P
+.Op Fl r
+.Op Fl t Ar sleep_time
+.Fl T Ar target_pid
+.Sh DESCRIPTION
+.Nm
+is similar to
+.Xr time 1
+in that it allows you to execute a utility program. However after execution
+completes, it reports the system-wide time that was spent
+during that time period, instead of just the portion directly caused
+by the utility. This can be used to gather information about CPU
+utilization by kernel threads (AIO, networking) and interrupt routines
+on behalf of a program, but not directly attributed to it.
+.Pp
+The
+.Nm
+program can also be used to snapshot counters with
+.Fl p
+and then later used with
+.Fl u Fl s Fl i
+to calculate time spent during a time interval that doesn't correlate
+to a specific command execution. For example:
+.Pp
+.Bd -ragged -offset indent
+$ eval `systime -p`
+.Pp
+$ ... time passes ...
+.Pp
+$ systime -u $systime_user -s $systime_sys -i $systime_idle
+.Pp
+18.79 real 2.03 user 1.04 sys
+.Ed
+.Pp
+The
+.Nm
+program can also be used to print the usage of a process with
+.Fl T Ar target_pid
+, also printing the system wide usage
+.Pp
+.Fl P
+can be used to print time spent as a percentage of overall CPU capacity
+of the system (capped at 100%)
+.Pp
+.Fl r
+can be used to print the usage iteratively with
+.Ar sleep_time
+seconds sleep between iterations
+.Pp
+.Fl t Ar sleep_time
+can be used to specify sleep_time between iterations, defaults to 1 second if not specified.
+.Sh SEE ALSO
+.Xr time 1 ,
+.Xr top 1
diff --git a/shell_cmds/systime/systime.c b/shell_cmds/systime/systime.c
new file mode 100644
index 0000000..37cee8b
--- /dev/null
+++ b/shell_cmds/systime/systime.c
@@ -0,0 +1,365 @@
+/*
+ * Copyright (c) 2012 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <mach/mach.h>
+#include <err.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <libproc.h>
+#include <mach/mach_time.h>
+
+static void usage(void);
+static void do_print(void);
+static void do_difftime(bool usepercent, uint64_t *olduser, uint64_t *oldsystem, uint64_t *oldidle);
+static void do_piddifftime(bool userpercent, int pid, uint64_t *old_pid_user, uint64_t *old_pid_system, uint64_t *old_pid_time);
+static kern_return_t get_processor_time(uint64_t *user, uint64_t *sys, uint64_t *idle);
+static kern_return_t get_processor_count(int *ncpu);
+static mach_timebase_info_data_t timebase_info;
+
+int
+main(int argc, char *argv[])
+{
+ int ch;
+ const char *optu = NULL;
+ const char *opts = NULL;
+ const char *opti = NULL;
+ const char *tpid = NULL;
+ const char *opt_sleep_time = NULL;
+ int sleep_time = 1;
+ int target_pid;
+ bool systemwide_time = false;
+ int pid;
+ int status;
+ uint64_t olduser, oldsystem, oldidle;
+ uint64_t old_pid_time;
+ uint64_t old_pid_user, old_pid_system;
+ kern_return_t kret;
+ bool usepercent = false;
+ bool recurring = false;
+
+ while ((ch = getopt(argc, argv, "PrT:t:pu:s:i:")) != -1) {
+ switch (ch) {
+ case 'P':
+ usepercent = true;
+ break;
+ case 'r':
+ recurring = true;
+ break;
+ case 't':
+ opt_sleep_time = optarg;
+ break;
+ case 'T':
+ tpid = optarg;
+ break;
+ case 'p':
+ systemwide_time = true;
+ break;
+ case 'u':
+ optu = optarg;
+ break;
+ case 's':
+ opts = optarg;
+ break;
+ case 'i':
+ opti = optarg;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ }
+
+ mach_timebase_info(&timebase_info);
+
+ if (opt_sleep_time) {
+ char *endstr;
+ sleep_time = (int)strtoul(opt_sleep_time, &endstr, 0);
+ if (opt_sleep_time[0] == '\0' || endstr[0] != '\0')
+ usage();
+ }
+
+ if (systemwide_time) {
+ bool first_pass = true;
+ olduser = oldsystem = oldidle = 0;
+
+ if (recurring != true) {
+ do_print();
+ exit(0);
+ }
+ do {
+ if (first_pass) {
+ do_difftime(false, &olduser, &oldsystem, &oldidle);
+ first_pass = false;
+ } else {
+ do_difftime(usepercent, &olduser, &oldsystem, &oldidle);
+ }
+ sleep(sleep_time);
+ } while (recurring);
+
+ exit(0);
+ }
+
+
+ if (tpid) {
+ char *endstr;
+ bool first_pass = true;
+
+ target_pid = (int)strtoul(tpid, &endstr, 0);
+ if (tpid[0] == '\0' || endstr[0] != '\0')
+ usage();
+
+ olduser = oldsystem = oldidle = 0;
+ old_pid_user = old_pid_system = old_pid_time = 0;
+
+ do {
+ if (first_pass) {
+ do_difftime(false, &olduser, &oldsystem, &oldidle);
+ do_piddifftime(false, target_pid, &old_pid_user, &old_pid_system, &old_pid_time);
+ first_pass = false;
+ } else {
+ do_difftime(usepercent, &olduser, &oldsystem, &oldidle);
+ do_piddifftime(usepercent, target_pid, &old_pid_user, &old_pid_system, &old_pid_time);
+ }
+
+ sleep(sleep_time);
+ } while (recurring);
+ exit(0);
+ }
+
+ if (optu || opts || opti) {
+ char *endstr;
+
+ if (!optu)
+ usage();
+ olduser = strtoull(optu, &endstr, 0);
+ if (optu[0] == '\0' || endstr[0] != '\0')
+ usage();
+
+ if (!opts)
+ usage();
+ oldsystem = strtoull(opts, &endstr, 0);
+ if (opts[0] == '\0' || endstr[0] != '\0')
+ usage();
+
+ if (!opti)
+ usage();
+ oldidle = strtoull(opti, &endstr, 0);
+ if (opti[0] == '\0' || endstr[0] != '\0')
+ usage();
+
+ do_difftime(usepercent, &olduser, &oldsystem, &oldidle);
+ exit(0);
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc == 0)
+ usage();
+
+ do {
+ kret = get_processor_time(&olduser, &oldsystem, &oldidle);
+ if (kret)
+ errx(1, "Error getting processor time: %s (%d)", mach_error_string(kret), kret);
+
+ switch(pid = vfork()) {
+ case -1: /* error */
+ perror("time");
+ exit(1);
+ /* NOTREACHED */
+ case 0: /* child */
+ execvp(*argv, argv);
+ perror(*argv);
+ _exit((errno == ENOENT) ? 127 : 126);
+ /* NOTREACHED */
+ }
+
+ /* parent */
+ (void)signal(SIGINT, SIG_IGN);
+ (void)signal(SIGQUIT, SIG_IGN);
+ while (wait(&status) != pid);
+ (void)signal(SIGINT, SIG_DFL);
+ (void)signal(SIGQUIT, SIG_DFL);
+
+ do_difftime(usepercent, &olduser, &oldsystem, &oldidle);
+
+ sleep(sleep_time);
+ } while (recurring);
+
+ exit (WIFEXITED(status) ? WEXITSTATUS(status) : EXIT_FAILURE);
+
+ return 0;
+}
+
+static void
+usage(void)
+{
+ fprintf(stderr, "usage: systime [-P] [-r] [-t sleep_time] utility [argument ...]\n"
+ " systime -p [-r] [-t sleep_time]\n"
+ " systime [-P] -u user -s sys -i idle\n"
+ " systime [-P] [-r] [-t sleep_time] -T target_pid\n");
+ exit(1);
+}
+
+static void
+do_print(void)
+{
+ uint64_t user, system, idle;
+ kern_return_t kret;
+
+ kret = get_processor_time(&user, &system, &idle);
+ if (kret)
+ errx(1, "Error getting processor time: %s (%d)", mach_error_string(kret), kret);
+
+ printf("systime_user=%llu\n", user);
+ printf("systime_sys=%llu\n", system);
+ printf("systime_idle=%llu\n", idle);
+}
+
+static void
+do_difftime(bool usepercent, uint64_t *olduser, uint64_t *oldsystem, uint64_t *oldidle)
+{
+ uint64_t user, system, idle;
+ uint64_t userelapsed, systemelapsed, idleelapsed, totalelapsed;
+ kern_return_t kret;
+
+ kret = get_processor_time(&user, &system, &idle);
+ if (kret)
+ errx(1, "Error getting processor time: %s (%d)", mach_error_string(kret), kret);
+
+ userelapsed = user - *olduser;
+ systemelapsed = system - *oldsystem;
+ idleelapsed = idle - *oldidle;
+ totalelapsed = userelapsed + systemelapsed + idleelapsed;
+
+ if (usepercent) {
+ fprintf(stderr, "%1.02f%% user %1.02f%% sys %1.02f%% idle\n",
+ ((double)userelapsed * 100)/totalelapsed,
+ ((double)systemelapsed * 100)/totalelapsed,
+ ((double)idleelapsed * 100)/totalelapsed);
+ } else {
+ int ncpu;
+
+ kret = get_processor_count(&ncpu);
+ if (kret)
+ errx(1, "Error getting processor count: %s (%d)", mach_error_string(kret), kret);
+
+ fprintf(stderr, "%1.02f real %1.02f user %1.02f sys\n",
+ ((double)totalelapsed) / 1000 /* ms per sec */ / ncpu,
+ ((double)userelapsed) / 1000,
+ ((double)systemelapsed) / 1000);
+ }
+ *olduser = user;
+ *oldsystem = system;
+ *oldidle = idle;
+}
+
+static void
+do_piddifftime(bool usepercent, int pid, uint64_t *old_pid_user, uint64_t *old_pid_system, uint64_t *old_pid_time)
+{
+ uint64_t pid_user, pid_system, pid_time;
+ uint64_t userelapsed, systemelapsed, totalelapsed;
+ struct proc_taskinfo info;
+ int size;
+
+ size = proc_pidinfo(pid, PROC_PIDTASKINFO, 0, &info, sizeof(info));
+ if (size == PROC_PIDTASKINFO_SIZE) {
+ pid_user = info.pti_total_user;
+ pid_system = info.pti_total_system;
+ } else {
+ fprintf(stderr, "Error in proc_pidinfo(): %s",
+ strerror(errno));
+ exit(1);
+ }
+
+ pid_time = mach_absolute_time();
+
+ userelapsed = pid_user - *old_pid_user;
+ systemelapsed = pid_system - *old_pid_system;
+ totalelapsed = pid_time - *old_pid_time;
+
+ if (usepercent) {
+ fprintf(stderr, "Pid %d: %1.02f%% user %1.02f%% sys\n",
+ pid,
+ ((double)userelapsed * 100)/totalelapsed,
+ ((double)systemelapsed * 100)/totalelapsed);
+ } else {
+ fprintf(stderr, "Pid %d: %1.02f user %1.02f sys\n",
+ pid,
+ (((double)userelapsed) * timebase_info.numer / timebase_info.denom) / 1000000000,
+ (((double)systemelapsed) * timebase_info.numer / timebase_info.denom) / 1000000000);
+ }
+
+ *old_pid_user = pid_user;
+ *old_pid_system = pid_system;
+ *old_pid_time = pid_time;
+
+}
+
+static kern_return_t
+get_processor_time(uint64_t *user, uint64_t *sys, uint64_t *idle)
+{
+ host_name_port_t host;
+ kern_return_t kret;
+ host_cpu_load_info_data_t host_load;
+ mach_msg_type_number_t count;
+
+ host = mach_host_self();
+
+ count = HOST_CPU_LOAD_INFO_COUNT;
+
+ kret = host_statistics(host, HOST_CPU_LOAD_INFO, (host_info_t)&host_load, &count);
+ if (kret)
+ return kret;
+
+ *user = ((uint64_t)host_load.cpu_ticks[CPU_STATE_USER]) * 10 /* ms per tick */;
+ *sys = ((uint64_t)host_load.cpu_ticks[CPU_STATE_SYSTEM]) * 10;
+ *idle = ((uint64_t)host_load.cpu_ticks[CPU_STATE_IDLE]) * 10;
+
+ return KERN_SUCCESS;
+}
+
+static kern_return_t
+get_processor_count(int *ncpu)
+{
+ host_name_port_t host;
+ kern_return_t kret;
+ host_basic_info_data_t hi;
+ mach_msg_type_number_t count;
+
+ host = mach_host_self();
+
+ count = HOST_BASIC_INFO_COUNT;
+
+ kret = host_info(host, HOST_BASIC_INFO, (host_info_t)&hi, &count);
+ if (kret)
+ return kret;
+
+ *ncpu = hi.avail_cpus;
+
+ return KERN_SUCCESS;
+}
diff --git a/shell_cmds/tee/tee.1 b/shell_cmds/tee/tee.1
new file mode 100644
index 0000000..19d2d40
--- /dev/null
+++ b/shell_cmds/tee/tee.1
@@ -0,0 +1,90 @@
+.\" $NetBSD: tee.1,v 1.5 1997/10/20 00:37:11 lukem Exp $
+.\"
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)tee.1 8.1 (Berkeley) 6/6/93
+.\"
+.Dd June 6, 1993
+.Dt TEE 1
+.Os
+.Sh NAME
+.Nm tee
+.Nd pipe fitting
+.Sh SYNOPSIS
+.Nm
+.Op Fl ai
+.Op Ar file ...
+.Sh DESCRIPTION
+The
+.Nm
+utility copies standard input to standard output,
+making a copy in zero or more files.
+The output is unbuffered.
+.Pp
+The following options are available:
+.Bl -tag -width Ds
+.It Fl a
+Append the output to the files rather than
+overwriting them.
+.It Fl i
+Ignore the
+.Dv SIGINT
+signal.
+.El
+.Pp
+The following operands are available:
+.Bl -tag -width file
+.It file
+A pathname of an output
+.Ar file .
+.El
+.Pp
+The
+.Nm
+utility takes the default action for all signals,
+except in the event of the
+.Fl i
+option.
+.Pp
+The
+.Nm
+utility exits 0 on success, and >0 if an error occurs.
+.Sh STANDARDS
+The
+.Nm
+function is expected to be
+.Tn POSIX
+.St -p1003.2
+compatible.
diff --git a/shell_cmds/tee/tee.c b/shell_cmds/tee/tee.c
new file mode 100644
index 0000000..e916d90
--- /dev/null
+++ b/shell_cmds/tee/tee.c
@@ -0,0 +1,156 @@
+/* $NetBSD: tee.c,v 1.6 1997/10/20 00:37:11 lukem Exp $ */
+
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1988, 1993\n\
+ The Regents of the University of California. All rights reserved.\n");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)tee.c 8.1 (Berkeley) 6/6/93";
+#endif
+__RCSID("$NetBSD: tee.c,v 1.6 1997/10/20 00:37:11 lukem Exp $");
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <locale.h>
+#include <err.h>
+
+typedef struct _list {
+ struct _list *next;
+ int fd;
+ char *name;
+} LIST;
+LIST *head;
+
+void add __P((int, char *));
+int main __P((int, char **));
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ LIST *p;
+ int n, fd, rval, wval;
+ char *bp;
+ int append, ch, exitval;
+ char *buf;
+#define BSIZE (8 * 1024)
+
+ setlocale(LC_ALL, "");
+
+ append = 0;
+ while ((ch = getopt(argc, argv, "ai")) != -1)
+ switch((char)ch) {
+ case 'a':
+ append = 1;
+ break;
+ case 'i':
+ (void)signal(SIGINT, SIG_IGN);
+ break;
+ case '?':
+ default:
+ (void)fprintf(stderr, "usage: tee [-ai] [file ...]\n");
+ exit(1);
+ }
+ argv += optind;
+ argc -= optind;
+
+ if ((buf = malloc((size_t)BSIZE)) == NULL)
+ err(1, "malloc");
+
+ add(STDOUT_FILENO, "stdout");
+
+ for (exitval = 0; *argv; ++argv)
+ if ((fd = open(*argv, append ? O_WRONLY|O_CREAT|O_APPEND :
+ O_WRONLY|O_CREAT|O_TRUNC, DEFFILEMODE)) < 0) {
+ warn("%s", *argv);
+ exitval = 1;
+ } else
+ add(fd, *argv);
+
+ while ((rval = read(STDIN_FILENO, buf, BSIZE)) > 0)
+ for (p = head; p; p = p->next) {
+ n = rval;
+ bp = buf;
+ do {
+ if ((wval = write(p->fd, bp, n)) == -1) {
+ warn("%s", p->name);
+ exitval = 1;
+ break;
+ }
+ bp += wval;
+ } while (n -= wval);
+ }
+ if (rval < 0) {
+ warn("read");
+ exitval = 1;
+ }
+
+ for (p = head; p; p = p->next) {
+ if (close(p->fd) == -1) {
+ warn("%s", p->name);
+ exitval = 1;
+ }
+ }
+
+ exit(exitval);
+}
+
+void
+add(fd, name)
+ int fd;
+ char *name;
+{
+ LIST *p;
+
+ if ((p = malloc((size_t)sizeof(LIST))) == NULL)
+ err(1, "malloc");
+ p->fd = fd;
+ p->name = name;
+ p->next = head;
+ head = p;
+}
diff --git a/shell_cmds/test/[.1 b/shell_cmds/test/[.1
new file mode 100644
index 0000000..84e0568
--- /dev/null
+++ b/shell_cmds/test/[.1
@@ -0,0 +1 @@
+.so man1/test.1
diff --git a/shell_cmds/test/test.1 b/shell_cmds/test/test.1
new file mode 100644
index 0000000..136ee57
--- /dev/null
+++ b/shell_cmds/test/test.1
@@ -0,0 +1,390 @@
+.\"-
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)test.1 8.1 (Berkeley) 5/31/93
+.\" $FreeBSD$
+.\"
+.Dd June 1, 2013
+.Dt TEST 1
+.Os
+.Sh NAME
+.Nm test ,
+.Nm \&[
+.Nd condition evaluation utility
+.Sh SYNOPSIS
+.Nm
+.Ar expression
+.Nm \&[
+.Ar expression Cm \&]
+.Sh DESCRIPTION
+The
+.Nm
+utility evaluates the expression and, if it evaluates
+to true, returns a zero (true) exit status; otherwise
+it returns 1 (false).
+If there is no expression,
+.Nm
+also
+returns 1 (false).
+.Pp
+All operators and flags are separate arguments to the
+.Nm
+utility.
+.Pp
+The following primaries are used to construct expression:
+.Bl -tag -width Ar
+.It Fl b Ar file
+True if
+.Ar file
+exists and is a block special
+file.
+.It Fl c Ar file
+True if
+.Ar file
+exists and is a character
+special file.
+.It Fl d Ar file
+True if
+.Ar file
+exists and is a directory.
+.It Fl e Ar file
+True if
+.Ar file
+exists (regardless of type).
+.It Fl f Ar file
+True if
+.Ar file
+exists and is a regular file.
+.It Fl g Ar file
+True if
+.Ar file
+exists and its set group ID flag
+is set.
+.It Fl h Ar file
+True if
+.Ar file
+exists and is a symbolic link.
+This operator is retained for compatibility with previous versions of
+this program.
+Do not rely on its existence; use
+.Fl L
+instead.
+.It Fl k Ar file
+True if
+.Ar file
+exists and its sticky bit is set.
+.It Fl n Ar string
+True if the length of
+.Ar string
+is nonzero.
+.It Fl p Ar file
+True if
+.Ar file
+is a named pipe
+.Pq Tn FIFO .
+.It Fl r Ar file
+True if
+.Ar file
+exists and is readable.
+.It Fl s Ar file
+True if
+.Ar file
+exists and has a size greater
+than zero.
+.It Fl t Ar file_descriptor
+True if the file whose file descriptor number
+is
+.Ar file_descriptor
+is open and is associated with a terminal.
+.It Fl u Ar file
+True if
+.Ar file
+exists and its set user ID flag
+is set.
+.It Fl w Ar file
+True if
+.Ar file
+exists and is writable.
+True
+indicates only that the write flag is on.
+The file is not writable on a read-only file
+system even if this test indicates true.
+.It Fl x Ar file
+True if
+.Ar file
+exists and is executable.
+True
+indicates only that the execute flag is on.
+If
+.Ar file
+is a directory, true indicates that
+.Ar file
+can be searched.
+.It Fl z Ar string
+True if the length of
+.Ar string
+is zero.
+.It Fl L Ar file
+True if
+.Ar file
+exists and is a symbolic link.
+.It Fl O Ar file
+True if
+.Ar file
+exists and its owner matches the effective user id of this process.
+.It Fl G Ar file
+True if
+.Ar file
+exists and its group matches the effective group id of this process.
+.It Fl S Ar file
+True if
+.Ar file
+exists and is a socket.
+.It Ar file1 Fl nt Ar file2
+True if
+.Ar file1
+exists and is newer than
+.Ar file2 .
+.It Ar file1 Fl ot Ar file2
+True if
+.Ar file1
+exists and is older than
+.Ar file2 .
+.It Ar file1 Fl ef Ar file2
+True if
+.Ar file1
+and
+.Ar file2
+exist and refer to the same file.
+.It Ar string
+True if
+.Ar string
+is not the null
+string.
+.It Ar s1 Cm = Ar s2
+True if the strings
+.Ar s1
+and
+.Ar s2
+are identical.
+.It Ar s1 Cm != Ar s2
+True if the strings
+.Ar s1
+and
+.Ar s2
+are not identical.
+.It Ar s1 Cm < Ar s2
+True if string
+.Ar s1
+comes before
+.Ar s2
+based on the binary value of their characters.
+.It Ar s1 Cm > Ar s2
+True if string
+.Ar s1
+comes after
+.Ar s2
+based on the binary value of their characters.
+.It Ar n1 Fl eq Ar n2
+True if the integers
+.Ar n1
+and
+.Ar n2
+are algebraically
+equal.
+.It Ar n1 Fl ne Ar n2
+True if the integers
+.Ar n1
+and
+.Ar n2
+are not
+algebraically equal.
+.It Ar n1 Fl gt Ar n2
+True if the integer
+.Ar n1
+is algebraically
+greater than the integer
+.Ar n2 .
+.It Ar n1 Fl ge Ar n2
+True if the integer
+.Ar n1
+is algebraically
+greater than or equal to the integer
+.Ar n2 .
+.It Ar n1 Fl lt Ar n2
+True if the integer
+.Ar n1
+is algebraically less
+than the integer
+.Ar n2 .
+.It Ar n1 Fl le Ar n2
+True if the integer
+.Ar n1
+is algebraically less
+than or equal to the integer
+.Ar n2 .
+.El
+.Pp
+If
+.Ar file
+is a symbolic link,
+.Nm
+will fully dereference it and then evaluate the expression
+against the file referenced, except for the
+.Fl h
+and
+.Fl L
+primaries.
+.Pp
+These primaries can be combined with the following operators:
+.Bl -tag -width Ar
+.It Cm \&! Ar expression
+True if
+.Ar expression
+is false.
+.It Ar expression1 Fl a Ar expression2
+True if both
+.Ar expression1
+and
+.Ar expression2
+are true.
+.It Ar expression1 Fl o Ar expression2
+True if either
+.Ar expression1
+or
+.Ar expression2
+are true.
+.It Cm \&( Ar expression Cm \&)
+True if expression is true.
+.El
+.Pp
+The
+.Fl a
+operator has higher precedence than the
+.Fl o
+operator.
+.Pp
+Some shells may provide a builtin
+.Nm
+command which is similar or identical to this utility.
+Consult the
+.Xr builtin 1
+manual page.
+.Sh GRAMMAR AMBIGUITY
+The
+.Nm
+grammar is inherently ambiguous.
+In order to assure a degree of consistency,
+the cases described in the
+.St -p1003.2 ,
+section D11.2/4.62.4, standard
+are evaluated consistently according to the rules specified in the
+standards document.
+All other cases are subject to the ambiguity in the
+command semantics.
+.Pp
+In particular, only expressions containing
+.Fl a ,
+.Fl o ,
+.Cm \&(
+or
+.Cm \&)
+can be ambiguous.
+.Sh EXIT STATUS
+The
+.Nm
+utility exits with one of the following values:
+.Bl -tag -width indent
+.It 0
+expression evaluated to true.
+.It 1
+expression evaluated to false or expression was
+missing.
+.It >1
+An error occurred.
+.El
+.Sh EXAMPLES
+Implement
+.Li test FILE1 -nt FILE2
+using only
+.Tn POSIX
+functionality:
+.Pp
+.Dl test -n \&"$(find -L -- FILE1 -prune -newer FILE2 2>/dev/null)\&"
+.Pp
+This can be modified using non-standard
+.Xr find 1
+primaries like
+.Cm -newerca
+to compare other timestamps.
+.Sh COMPATIBILITY
+For compatibility with some other implementations,
+the
+.Cm =
+primary can be substituted with
+.Cm ==
+with the same meaning.
+.Sh SEE ALSO
+.Xr builtin 1 ,
+.Xr expr 1 ,
+.Xr find 1 ,
+.Xr sh 1 ,
+.Xr stat 1 ,
+.Xr symlink 7
+.Sh STANDARDS
+The
+.Nm
+utility implements a superset of the
+.St -p1003.2
+specification.
+The primaries
+.Cm < ,
+.Cm == ,
+.Cm > ,
+.Fl ef ,
+.Fl nt ,
+.Fl ot ,
+.Fl G ,
+and
+.Fl O
+are extensions.
+.Sh BUGS
+Both sides are always evaluated in
+.Fl a
+and
+.Fl o .
+For instance, the writable status of
+.Pa file
+will be tested by the following command even though the former expression
+indicated false, which results in a gratuitous access to the file system:
+.Dl "[ -z abc -a -w file ]"
+To avoid this, write
+.Dl "[ -z abc ] && [ -w file ]"
diff --git a/shell_cmds/test/test.c b/shell_cmds/test/test.c
new file mode 100644
index 0000000..14bd3a3
--- /dev/null
+++ b/shell_cmds/test/test.c
@@ -0,0 +1,611 @@
+/* $NetBSD: test.c,v 1.21 1999/04/05 09:48:38 kleink Exp $ */
+
+/*-
+ * test(1); version 7-like -- author Erik Baalbergen
+ * modified by Eric Gisin to be used as built-in.
+ * modified by Arnold Robbins to add SVR3 compatibility
+ * (-x -c -b -p -u -g -k) plus Korn's -L -nt -ot -ef and new -S (socket).
+ * modified by J.T. Conklin for NetBSD.
+ *
+ * This program is in the Public Domain.
+ */
+/*
+ * Important: This file is used both as a standalone program /bin/test and
+ * as a builtin for /bin/sh (#define SHELL).
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#ifdef __APPLE__
+#include <fcntl.h>
+#endif /* __APPLE__ */
+#include <inttypes.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifdef __APPLE__
+#define eaccess(path, mode) faccessat(AT_FDCWD, path, mode, AT_EACCESS)
+#define st_mtim st_mtimespec
+#endif /* __APPLE__ */
+
+#ifdef SHELL
+#define main testcmd
+#include "bltin/bltin.h"
+#else
+#include <locale.h>
+
+static void error(const char *, ...) __dead2 __printf0like(1, 2);
+
+static void
+error(const char *msg, ...)
+{
+ va_list ap;
+ va_start(ap, msg);
+ verrx(2, msg, ap);
+ /*NOTREACHED*/
+ va_end(ap);
+}
+#endif
+
+/* test(1) accepts the following grammar:
+ oexpr ::= aexpr | aexpr "-o" oexpr ;
+ aexpr ::= nexpr | nexpr "-a" aexpr ;
+ nexpr ::= primary | "!" primary
+ primary ::= unary-operator operand
+ | operand binary-operator operand
+ | operand
+ | "(" oexpr ")"
+ ;
+ unary-operator ::= "-r"|"-w"|"-x"|"-f"|"-d"|"-c"|"-b"|"-p"|
+ "-u"|"-g"|"-k"|"-s"|"-t"|"-z"|"-n"|"-o"|"-O"|"-G"|"-L"|"-S";
+
+ binary-operator ::= "="|"!="|"-eq"|"-ne"|"-ge"|"-gt"|"-le"|"-lt"|
+ "-nt"|"-ot"|"-ef";
+ operand ::= <any legal UNIX file name>
+*/
+
+enum token_types {
+ UNOP = 0x100,
+ BINOP = 0x200,
+ BUNOP = 0x300,
+ BBINOP = 0x400,
+ PAREN = 0x500
+};
+
+enum token {
+ EOI,
+ OPERAND,
+ FILRD = UNOP + 1,
+ FILWR,
+ FILEX,
+ FILEXIST,
+ FILREG,
+ FILDIR,
+ FILCDEV,
+ FILBDEV,
+ FILFIFO,
+ FILSOCK,
+ FILSYM,
+ FILGZ,
+ FILTT,
+ FILSUID,
+ FILSGID,
+ FILSTCK,
+ STREZ,
+ STRNZ,
+ FILUID,
+ FILGID,
+ FILNT = BINOP + 1,
+ FILOT,
+ FILEQ,
+ STREQ,
+ STRNE,
+ STRLT,
+ STRGT,
+ INTEQ,
+ INTNE,
+ INTGE,
+ INTGT,
+ INTLE,
+ INTLT,
+ UNOT = BUNOP + 1,
+ BAND = BBINOP + 1,
+ BOR,
+ LPAREN = PAREN + 1,
+ RPAREN
+};
+
+#define TOKEN_TYPE(token) ((token) & 0xff00)
+
+static struct t_op {
+ char op_text[4];
+ short op_num;
+} const ops [] = {
+ {"-r", FILRD},
+ {"-w", FILWR},
+ {"-x", FILEX},
+ {"-e", FILEXIST},
+ {"-f", FILREG},
+ {"-d", FILDIR},
+ {"-c", FILCDEV},
+ {"-b", FILBDEV},
+ {"-p", FILFIFO},
+ {"-u", FILSUID},
+ {"-g", FILSGID},
+ {"-k", FILSTCK},
+ {"-s", FILGZ},
+ {"-t", FILTT},
+ {"-z", STREZ},
+ {"-n", STRNZ},
+ {"-h", FILSYM}, /* for backwards compat */
+ {"-O", FILUID},
+ {"-G", FILGID},
+ {"-L", FILSYM},
+ {"-S", FILSOCK},
+ {"=", STREQ},
+ {"==", STREQ},
+ {"!=", STRNE},
+ {"<", STRLT},
+ {">", STRGT},
+ {"-eq", INTEQ},
+ {"-ne", INTNE},
+ {"-ge", INTGE},
+ {"-gt", INTGT},
+ {"-le", INTLE},
+ {"-lt", INTLT},
+ {"-nt", FILNT},
+ {"-ot", FILOT},
+ {"-ef", FILEQ},
+ {"!", UNOT},
+ {"-a", BAND},
+ {"-o", BOR},
+ {"(", LPAREN},
+ {")", RPAREN},
+ {"", 0}
+};
+
+static int nargc;
+static char **t_wp;
+static int parenlevel;
+
+static int aexpr(enum token);
+static int binop(enum token);
+static int equalf(const char *, const char *);
+static int filstat(char *, enum token);
+static int getn(const char *);
+static intmax_t getq(const char *);
+static int intcmp(const char *, const char *);
+static int isunopoperand(void);
+static int islparenoperand(void);
+static int isrparenoperand(void);
+static int newerf(const char *, const char *);
+static int nexpr(enum token);
+static int oexpr(enum token);
+static int olderf(const char *, const char *);
+static int primary(enum token);
+static void syntax(const char *, const char *);
+static enum token t_lex(char *);
+
+int
+main(int argc, char **argv)
+{
+ int res;
+ char *p;
+
+ /* radar:4689479 */
+ if (argc == 0)
+ return 1;
+
+ if ((p = strrchr(argv[0], '/')) == NULL)
+ p = argv[0];
+ else
+ p++;
+ if (strcmp(p, "[") == 0) {
+ if (strcmp(argv[--argc], "]") != 0)
+ error("missing ]");
+ argv[argc] = NULL;
+ }
+
+ /* no expression => false */
+ if (--argc <= 0)
+ return 1;
+
+#ifndef SHELL
+ (void)setlocale(LC_CTYPE, "");
+#endif
+ nargc = argc;
+ t_wp = &argv[1];
+ parenlevel = 0;
+ if (nargc == 4 && strcmp(*t_wp, "!") == 0) {
+ /* Things like ! "" -o x do not fit in the normal grammar. */
+ --nargc;
+ ++t_wp;
+ res = oexpr(t_lex(*t_wp));
+ } else
+ res = !oexpr(t_lex(*t_wp));
+
+ if (--nargc > 0)
+ syntax(*t_wp, "unexpected operator");
+
+ return res;
+}
+
+static void
+syntax(const char *op, const char *msg)
+{
+
+ if (op && *op)
+ error("%s: %s", op, msg);
+ else
+ error("%s", msg);
+}
+
+static int
+oexpr(enum token n)
+{
+ int res;
+
+ res = aexpr(n);
+ if (t_lex(nargc > 0 ? (--nargc, *++t_wp) : NULL) == BOR)
+ return oexpr(t_lex(nargc > 0 ? (--nargc, *++t_wp) : NULL)) ||
+ res;
+ t_wp--;
+ nargc++;
+ return res;
+}
+
+static int
+aexpr(enum token n)
+{
+ int res;
+
+ res = nexpr(n);
+ if (t_lex(nargc > 0 ? (--nargc, *++t_wp) : NULL) == BAND)
+ return aexpr(t_lex(nargc > 0 ? (--nargc, *++t_wp) : NULL)) &&
+ res;
+ t_wp--;
+ nargc++;
+ return res;
+}
+
+static int
+nexpr(enum token n)
+{
+ if (n == UNOT)
+ return !nexpr(t_lex(nargc > 0 ? (--nargc, *++t_wp) : NULL));
+ return primary(n);
+}
+
+static int
+primary(enum token n)
+{
+ enum token nn;
+ int res;
+
+ if (n == EOI)
+ return 0; /* missing expression */
+ if (n == LPAREN) {
+ parenlevel++;
+ if ((nn = t_lex(nargc > 0 ? (--nargc, *++t_wp) : NULL)) ==
+ RPAREN) {
+ parenlevel--;
+ return 0; /* missing expression */
+ }
+ res = oexpr(nn);
+ if (t_lex(nargc > 0 ? (--nargc, *++t_wp) : NULL) != RPAREN)
+ syntax(NULL, "closing paren expected");
+ parenlevel--;
+ return res;
+ }
+ if (TOKEN_TYPE(n) == UNOP) {
+ /* unary expression */
+ if (--nargc == 0)
+ syntax(NULL, "argument expected"); /* impossible */
+ switch (n) {
+ case STREZ:
+ return strlen(*++t_wp) == 0;
+ case STRNZ:
+ return strlen(*++t_wp) != 0;
+ case FILTT:
+ return isatty(getn(*++t_wp));
+ default:
+ return filstat(*++t_wp, n);
+ }
+ }
+
+ nn = t_lex(nargc > 0 ? t_wp[1] : NULL);
+ if (TOKEN_TYPE(nn) == BINOP)
+ return binop(nn);
+
+ return strlen(*t_wp) > 0;
+}
+
+static int
+binop(enum token n)
+{
+ const char *opnd1, *op, *opnd2;
+
+ opnd1 = *t_wp;
+ op = nargc > 0 ? (--nargc, *++t_wp) : NULL;
+
+ if ((opnd2 = nargc > 0 ? (--nargc, *++t_wp) : NULL) == NULL)
+ syntax(op, "argument expected");
+
+ switch (n) {
+ case STREQ:
+ return strcmp(opnd1, opnd2) == 0;
+ case STRNE:
+ return strcmp(opnd1, opnd2) != 0;
+ case STRLT:
+ return strcmp(opnd1, opnd2) < 0;
+ case STRGT:
+ return strcmp(opnd1, opnd2) > 0;
+ case INTEQ:
+ return intcmp(opnd1, opnd2) == 0;
+ case INTNE:
+ return intcmp(opnd1, opnd2) != 0;
+ case INTGE:
+ return intcmp(opnd1, opnd2) >= 0;
+ case INTGT:
+ return intcmp(opnd1, opnd2) > 0;
+ case INTLE:
+ return intcmp(opnd1, opnd2) <= 0;
+ case INTLT:
+ return intcmp(opnd1, opnd2) < 0;
+ case FILNT:
+ return newerf (opnd1, opnd2);
+ case FILOT:
+ return olderf (opnd1, opnd2);
+ case FILEQ:
+ return equalf (opnd1, opnd2);
+ default:
+ abort();
+ /* NOTREACHED */
+ }
+}
+
+static int
+filstat(char *nm, enum token mode)
+{
+ struct stat s;
+
+ if (mode == FILSYM ? lstat(nm, &s) : stat(nm, &s))
+ return 0;
+
+ switch (mode) {
+ case FILRD:
+ return (eaccess(nm, R_OK) == 0);
+ case FILWR:
+ return (eaccess(nm, W_OK) == 0);
+ case FILEX:
+ /* XXX work around eaccess(2) false positives for superuser */
+ if (eaccess(nm, X_OK) != 0)
+ return 0;
+ if (S_ISDIR(s.st_mode) || geteuid() != 0)
+ return 1;
+ return (s.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0;
+ case FILEXIST:
+ return (eaccess(nm, F_OK) == 0);
+ case FILREG:
+ return S_ISREG(s.st_mode);
+ case FILDIR:
+ return S_ISDIR(s.st_mode);
+ case FILCDEV:
+ return S_ISCHR(s.st_mode);
+ case FILBDEV:
+ return S_ISBLK(s.st_mode);
+ case FILFIFO:
+ return S_ISFIFO(s.st_mode);
+ case FILSOCK:
+ return S_ISSOCK(s.st_mode);
+ case FILSYM:
+ return S_ISLNK(s.st_mode);
+ case FILSUID:
+ return (s.st_mode & S_ISUID) != 0;
+ case FILSGID:
+ return (s.st_mode & S_ISGID) != 0;
+ case FILSTCK:
+ return (s.st_mode & S_ISVTX) != 0;
+ case FILGZ:
+ return s.st_size > (off_t)0;
+ case FILUID:
+ return s.st_uid == geteuid();
+ case FILGID:
+ return s.st_gid == getegid();
+ default:
+ return 1;
+ }
+}
+
+static enum token
+t_lex(char *s)
+{
+ struct t_op const *op = ops;
+
+ if (s == 0) {
+ return EOI;
+ }
+ while (*op->op_text) {
+ if (strcmp(s, op->op_text) == 0) {
+ if (((TOKEN_TYPE(op->op_num) == UNOP ||
+ TOKEN_TYPE(op->op_num) == BUNOP)
+ && isunopoperand()) ||
+ (op->op_num == LPAREN && islparenoperand()) ||
+ (op->op_num == RPAREN && isrparenoperand()))
+ break;
+ return op->op_num;
+ }
+ op++;
+ }
+ return OPERAND;
+}
+
+static int
+isunopoperand(void)
+{
+ struct t_op const *op = ops;
+ char *s;
+ char *t;
+
+ if (nargc == 1)
+ return 1;
+ s = *(t_wp + 1);
+ if (nargc == 2)
+ return parenlevel == 1 && strcmp(s, ")") == 0;
+ t = *(t_wp + 2);
+ while (*op->op_text) {
+ if (strcmp(s, op->op_text) == 0)
+ return TOKEN_TYPE(op->op_num) == BINOP &&
+ (parenlevel == 0 || t[0] != ')' || t[1] != '\0');
+ op++;
+ }
+ return 0;
+}
+
+static int
+islparenoperand(void)
+{
+ struct t_op const *op = ops;
+ char *s;
+
+ if (nargc == 1)
+ return 1;
+ s = *(t_wp + 1);
+ if (nargc == 2)
+ return parenlevel == 1 && strcmp(s, ")") == 0;
+ if (nargc != 3)
+ return 0;
+ while (*op->op_text) {
+ if (strcmp(s, op->op_text) == 0)
+ return TOKEN_TYPE(op->op_num) == BINOP;
+ op++;
+ }
+ return 0;
+}
+
+static int
+isrparenoperand(void)
+{
+ char *s;
+
+ if (nargc == 1)
+ return 0;
+ s = *(t_wp + 1);
+ if (nargc == 2)
+ return parenlevel == 1 && strcmp(s, ")") == 0;
+ return 0;
+}
+
+/* atoi with error detection */
+static int
+getn(const char *s)
+{
+ char *p;
+ long r;
+
+ errno = 0;
+ r = strtol(s, &p, 10);
+
+ if (s == p)
+ error("%s: bad number", s);
+
+ if (errno != 0)
+ error((errno == EINVAL) ? "%s: bad number" :
+ "%s: out of range", s);
+
+ while (isspace((unsigned char)*p))
+ p++;
+
+ if (*p)
+ error("%s: bad number", s);
+
+ return (int) r;
+}
+
+/* atoi with error detection and 64 bit range */
+static intmax_t
+getq(const char *s)
+{
+ char *p;
+ intmax_t r;
+
+ errno = 0;
+ r = strtoimax(s, &p, 10);
+
+ if (s == p)
+ error("%s: bad number", s);
+
+ if (errno != 0)
+ error((errno == EINVAL) ? "%s: bad number" :
+ "%s: out of range", s);
+
+ while (isspace((unsigned char)*p))
+ p++;
+
+ if (*p)
+ error("%s: bad number", s);
+
+ return r;
+}
+
+static int
+intcmp (const char *s1, const char *s2)
+{
+ intmax_t q1, q2;
+
+
+ q1 = getq(s1);
+ q2 = getq(s2);
+
+ if (q1 > q2)
+ return 1;
+
+ if (q1 < q2)
+ return -1;
+
+ return 0;
+}
+
+static int
+newerf (const char *f1, const char *f2)
+{
+ struct stat b1, b2;
+
+ if (stat(f1, &b1) != 0 || stat(f2, &b2) != 0)
+ return 0;
+
+ if (b1.st_mtim.tv_sec > b2.st_mtim.tv_sec)
+ return 1;
+ if (b1.st_mtim.tv_sec < b2.st_mtim.tv_sec)
+ return 0;
+
+ return (b1.st_mtim.tv_nsec > b2.st_mtim.tv_nsec);
+}
+
+static int
+olderf (const char *f1, const char *f2)
+{
+ return (newerf(f2, f1));
+}
+
+static int
+equalf (const char *f1, const char *f2)
+{
+ struct stat b1, b2;
+
+ return (stat (f1, &b1) == 0 &&
+ stat (f2, &b2) == 0 &&
+ b1.st_dev == b2.st_dev &&
+ b1.st_ino == b2.st_ino);
+}
diff --git a/shell_cmds/test/test.plist.part b/shell_cmds/test/test.plist.part
new file mode 100644
index 0000000..e645422
--- /dev/null
+++ b/shell_cmds/test/test.plist.part
@@ -0,0 +1,19 @@
+ <dict>
+ <key>OpenSourceProject</key>
+ <string>test</string>
+ <key>OpenSourceVersion</key>
+ <string>2013-12-05</string>
+ <key>OpenSourceWebsiteURL</key>
+ <string>http://svnweb.freebsd.org/base/head/bin/test/</string>
+ <key>OpenSourceSCM</key>
+ <string>svn co http://svn.freebsd.org/base/head/bin/test/</string>
+ <key>OpenSourceImportDate</key>
+ <string>2015-07-31</string>
+ <key>OpenSourceModifications</key>
+ <array>
+ <string>4689479</string>
+ <string>compatibility for eaccess, st_mtim</string>
+ </array>
+ <key>OpenSourceLicense</key>
+ <string>bsd</string>
+ </dict>
diff --git a/shell_cmds/test/tests/Makefile b/shell_cmds/test/tests/Makefile
new file mode 100644
index 0000000..5ee337a
--- /dev/null
+++ b/shell_cmds/test/tests/Makefile
@@ -0,0 +1,15 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+TESTSDIR= ${TESTSBASE}/bin/test
+
+TAP_TESTS_SH= legacy_test
+# Some tests in here are silently not run when the tests are executed as
+# root. Explicitly tell Kyua to drop privileges.
+#
+# TODO(jmmv): Kyua needs to do this by default, not only when explicitly
+# requested. See https://code.google.com/p/kyua/issues/detail?id=6
+TEST_METADATA.legacy_test+= required_user="unprivileged"
+
+.include <bsd.test.mk>
diff --git a/shell_cmds/test/tests/legacy_test.sh b/shell_cmds/test/tests/legacy_test.sh
new file mode 100644
index 0000000..21c74a8
--- /dev/null
+++ b/shell_cmds/test/tests/legacy_test.sh
@@ -0,0 +1,203 @@
+#!/bin/sh
+
+#-
+# Copyright (c) June 1996 Wolfram Schneider <wosch@FreeBSD.org>. Berlin.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+
+#
+# TEST.sh - check if test(1) or builtin test works
+#
+# $FreeBSD$
+
+enable -n test
+
+# force a specified test program, e.g. `env test=/bin/test sh regress.sh'
+: ${test=test}
+
+t ()
+{
+ # $1 -> exit code
+ # $2 -> $test expression
+
+ count=$((count+1))
+ printf "[BEGIN] test $count\n"
+ # check for syntax errors
+ syntax="`eval $test $2 2>&1`"
+ ret=$?
+ if test -n "$syntax"; then
+ printf "not ok %s - (syntax error)\n" "$count $2"
+ printf "[FAIL] test $count\n"
+ elif [ "$ret" != "$1" ]; then
+ printf "not ok %s - (got $ret, expected $1)\n" "$count $2"
+ printf "[FAIL] test $count\n"
+ else
+ printf "ok %s\n" "$count $2"
+ printf "[PASS] test $count\n"
+ fi
+}
+
+count=0
+echo "1..130"
+printf "[TEST] shell_cmds: test\n"
+
+t 0 'b = b'
+t 0 'b == b'
+t 1 'b != b'
+t 0 '\( b = b \)'
+t 0 '\( b == b \)'
+t 1 '! \( b = b \)'
+t 1 '! \( b == b \)'
+t 1 '! -f /etc/passwd'
+
+t 0 '-h = -h'
+t 0 '-o = -o'
+t 1 '-f = h'
+t 1 '-h = f'
+t 1 '-o = f'
+t 1 'f = -o'
+t 0 '\( -h = -h \)'
+t 1 '\( a = -h \)'
+t 1 '\( -f = h \)'
+t 0 '-h = -h -o a'
+t 0 '\( -h = -h \) -o 1'
+t 0 '-h = -h -o -h = -h'
+t 0 '\( -h = -h \) -o \( -h = -h \)'
+t 0 'roedelheim = roedelheim'
+t 1 'potsdam = berlin-dahlem'
+
+t 0 '-d /'
+t 0 '-d / -a a != b'
+t 1 '-z "-z"'
+t 0 '-n -n'
+
+t 0 '0'
+t 0 '\( 0 \)'
+t 0 '-E'
+t 0 '-X -a -X'
+t 0 '-XXX'
+t 0 '\( -E \)'
+t 0 'true -o X'
+t 0 'true -o -X'
+t 0 '\( \( \( a = a \) -o 1 \) -a 1 \) -a true'
+t 1 '-h /'
+t 0 '-r /'
+t 1 '-w /'
+t 0 '-x /bin/sh'
+t 0 '-c /dev/null'
+t 0 '-f /etc/passwd'
+t 0 '-s /etc/passwd'
+
+t 1 '! \( 700 -le 1000 -a -n "1" -a "20" = "20" \)'
+t 0 '100 -eq 100'
+t 0 '100 -lt 200'
+t 1 '1000 -lt 200'
+t 0 '1000 -gt 200'
+t 0 '1000 -ge 200'
+t 0 '1000 -ge 1000'
+t 1 '2 -ne 2'
+t 0 '0 -eq 0'
+t 1 '-5 -eq 5'
+t 0 '\( 0 -eq 0 \)'
+t 1 '1 -eq 0 -o a = a -a 1 -eq 0 -o a = aa'
+
+t 1 '"" -o ""'
+t 1 '"" -a ""'
+t 1 '"a" -a ""'
+t 0 '"a" -a ! ""'
+t 1 '""'
+t 0 '! ""'
+
+t 0 '!'
+t 0 '\('
+t 0 '\)'
+
+t 1 '\( = \)'
+t 0 '\( != \)'
+t 0 '\( ! \)'
+t 0 '\( \( \)'
+t 0 '\( \) \)'
+t 0 '! = !'
+t 1 '! != !'
+t 1 '-n = \)'
+t 0 '! != \)'
+t 1 '! = a'
+t 0 '! != -n'
+t 0 '! -c /etc/passwd'
+
+t 1 '! = = ='
+t 0 '! = = \)'
+t 0 '! "" -o ""'
+t 1 '! "x" -o ""'
+t 1 '! "" -o "x"'
+t 1 '! "x" -o "x"'
+t 0 '\( -f /etc/passwd \)'
+t 0 '\( ! "" \)'
+t 1 '\( ! -e \)'
+
+t 0 '0 -eq 0 -a -d /'
+t 0 '-s = "" -o "" = ""'
+t 0 '"" = "" -o -s = ""'
+t 1 '-s = "" -o -s = ""'
+t 0 '-z x -o x = "#" -o x = x'
+t 1 '-z y -o y = "#" -o y = x'
+t 0 '0 -ne 0 -o ! -f /'
+t 0 '1 -ne 0 -o ! -f /etc/passwd'
+t 1 '0 -ne 0 -o ! -f /etc/passwd'
+
+t 0 '-n ='
+t 1 '-z ='
+t 1 '! ='
+t 0 '-n -eq'
+t 1 '-z -eq'
+t 1 '! -eq'
+t 0 '-n -a'
+t 1 '-z -a'
+t 1 '! -a'
+t 0 '-n -o'
+t 1 '-z -o'
+t 1 '! -o'
+t 1 '! -n ='
+t 0 '! -z ='
+t 0 '! ! ='
+t 1 '! -n -eq'
+t 0 '! -z -eq'
+t 0 '! ! -eq'
+t 1 '! -n -a'
+t 0 '! -z -a'
+t 0 '! ! -a'
+t 1 '! -n -o'
+t 0 '! -z -o'
+t 0 '! ! -o'
+t 0 '\( -n = \)'
+t 1 '\( -z = \)'
+t 1 '\( ! = \)'
+t 0 '\( -n -eq \)'
+t 1 '\( -z -eq \)'
+t 1 '\( ! -eq \)'
+t 0 '\( -n -a \)'
+t 1 '\( -z -a \)'
+t 1 '\( ! -a \)'
+t 0 '\( -n -o \)'
+t 1 '\( -z -o \)'
+t 1 '\( ! -o \)'
diff --git a/shell_cmds/tests/regress.m4 b/shell_cmds/tests/regress.m4
new file mode 100644
index 0000000..c06caa1
--- /dev/null
+++ b/shell_cmds/tests/regress.m4
@@ -0,0 +1,59 @@
+# $FreeBSD: head/usr.bin/tests/regress.m4 263227 2014-03-16 08:04:06Z jmmv $
+
+dnl A library of routines for doing regression tests for userland utilities.
+
+dnl Start up. We initialise the exit status to 0 (no failure) and change
+dnl into the directory specified by our first argument, which is the
+dnl directory to run the tests inside.
+define(`REGRESSION_START',
+TESTDIR=$1
+if [ -z "$TESTDIR" ]; then
+ TESTDIR=.
+fi
+cd $TESTDIR
+
+STATUS=0)
+
+dnl Check $? to see if we passed or failed. The first parameter is the test
+dnl which passed or failed. It may be nil.
+define(`REGRESSION_PASSFAIL',
+if [ $? -eq 0 ]; then
+ echo "ok - $1 # Test detected no regression. (in $TESTDIR)"
+else
+ STATUS=$?
+ echo "not ok - $1 # Test failed: regression detected. See above. (in $TESTDIR)"
+fi)
+
+dnl An actual test. The first parameter is the test name. The second is the
+dnl command/commands to execute for the actual test. Their exit status is
+dnl checked. It is assumed that the test will output to stdout, and that the
+dnl output to be used to check for regression will be in regress.TESTNAME.out.
+define(`REGRESSION_TEST',
+$2 | diff -u ${SRCDIR:-.}/regress.$1.out -
+REGRESSION_PASSFAIL($1))
+
+dnl A freeform regression test. Only exit status is checked.
+define(`REGRESSION_TEST_FREEFORM',
+$2
+REGRESSION_PASSFAIL($1))
+
+dnl A regression test like REGRESSION_TEST, except only regress.out is used
+dnl for checking output differences. The first argument is the command, the
+dnl second argument (which may be empty) is the test name.
+define(`REGRESSION_TEST_ONE',
+$1 | diff -u ${SRCDIR:-.}/regress.out -
+REGRESSION_PASSFAIL($2))
+
+dnl A fatal error. This will exit with the given status (first argument) and
+dnl print the message (second argument) prefixed with the string "FATAL :" to
+dnl the error stream.
+define(`REGRESSION_FATAL',
+echo "Bail out! $2 (in $TESTDIR)" > /dev/stderr
+exit $1)
+
+dnl Cleanup. Exit with the status code of the last failure. Should probably
+dnl be the number of failed tests, but hey presto, this is what it does. This
+dnl could also clean up potential droppings, if some forms of regression tests
+dnl end up using mktemp(1) or such.
+define(`REGRESSION_END',
+exit $STATUS)
diff --git a/shell_cmds/tests/shell_cmds.plist b/shell_cmds/tests/shell_cmds.plist
new file mode 100644
index 0000000..bdeb182
--- /dev/null
+++ b/shell_cmds/tests/shell_cmds.plist
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>Project</key>
+ <string>libutil</string>
+ <key>Tests</key>
+ <array>
+ <dict>
+ <key>Command</key>
+ <array>
+ <string>/bin/sh</string>
+ <string>/AppleInternal/Tests/shell_cmds/printf/legacy_test.sh</string>
+ </array>
+ <key>IgnoreOutput</key><true/>
+ <key>TestName</key><string>shell_cmds.printf</string>
+ <key>WhenToRun</key>
+ <array>
+ <string>PRESUBMISSION</string>
+ <string>NIGHTLY</string>
+ </array>
+ </dict>
+ <dict>
+ <key>Command</key>
+ <array>
+ <string>/bin/sh</string>
+ <string>/AppleInternal/Tests/shell_cmds/test/legacy_test.sh</string>
+ </array>
+ <key>TestName</key><string>shell_cmds.test</string>
+ <key>WhenToRun</key>
+ <array>
+ <string>PRESUBMISSION</string>
+ <string>NIGHTLY</string>
+ </array>
+ </dict>
+ <dict>
+ <key>Command</key>
+ <array>
+ <string>/bin/sh</string>
+ <string>/AppleInternal/Tests/shell_cmds/time/test_time.sh</string>
+ </array>
+ <key>TestName</key><string>shell_cmds.time</string>
+ <key>WhenToRun</key>
+ <array>
+ <string>PRESUBMISSION</string>
+ <string>NIGHTLY</string>
+ </array>
+ </dict>
+ </array>
+ <key>Timeout</key>
+ <integer>30</integer>
+</dict>
+</plist>
diff --git a/shell_cmds/time/tests/test_time.sh b/shell_cmds/time/tests/test_time.sh
new file mode 100755
index 0000000..6cf002d
--- /dev/null
+++ b/shell_cmds/time/tests/test_time.sh
@@ -0,0 +1,60 @@
+#!/bin/sh
+
+set -o nounset
+
+TIME="${TIME-/usr/bin/time}"
+echo "SUITE: time(1)"
+what $TIME
+echo
+
+EXIT=0
+
+echo TEST: check real time
+
+TIME_SLEEP=`$TIME 2>&1 sleep 1 | sed -n -E 's/[ ]+([0-9]+).*/\1/p'`
+TIME_STATUS=$?
+
+if [ "$TIME_STATUS" -ne "0" ]; then
+ echo FAIL: time failed with "$TIME_STATUS"
+ EXIT=1
+fi
+
+if [ "$TIME_SLEEP" -lt "0" ]; then
+ echo FAIL: time mis-timed sleep
+ EXIT=2
+fi
+
+MONOTONIC=`sysctl -n kern.monotonic.task_thread_counting`
+if [ "$MONOTONIC" -ne "0" ]; then
+ echo TEST: check instructions retired
+
+ TIME_INSTRS=`$TIME -l 2>&1 sleep 1 | sed -E -n '/instructions/p'`
+ if [ -z "$TIME_INSTRS" ]; then
+ echo FAIL: time is not showing instructions retired
+ EXIT=3
+ fi
+else
+ echo SKIP: check instructions retired
+fi
+
+# NB: SIGINT and SIGQUIT work locally, but the automated test harnesses tries to
+# handle those signals itself before the fork.
+
+echo TEST: check child SIGUSR1
+
+TIME_USR1=`$TIME 2>&1 sh -c 'kill -USR1 $$ && sleep 5 && true'`
+TIME_STATUS=$?
+if [ "$TIME_STATUS" -eq "0" ]; then
+ echo FAIL: time should allow child to receive SIGUSR1
+ EXIT=4
+fi
+
+echo TEST: check non-existent binary
+TIME_NONEXIST=`$TIME 2>&1 ./this-wont-exist`
+TIME_STATUS=$?
+if [ "$TIME_STATUS" -ne "127" ]; then
+ echo FAIL: time should error when measuring a non-existent command
+ EXIT=5
+fi
+
+exit $EXIT
diff --git a/shell_cmds/time/time.1 b/shell_cmds/time/time.1
new file mode 100644
index 0000000..b4e7017
--- /dev/null
+++ b/shell_cmds/time/time.1
@@ -0,0 +1,116 @@
+.\" $NetBSD: time.1,v 1.7 1997/10/20 03:28:20 lukem Exp $
+.\"
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)time.1 8.1 (Berkeley) 6/6/93
+.\"
+.Dd June 6, 1993
+.Dt TIME 1
+.Os
+.Sh NAME
+.Nm time
+.Nd time command execution
+.Sh SYNOPSIS
+.Nm
+.Op Fl lp
+.Ar utility
+.Sh DESCRIPTION
+The
+.Nm
+utility
+executes and
+times
+.Ar utility .
+After the
+.Ar utility
+finishes,
+.Nm
+writes the total time elapsed,
+the time consumed by system overhead,
+and the time used to execute
+.Ar utility
+to the standard error stream.
+Times are reported in seconds.
+.Pp
+Available options:
+.Bl -tag -width Ds
+.It Fl l
+The contents of the
+.Em rusage
+structure are printed.
+.It Fl p
+The output is formatted as specified by
+.St -p1003.2-92 .
+.El
+.Pp
+Some shells may provide a builtin
+.Nm
+command which is similar or identical to this utility.
+Consult the
+.Xr builtin 1
+manual page.
+.Sh DIAGNOSTICS
+The
+.Nm
+utility shall exit with one of the following values:
+.Bl -tag -width indent
+.It 1-125
+An error occurred in the
+.Nm
+utility.
+.It 126
+The
+.Ar utility
+was found but could not be invoked.
+.It 127
+The
+.Ar utility
+could not be found.
+.El
+.Pp
+Otherwise, the exit status of
+.Nm
+shall be that of
+.Ar utility .
+.Sh SEE ALSO
+.Xr builtin 1 ,
+.Xr csh 1 ,
+.Xr getrusage 2
+.Sh FILES
+.Bl -tag -width /usr/include/sys/resource.h -compact
+.It Pa /usr/include/sys/resource.h
+.El
+.Sh STANDARDS
+The
+.Nm
+utility conforms to
+.St -p1003.2-92 .
diff --git a/shell_cmds/time/time.c b/shell_cmds/time/time.c
new file mode 100644
index 0000000..afaaed0
--- /dev/null
+++ b/shell_cmds/time/time.c
@@ -0,0 +1,245 @@
+/* $NetBSD: time.c,v 1.9 1997/10/20 03:28:21 lukem Exp $ */
+
+/*
+ * Copyright (c) 1987, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <errno.h>
+#include <err.h>
+#include <inttypes.h>
+#include <langinfo.h>
+#include <libproc.h>
+#include <locale.h>
+#include <sys/cdefs.h>
+#include <sysexits.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+
+int lflag;
+int portableflag;
+bool child_running = true;
+
+void
+child_handler(int sig)
+{
+ child_running = false;
+}
+
+int
+main(int argc, char **argv)
+{
+ int pid;
+ int ch, status, rusage_ret = -1;
+ uint64_t before_ns, after_ns, duration_ns, duration_secs, duration_frac_ns;
+ struct rusage ru;
+ struct rusage_info_v4 ruinfo;
+ sigset_t sigmask, suspmask, origmask;
+
+ lflag = 0;
+ while ((ch = getopt(argc, argv, "lp")) != -1) {
+ switch((char)ch) {
+ case 'p':
+ portableflag = 1;
+ break;
+ case 'l':
+ lflag = 1;
+ break;
+ case '?':
+ default:
+ fprintf(stderr, "usage: time [-lp] <command>\n");
+ exit(1);
+ }
+ }
+
+ if (!(argc -= optind)) {
+ exit(0);
+ }
+ argv += optind;
+
+ sigemptyset(&sigmask);
+ /*
+ * Block SIGCHLD so that the check for `child_running` doesn't miss the
+ * handler before calling `sigsuspend` and blocking forever.
+ */
+ sigaddset(&sigmask, SIGCHLD);
+ sigprocmask(SIG_BLOCK, &sigmask, &origmask);
+
+ /*
+ * Ensure child signals are handled by the parent prior to fork; otherwise,
+ * they could be missed between the child forking and calling `sigsuspend`.
+ */
+ (void)signal(SIGCHLD, child_handler);
+
+ sigemptyset(&suspmask);
+
+ before_ns = clock_gettime_nsec_np(CLOCK_UPTIME_RAW);
+ /*
+ * NB: Don't add anything between these two lines -- measurement is
+ * happening now.
+ */
+ switch (pid = vfork()) {
+ case -1: /* error */
+ err(EX_OSERR, "time");
+ __builtin_unreachable();
+ case 0: /* child */
+ /*
+ * Allow the child to respond to signals by resetting to the original
+ * signal handling behavior.
+ */
+ (void)sigprocmask(SIG_SETMASK, &origmask, NULL);
+ execvp(*argv, argv);
+ perror(*argv);
+ _exit((errno == ENOENT) ? 127 : 126);
+ __builtin_unreachable();
+ default: /* parent */
+ break;
+ }
+
+ /*
+ * Let the child handle signals that normally exit.
+ */
+ (void)signal(SIGINT, SIG_IGN);
+ (void)signal(SIGQUIT, SIG_IGN);
+
+ while (child_running) {
+ /*
+ * This would be racy, but SIGCHLD is blocked above (as part of
+ * `sigmask`.
+ */
+ sigsuspend(&suspmask);
+ }
+ /*
+ * NB: Minimize what's added between these statements to preserve the
+ * accuracy of the time measurement.
+ */
+ after_ns = clock_gettime_nsec_np(CLOCK_UPTIME_RAW);
+ if (lflag) {
+ rusage_ret = proc_pid_rusage(pid, RUSAGE_INFO_V4, (void **)&ruinfo);
+ }
+ while (wait3(&status, 0, &ru) != pid) {
+ }
+ if (!WIFEXITED(status)) {
+ fprintf(stderr, "Command terminated abnormally.\n");
+ }
+ duration_ns = after_ns - before_ns;
+ duration_secs = duration_ns / (1000 * 1000 * 1000);
+ duration_frac_ns = duration_ns - (duration_secs * 1000 * 1000 * 1000);
+
+ if (portableflag) {
+ char *radix = NULL;
+
+ setlocale(LC_ALL, "");
+
+ radix = nl_langinfo(RADIXCHAR);
+ if (!radix || radix[0] == '\0') {
+ radix = ".";
+ }
+
+ fprintf(stderr, "real %9" PRIu64 "%s%02" PRIu64 "\n",
+ duration_secs, radix, duration_frac_ns / (10 * 1000 * 1000));
+ fprintf(stderr, "user %9ld%s%02ld\n",
+ (long)ru.ru_utime.tv_sec, radix, (long)ru.ru_utime.tv_usec/10000);
+ fprintf(stderr, "sys %9ld%s%02ld\n",
+ (long)ru.ru_stime.tv_sec, radix, (long)ru.ru_stime.tv_usec/10000);
+ } else {
+ fprintf(stderr, "%9" PRIu64 ".%02" PRIu64 " real ",
+ duration_secs, duration_frac_ns / (10 * 1000 * 1000));
+ fprintf(stderr, "%9ld.%02ld user ",
+ (long)ru.ru_utime.tv_sec, (long)ru.ru_utime.tv_usec/10000);
+ fprintf(stderr, "%9ld.%02ld sys\n",
+ (long)ru.ru_stime.tv_sec, (long)ru.ru_stime.tv_usec/10000);
+ }
+
+ if (lflag) {
+ int hz = 100; /* XXX */
+ long ticks;
+
+ ticks = hz * (ru.ru_utime.tv_sec + ru.ru_stime.tv_sec) +
+ hz * (ru.ru_utime.tv_usec + ru.ru_stime.tv_usec) / 1000000;
+
+ fprintf(stderr, "%20ld %s\n",
+ ru.ru_maxrss, "maximum resident set size");
+ fprintf(stderr, "%20ld %s\n", ticks ? ru.ru_ixrss / ticks : 0,
+ "average shared memory size");
+ fprintf(stderr, "%20ld %s\n", ticks ? ru.ru_idrss / ticks : 0,
+ "average unshared data size");
+ fprintf(stderr, "%20ld %s\n", ticks ? ru.ru_isrss / ticks : 0,
+ "average unshared stack size");
+ fprintf(stderr, "%20ld %s\n",
+ ru.ru_minflt, "page reclaims");
+ fprintf(stderr, "%20ld %s\n",
+ ru.ru_majflt, "page faults");
+ fprintf(stderr, "%20ld %s\n",
+ ru.ru_nswap, "swaps");
+ fprintf(stderr, "%20ld %s\n",
+ ru.ru_inblock, "block input operations");
+ fprintf(stderr, "%20ld %s\n",
+ ru.ru_oublock, "block output operations");
+ fprintf(stderr, "%20ld %s\n",
+ ru.ru_msgsnd, "messages sent");
+ fprintf(stderr, "%20ld %s\n",
+ ru.ru_msgrcv, "messages received");
+ fprintf(stderr, "%20ld %s\n",
+ ru.ru_nsignals, "signals received");
+ fprintf(stderr, "%20ld %s\n",
+ ru.ru_nvcsw, "voluntary context switches");
+ fprintf(stderr, "%20ld %s\n",
+ ru.ru_nivcsw, "involuntary context switches");
+
+ if (rusage_ret >= 0) {
+ if (ruinfo.ri_instructions > 0) {
+ fprintf(stderr, "%20" PRIu64 " %s\n", ruinfo.ri_instructions,
+ "instructions retired");
+ }
+ if (ruinfo.ri_cycles > 0) {
+ fprintf(stderr, "%20" PRIu64 " %s\n", ruinfo.ri_cycles,
+ "cycles elapsed");
+ }
+ if (ruinfo.ri_lifetime_max_phys_footprint > 0) {
+ fprintf(stderr, "%20" PRIu64 " %s\n",
+ ruinfo.ri_lifetime_max_phys_footprint,
+ "peak memory footprint");
+ }
+ }
+ }
+
+ exit(WIFEXITED(status) ? WEXITSTATUS(status) : EXIT_FAILURE);
+}
diff --git a/shell_cmds/true/true.1 b/shell_cmds/true/true.1
new file mode 100644
index 0000000..b022042
--- /dev/null
+++ b/shell_cmds/true/true.1
@@ -0,0 +1,60 @@
+.\" $NetBSD: true.1,v 1.5 1997/10/20 01:00:41 lukem Exp $
+.\"
+.\" Copyright (c) 1983, 1985, 1990 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" from: @(#)true.1 6.4 (Berkeley) 6/27/91
+.\" $NetBSD: true.1,v 1.5 1997/10/20 01:00:41 lukem Exp $
+.\"
+.Dd June 27, 1991
+.Dt TRUE 1
+.Os
+.Sh NAME
+.Nm true
+.Nd Return true value.
+.Sh SYNOPSIS
+.Nm
+.Sh DESCRIPTION
+The
+.Nm
+utility always returns with exit code zero.
+.Sh SEE ALSO
+.Xr csh 1 ,
+.Xr sh 1 ,
+.Xr false 1
+.Sh STANDARDS
+The
+.Nm
+utility conforms to
+.St -p1003.2-92 .
diff --git a/shell_cmds/true/true.c b/shell_cmds/true/true.c
new file mode 100644
index 0000000..d973485
--- /dev/null
+++ b/shell_cmds/true/true.c
@@ -0,0 +1,2 @@
+#include <stdlib.h>
+int main () { exit(0); }
diff --git a/shell_cmds/true/true.sh b/shell_cmds/true/true.sh
new file mode 100644
index 0000000..20f87ef
--- /dev/null
+++ b/shell_cmds/true/true.sh
@@ -0,0 +1,2 @@
+#! /bin/sh
+exit 0
diff --git a/shell_cmds/uname/uname.1 b/shell_cmds/uname/uname.1
new file mode 100644
index 0000000..0c62868
--- /dev/null
+++ b/shell_cmds/uname/uname.1
@@ -0,0 +1,87 @@
+.\" $NetBSD: uname.1,v 1.12 2005/03/27 18:41:22 peter Exp $
+.\"
+.\" Copyright (c) 1990 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" from: @(#)du.1 6.13 (Berkeley) 6/20/91
+.\" $NetBSD: uname.1,v 1.12 2005/03/27 18:41:22 peter Exp $
+.\"
+.Dd November 9, 1998
+.Dt UNAME 1
+.Os
+.Sh NAME
+.Nm uname
+.Nd Print operating system name
+.Sh SYNOPSIS
+.Nm
+.Op Fl amnprsv
+.Sh DESCRIPTION
+The
+.Nm
+utility writes symbols representing one or more system characteristics
+to the standard output.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl a
+Behave as though all of the options
+.Fl mnrsv
+were specified.
+.It Fl m
+print the machine hardware name.
+.It Fl n
+print the nodename (the nodename may be a name
+that the system is known by to a communications
+network).
+.It Fl p
+print the machine processor architecture name.
+.It Fl r
+print the operating system release.
+.It Fl s
+print the operating system name.
+.It Fl v
+print the operating system version.
+.El
+.Pp
+If no options are specified,
+.Nm
+prints the operating system name as if the
+.Fl s
+option had been specified.
+.Sh SEE ALSO
+.Xr hostname 1 ,
+.Xr machine 1 ,
+.Xr sw_vers 1 ,
+.Xr uname 3
+.Sh STANDARDS
+The
+.Nm
+utility conforms to
+.St -p1003.2-92 .
+The
+.Fl p
+option is an extension to the standard.
diff --git a/shell_cmds/uname/uname.c b/shell_cmds/uname/uname.c
new file mode 100644
index 0000000..7dadd52
--- /dev/null
+++ b/shell_cmds/uname/uname.c
@@ -0,0 +1,208 @@
+/* $NetBSD: uname.c,v 1.10 1998/11/09 13:24:05 kleink Exp $ */
+
+/*
+ * Copyright (c) 1994 Winning Strategies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Winning Strategies, Inc.
+ * 4. The name of Winning Strategies, Inc. may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__RCSID("$NetBSD: uname.c,v 1.10 1998/11/09 13:24:05 kleink Exp $");
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <limits.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <err.h>
+#ifdef __APPLE__
+#include <string.h>
+#endif /* __APPLE__ */
+
+#include <sys/sysctl.h>
+#include <sys/utsname.h>
+
+#ifdef __APPLE__
+#include <get_compat.h>
+#else /* !__APPLE__ */
+#define COMPAT_MODE(a,b) (1)
+#endif /* __APPLE__ */
+
+int main __P((int, char **));
+static void usage __P((void));
+
+/* Note that PRINT_MACHINE_ARCH is excluded from PRINT_ALL! */
+#define PRINT_SYSNAME 0x01
+#define PRINT_NODENAME 0x02
+#define PRINT_RELEASE 0x04
+#define PRINT_VERSION 0x08
+#define PRINT_MACHINE 0x10
+#define PRINT_MACHINE_ARCH 0x20
+#define PRINT_ALL \
+ (PRINT_SYSNAME|PRINT_NODENAME|PRINT_RELEASE|PRINT_VERSION|PRINT_MACHINE)
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ struct utsname u;
+#ifndef __APPLE__
+ char machine_arch[SYS_NMLN];
+#endif /* !__APPLE__ */
+ int c;
+ int space = 0;
+ int print_mask = 0;
+
+ (void)setlocale(LC_ALL, "");
+
+ while ((c = getopt(argc,argv,"amnprsv")) != -1) {
+ switch (c) {
+ case 'a':
+ print_mask |= PRINT_ALL;
+#ifdef __APPLE__
+ if (!COMPAT_MODE("bin/uname", "Unix2003")) {
+ print_mask |= PRINT_MACHINE_ARCH;
+ }
+#endif /* __APPLE__ */
+ break;
+ case 'm':
+ print_mask |= PRINT_MACHINE;
+ break;
+ case 'n':
+ print_mask |= PRINT_NODENAME;
+ break;
+ case 'p':
+ print_mask |= PRINT_MACHINE_ARCH;
+ break;
+ case 'r':
+ print_mask |= PRINT_RELEASE;
+ break;
+ case 's':
+ print_mask |= PRINT_SYSNAME;
+ break;
+ case 'v':
+ print_mask |= PRINT_VERSION;
+ break;
+ default:
+ usage();
+ /* NOTREACHED */
+ }
+ }
+
+ if (optind != argc) {
+ usage();
+ /* NOTREACHED */
+ }
+
+ if (!print_mask) {
+ print_mask = PRINT_SYSNAME;
+ }
+
+ if (uname(&u) != 0) {
+ err(EXIT_FAILURE, "uname");
+ /* NOTREACHED */
+ }
+#ifndef __APPLE__
+ if (print_mask & PRINT_MACHINE_ARCH) {
+ int mib[2] = { CTL_HW, HW_MACHINE_ARCH };
+ size_t len = sizeof (machine_arch);
+
+ if (sysctl(mib, sizeof (mib) / sizeof (mib[0]), machine_arch,
+ &len, NULL, 0) < 0)
+ err(EXIT_FAILURE, "sysctl");
+ }
+#endif /* !__APPLE__ */
+
+#ifdef __APPLE__
+ /*
+ * Let's allow the user to override the output of uname via the shell environment.
+ * This is a useful feature for cross-compiling (eg. during an OS bringup).
+ * Otherwise, you have to hack your kernel with the desired strings.
+ */
+ {
+ char *s;
+ s = getenv ("UNAME_SYSNAME"); if (s) strncpy (u.sysname, s, sizeof (u.sysname));
+ s = getenv ("UNAME_NODENAME"); if (s) strncpy (u.nodename, s, sizeof (u.nodename));
+ s = getenv ("UNAME_RELEASE"); if (s) strncpy (u.release, s, sizeof (u.release));
+ s = getenv ("UNAME_VERSION"); if (s) strncpy (u.version, s, sizeof (u.version));
+ s = getenv ("UNAME_MACHINE"); if (s) strncpy (u.machine, s, sizeof (u.machine));
+ }
+#endif /* __APPLE__ */
+
+ if (print_mask & PRINT_SYSNAME) {
+ space++;
+ fputs(u.sysname, stdout);
+ }
+ if (print_mask & PRINT_NODENAME) {
+ if (space++) putchar(' ');
+ fputs(u.nodename, stdout);
+ }
+ if (print_mask & PRINT_RELEASE) {
+ if (space++) putchar(' ');
+ fputs(u.release, stdout);
+ }
+ if (print_mask & PRINT_VERSION) {
+ if (space++) putchar(' ');
+ fputs(u.version, stdout);
+ }
+ if (print_mask & PRINT_MACHINE) {
+ if (space++) putchar(' ');
+ fputs(u.machine, stdout);
+ }
+ if (print_mask & PRINT_MACHINE_ARCH) {
+ if (space++) putchar(' ');
+#ifndef __APPLE__
+ fputs(machine_arch, stdout);
+#else
+#if defined(__ppc__) || defined(__ppc64__)
+ fputs("powerpc", stdout);
+#elif defined(__i386__) || defined(__x86_64__)
+ fputs("i386", stdout);
+#elif defined(__arm__) || defined(__arm64__)
+ fputs("arm", stdout);
+#else
+ fputs("unknown", stdout);
+#endif
+#endif /* __APPLE__ */
+ }
+ putchar('\n');
+
+ exit(EXIT_SUCCESS);
+ /* NOTREACHED */
+}
+
+static void
+usage()
+{
+ fprintf(stderr, "usage: uname [-amnprsv]\n");
+ exit(EXIT_FAILURE);
+}
diff --git a/shell_cmds/users/users.1 b/shell_cmds/users/users.1
new file mode 100644
index 0000000..5c4f872
--- /dev/null
+++ b/shell_cmds/users/users.1
@@ -0,0 +1,61 @@
+.\" $NetBSD: users.1,v 1.5 1997/10/20 02:41:21 lukem Exp $
+.\"
+.\" Copyright (c) 1980, 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)users.1 8.1 (Berkeley) 6/6/93
+.\"
+.Dd June 6, 1993
+.Dt USERS 1
+.Os BSD 3
+.Sh NAME
+.Nm users
+.Nd list current users
+.Sh SYNOPSIS
+.Nm
+.Sh DESCRIPTION
+.Nm
+lists the login names of the users currently on the system,
+in sorted order, space separated, on a single line.
+.Sh FILES
+.Bl -tag -width /var/run/utmpx
+.It Pa /var/run/utmpx
+.El
+.Sh SEE ALSO
+.Xr finger 1 ,
+.Xr last 1 ,
+.Xr who 1 ,
+.Xr utmpx 5
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 3.0 .
diff --git a/shell_cmds/users/users.c b/shell_cmds/users/users.c
new file mode 100644
index 0000000..ff24ecb
--- /dev/null
+++ b/shell_cmds/users/users.c
@@ -0,0 +1,123 @@
+/* $NetBSD: users.c,v 1.7 1998/02/03 04:19:15 perry Exp $ */
+
+/*
+ * Copyright (c) 1980, 1987, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1980, 1987, 1993\n\
+ The Regents of the University of California. All rights reserved.\n");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)users.c 8.1 (Berkeley) 6/6/93";
+#endif
+__RCSID("$NetBSD: users.c,v 1.7 1998/02/03 04:19:15 perry Exp $");
+#endif /* not lint */
+
+#include <sys/types.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <unistd.h>
+#include <utmpx.h>
+
+typedef char namebuf[_UTX_USERSIZE];
+
+int main __P((int, char **));
+int scmp __P((const void *, const void *));
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ namebuf *names = NULL;
+ int ncnt = 0;
+ int nmax = 0;
+ int cnt;
+ struct utmpx *ux;
+ int ch;
+
+ while ((ch = getopt(argc, argv, "")) != -1)
+ switch(ch) {
+ case '?':
+ default:
+ (void)fprintf(stderr, "usage: users\n");
+ exit(1);
+ }
+ argc -= optind;
+ argv += optind;
+
+ setutxent();
+
+ while ((ux = getutxent()) != NULL) {
+ if (*ux->ut_user && ux->ut_type == USER_PROCESS)
+ {
+ if (ncnt >= nmax) {
+ nmax += 32;
+ names = realloc(names,
+ sizeof (*names) * nmax);
+
+ if (!names) {
+ err(1, "realloc");
+ /* NOTREACHED */
+ }
+ }
+
+ (void)strncpy(names[ncnt], ux->ut_user, _UTX_USERSIZE);
+ ++ncnt;
+ }
+ }
+
+ if (ncnt) {
+ qsort(names, ncnt, _UTX_USERSIZE, scmp);
+ (void)printf("%.*s", _UTX_USERSIZE, names[0]);
+ for (cnt = 1; cnt < ncnt; ++cnt)
+ if (strncmp(names[cnt], names[cnt - 1], _UTX_USERSIZE))
+ (void)printf(" %.*s", _UTX_USERSIZE, names[cnt]);
+ (void)printf("\n");
+ }
+ exit(0);
+}
+
+int
+scmp(p, q)
+ const void *p, *q;
+{
+ return(strncmp((char *) p, (char *) q, _UTX_USERSIZE));
+}
diff --git a/shell_cmds/w/extern.h b/shell_cmds/w/extern.h
new file mode 100644
index 0000000..8fe24bb
--- /dev/null
+++ b/shell_cmds/w/extern.h
@@ -0,0 +1,44 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)extern.h 8.1 (Berkeley) 6/6/93
+ * $FreeBSD: src/usr.bin/w/extern.h,v 1.5 2002/03/22 01:42:43 imp Exp $
+ */
+
+
+extern int use_ampm;
+
+struct kinfo_proc;
+
+#ifdef __APPLE__
+#define KI_PROC(ki) (&(ki)->kp->kp_proc)
+#endif
+
+void pr_attime(time_t *, time_t *);
+int pr_idle(time_t);
+int proc_compare(struct kinfo_proc *, struct kinfo_proc *);
diff --git a/shell_cmds/w/fmt.c b/shell_cmds/w/fmt.c
new file mode 100644
index 0000000..31a6e50
--- /dev/null
+++ b/shell_cmds/w/fmt.c
@@ -0,0 +1,129 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)fmt.c 8.4 (Berkeley) 4/15/94";
+#endif
+#endif
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <vis.h>
+
+//#include "ps.h"
+
+static char *cmdpart(char *);
+static char *shquote(char **);
+
+/*
+ * XXX
+ * This is a stub until marc does the real one.
+ */
+static char *
+shquote(char **argv)
+{
+ static long arg_max = -1;
+ size_t len;
+ char **p, *dst, *src;
+ static char *buf = NULL;
+
+ if (buf == NULL) {
+ if ((arg_max = sysconf(_SC_ARG_MAX)) == -1)
+ errx(1, "sysconf _SC_ARG_MAX failed");
+ if ((buf = malloc((u_int)(4 * arg_max) + 1)) == NULL)
+ errx(1, "malloc failed");
+ }
+
+ if (*argv == 0) {
+ buf[0] = 0;
+ return (buf);
+ }
+ dst = buf;
+ for (p = argv; (src = *p++) != 0; ) {
+ if (*src == 0)
+ continue;
+ len = (size_t)(4 * arg_max - (dst - buf)) / 4;
+ strvisx(dst, src, strlen(src) < len ? strlen(src) : len,
+ VIS_NL | VIS_CSTYLE);
+ while (*dst)
+ dst++;
+ if ((4 * arg_max - (dst - buf)) / 4 > 0)
+ *dst++ = ' ';
+ }
+ /* Chop off trailing space */
+ if (dst != buf && dst[-1] == ' ')
+ dst--;
+ *dst = '\0';
+ return (buf);
+}
+
+static char *
+cmdpart(char *arg0)
+{
+ char *cp;
+
+ return ((cp = strrchr(arg0, '/')) != NULL ? cp + 1 : arg0);
+}
+
+const char *
+fmt_argv(char **argv, char *cmd, size_t maxlen)
+{
+ size_t len;
+ char *ap, *cp;
+
+ if (argv == NULL || argv[0] == NULL) {
+ if (cmd == NULL)
+ return ("");
+ ap = NULL;
+ len = maxlen + 3;
+ } else {
+ ap = shquote(argv);
+ len = strlen(ap) + maxlen + 4;
+ }
+ cp = malloc(len);
+ if (cp == NULL)
+ return (NULL);
+ if (ap == NULL)
+ sprintf(cp, " (%.*s)", (int)maxlen, cmd);
+ else if (strncmp(cmdpart(argv[0]), cmd, maxlen) != 0)
+ sprintf(cp, "%s (%.*s)", ap, (int)maxlen, cmd);
+ else
+ (void) strcpy(cp, ap);
+ return (cp);
+}
diff --git a/shell_cmds/w/pr_time.c b/shell_cmds/w/pr_time.c
new file mode 100644
index 0000000..77d506d
--- /dev/null
+++ b/shell_cmds/w/pr_time.c
@@ -0,0 +1,117 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#ifndef __APPLE__
+__FBSDID("$FreeBSD: src/usr.bin/w/pr_time.c,v 1.19 2002/06/07 01:41:54 jmallett Exp $");
+#endif
+
+#ifndef lint
+static const char sccsid[] = "@(#)pr_time.c 8.2 (Berkeley) 4/4/94";
+#endif
+
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include "extern.h"
+
+/*
+ * pr_attime --
+ * Print the time since the user logged in.
+ */
+void
+pr_attime(time_t *started, time_t *now)
+{
+ static char buf[256];
+ struct tm tp, tm;
+ time_t diff;
+ char fmt[20];
+
+ tp = *localtime(started);
+ tm = *localtime(now);
+ diff = *now - *started;
+
+ /* If more than a week, use day-month-year. */
+ if (diff > 86400 * 7)
+ (void)strcpy(fmt, "%d%b%y");
+
+ /* If not today, use day-hour-am/pm. */
+ else if (tm.tm_mday != tp.tm_mday ||
+ tm.tm_mon != tp.tm_mon ||
+ tm.tm_year != tp.tm_year) {
+ /* The line below does not take DST into consideration */
+ /* else if (*now / 86400 != *started / 86400) { */
+ (void)strcpy(fmt, use_ampm ? "%a%I%p" : "%a%H");
+ }
+
+ /* Default is hh:mm{am,pm}. */
+ else {
+ (void)strcpy(fmt, use_ampm ? "%l:%M%p" : "%k:%M");
+ }
+
+ (void)strftime(buf, sizeof(buf), fmt, &tp);
+ (void)printf("%-7.7s", buf);
+}
+
+/*
+ * pr_idle --
+ * Display the idle time.
+ * Returns number of excess characters that were used for long idle time.
+ */
+int
+pr_idle(time_t idle)
+{
+ /* If idle more than 36 hours, print as a number of days. */
+ if (idle >= 36 * 3600) {
+ int days = idle / 86400;
+ (void)printf(" %dday%s ", days, days > 1 ? "s" : " " );
+ if (days >= 100)
+ return (2);
+ if (days >= 10)
+ return (1);
+ }
+
+ /* If idle more than an hour, print as HH:MM. */
+ else if (idle >= 3600)
+ (void)printf(" %2d:%02d ",
+ (int)(idle / 3600), (int)((idle % 3600) / 60));
+
+ else if (idle / 60 == 0)
+ (void)printf(" - ");
+
+ /* Else print the minutes idle. */
+ else
+ (void)printf(" %2d ", (int)(idle / 60));
+
+ return (0); /* not idle longer than 9 days */
+}
diff --git a/shell_cmds/w/proc_compare.c b/shell_cmds/w/proc_compare.c
new file mode 100644
index 0000000..806f571
--- /dev/null
+++ b/shell_cmds/w/proc_compare.c
@@ -0,0 +1,144 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)proc_compare.c 8.2 (Berkeley) 9/23/93";
+#endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+#ifndef __APPLE__
+__FBSDID("$FreeBSD: src/usr.bin/w/proc_compare.c,v 1.9 2004/04/14 09:34:17 bde Exp $");
+#endif
+
+#include <sys/param.h>
+#ifdef __APPLE__
+#include <sys/time.h>
+#endif
+#include <sys/proc.h>
+#include <sys/time.h>
+#include <sys/user.h>
+
+#include "extern.h"
+
+/*
+ * Returns 1 if p2 is "better" than p1
+ *
+ * The algorithm for picking the "interesting" process is thus:
+ *
+ * 1) Only foreground processes are eligible - implied.
+ * 2) Runnable processes are favored over anything else. The runner
+ * with the highest cpu utilization is picked (p_estcpu). Ties are
+ * broken by picking the highest pid.
+ * 3) The sleeper with the shortest sleep time is next. With ties,
+ * we pick out just "short-term" sleepers (TDF_SINTR == 0).
+ * 4) Further ties are broken by picking the highest pid.
+ *
+ * If you change this, be sure to consider making the change in the kernel
+ * too (^T in kern/tty.c).
+ *
+ * TODO - consider whether pctcpu should be used.
+ */
+
+#if !HAVE_KVM
+#define ki_estcpu p_estcpu
+#define ki_pid p_pid
+#define ki_slptime p_slptime
+#define ki_stat p_stat
+#define ki_tdflags p_tdflags
+#endif
+
+#define ISRUN(p) (((p)->ki_stat == SRUN) || ((p)->ki_stat == SIDL))
+#define TESTAB(a, b) ((a)<<1 | (b))
+#define ONLYA 2
+#define ONLYB 1
+#define BOTH 3
+
+#if HAVE_KVM
+int
+proc_compare(struct kinfo_proc *p1, struct kinfo_proc *p2)
+{
+#else
+int
+proc_compare(struct kinfo_proc *arg1, struct kinfo_proc *arg2)
+{
+ struct extern_proc* p1 = &arg1->kp_proc;
+ struct extern_proc* p2 = &arg2->kp_proc;
+#endif
+
+ if (p1 == NULL)
+ return (1);
+ /*
+ * see if at least one of them is runnable
+ */
+ switch (TESTAB(ISRUN(p1), ISRUN(p2))) {
+ case ONLYA:
+ return (0);
+ case ONLYB:
+ return (1);
+ case BOTH:
+ /*
+ * tie - favor one with highest recent cpu utilization
+ */
+ if (p2->ki_estcpu > p1->ki_estcpu)
+ return (1);
+ if (p1->ki_estcpu > p2->ki_estcpu)
+ return (0);
+ return (p2->ki_pid > p1->ki_pid); /* tie - return highest pid */
+ }
+ /*
+ * weed out zombies
+ */
+ switch (TESTAB(p1->ki_stat == SZOMB, p2->ki_stat == SZOMB)) {
+ case ONLYA:
+ return (1);
+ case ONLYB:
+ return (0);
+ case BOTH:
+ return (p2->ki_pid > p1->ki_pid); /* tie - return highest pid */
+ }
+ /*
+ * pick the one with the smallest sleep time
+ */
+ if (p2->ki_slptime > p1->ki_slptime)
+ return (0);
+ if (p1->ki_slptime > p2->ki_slptime)
+ return (1);
+#ifndef __APPLE__
+ /*
+ * favor one sleeping in a non-interruptible sleep
+ */
+ if (p1->ki_tdflags & TDF_SINTR && (p2->ki_tdflags & TDF_SINTR) == 0)
+ return (1);
+ if (p2->ki_tdflags & TDF_SINTR && (p1->ki_tdflags & TDF_SINTR) == 0)
+ return (0);
+#endif
+ return (p2->ki_pid > p1->ki_pid); /* tie - return highest pid */
+}
diff --git a/shell_cmds/w/uptime.1 b/shell_cmds/w/uptime.1
new file mode 100644
index 0000000..a2c372a
--- /dev/null
+++ b/shell_cmds/w/uptime.1
@@ -0,0 +1,52 @@
+.\" Copyright (c) 1980, 1990, 1993, 1994
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)uptime.1 8.2 (Berkeley) 4/18/94
+.\" $FreeBSD: src/usr.bin/w/uptime.1,v 1.8 2002/05/09 11:47:40 joe Exp $
+.\"
+.Dd April 18, 1994
+.Dt UPTIME 1
+.Os
+.Sh NAME
+.Nm uptime
+.Nd show how long system has been running
+.Sh SYNOPSIS
+.Nm
+.Sh DESCRIPTION
+The
+.Nm
+utility displays the current time,
+the length of time the system has been up,
+the number of users, and the load average of the system over the last
+1, 5, and 15 minutes.
+.Sh SEE ALSO
+.Xr w 1
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 3.0 .
diff --git a/shell_cmds/w/w.1 b/shell_cmds/w/w.1
new file mode 100644
index 0000000..e94c39b
--- /dev/null
+++ b/shell_cmds/w/w.1
@@ -0,0 +1,127 @@
+.\" Copyright (c) 1980, 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)w.1 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD: src/usr.bin/w/w.1,v 1.20 2005/02/13 22:25:25 ru Exp $
+.\"
+.Dd June 6, 1993
+.Dt W 1
+.Os
+.Sh NAME
+.Nm w
+.Nd "display who is logged in and what they are doing"
+.Sh SYNOPSIS
+.Nm
+.Op Fl hin
+.Op Ar user ...
+.Sh DESCRIPTION
+The
+.Nm
+utility prints a summary of the current activity on the system,
+including what each user is doing.
+The first line displays the current time of day, how long the system has
+been running, the number of users logged into the system, and the load
+averages.
+The load average numbers give the number of jobs in the run queue averaged
+over 1, 5 and 15 minutes.
+.Pp
+The fields output are the user's login name, the name of the terminal the
+user is on, the host from which the user is logged in, the time the user
+logged on, the time since the user last typed anything,
+and the name and arguments of the current process.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl h
+Suppress the heading.
+.It Fl i
+Output is sorted by idle time.
+.El
+.Pp
+If one or more
+.Ar user
+names are specified, the output is restricted to those users.
+.Sh COMPATIBILITY
+The
+.Fl M ,
+.FL N ,
+.Fl d ,
+.Fl f ,
+.Fl l ,
+.Fl n ,
+.Fl s ,
+and
+.Fl w
+flags are no longer supported.
+.Sh SEE ALSO
+.Xr finger 1 ,
+.Xr ps 1 ,
+.Xr uptime 1 ,
+.Xr who 1
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 3.0 .
+.Sh BUGS
+The notion of the
+.Dq current process
+is muddy.
+The current algorithm is ``the highest numbered process on the terminal
+that is not ignoring interrupts, or, if there is none, the highest numbered
+process on the terminal''.
+This fails, for example, in critical sections of programs like the shell
+and editor, or when faulty programs running in the background fork and fail
+to ignore interrupts.
+(In cases where no process can be found,
+.Nm
+prints
+.Dq \- . )
+.Pp
+The
+.Tn CPU
+time is only an estimate, in particular, if someone leaves a background
+process running after logging out, the person currently on that terminal is
+.Dq charged
+with the time.
+.Pp
+Background processes are not shown, even though they account for
+much of the load on the system.
+.Pp
+Sometimes processes, typically those in the background, are printed with
+null or garbaged arguments.
+In these cases, the name of the command is printed in parentheses.
+.Pp
+The
+.Nm
+utility does not know about the new conventions for detection of background
+jobs.
+It will sometimes find a background job instead of the right one.
+.Pp
+Long hostnames and IPv6 addresses may be truncated; however, the
+.Xr who 1
+utility will display full hostnames.
diff --git a/shell_cmds/w/w.c b/shell_cmds/w/w.c
new file mode 100644
index 0000000..e493734
--- /dev/null
+++ b/shell_cmds/w/w.c
@@ -0,0 +1,776 @@
+/*-
+ * Copyright (c) 1980, 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ * Portions copyright (c) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#ifndef __APPLE__
+__FBSDID("$FreeBSD: src/usr.bin/w/w.c,v 1.58 2005/06/04 23:40:09 gad Exp $");
+#endif
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1980, 1991, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif
+
+#ifndef lint
+static const char sccsid[] = "@(#)w.c 8.4 (Berkeley) 4/16/94";
+#endif
+
+/*
+ * w - print system status (who and what)
+ *
+ * This program is similar to the systat command on Tenex/Tops 10/20
+ *
+ */
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/tty.h>
+
+#ifndef __APPLE__
+#include <machine/cpu.h>
+#endif
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#if HAVE_KVM
+#include <kvm.h>
+#endif
+#include <langinfo.h>
+#include <libutil.h>
+#include <limits.h>
+#include <locale.h>
+#include <netdb.h>
+#include <nlist.h>
+#include <paths.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <timeconv.h>
+#include <unistd.h>
+#if HAVE_UTMPX
+#include <utmpx.h>
+/* use utmp values so formatting is the same */
+#define UT_NAMESIZE 8
+#define UT_LINESIZE 8
+#else /* HAVE_UTMPX */
+#include <utmp.h>
+#endif /* HAVE_UTMPX */
+#include <vis.h>
+
+#include <TargetConditionals.h>
+
+#include "extern.h"
+
+struct timeval boottime;
+#if !HAVE_UTMPX
+struct utmp utmp;
+#endif
+struct winsize ws;
+#if HAVE_KVM
+kvm_t *kd;
+#endif
+time_t now; /* the current time of day */
+int ttywidth; /* width of tty */
+int argwidth; /* width of tty */
+int header = 1; /* true if -h flag: don't print heading */
+#if !HAVE_UTMPX
+int nflag; /* true if -n flag: don't convert addrs */
+#endif
+#ifndef __APPLE__
+int dflag; /* true if -d flag: output debug info */
+#endif
+int sortidle; /* sort by idle time */
+int use_ampm; /* use AM/PM time */
+int use_comma; /* use comma as floats separator */
+char **sel_users; /* login array of particular users selected */
+
+/*
+ * One of these per active utmp entry.
+ */
+struct entry {
+ struct entry *next;
+#if HAVE_UTMPX
+ struct utmpx utmp;
+#else
+ struct utmp utmp;
+#endif
+ dev_t tdev; /* dev_t of terminal */
+ time_t idle; /* idle time of terminal in seconds */
+ struct kinfo_proc *kp; /* `most interesting' proc */
+ char *args; /* arg list of interesting process */
+ struct kinfo_proc *dkp; /* debug option proc list */
+} *ep, *ehead = NULL, **nextp = &ehead;
+
+#ifndef __APPLE__
+#define debugproc(p) *((struct kinfo_proc **)&(p)->ki_udata)
+#else
+#define debugproc(p) *((struct kinfo_proc **)&(p)->ki_spare[0])
+#endif
+
+/* W_DISPHOSTSIZE should not be greater than UT_HOSTSIZE */
+#define W_DISPHOSTSIZE 16
+
+static void pr_header(time_t *, int);
+static struct stat *ttystat(char *, int);
+static void usage(int);
+static int this_is_uptime(const char *s);
+#if !HAVE_KVM
+static void w_getargv(void);
+#endif
+
+char *fmt_argv(char **, char *, int); /* ../../bin/ps/fmt.c */
+
+int
+main(int argc, char *argv[])
+{
+ struct kinfo_proc *kp;
+ struct kinfo_proc *kprocbuf;
+ struct kinfo_proc *dkp;
+ struct stat *stp;
+#if HAVE_UTMPX
+ struct utmpx *ux;
+#else
+ FILE *ut;
+#endif
+ time_t touched;
+#if HAVE_KVM
+ int ch, i, nentries, nusers, wcmd, longidle, dropgid;
+ const char *memf, *nlistf, *p;
+#else
+ int ch, i, nentries, nusers, wcmd, longidle;
+ const char *p;
+#endif /* HAVE_KVM */
+ char *x_suffix;
+#ifdef __APPLE__
+ char buf[MAXHOSTNAMELEN];
+#else
+ char buf[MAXHOSTNAMELEN], errbuf[_POSIX2_LINE_MAX];
+ char fn[MAXHOSTNAMELEN];
+#endif /* __APPLE__ */
+ char *dot;
+#if !HAVE_KVM
+ int local_error = 0, retry_count = 0;
+ size_t bufSize = 0;
+ size_t orig_bufSize = 0;
+ int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 };
+#endif
+
+ (void)setlocale(LC_ALL, "");
+#ifndef __APPLE__
+ use_ampm = (*nl_langinfo(T_FMT_AMPM) != '\0');
+ use_comma = (*nl_langinfo(RADIXCHAR) != ',');
+#endif
+
+ /* Are we w(1) or uptime(1)? */
+ if (this_is_uptime(argv[0]) == 0) {
+ wcmd = 0;
+ p = "";
+ } else {
+ wcmd = 1;
+ p = "dhiflM:N:nsuw";
+ }
+
+#if HAVE_KVM
+ dropgid = 0;
+ memf = nlistf = _PATH_DEVNULL;
+#endif
+ while ((ch = getopt(argc, argv, p)) != -1)
+ switch (ch) {
+#ifndef __APPLE__
+ case 'd':
+ dflag = 1;
+ break;
+#endif
+ case 'h':
+ header = 0;
+ break;
+ case 'i':
+ sortidle = 1;
+ break;
+#if HAVE_KVM
+ case 'M':
+ header = 0;
+ memf = optarg;
+ dropgid = 1;
+ break;
+ case 'N':
+ nlistf = optarg;
+ dropgid = 1;
+ break;
+#endif /* HAVE_KVM */
+#if !HAVE_UTMPX
+ case 'n':
+ nflag = 1;
+ break;
+#else /* !HAVE_UTMPX */
+ case 'n':
+#endif /* !HAVE_UTMPX */
+ case 'f': case 'l': case 's': case 'u': case 'w':
+#if !HAVE_KVM
+ case 'M': case 'N':
+#endif
+#ifdef __APPLE__
+ case 'd':
+ warnx("[-MNdflnsuw] no longer supported");
+#else
+ warnx("[-flsuw] no longer supported");
+#endif
+ /* FALLTHROUGH */
+ case '?':
+ default:
+ usage(wcmd);
+ }
+ argc -= optind;
+ argv += optind;
+
+#if !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+ if (!(_res.options & RES_INIT))
+ res_init();
+ _res.retrans = 2; /* resolver timeout to 2 seconds per try */
+ _res.retry = 1; /* only try once.. */
+#endif
+
+#if HAVE_KVM
+ /*
+ * Discard setgid privileges if not the running kernel so that bad
+ * guys can't print interesting stuff from kernel memory.
+ */
+ if (dropgid)
+ setgid(getgid());
+
+ if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf)) == NULL)
+ errx(1, "%s", errbuf);
+#endif
+
+ (void)time(&now);
+#if HAVE_UTMPX
+ setutxent();
+#else
+ if ((ut = fopen(_PATH_UTMP, "r")) == NULL)
+ err(1, "%s", _PATH_UTMP);
+#endif
+
+ if (*argv)
+ sel_users = argv;
+
+#if HAVE_UTMPX
+ for (nusers = 0; (ux = getutxent());) {
+ if (ux->ut_user[0] == '\0' || ux->ut_type != USER_PROCESS)
+ continue;
+ if (!(stp = ttystat(ux->ut_line, sizeof(ux->ut_line))))
+ continue; /* corrupted record */
+#else
+ for (nusers = 0; fread(&utmp, sizeof(utmp), 1, ut);) {
+ if (utmp.ut_name[0] == '\0')
+ continue;
+ if (!(stp = ttystat(utmp.ut_line, UT_LINESIZE)))
+ continue; /* corrupted record */
+#endif
+ ++nusers;
+ if (wcmd == 0)
+ continue;
+ if (sel_users) {
+ int usermatch;
+ char **user;
+
+ usermatch = 0;
+ for (user = sel_users; !usermatch && *user; user++)
+#if HAVE_UTMPX
+ if (!strncmp(ux->ut_user, *user, sizeof(ux->ut_user)))
+#else
+ if (!strncmp(utmp.ut_name, *user, UT_NAMESIZE))
+#endif
+ usermatch = 1;
+ if (!usermatch)
+ continue;
+ }
+ if ((ep = calloc(1, sizeof(struct entry))) == NULL)
+ errx(1, "calloc");
+ *nextp = ep;
+ nextp = &ep->next;
+#if HAVE_UTMPX
+ memmove(&ep->utmp, ux, sizeof(*ux));
+#else
+ memmove(&ep->utmp, &utmp, sizeof(struct utmp));
+#endif
+ ep->tdev = stp->st_rdev;
+#ifdef CPU_CONSDEV
+ /*
+ * If this is the console device, attempt to ascertain
+ * the true console device dev_t.
+ */
+ if (ep->tdev == 0) {
+ int mib[2];
+ size_t size;
+
+ mib[0] = CTL_MACHDEP;
+ mib[1] = CPU_CONSDEV;
+ size = sizeof(dev_t);
+ (void)sysctl(mib, 2, &ep->tdev, &size, NULL, 0);
+ }
+#endif
+ touched = stp->st_atime;
+#ifdef __APPLE__
+ if (touched < ep->utmp.ut_tv.tv_sec) {
+ /* tty untouched since before login */
+ touched = ep->utmp.ut_tv.tv_sec;
+ }
+#else
+ if (touched < ep->utmp.ut_time) {
+ /* tty untouched since before login */
+ touched = ep->utmp.ut_time;
+ }
+#endif
+ if ((ep->idle = now - touched) < 0)
+ ep->idle = 0;
+ }
+#if HAVE_UTMPX
+ endutxent();
+#else
+ (void)fclose(ut);
+#endif
+
+ if (header || wcmd == 0) {
+ pr_header(&now, nusers);
+ if (wcmd == 0) {
+#if HAVE_KVM
+ (void)kvm_close(kd);
+#endif
+ exit(0);
+ }
+
+#define HEADER_USER "USER"
+#define HEADER_TTY "TTY"
+#define HEADER_FROM "FROM"
+#define HEADER_LOGIN_IDLE "LOGIN@ IDLE "
+#define HEADER_WHAT "WHAT\n"
+#define WUSED (UT_NAMESIZE + UT_LINESIZE + W_DISPHOSTSIZE + \
+ sizeof(HEADER_LOGIN_IDLE) + 3) /* header width incl. spaces */
+ (void)printf("%-*.*s %-*.*s %-*.*s %s",
+ UT_NAMESIZE, UT_NAMESIZE, HEADER_USER,
+ UT_LINESIZE, UT_LINESIZE, HEADER_TTY,
+ W_DISPHOSTSIZE, W_DISPHOSTSIZE, HEADER_FROM,
+ HEADER_LOGIN_IDLE HEADER_WHAT);
+ }
+
+#if HAVE_KVM
+ if ((kp = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nentries)) == NULL)
+ err(1, "%s", kvm_geterr(kd));
+#else
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_ALL;
+ mib[3] = 0;
+
+ if (sysctl(mib, 4, NULL, &bufSize, NULL, 0) < 0) {
+ perror("Failure calling sysctl");
+ exit(1);
+ }
+
+ kprocbuf = kp = (struct kinfo_proc *)malloc(bufSize);
+
+ retry_count = 0;
+ orig_bufSize = bufSize;
+ for (retry_count = 0; ; retry_count++) {
+ local_error = 0;
+ bufSize = orig_bufSize;
+ if ((local_error = sysctl(mib, 4, kp, &bufSize, NULL, 0)) < 0) {
+ if (retry_count < 1000) {
+ sleep(1);
+ continue;
+ }
+ perror("Failure calling sysctl");
+ exit(1);
+ } else if (local_error == 0) {
+ break;
+ }
+ sleep(1);
+ }
+ nentries = bufSize / sizeof(struct kinfo_proc);
+#endif /* !HAVE_KVM */
+
+#if !HAVE_KVM
+#define ki_stat kp_proc.p_stat
+#define ki_pgid kp_eproc.e_pgid
+#define ki_tpgid kp_eproc.e_tpgid
+#define ki_tdev kp_eproc.e_tdev
+#endif /* !HAVE_KVM */
+ for (i = 0; i < nentries; i++, kp++) {
+ if (kp->ki_stat == SIDL || kp->ki_stat == SZOMB)
+ continue;
+ for (ep = ehead; ep != NULL; ep = ep->next) {
+ if (ep->tdev == kp->ki_tdev) {
+ /*
+ * proc is associated with this terminal
+ */
+ if (ep->kp == NULL && kp->ki_pgid == kp->ki_tpgid) {
+ /*
+ * Proc is 'most interesting'
+ */
+ if (proc_compare(ep->kp, kp))
+ ep->kp = kp;
+ }
+ /*
+ * Proc debug option info; add to debug
+ * list using kinfo_proc ki_spare[0]
+ * as next pointer; ptr to ptr avoids the
+ * ptr = long assumption.
+ */
+ dkp = ep->dkp;
+ ep->dkp = kp;
+#ifndef __APPLE__
+ debugproc(kp) = dkp;
+#endif
+ }
+ }
+ }
+ if ((ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == -1 &&
+ ioctl(STDERR_FILENO, TIOCGWINSZ, &ws) == -1 &&
+ ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1) || ws.ws_col == 0)
+ ttywidth = 79;
+ else
+ ttywidth = ws.ws_col - 1;
+ argwidth = ttywidth - WUSED;
+ if (argwidth < 4)
+ argwidth = 8;
+ for (ep = ehead; ep != NULL; ep = ep->next) {
+ if (ep->kp == NULL) {
+ ep->args = strdup("-");
+ continue;
+ }
+#if HAVE_KVM
+ ep->args = fmt_argv(kvm_getargv(kd, ep->kp, argwidth),
+ ep->kp->ki_comm, MAXCOMLEN);
+#else
+ w_getargv();
+#endif /* HAVE_KVM */
+ if (ep->args == NULL)
+ err(1, NULL);
+ }
+ /* sort by idle time */
+ if (sortidle && ehead != NULL) {
+ struct entry *from, *save;
+
+ from = ehead;
+ ehead = NULL;
+ while (from != NULL) {
+ for (nextp = &ehead;
+ (*nextp) && from->idle >= (*nextp)->idle;
+ nextp = &(*nextp)->next)
+ continue;
+ save = from;
+ from = from->next;
+ save->next = *nextp;
+ *nextp = save;
+ }
+ }
+
+ for (ep = ehead; ep != NULL; ep = ep->next) {
+#if HAVE_UTMPX
+ char host_buf[sizeof(ep->utmp.ut_host) + 1];
+ strlcpy(host_buf, ep->utmp.ut_host, sizeof(host_buf));
+#else
+ char host_buf[UT_HOSTSIZE + 1];
+ struct sockaddr_storage ss;
+ struct sockaddr *sa = (struct sockaddr *)&ss;
+ struct sockaddr_in *lsin = (struct sockaddr_in *)&ss;
+ struct sockaddr_in6 *lsin6 = (struct sockaddr_in6 *)&ss;
+ time_t t;
+ int isaddr;
+
+ host_buf[UT_HOSTSIZE] = '\0';
+ strncpy(host_buf, ep->utmp.ut_host, UT_HOSTSIZE);
+#endif /* HAVE_UTMPX */
+ p = *host_buf ? host_buf : "-";
+ if ((x_suffix = strrchr(p, ':')) != NULL) {
+ if ((dot = strchr(x_suffix, '.')) != NULL &&
+ strchr(dot+1, '.') == NULL)
+ *x_suffix++ = '\0';
+ else
+ x_suffix = NULL;
+ }
+#if !HAVE_UTMPX
+ if (!nflag) {
+ /* Attempt to change an IP address into a name */
+ isaddr = 0;
+ memset(&ss, '\0', sizeof(ss));
+ if (inet_pton(AF_INET6, p, &lsin6->sin6_addr) == 1) {
+ lsin6->sin6_len = sizeof(*lsin6);
+ lsin6->sin6_family = AF_INET6;
+ isaddr = 1;
+ } else if (inet_pton(AF_INET, p, &lsin->sin_addr) == 1) {
+ lsin->sin_len = sizeof(*lsin);
+ lsin->sin_family = AF_INET;
+ isaddr = 1;
+ }
+ if (isaddr && realhostname_sa(fn, sizeof(fn), sa,
+ sa->sa_len) == HOSTNAME_FOUND)
+ p = fn;
+ }
+#endif /* !HAVE_UTMPX */
+ if (x_suffix) {
+ (void)snprintf(buf, sizeof(buf), "%s:%s", p, x_suffix);
+ p = buf;
+ }
+#ifndef __APPLE__
+ if (dflag) {
+ for (dkp = ep->dkp; dkp != NULL; dkp = debugproc(dkp)) {
+ const char *ptr;
+
+ ptr = fmt_argv(kvm_getargv(kd, dkp, argwidth),
+ dkp->ki_comm, MAXCOMLEN);
+ if (ptr == NULL)
+ ptr = "-";
+ (void)printf("\t\t%-9d %s\n",
+ dkp->ki_pid, ptr);
+ }
+ }
+#endif /* !__APPLE__ */
+ (void)printf("%-*.*s %-*.*s %-*.*s ",
+#if HAVE_UTMPX
+ UT_NAMESIZE, (int)sizeof(ep->utmp.ut_user), ep->utmp.ut_user,
+ UT_LINESIZE, (int)sizeof(ep->utmp.ut_line),
+#else
+ UT_NAMESIZE, UT_NAMESIZE, ep->utmp.ut_name,
+ UT_LINESIZE, UT_LINESIZE,
+#endif
+ strncmp(ep->utmp.ut_line, "tty", 3) &&
+ strncmp(ep->utmp.ut_line, "cua", 3) ?
+ ep->utmp.ut_line : ep->utmp.ut_line + 3,
+ W_DISPHOSTSIZE, W_DISPHOSTSIZE, *p ? p : "-");
+#ifdef __APPLE__
+ pr_attime(&ep->utmp.ut_tv.tv_sec, &now);
+#else
+ t = _time_to_time32(ep->utmp.ut_time);
+ pr_attime(&t, &now);
+#endif
+ longidle = pr_idle(ep->idle);
+ (void)printf("%.*s\n", argwidth - longidle, ep->args);
+#ifdef __APPLE__
+ free(ep->args);
+#endif
+ }
+#if HAVE_KVM
+ (void)kvm_close(kd);
+#else
+ free(kprocbuf);
+#endif /* HAVE_KVM */
+ exit(0);
+}
+
+static void
+pr_header(time_t *nowp, int nusers)
+{
+ double avenrun[3];
+ time_t uptime;
+ int days, hrs, i, mins, secs;
+ int mib[2];
+ size_t size;
+ char buf[256];
+
+ /*
+ * Print time of day.
+ */
+ if (strftime(buf, sizeof(buf),
+ use_ampm ? "%l:%M%p" : "%k:%M", localtime(nowp)) != 0)
+ (void)printf("%s ", buf);
+ /*
+ * Print how long system has been up.
+ * (Found by looking getting "boottime" from the kernel)
+ */
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_BOOTTIME;
+ size = sizeof(boottime);
+ if (sysctl(mib, 2, &boottime, &size, NULL, 0) != -1 &&
+ boottime.tv_sec != 0) {
+ uptime = now - boottime.tv_sec;
+ if (uptime > 60)
+ uptime += 30;
+ days = uptime / 86400;
+ uptime %= 86400;
+ hrs = uptime / 3600;
+ uptime %= 3600;
+ mins = uptime / 60;
+ secs = uptime % 60;
+ (void)printf(" up");
+ if (days > 0)
+ (void)printf(" %d day%s,", days, days > 1 ? "s" : "");
+ if (hrs > 0 && mins > 0)
+ (void)printf(" %2d:%02d,", hrs, mins);
+ else if (hrs > 0)
+ (void)printf(" %d hr%s,", hrs, hrs > 1 ? "s" : "");
+ else if (mins > 0)
+ (void)printf(" %d min%s,", mins, mins > 1 ? "s" : "");
+ else
+ (void)printf(" %d sec%s,", secs, secs > 1 ? "s" : "");
+ }
+
+ /* Print number of users logged in to system */
+ (void)printf(" %d user%s", nusers, nusers == 1 ? "" : "s");
+
+ /*
+ * Print 1, 5, and 15 minute load averages.
+ */
+ if (getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])) == -1)
+ (void)printf(", no load average information available\n");
+ else {
+ (void)printf(", load averages:");
+ for (i = 0; i < (int)(sizeof(avenrun) / sizeof(avenrun[0])); i++) {
+ if (use_comma && i > 0)
+ (void)printf(",");
+ (void)printf(" %.2f", avenrun[i]);
+ }
+ (void)printf("\n");
+ }
+}
+
+static struct stat *
+ttystat(char *line, int sz)
+{
+ static struct stat sb;
+ char ttybuf[MAXPATHLEN];
+
+ (void)snprintf(ttybuf, sizeof(ttybuf), "%s%.*s", _PATH_DEV, sz, line);
+ if (stat(ttybuf, &sb) == 0) {
+ return (&sb);
+ } else {
+ warn("%s", ttybuf);
+ return (NULL);
+ }
+}
+
+static void
+usage(int wcmd)
+{
+ if (wcmd)
+ (void)fprintf(stderr,
+ "usage: w [hi] [user ...]\n");
+ else
+ (void)fprintf(stderr, "usage: uptime\n");
+ exit(1);
+}
+
+static int
+this_is_uptime(const char *s)
+{
+ const char *u;
+
+ if ((u = strrchr(s, '/')) != NULL)
+ ++u;
+ else
+ u = s;
+ if (strcmp(u, "uptime") == 0)
+ return (0);
+ return (-1);
+}
+
+#if !HAVE_KVM
+static void
+w_getargv(void)
+{
+ int mib[3], argmax;
+ size_t size;
+ char *procargs, *sp, *np, *cp;
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_ARGMAX;
+
+ size = sizeof(argmax);
+ if (sysctl(mib, 2, &argmax, &size, NULL, 0) == -1) {
+ goto ERROR;
+ }
+
+ procargs = malloc(argmax);
+ if (procargs == NULL) {
+ goto ERROR;
+ }
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROCARGS;
+ mib[2] = KI_PROC(ep)->p_pid;
+
+ size = (size_t)argmax;
+ if (sysctl(mib, 3, procargs, &size, NULL, 0) == -1) {
+ goto ERROR_FREE;
+ }
+
+ for (cp = procargs; cp < &procargs[size]; cp++) {
+ if (*cp == '\0') {
+ break;
+ }
+ }
+ if (cp == &procargs[size]) {
+ goto ERROR_FREE;
+ }
+
+ sp = cp;
+
+ for (np = NULL; cp < &procargs[size]; cp++) {
+ if (*cp == '\0') {
+ if (np != NULL) {
+ *np = ' ';
+ }
+ np = cp;
+ } else if (*cp == '=') {
+ break;
+ }
+ }
+
+ for (np = sp; (np < &procargs[size]) && (*np == ' '); np++);
+
+ ep->args = strdup(np);
+ free(procargs);
+ return;
+
+ERROR_FREE:
+ free(procargs);
+ERROR:
+/*
+ ep->args = malloc(2);
+ ep->args[0] = '-';
+ ep->args[1] = '\0';
+*/
+ asprintf(&ep->args, "%s", KI_PROC(ep)->p_comm);
+ return;
+}
+#endif /* HAVE_KVM */
diff --git a/shell_cmds/what/what.1 b/shell_cmds/what/what.1
new file mode 100644
index 0000000..fff56be
--- /dev/null
+++ b/shell_cmds/what/what.1
@@ -0,0 +1,70 @@
+.\" $NetBSD: what.1,v 1.4 1997/10/20 03:16:30 lukem Exp $
+.\"
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)what.1 8.1 (Berkeley) 6/6/93
+.\"
+.Dd June 6, 1993
+.Dt WHAT 1
+.Os BSD 4
+.Sh NAME
+.Nm what
+.Nd "show what versions of object modules were used to construct a file"
+.Sh SYNOPSIS
+.Nm
+.Ar name Ar ...
+.Sh DESCRIPTION
+.Nm
+reads each file
+.Ar name
+and searches for sequences of the form
+.Dq \&@(#) ,
+as inserted by the source code control system. It prints the remainder
+of the string following this marker, up to a null character, newline, double
+quote, or
+.Dq \&> character.
+.Sh BUGS
+As
+.Bx
+is not licensed to distribute
+.Tn SCCS .
+This is a rewrite of the
+.Nm
+command which is part of
+.Tn SCCS ;
+it may not behave in exactly the same manner as that
+command does.
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.0 .
diff --git a/shell_cmds/what/what.c b/shell_cmds/what/what.c
new file mode 100644
index 0000000..2f70e2d
--- /dev/null
+++ b/shell_cmds/what/what.c
@@ -0,0 +1,97 @@
+/* $NetBSD: what.c,v 1.6 1997/10/20 03:16:31 lukem Exp $ */
+
+/*
+ * Copyright (c) 1980, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1980, 1988, 1993\n\
+ The Regents of the University of California. All rights reserved.\n");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)what.c 8.1 (Berkeley) 6/6/93";
+#endif
+__RCSID("$NetBSD: what.c,v 1.6 1997/10/20 03:16:31 lukem Exp $");
+#endif /* not lint */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+void search __P((void));
+int main __P((int, char **));
+
+/*
+ * what
+ */
+/* ARGSUSED */
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ if (!*++argv)
+ search();
+ else do {
+ if (!freopen(*argv, "r", stdin)) {
+ perror(*argv);
+ exit(1);
+ }
+ printf("%s\n", *argv);
+ search();
+ } while(*++argv);
+ exit(0);
+}
+
+void
+search()
+{
+ int c;
+
+ while ((c = getchar()) != EOF) {
+loop: if (c != '@')
+ continue;
+ if ((c = getchar()) != '(')
+ goto loop;
+ if ((c = getchar()) != '#')
+ goto loop;
+ if ((c = getchar()) != ')')
+ goto loop;
+ putchar('\t');
+ while ((c = getchar()) != EOF && c && c != '"' &&
+ c != '>' && c != '\n')
+ putchar(c);
+ putchar('\n');
+ }
+}
diff --git a/shell_cmds/whereis/whereis.1 b/shell_cmds/whereis/whereis.1
new file mode 100644
index 0000000..4df4b27
--- /dev/null
+++ b/shell_cmds/whereis/whereis.1
@@ -0,0 +1,70 @@
+.\" $NetBSD: whereis.1,v 1.7 1998/02/06 06:20:06 perry Exp $
+.\"
+.\" Copyright (c) 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)whereis.1 8.3 (Berkeley) 4/27/95
+.\"
+.Dd April 27, 1995
+.Dt WHEREIS 1
+.Os
+.Sh NAME
+.Nm whereis
+.Nd locate programs
+.Sh SYNOPSIS
+.Nm
+.Op Ar program ...
+.Sh DESCRIPTION
+The
+.Nm
+utility checks the standard binary directories for the specified programs,
+printing out the paths of any it finds.
+.Pp
+The path searched is the string returned by the
+.Xr sysctl 8
+utility for the
+.Dq user.cs_path
+string.
+.Sh SEE ALSO
+.Xr find 1 ,
+.Xr locate 1 ,
+.Xr man 1 ,
+.Xr which 1 ,
+.Xr sysctl 8
+.Sh COMPATIBILITY
+The historic flags and arguments for the
+.Nm
+utility are no longer available in this version.
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 3.0 .
diff --git a/shell_cmds/whereis/whereis.c b/shell_cmds/whereis/whereis.c
new file mode 100644
index 0000000..680f1f3
--- /dev/null
+++ b/shell_cmds/whereis/whereis.c
@@ -0,0 +1,128 @@
+/* $NetBSD: whereis.c,v 1.8 1997/10/20 02:22:55 mrg Exp $ */
+
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1993\n\
+ The Regents of the University of California. All rights reserved.\n");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)whereis.c 8.3 (Berkeley) 5/4/95";
+#endif
+__RCSID("$NetBSD: whereis.c,v 1.8 1997/10/20 02:22:55 mrg Exp $");
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+void usage __P((void));
+int main __P((int, char *[]));
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ struct stat sb;
+ size_t len;
+ int ch, sverrno, mib[2];
+ char *p, *t, *std, path[MAXPATHLEN];
+
+ while ((ch = getopt(argc, argv, "")) != -1)
+ switch (ch) {
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc == 0)
+ usage();
+
+ /* Retrieve the standard path. */
+ mib[0] = CTL_USER;
+ mib[1] = USER_CS_PATH;
+ if (sysctl(mib, 2, NULL, &len, NULL, 0) == -1)
+ return (-1);
+ if (len == 0)
+ err(1, "user_cs_path: sysctl: zero length\n");
+ if ((std = malloc(len)) == NULL)
+ err(1, "%s", "");
+ if (sysctl(mib, 2, std, &len, NULL, 0) == -1) {
+ sverrno = errno;
+ free(std);
+ errno = sverrno;
+ err(1, "sysctl: user_cs_path");
+ }
+
+ /* For each path, for each program... */
+ for (; *argv; ++argv)
+ for (p = std;; *p++ = ':') {
+ t = p;
+ if ((p = strchr(p, ':')) != NULL) {
+ *p = '\0';
+ if (t == p)
+ t = ".";
+ } else
+ if (strlen(t) == 0)
+ t = ".";
+ (void)snprintf(path, sizeof(path), "%s/%s", t, *argv);
+ if (!stat(path, &sb))
+ (void)printf("%s\n", path);
+ if (p == NULL)
+ break;
+ }
+
+ return (0);
+}
+
+void
+usage()
+{
+
+ (void)fprintf(stderr, "usage: whereis program [...]\n");
+ exit (1);
+}
diff --git a/shell_cmds/which/which.1 b/shell_cmds/which/which.1
new file mode 100644
index 0000000..d0f2fcb
--- /dev/null
+++ b/shell_cmds/which/which.1
@@ -0,0 +1,85 @@
+.\" Manpage Copyright (c) 1995, Jordan Hubbard <jkh@FreeBSD.org>
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the FreeBSD Project
+.\" its contributors.
+.\" 4. Neither the name of the FreeBSD Project nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE CONTRIBUTOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD: head/usr.bin/which/which.1 267773 2014-06-23 08:23:05Z bapt $
+.\"
+.Dd December 13, 2006
+.Dt WHICH 1
+.Os
+.Sh NAME
+.Nm which
+.Nd "locate a program file in the user's path"
+.Sh SYNOPSIS
+.Nm
+.Op Fl as
+.Ar program ...
+.Sh DESCRIPTION
+The
+.Nm
+utility
+takes a list of command names and searches the path for each executable
+file that would be run had these commands actually been invoked.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl a
+List all instances of executables found (instead of just the first one
+of each).
+.It Fl s
+No output, just return 0 if all of the executables are found, or 1 if
+some were not found.
+.El
+.Pp
+Some shells may provide a builtin
+.Nm
+command which is similar or identical to this utility.
+Consult the
+.Xr builtin 1
+manual page.
+.Sh SEE ALSO
+.Xr builtin 1 ,
+.Xr csh 1 ,
+.Xr find 1 ,
+.Xr locate 1 ,
+.Xr whereis 1
+.Sh HISTORY
+The
+.Nm
+command first appeared in
+.Fx 2.1 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm
+utility was originally written in Perl and was contributed by
+.An Wolfram Schneider Aq Mt wosch@FreeBSD.org .
+The current version of
+.Nm
+was rewritten in C by
+.An Daniel Papasian Aq Mt dpapasia@andrew.cmu.edu .
diff --git a/shell_cmds/which/which.c b/shell_cmds/which/which.c
new file mode 100644
index 0000000..7e9d662
--- /dev/null
+++ b/shell_cmds/which/which.c
@@ -0,0 +1,146 @@
+/**
+ * Copyright (c) 2000 Dan Papasian. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+__FBSDID("$FreeBSD: head/usr.bin/which/which.c 227245 2011-11-06 18:50:26Z ed $");
+
+#include <sys/stat.h>
+#include <sys/param.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+static void usage(void);
+static int print_matches(char *, char *);
+
+static int silent;
+static int allpaths;
+
+int
+main(int argc, char **argv)
+{
+ char *p, *path;
+ ssize_t pathlen;
+ int opt, status;
+
+ status = EXIT_SUCCESS;
+
+ while ((opt = getopt(argc, argv, "as")) != -1) {
+ switch (opt) {
+ case 'a':
+ allpaths = 1;
+ break;
+ case 's':
+ silent = 1;
+ break;
+ default:
+ usage();
+ break;
+ }
+ }
+
+ argv += optind;
+ argc -= optind;
+
+ if (argc == 0)
+ usage();
+
+ if ((p = getenv("PATH")) == NULL)
+ exit(EXIT_FAILURE);
+ pathlen = strlen(p) + 1;
+ path = malloc(pathlen);
+ if (path == NULL)
+ err(EXIT_FAILURE, NULL);
+
+ while (argc > 0) {
+ memcpy(path, p, pathlen);
+
+ if (strlen(*argv) >= FILENAME_MAX ||
+ print_matches(path, *argv) == -1)
+ status = EXIT_FAILURE;
+
+ argv++;
+ argc--;
+ }
+
+ exit(status);
+}
+
+static void
+usage(void)
+{
+
+ (void)fprintf(stderr, "usage: which [-as] program ...\n");
+ exit(EXIT_FAILURE);
+}
+
+static int
+is_there(char *candidate)
+{
+ struct stat fin;
+
+ /* XXX work around access(2) false positives for superuser */
+ if (access(candidate, X_OK) == 0 &&
+ stat(candidate, &fin) == 0 &&
+ S_ISREG(fin.st_mode) &&
+ (getuid() != 0 ||
+ (fin.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0)) {
+ if (!silent)
+ printf("%s\n", candidate);
+ return (1);
+ }
+ return (0);
+}
+
+static int
+print_matches(char *path, char *filename)
+{
+ char candidate[PATH_MAX];
+ const char *d;
+ int found;
+
+ if (strchr(filename, '/') != NULL)
+ return (is_there(filename) ? 0 : -1);
+ found = 0;
+ while ((d = strsep(&path, ":")) != NULL) {
+ if (*d == '\0')
+ d = ".";
+ if (snprintf(candidate, sizeof(candidate), "%s/%s", d,
+ filename) >= (int)sizeof(candidate))
+ continue;
+ if (is_there(candidate)) {
+ found = 1;
+ if (!allpaths)
+ break;
+ }
+ }
+ return (found ? 0 : -1);
+}
+
diff --git a/shell_cmds/who/utmpentry.c b/shell_cmds/who/utmpentry.c
new file mode 100644
index 0000000..b0e0914
--- /dev/null
+++ b/shell_cmds/who/utmpentry.c
@@ -0,0 +1,348 @@
+/* $NetBSD: utmpentry.c,v 1.15 2008/07/13 20:07:48 dholland Exp $ */
+
+/*-
+ * Copyright (c) 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__RCSID("$NetBSD: utmpentry.c,v 1.15 2008/07/13 20:07:48 dholland Exp $");
+#endif
+
+#include <sys/stat.h>
+
+#include <time.h>
+#include <string.h>
+#include <err.h>
+#include <stdlib.h>
+#ifdef __APPLE__
+#include <stdint.h>
+#endif /* __APPLE__ */
+
+#ifdef SUPPORT_UTMP
+#include <utmp.h>
+#endif
+#ifdef SUPPORT_UTMPX
+#include <utmpx.h>
+#endif
+
+#include "utmpentry.h"
+
+#ifdef __APPLE__
+#define timespecclear(tsp) (tsp)->tv_sec = (time_t)((tsp)->tv_nsec = 0L)
+#define timespeccmp(tsp, usp, cmp) \
+ (((tsp)->tv_sec == (usp)->tv_sec) ? \
+ ((tsp)->tv_nsec cmp (usp)->tv_nsec) : \
+ ((tsp)->tv_sec cmp (usp)->tv_sec))
+#endif /* __APPLE__ */
+
+/* Fail the compile if x is not true, by constructing an illegal type. */
+#define COMPILE_ASSERT(x) ((void)sizeof(struct { unsigned : ((x) ? 1 : -1); }))
+
+
+#ifdef SUPPORT_UTMP
+static void getentry(struct utmpentry *, struct utmp *);
+static struct timespec utmptime = {0, 0};
+#endif
+#ifdef SUPPORT_UTMPX
+static void getentryx(struct utmpentry *, struct utmpx *);
+static struct timespec utmpxtime = {0, 0};
+#endif
+#if defined(SUPPORT_UTMPX) || defined(SUPPORT_UTMP)
+static int setup(const char *);
+static void adjust_size(struct utmpentry *e);
+#endif
+
+int maxname = 8, maxline = 8, maxhost = 16;
+int etype = 1 << USER_PROCESS;
+static int numutmp = 0;
+static struct utmpentry *ehead;
+
+#if defined(SUPPORT_UTMPX) || defined(SUPPORT_UTMP)
+static void
+adjust_size(struct utmpentry *e)
+{
+ int max;
+
+ if ((max = strlen(e->name)) > maxname)
+ maxname = max;
+ if ((max = strlen(e->line)) > maxline)
+ maxline = max;
+ if ((max = strlen(e->host)) > maxhost)
+ maxhost = max;
+}
+
+static int
+setup(const char *fname)
+{
+ int what = 3;
+ struct stat st;
+ const char *sfname;
+
+ if (fname == NULL) {
+#ifdef SUPPORT_UTMPX
+ setutxent();
+#endif
+#ifdef SUPPORT_UTMP
+ setutent();
+#endif
+ } else {
+ size_t len = strlen(fname);
+ if (len == 0)
+ errx(1, "Filename cannot be 0 length.");
+#ifdef __APPLE__
+ what = 1;
+#else /* !__APPLE__ */
+ what = fname[len - 1] == 'x' ? 1 : 2;
+#endif /* __APPLE__ */
+ if (what == 1) {
+#ifdef SUPPORT_UTMPX
+ if (utmpxname(fname) == 0)
+ warnx("Cannot set utmpx file to `%s'",
+ fname);
+#else
+ warnx("utmpx support not compiled in");
+#endif
+ } else {
+#ifdef SUPPORT_UTMP
+ if (utmpname(fname) == 0)
+ warnx("Cannot set utmp file to `%s'",
+ fname);
+#else
+ warnx("utmp support not compiled in");
+#endif
+ }
+ }
+#ifdef SUPPORT_UTMPX
+ if (what & 1) {
+ sfname = fname ? fname : _PATH_UTMPX;
+ if (stat(sfname, &st) == -1) {
+ warn("Cannot stat `%s'", sfname);
+ what &= ~1;
+ } else {
+ if (timespeccmp(&st.st_mtimespec, &utmpxtime, >))
+ utmpxtime = st.st_mtimespec;
+ else
+ what &= ~1;
+ }
+ }
+#endif
+#ifdef SUPPORT_UTMP
+ if (what & 2) {
+ sfname = fname ? fname : _PATH_UTMP;
+ if (stat(sfname, &st) == -1) {
+ warn("Cannot stat `%s'", sfname);
+ what &= ~2;
+ } else {
+ if (timespeccmp(&st.st_mtimespec, &utmptime, >))
+ utmptime = st.st_mtimespec;
+ else
+ what &= ~2;
+ }
+ }
+#endif
+ return what;
+}
+#endif
+
+void
+endutentries(void)
+{
+ struct utmpentry *ep;
+
+#ifdef SUPPORT_UTMP
+ timespecclear(&utmptime);
+#endif
+#ifdef SUPPORT_UTMPX
+ timespecclear(&utmpxtime);
+#endif
+ ep = ehead;
+ while (ep) {
+ struct utmpentry *sep = ep;
+ ep = ep->next;
+ free(sep);
+ }
+ ehead = NULL;
+ numutmp = 0;
+}
+
+int
+getutentries(const char *fname, struct utmpentry **epp)
+{
+#ifdef SUPPORT_UTMPX
+ struct utmpx *utx;
+#endif
+#ifdef SUPPORT_UTMP
+ struct utmp *ut;
+#endif
+#if defined(SUPPORT_UTMP) || defined(SUPPORT_UTMPX)
+ struct utmpentry *ep;
+ int what = setup(fname);
+ struct utmpentry **nextp = &ehead;
+ switch (what) {
+ case 0:
+ /* No updates */
+ *epp = ehead;
+ return numutmp;
+ default:
+ /* Need to re-scan */
+ ehead = NULL;
+ numutmp = 0;
+ }
+#endif
+
+#ifdef SUPPORT_UTMPX
+ while ((what & 1) && (utx = getutxent()) != NULL) {
+#ifdef __APPLE__
+ if (((1 << utx->ut_type) & etype) == 0)
+#else /* !__APPLE__ */
+ if (fname == NULL && ((1 << utx->ut_type) & etype) == 0)
+#endif /* __APPLE__ */
+ continue;
+ if ((ep = calloc(1, sizeof(struct utmpentry))) == NULL) {
+ warn(NULL);
+ return 0;
+ }
+ getentryx(ep, utx);
+ *nextp = ep;
+ nextp = &(ep->next);
+ }
+#endif
+
+#ifdef SUPPORT_UTMP
+ if ((etype & (1 << USER_PROCESS)) != 0) {
+ while ((what & 2) && (ut = getutent()) != NULL) {
+ if (fname == NULL && (*ut->ut_name == '\0' ||
+ *ut->ut_line == '\0'))
+ continue;
+ /* Don't process entries that we have utmpx for */
+ for (ep = ehead; ep != NULL; ep = ep->next) {
+ if (strncmp(ep->line, ut->ut_line,
+ sizeof(ut->ut_line)) == 0)
+ break;
+ }
+ if (ep != NULL)
+ continue;
+ if ((ep = calloc(1, sizeof(*ep))) == NULL) {
+ warn(NULL);
+ return 0;
+ }
+ getentry(ep, ut);
+ *nextp = ep;
+ nextp = &(ep->next);
+ }
+ }
+#endif
+ numutmp = 0;
+#if defined(SUPPORT_UTMP) || defined(SUPPORT_UTMPX)
+ if (ehead != NULL) {
+ struct utmpentry *from = ehead, *save;
+
+ ehead = NULL;
+ while (from != NULL) {
+ for (nextp = &ehead;
+ (*nextp) && strcmp(from->line, (*nextp)->line) > 0;
+ nextp = &(*nextp)->next)
+ continue;
+ save = from;
+ from = from->next;
+ save->next = *nextp;
+ *nextp = save;
+ numutmp++;
+ }
+ }
+ *epp = ehead;
+ return numutmp;
+#else
+ *epp = NULL;
+ return 0;
+#endif
+}
+
+#ifdef SUPPORT_UTMP
+static void
+getentry(struct utmpentry *e, struct utmp *up)
+{
+ COMPILE_ASSERT(sizeof(e->name) > sizeof(up->ut_name));
+ COMPILE_ASSERT(sizeof(e->line) > sizeof(up->ut_line));
+ COMPILE_ASSERT(sizeof(e->host) > sizeof(up->ut_host));
+
+ /*
+ * e has just been calloc'd. We don't need to clear it or
+ * append null-terminators, because its length is strictly
+ * greater than the source string. Use strncpy to _read_
+ * up->ut_* because they may not be terminated. For this
+ * reason we use the size of the _source_ as the length
+ * argument.
+ */
+ (void)strncpy(e->name, up->ut_name, sizeof(up->ut_name));
+ (void)strncpy(e->line, up->ut_line, sizeof(up->ut_line));
+ (void)strncpy(e->host, up->ut_host, sizeof(up->ut_host));
+
+ e->tv.tv_sec = up->ut_time;
+ e->tv.tv_usec = 0;
+ e->pid = 0;
+ e->term = 0;
+ e->exit = 0;
+ e->sess = 0;
+ e->type = USER_PROCESS;
+ adjust_size(e);
+}
+#endif
+
+#ifdef SUPPORT_UTMPX
+static void
+getentryx(struct utmpentry *e, struct utmpx *up)
+{
+ COMPILE_ASSERT(sizeof(e->name) > sizeof(up->ut_name));
+ COMPILE_ASSERT(sizeof(e->line) > sizeof(up->ut_line));
+ COMPILE_ASSERT(sizeof(e->host) > sizeof(up->ut_host));
+
+ /*
+ * e has just been calloc'd. We don't need to clear it or
+ * append null-terminators, because its length is strictly
+ * greater than the source string. Use strncpy to _read_
+ * up->ut_* because they may not be terminated. For this
+ * reason we use the size of the _source_ as the length
+ * argument.
+ */
+ (void)strncpy(e->name, up->ut_name, sizeof(up->ut_name));
+ (void)strncpy(e->line, up->ut_line, sizeof(up->ut_line));
+ (void)strncpy(e->host, up->ut_host, sizeof(up->ut_host));
+
+ e->tv = up->ut_tv;
+ e->pid = up->ut_pid;
+#ifndef __APPLE__
+ e->term = up->ut_exit.e_termination;
+ e->exit = up->ut_exit.e_exit;
+ e->sess = up->ut_session;
+#endif /* !__APPLE__ */
+ e->type = up->ut_type;
+ adjust_size(e);
+}
+#endif
diff --git a/shell_cmds/who/utmpentry.h b/shell_cmds/who/utmpentry.h
new file mode 100644
index 0000000..012478a
--- /dev/null
+++ b/shell_cmds/who/utmpentry.h
@@ -0,0 +1,78 @@
+/* $NetBSD: utmpentry.h,v 1.7 2008/07/13 20:07:49 dholland Exp $ */
+
+/*-
+ * Copyright (c) 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(SUPPORT_UTMPX)
+# include <utmpx.h>
+# define WHO_NAME_LEN _UTX_USERSIZE
+# define WHO_LINE_LEN _UTX_LINESIZE
+# define WHO_HOST_LEN _UTX_HOSTSIZE
+#elif defined(SUPPORT_UTMP)
+# include <utmp.h>
+# define WHO_NAME_LEN UT_NAMESIZE
+# define WHO_LINE_LEN UT_LINESIZE
+# define WHO_HOST_LEN UT_HOSTSIZE
+#else
+# error Either SUPPORT_UTMPX or SUPPORT_UTMP must be defined!
+#endif
+
+
+struct utmpentry {
+ char name[WHO_NAME_LEN + 1];
+ char line[WHO_LINE_LEN + 1];
+ char host[WHO_HOST_LEN + 1];
+ struct timeval tv;
+ pid_t pid;
+#ifndef __APPLE__
+ uint16_t term;
+ uint16_t exit;
+ uint16_t sess;
+#endif /* !__APPLE__ */
+ uint16_t type;
+ struct utmpentry *next;
+};
+
+extern int maxname, maxline, maxhost;
+extern int etype;
+
+/*
+ * getutentries provides a linked list of struct utmpentry and returns
+ * the number of entries. The first argument, if not null, names an
+ * alternate utmp(x) file to look in.
+ *
+ * The memory returned by getutentries belongs to getutentries. The
+ * list returned (or elements of it) may be returned again later if
+ * utmp hasn't changed in the meantime.
+ *
+ * endutentries clears and frees the cached data.
+ */
+
+int getutentries(const char *, struct utmpentry **);
+void endutentries(void);
diff --git a/shell_cmds/who/who.1 b/shell_cmds/who/who.1
new file mode 100644
index 0000000..dbcbdf1
--- /dev/null
+++ b/shell_cmds/who/who.1
@@ -0,0 +1,130 @@
+.\" $NetBSD: who.1,v 1.22 2007/01/18 00:15:05 wiz Exp $
+.\"
+.\" Copyright (c) 1986, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)who.1 8.2 (Berkeley) 12/30/93
+.\"
+.Dd January 17, 2007
+.Dt WHO 1
+.Os
+.Sh NAME
+.Nm who
+.Nd display who is logged in
+.Sh SYNOPSIS
+.Nm
+.Op Fl abdHlmpqrsTtu
+.Op Ar file
+.Nm
+.Ar am i
+.Sh DESCRIPTION
+The
+.Nm
+utility displays a list of all users currently logged on, showing for
+each user the login name, tty name, the date and time of login, and
+hostname if not local.
+.Pp
+Available options:
+.Pp
+.Bl -tag -width file
+.It Fl a
+Same as
+.Fl bdlprTtu .
+.It Fl b
+Time of last system boot.
+.It Fl d
+Print dead processes.
+.It Fl H
+Write column headings above the regular output.
+.It Fl l
+Print system login processes (unsupported).
+.It Fl m
+Only print information about the current terminal.
+This is the
+.Tn POSIX
+way of saying
+.Nm
+.Ar am i .
+.It Fl p
+Print active processes spawned by
+.Xr launchd 8
+(unsupported).
+.It Fl q
+.Dq Quick mode :
+List only the names and the number of users currently logged on.
+When this option is used, all other options are ignored.
+.It Fl r
+Print the current runlevel.
+This is meaningless on Mac OS X.
+.It Fl s
+List only the name, line and time fields.
+This is the default.
+.It Fl T
+Print a character after the user name indicating the state of the
+terminal line:
+.Sq +
+if the terminal is writable;
+.Sq -
+if it is not;
+and
+.Sq \&?
+if a bad line is encountered.
+.It Fl t
+Print last system clock change (unsupported).
+.It Fl u
+Print the idle time for each user, and the associated process ID.
+.It Ar \&am I
+Returns the invoker's real user name.
+.It Ar file
+By default,
+.Nm
+gathers information from the file
+.Pa /var/run/utmpx .
+An alternative
+.Ar file
+may be specified.
+.El
+.Sh FILES
+.Bl -tag -width /var/run/utmpx -compact
+.It Pa /var/run/utmpx
+.El
+.Sh SEE ALSO
+.Xr last 1 ,
+.Xr mesg 1 ,
+.Xr users 1 ,
+.Xr getuid 2 ,
+.Xr utmpx 5
+.Sh STANDARDS
+The
+.Nm
+utility conforms to
+.St -p1003.1-2001 .
+.Sh HISTORY
+A
+.Nm
+utility appeared in
+.At v6 .
diff --git a/shell_cmds/who/who.c b/shell_cmds/who/who.c
new file mode 100644
index 0000000..f0e356f
--- /dev/null
+++ b/shell_cmds/who/who.c
@@ -0,0 +1,453 @@
+/* $NetBSD: who.c,v 1.23 2008/07/24 15:35:41 christos Exp $ */
+
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Michael Fischbein.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1989, 1993\
+ The Regents of the University of California. All rights reserved.");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)who.c 8.1 (Berkeley) 6/6/93";
+#endif
+__RCSID("$NetBSD: who.c,v 1.23 2008/07/24 15:35:41 christos Exp $");
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <locale.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#ifdef SUPPORT_UTMP
+#include <utmp.h>
+#endif
+#ifdef SUPPORT_UTMPX
+#include <utmpx.h>
+#endif
+#ifdef __APPLE__
+#include <limits.h>
+#include <paths.h>
+#include <stdint.h>
+#endif /* __APPLE__ */
+
+#include "utmpentry.h"
+
+#ifdef __APPLE__
+#define __UNCONST(a) ((void *)(unsigned long)(const void *)(a))
+#endif /* __APPLE__ */
+
+static void output_labels(void);
+static void who_am_i(const char *, int);
+static void usage(void) __dead;
+static void process(const char *, int);
+static void eprint(const struct utmpentry *);
+static void print(const char *, const char *, time_t, const char *, pid_t pid,
+ uint16_t term, uint16_t xit, uint16_t sess, uint16_t type);
+static void quick(const char *);
+
+static int show_term; /* show term state */
+static int show_idle; /* show idle time */
+#ifndef __APPLE__
+static int show_details; /* show exit status etc. */
+#endif /* !__APPLE__ */
+
+struct ut_type_names {
+ int type;
+ const char *name;
+} ut_type_names[] = {
+#ifdef SUPPORT_UTMPX
+ { EMPTY, "empty" },
+ { RUN_LVL, "run level" },
+ { BOOT_TIME, "boot time" },
+ { OLD_TIME, "old time" },
+ { NEW_TIME, "new time" },
+ { INIT_PROCESS, "init process" },
+ { LOGIN_PROCESS, "login process" },
+ { USER_PROCESS, "user process" },
+ { DEAD_PROCESS, "dead process" },
+#if defined(_NETBSD_SOURCE)
+ { ACCOUNTING, "accounting" },
+ { SIGNATURE, "signature" },
+ { DOWN_TIME, "down time" },
+#endif /* _NETBSD_SOURCE */
+#endif /* SUPPORT_UTMPX */
+ { -1, "unknown" }
+};
+
+int
+main(int argc, char *argv[])
+{
+ int c, only_current_term, show_labels, quick_mode, default_mode;
+ int et = 0;
+
+ setlocale(LC_ALL, "");
+
+ only_current_term = show_term = show_idle = show_labels = 0;
+ quick_mode = default_mode = 0;
+
+ while ((c = getopt(argc, argv, "abdHlmpqrsTtuv")) != -1) {
+ switch (c) {
+ case 'a':
+ et = -1;
+#ifdef __APPLE__
+ show_idle = 1;
+#else /* !__APPLE__ */
+ show_idle = show_details = 1;
+#endif /* __APPLE__ */
+ break;
+ case 'b':
+ et |= (1 << BOOT_TIME);
+ break;
+ case 'd':
+ et |= (1 << DEAD_PROCESS);
+ break;
+ case 'H':
+ show_labels = 1;
+ break;
+ case 'l':
+ et |= (1 << LOGIN_PROCESS);
+ break;
+ case 'm':
+ only_current_term = 1;
+ break;
+ case 'p':
+ et |= (1 << INIT_PROCESS);
+ break;
+ case 'q':
+ quick_mode = 1;
+ break;
+ case 'r':
+ et |= (1 << RUN_LVL);
+ break;
+ case 's':
+ default_mode = 1;
+ break;
+ case 'T':
+ show_term = 1;
+ break;
+ case 't':
+ et |= (1 << NEW_TIME);
+ break;
+ case 'u':
+ show_idle = 1;
+ break;
+#ifndef __APPLE__
+ case 'v':
+ show_details = 1;
+ break;
+#endif /* !__APPLE__ */
+ default:
+ usage();
+ /* NOTREACHED */
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (et != 0)
+ etype = et;
+
+#ifndef __APPLE__
+ if (chdir("/dev")) {
+ err(EXIT_FAILURE, "cannot change directory to /dev");
+ /* NOTREACHED */
+ }
+#endif /* !__APPLE__ */
+
+ if (default_mode)
+ only_current_term = show_term = show_idle = 0;
+
+ switch (argc) {
+ case 0: /* who */
+ if (quick_mode) {
+ quick(NULL);
+ } else if (only_current_term) {
+ who_am_i(NULL, show_labels);
+ } else {
+ process(NULL, show_labels);
+ }
+ break;
+ case 1: /* who utmp_file */
+ if (quick_mode) {
+ quick(*argv);
+ } else if (only_current_term) {
+ who_am_i(*argv, show_labels);
+ } else {
+ process(*argv, show_labels);
+ }
+ break;
+ case 2: /* who am i */
+ who_am_i(NULL, show_labels);
+ break;
+ default:
+ usage();
+ /* NOTREACHED */
+ }
+
+ return 0;
+}
+
+static char *
+strrstr(const char *str, const char *pat)
+{
+ const char *estr;
+ size_t len;
+ if (*pat == '\0')
+ return __UNCONST(str);
+
+ len = strlen(pat);
+
+ for (estr = str + strlen(str); str < estr; estr--)
+ if (strncmp(estr, pat, len) == 0)
+ return __UNCONST(estr);
+ return NULL;
+}
+
+static void
+who_am_i(const char *fname, int show_labels)
+{
+ struct passwd *pw;
+ const char *p;
+ char *t;
+ time_t now;
+ struct utmpentry *ehead, *ep;
+
+ /* search through the utmp and find an entry for this tty */
+ if ((p = ttyname(STDIN_FILENO)) != NULL) {
+
+ /* strip directory prefixes for ttys */
+ if ((t = strrstr(p, "/pts/")) != NULL ||
+ (t = strrchr(p, '/')) != NULL)
+ p = t + 1;
+
+ (void)getutentries(fname, &ehead);
+ for (ep = ehead; ep; ep = ep->next)
+ if (strcmp(ep->line, p) == 0) {
+ if (show_labels)
+ output_labels();
+ eprint(ep);
+ return;
+ }
+ } else
+ p = "tty??";
+
+ (void)time(&now);
+ pw = getpwuid(getuid());
+ if (show_labels)
+ output_labels();
+ print(pw ? pw->pw_name : "?", p, now, "", getpid(), 0, 0, 0, 0);
+}
+
+static void
+process(const char *fname, int show_labels)
+{
+ struct utmpentry *ehead, *ep;
+ (void)getutentries(fname, &ehead);
+ if (show_labels)
+ output_labels();
+ for (ep = ehead; ep != NULL; ep = ep->next)
+ eprint(ep);
+#ifdef __APPLE__
+ if ((etype & (1 << RUN_LVL)) != 0) {
+ printf(" . run-level 3\n");
+ }
+#endif /* __APPLE__ */
+}
+
+static void
+eprint(const struct utmpentry *ep)
+{
+ print(ep->name, ep->line, (time_t)ep->tv.tv_sec, ep->host, ep->pid,
+#ifdef __APPLE__
+ 0, 0, 0, ep->type);
+#else /* !__APPLE__ */
+ ep->term, ep->exit, ep->sess, ep->type);
+#endif /* __APPLE__ */
+}
+
+static void
+print(const char *name, const char *line, time_t t, const char *host,
+ pid_t pid, uint16_t term, uint16_t xit, uint16_t sess, uint16_t type)
+{
+ struct stat sb;
+ char state;
+ static time_t now = 0;
+ time_t idle;
+ const char *types = NULL;
+ size_t i;
+
+ state = '?';
+ idle = 0;
+
+ for (i = 0; ut_type_names[i].type >= 0; i++) {
+ types = ut_type_names[i].name;
+ if (ut_type_names[i].type == type)
+ break;
+ }
+
+ if (show_term || show_idle) {
+ if (now == 0)
+ time(&now);
+
+#ifdef __APPLE__
+ char tty[PATH_MAX + 1];
+ snprintf(tty, sizeof(tty), "%s%s", _PATH_DEV, line);
+ if (stat(tty, &sb) == 0) {
+#else /* !__APPLE__ */
+ if (stat(line, &sb) == 0) {
+#endif /* __APPLE__ */
+ state = (sb.st_mode & 020) ? '+' : '-';
+ idle = now - sb.st_atime;
+ }
+
+ }
+
+#ifdef __APPLE__
+ switch (type) {
+ case LOGIN_PROCESS:
+ (void)printf("%-*.*s ", maxname, maxname, "LOGIN");
+ break;
+ case BOOT_TIME:
+ (void)printf("%-*.*s ", maxname, maxname, "reboot");
+ break;
+ default:
+ (void)printf("%-*.*s ", maxname, maxname, name);
+ break;
+ }
+#else /* !__APPLE__ */
+ (void)printf("%-*.*s ", maxname, maxname, name);
+#endif /* __APPLE__ */
+
+ if (show_term)
+ (void)printf("%c ", state);
+
+#ifdef __APPLE__
+ (void)printf("%-*.*s ", maxline, maxline, type == BOOT_TIME ? "~" : line);
+#else /* !__APPLE__ */
+ (void)printf("%-*.*s ", maxline, maxline, line);
+#endif /* __APPLE__ */
+ (void)printf("%.12s ", ctime(&t) + 4);
+
+ if (show_idle) {
+ if (idle < 60)
+ (void)printf(" . ");
+ else if (idle < (24 * 60 * 60))
+ (void)printf("%02ld:%02ld ",
+ (long)(idle / (60 * 60)),
+ (long)(idle % (60 * 60)) / 60);
+ else
+ (void)printf(" old ");
+
+ (void)printf("\t%6d", pid);
+
+#ifndef __APPLE__
+ if (show_details) {
+ if (type == RUN_LVL)
+ (void)printf("\tnew=%c old=%c", term, xit);
+ else
+ (void)printf("\tterm=%d exit=%d", term, xit);
+ (void)printf(" sess=%d", sess);
+ (void)printf(" type=%s ", types);
+ }
+#endif /* !__APPLE__ */
+ }
+
+#ifdef __APPLE__
+ /* 6179576 */
+ if (type == DEAD_PROCESS)
+ (void)printf("\tterm=%d exit=%d", 0, 0);
+#endif /* __APPLE__ */
+
+ if (*host)
+ (void)printf("\t(%.*s)", maxhost, host);
+ (void)putchar('\n');
+}
+
+static void
+output_labels(void)
+{
+ (void)printf("%-*.*s ", maxname, maxname, "USER");
+
+ if (show_term)
+ (void)printf("S ");
+
+ (void)printf("%-*.*s ", maxline, maxline, "LINE");
+ (void)printf("WHEN ");
+
+ if (show_idle) {
+ (void)printf("IDLE ");
+ (void)printf("\t PID");
+
+ (void)printf("\tCOMMENT");
+ }
+
+ (void)putchar('\n');
+}
+
+static void
+quick(const char *fname)
+{
+ struct utmpentry *ehead, *ep;
+ int num = 0;
+
+ (void)getutentries(fname, &ehead);
+ for (ep = ehead; ep != NULL; ep = ep->next) {
+ (void)printf("%-*s ", maxname, ep->name);
+ if ((++num % 8) == 0)
+ (void)putchar('\n');
+ }
+ if (num % 8)
+ (void)putchar('\n');
+
+ (void)printf("# users = %d\n", num);
+}
+
+static void
+usage(void)
+{
+#ifdef __APPLE__
+ (void)fprintf(stderr, "Usage: %s [-abdHlmpqrsTtu] [file]\n\t%s am i\n",
+#else /* !__APPLE__ */
+ (void)fprintf(stderr, "Usage: %s [-abdHlmqrsTtuv] [file]\n\t%s am i\n",
+#endif /* __APPLE__ */
+ getprogname(), getprogname());
+ exit(EXIT_FAILURE);
+}
diff --git a/shell_cmds/xargs/pathnames.h b/shell_cmds/xargs/pathnames.h
new file mode 100644
index 0000000..45c0fff
--- /dev/null
+++ b/shell_cmds/xargs/pathnames.h
@@ -0,0 +1,36 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ *
+ * @(#)pathnames.h 8.1 (Berkeley) 6/6/93
+ */
+
+#define _PATH_ECHO "/bin/echo"
diff --git a/shell_cmds/xargs/strnsubst.c b/shell_cmds/xargs/strnsubst.c
new file mode 100644
index 0000000..b00b319
--- /dev/null
+++ b/shell_cmds/xargs/strnsubst.c
@@ -0,0 +1,109 @@
+/* $xMach: strnsubst.c,v 1.3 2002/02/23 02:10:24 jmallett Exp $ */
+
+/*
+ * Copyright (c) 2002 J. Mallett. All rights reserved.
+ * You may do whatever you want with this file as long as
+ * the above copyright and this notice remain intact, along
+ * with the following statement:
+ * For the man who taught me vi, and who got too old, too young.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/xargs/strnsubst.c,v 1.7 2004/10/18 15:40:47 cperciva Exp $");
+
+#include <err.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+void strnsubst(char **, const char *, const char *, size_t);
+
+/*
+ * Replaces str with a string consisting of str with match replaced with
+ * replstr as many times as can be done before the constructed string is
+ * maxsize bytes large. It does not free the string pointed to by str, it
+ * is up to the calling program to be sure that the original contents of
+ * str as well as the new contents are handled in an appropriate manner.
+ * If replstr is NULL, then that internally is changed to a nil-string, so
+ * that we can still pretend to do somewhat meaningful substitution.
+ * No value is returned.
+ */
+void
+strnsubst(char **str, const char *match, const char *replstr, size_t maxsize)
+{
+ char *s1, *s2, *this;
+
+ s1 = *str;
+ if (s1 == NULL)
+ return;
+ /*
+ * If maxsize is 0 then set it to the length of s1, because we have
+ * to duplicate s1. XXX we maybe should double-check whether the match
+ * appears in s1. If it doesn't, then we also have to set the length
+ * to the length of s1, to avoid modifying the argument. It may make
+ * sense to check if maxsize is <= strlen(s1), because in that case we
+ * want to return the unmodified string, too.
+ */
+ if (maxsize == 0) {
+ match = NULL;
+ maxsize = strlen(s1) + 1;
+ }
+ s2 = calloc(1, maxsize);
+ if (s2 == NULL)
+ err(1, "calloc");
+
+ if (replstr == NULL)
+ replstr = "";
+
+ if (match == NULL || replstr == NULL || maxsize == strlen(s1)) {
+ strlcpy(s2, s1, maxsize);
+ goto done;
+ }
+
+ for (;;) {
+ this = strstr(s1, match);
+ if (this == NULL)
+ break;
+ if ((strlen(s2) + strlen(s1) + strlen(replstr) -
+ strlen(match) + 1) > maxsize) {
+ strlcat(s2, s1, maxsize);
+ goto done;
+ }
+ strncat(s2, s1, (uintptr_t)this - (uintptr_t)s1);
+ strcat(s2, replstr);
+ s1 = this + strlen(match);
+ }
+ strcat(s2, s1);
+done:
+ *str = s2;
+ return;
+}
+
+#ifdef TEST
+#include <stdio.h>
+
+int
+main(void)
+{
+ char *x, *y, *z, *za;
+
+ x = "{}%$";
+ strnsubst(&x, "%$", "{} enpury!", 255);
+ y = x;
+ strnsubst(&y, "}{}", "ybir", 255);
+ z = y;
+ strnsubst(&z, "{", "v ", 255);
+ za = z;
+ strnsubst(&z, NULL, za, 255);
+ if (strcmp(z, "v ybir enpury!") == 0)
+ printf("strnsubst() seems to work!\n");
+ else
+ printf("strnsubst() is broken.\n");
+ printf("%s\n", z);
+ free(x);
+ free(y);
+ free(z);
+ free(za);
+ return 0;
+}
+#endif
diff --git a/shell_cmds/xargs/xargs.1 b/shell_cmds/xargs/xargs.1
new file mode 100644
index 0000000..b9d5add
--- /dev/null
+++ b/shell_cmds/xargs/xargs.1
@@ -0,0 +1,389 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" John B. Roll Jr. and the Institute of Electrical and Electronics
+.\" Engineers, Inc.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)xargs.1 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD: src/usr.bin/xargs/xargs.1,v 1.34 2005/05/21 09:55:09 ru Exp $
+.\" $xMach: xargs.1,v 1.2 2002/02/23 05:23:37 tim Exp $
+.\"
+.Dd August 4, 2015
+.Dt XARGS 1
+.Os
+.Sh NAME
+.Nm xargs
+.Nd "construct argument list(s) and execute utility"
+.Sh SYNOPSIS
+.Nm
+.Op Fl 0oprt
+.Op Fl E Ar eofstr
+.Oo
+.Fl I Ar replstr
+.Op Fl R Ar replacements
+.Op Fl S Ar replsize
+.Oc
+.Op Fl J Ar replstr
+.Op Fl L Ar number
+.Oo
+.Fl n Ar number
+.Op Fl x
+.Oc
+.Op Fl P Ar maxprocs
+.Op Fl s Ar size
+.Op Ar utility Op Ar argument ...
+.Sh DESCRIPTION
+The
+.Nm
+utility reads space, tab, newline and end-of-file delimited strings
+from the standard input and executes
+.Ar utility
+with the strings as
+arguments.
+.Pp
+Any arguments specified on the command line are given to
+.Ar utility
+upon each invocation, followed by some number of the arguments read
+from the standard input of
+.Nm .
+This is repeated until standard input is exhausted.
+.Pp
+Spaces, tabs and newlines may be embedded in arguments using single
+(``\ '\ '')
+or double (``"'') quotes or backslashes (``\e'').
+Single quotes escape all non-single quote characters, excluding newlines,
+up to the matching single quote.
+Double quotes escape all non-double quote characters, excluding newlines,
+up to the matching double quote.
+Any single character, including newlines, may be escaped by a backslash.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl 0
+Change
+.Nm
+to expect NUL
+(``\\0'')
+characters as separators, instead of spaces and newlines.
+This is expected to be used in concert with the
+.Fl print0
+function in
+.Xr find 1 .
+.It Fl E Ar eofstr
+Use
+.Ar eofstr
+as a logical EOF marker.
+.It Fl I Ar replstr
+Execute
+.Ar utility
+for each input line, replacing one or more occurrences of
+.Ar replstr
+in up to
+.Ar replacements
+(or 5 if no
+.Fl R
+flag is specified) arguments to
+.Ar utility
+with the entire line of input.
+The resulting arguments, after replacement is done, will not be allowed to grow
+beyond
+.Ar replsize
+(or 255 if no
+.Fl S
+flag is specified)
+bytes; this is implemented by concatenating as much of the argument
+containing
+.Ar replstr
+as possible, to the constructed arguments to
+.Ar utility ,
+up to
+.Ar replsize
+bytes.
+The size limit does not apply to arguments to
+.Ar utility
+which do not contain
+.Ar replstr ,
+and furthermore, no replacement will be done on
+.Ar utility
+itself.
+Implies
+.Fl x .
+.It Fl J Ar replstr
+If this option is specified,
+.Nm
+will use the data read from standard input to replace the first occurrence of
+.Ar replstr
+instead of appending that data after all other arguments.
+This option will not affect how many arguments will be read from input
+.Pq Fl n ,
+or the size of the command(s)
+.Nm
+will generate
+.Pq Fl s .
+The option just moves where those arguments will be placed in the command(s)
+that are executed.
+The
+.Ar replstr
+must show up as a distinct
+.Ar argument
+to
+.Nm .
+It will not be recognized if, for instance, it is in the middle of a
+quoted string.
+Furthermore, only the first occurrence of the
+.Ar replstr
+will be replaced.
+For example, the following command will copy the list of files and
+directories which start with an uppercase letter in the current
+directory to
+.Pa destdir :
+.Pp
+.Dl /bin/ls -1d [A-Z]* | xargs -J % cp -Rp % destdir
+.It Fl L Ar number
+Call
+.Ar utility
+for every
+.Ar number
+non-empty lines read.
+A line ending with a space continues to the next non-empty line.
+If EOF is reached and fewer lines have been read than
+.Ar number
+then
+.Ar utility
+will be called with the available lines.
+The
+.Fl L
+and
+.Fl n
+options are mutually-exclusive; the last one given will be used.
+.It Fl n Ar number
+Set the maximum number of arguments taken from standard input for each
+invocation of
+.Ar utility .
+An invocation of
+.Ar utility
+will use less than
+.Ar number
+standard input arguments if the number of bytes accumulated (see the
+.Fl s
+option) exceeds the specified
+.Ar size
+or there are fewer than
+.Ar number
+arguments remaining for the last invocation of
+.Ar utility .
+The current default value for
+.Ar number
+is 5000.
+.It Fl o
+Reopen stdin as
+.Pa /dev/tty
+in the child process before executing the command.
+This is useful if you want
+.Nm
+to run an interactive application.
+.It Fl P Ar maxprocs
+Parallel mode: run at most
+.Ar maxprocs
+invocations of
+.Ar utility
+at once.
+If
+.Ar maxprocs
+is set to 0,
+.Nm
+will run as many processes as possible.
+.It Fl p
+Echo each command to be executed and ask the user whether it should be
+executed.
+An affirmative response,
+.Ql y
+in the POSIX locale,
+causes the command to be executed, any other response causes it to be
+skipped.
+No commands are executed if the process is not attached to a terminal.
+.It Fl r
+Compatibility with GNU
+.Nm .
+The GNU version of
+.Nm
+runs the
+.Ar utility
+argument at least once, even if
+.Nm
+input is empty, and it supports a
+.Fl r
+option to inhibit this behavior.
+The
+.Fx
+version of
+.Nm
+does not run the
+.Ar utility
+argument on empty input, but it supports the
+.Fl r
+option for command-line compatibility with GNU
+.Nm ,
+but the
+.Fl r
+option does nothing in the
+.Fx
+version of
+.Nm .
+.It Fl R Ar replacements
+Specify the maximum number of arguments that
+.Fl I
+will do replacement in.
+If
+.Ar replacements
+is negative, the number of arguments in which to replace is unbounded.
+.It Fl S Ar replsize
+Specify the amount of space (in bytes) that
+.Fl I
+can use for replacements.
+The default for
+.Ar replsize
+is 255.
+.It Fl s Ar size
+Set the maximum number of bytes for the command line length provided to
+.Ar utility .
+The sum of the length of the utility name, the arguments passed to
+.Ar utility
+(including
+.Dv NULL
+terminators) and the current environment will be less than or equal to
+this number.
+The current default value for
+.Ar size
+is
+.Dv ARG_MAX
+- 4096.
+.It Fl t
+Echo the command to be executed to standard error immediately before it
+is executed.
+.It Fl x
+Force
+.Nm
+to terminate immediately if a command line containing
+.Ar number
+arguments will not fit in the specified (or default) command line length.
+.El
+.Pp
+If
+.Ar utility
+is omitted,
+.Xr echo 1
+is used.
+.Pp
+Undefined behavior may occur if
+.Ar utility
+reads from the standard input.
+.Pp
+The
+.Nm
+utility exits immediately (without processing any further input) if a
+command line cannot be assembled,
+.Ar utility
+cannot be invoked, an invocation of
+.Ar utility
+is terminated by a signal,
+or an invocation of
+.Ar utility
+exits with a value of 255, the
+.Nm
+utility stops processing input and exits after all invocations of
+.Ar utility
+finish processing.
+.Sh LEGACY DESCRIPTION
+In legacy mode, the
+.Fl L
+option treats all newlines as end-of-line, regardless of whether
+the line is empty or ends with a space.
+In addition, the
+.Fl L
+and
+.Fl n
+options are not mutually-exclusive.
+.Pp
+For more information about legacy mode, see
+.Xr compat 5 .
+.Sh EXIT STATUS
+The
+.Nm
+utility exits with a value of 0 if no error occurs.
+If
+.Ar utility
+cannot be found,
+.Nm
+exits with a value of 127, otherwise if
+.Ar utility
+cannot be executed,
+.Nm
+exits with a value of 126.
+If any other error occurs,
+.Nm
+exits with a value of 1.
+.Sh SEE ALSO
+.Xr echo 1 ,
+.Xr find 1 ,
+.Xr execvp 3 ,
+.Xr compat 5
+.Sh STANDARDS
+The
+.Nm
+utility is expected to be
+.St -p1003.2
+compliant.
+The
+.Fl J , o , P, R
+and
+.Fl S
+options are non-standard
+.Fx
+extensions which may not be available on other operating systems.
+.Sh HISTORY
+The
+.Nm
+utility appeared in PWB UNIX.
+.Sh BUGS
+If
+.Ar utility
+attempts to invoke another command such that the number of arguments or the
+size of the environment is increased, it risks
+.Xr execvp 3
+failing with
+.Er E2BIG .
+.Pp
+The
+.Nm
+utility does not take multibyte characters into account when performing
+string comparisons for the
+.Fl I
+and
+.Fl J
+options, which may lead to incorrect results in some locales.
diff --git a/shell_cmds/xargs/xargs.c b/shell_cmds/xargs/xargs.c
new file mode 100644
index 0000000..a1ee480
--- /dev/null
+++ b/shell_cmds/xargs/xargs.c
@@ -0,0 +1,840 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * John B. Roll Jr.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $xMach: xargs.c,v 1.6 2002/02/23 05:27:47 tim Exp $
+ */
+
+#if 0
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1990, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)xargs.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/param.h>
+#include <sys/resource.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <langinfo.h>
+#include <locale.h>
+#include <paths.h>
+#include <regex.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "pathnames.h"
+
+#ifdef __APPLE__
+#include <get_compat.h>
+#else
+#define COMPAT_MODE(a,b) (1)
+#endif /* __APPLE__ */
+
+static void parse_input(int, char *[]);
+static void prerun(int, char *[]);
+static int prompt(void);
+static void run(char **);
+static void usage(void);
+void strnsubst(char **, const char *, const char *, size_t);
+static pid_t xwait(int block, int *status);
+static void xexit(const char *, const int);
+static void waitchildren(const char *, int);
+static void pids_init(void);
+static int pids_empty(void);
+static int pids_full(void);
+static void pids_add(pid_t pid);
+static int pids_remove(pid_t pid);
+static int findslot(pid_t pid);
+static int findfreeslot(void);
+static void clearslot(int slot);
+
+static int last_was_newline = 1;
+static int last_was_blank = 0;
+
+static char echo[] = _PATH_ECHO;
+static char **av, **bxp, **ep, **endxp, **xp;
+static char *argp, *bbp, *ebp, *inpline, *p, *replstr;
+static const char *eofstr;
+static int count, insingle, indouble, oflag, pflag, tflag, Rflag, rval, zflag;
+static int cnt, Iflag, jfound, Lflag, Sflag, wasquoted, xflag;
+static int curprocs, maxprocs;
+static size_t pad9314053;
+static pid_t *childpids;
+
+static volatile int childerr;
+
+extern char **environ;
+
+int
+main(int argc, char *argv[])
+{
+ long arg_max;
+ int ch, Jflag, nflag, nline;
+ size_t nargs;
+ size_t linelen;
+ struct rlimit rl;
+ char *endptr;
+ const char *errstr;
+
+ inpline = replstr = NULL;
+ ep = environ;
+ eofstr = "";
+ Jflag = nflag = 0;
+
+ (void)setlocale(LC_ALL, "");
+
+ /*
+ * POSIX.2 limits the exec line length to ARG_MAX - 2K. Running that
+ * caused some E2BIG errors, so it was changed to ARG_MAX - 4K. Given
+ * that the smallest argument is 2 bytes in length, this means that
+ * the number of arguments is limited to:
+ *
+ * (ARG_MAX - 4K - LENGTH(utility + arguments)) / 2.
+ *
+ * We arbitrarily limit the number of arguments to 5000. This is
+ * allowed by POSIX.2 as long as the resulting minimum exec line is
+ * at least LINE_MAX. Realloc'ing as necessary is possible, but
+ * probably not worthwhile.
+ */
+ nargs = 5000;
+ if ((arg_max = sysconf(_SC_ARG_MAX)) == -1)
+ errx(1, "sysconf(_SC_ARG_MAX) failed");
+ nline = arg_max - MAXPATHLEN; /* for argv[0] from execvp() */
+ pad9314053 = sizeof(char *); /* reserve for string area rounding */
+ while (*ep != NULL) {
+ /* 1 byte for each '\0' */
+ nline -= strlen(*ep++) + 1 + sizeof(*ep);
+ }
+ nline -= pad9314053;
+ maxprocs = 1;
+ while ((ch = getopt(argc, argv, "0E:I:J:L:n:oP:pR:S:s:rtx")) != -1)
+ switch (ch) {
+ case 'E':
+ eofstr = optarg;
+ break;
+ case 'I':
+ Jflag = 0;
+ Iflag = 1;
+ Lflag = 1;
+ replstr = optarg;
+ break;
+ case 'J':
+ Iflag = 0;
+ Jflag = 1;
+ replstr = optarg;
+ break;
+ case 'L':
+ Lflag = strtonum(optarg, 0, INT_MAX, &errstr);
+ if (errstr)
+ errx(1, "-L %s: %s", optarg, errstr);
+ if (COMPAT_MODE("bin/xargs", "Unix2003")) {
+ nflag = 0; /* Override */
+ nargs = 5000;
+ }
+ break;
+ case 'n':
+ nflag = 1;
+ if ((nargs = strtol(optarg, NULL, 10)) <= 0)
+ errx(1, "illegal argument count");
+ if (COMPAT_MODE("bin/xargs", "Unix2003")) {
+ Lflag = 0; /* Override */
+ }
+ break;
+ case 'o':
+ oflag = 1;
+ break;
+ case 'P':
+ maxprocs = strtonum(optarg, 0, INT_MAX, &errstr);
+ if (errstr)
+ errx(1, "-P %s: %s", optarg, errstr);
+ if (getrlimit(RLIMIT_NPROC, &rl) != 0)
+ errx(1, "getrlimit failed");
+ if (maxprocs == 0 || maxprocs > rl.rlim_cur)
+ maxprocs = rl.rlim_cur;
+ break;
+ case 'p':
+ pflag = 1;
+ break;
+ case 'R':
+ Rflag = strtol(optarg, &endptr, 10);
+ if (*endptr != '\0')
+ errx(1, "replacements must be a number");
+ break;
+ case 'r':
+ /* GNU compatibility */
+ break;
+ case 'S':
+ Sflag = strtoul(optarg, &endptr, 10);
+ if (*endptr != '\0')
+ errx(1, "replsize must be a number");
+ break;
+ case 's':
+ nline = strtonum(optarg, 0, INT_MAX, &errstr);
+ if (errstr)
+ errx(1, "-s %s: %s", optarg, errstr);
+ pad9314053 = 0; /* assume the -s value is valid */
+ break;
+ case 't':
+ tflag = 1;
+ break;
+ case 'x':
+ xflag = 1;
+ break;
+ case '0':
+ zflag = 1;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (!Iflag && Rflag)
+ usage();
+ if (!Iflag && Sflag)
+ usage();
+ if (Iflag && !Rflag)
+ Rflag = 5;
+ if (Iflag && !Sflag)
+ Sflag = 255;
+ if (xflag && !nflag)
+ usage();
+ if (Iflag || Lflag)
+ xflag = 1;
+ if (replstr != NULL && *replstr == '\0')
+ errx(1, "replstr may not be empty");
+
+ pids_init();
+
+ /*
+ * Allocate pointers for the utility name, the utility arguments,
+ * the maximum arguments to be read from stdin and the trailing
+ * NULL.
+ */
+ linelen = 1 + argc + nargs + 1;
+ if ((av = bxp = malloc(linelen * sizeof(char *))) == NULL)
+ errx(1, "malloc failed");
+
+ /*
+ * Use the user's name for the utility as argv[0], just like the
+ * shell. Echo is the default. Set up pointers for the user's
+ * arguments.
+ */
+ if (*argv == NULL)
+ cnt = strlen(*bxp++ = echo) + pad9314053;
+ else {
+ do {
+ if (Jflag && strcmp(*argv, replstr) == 0) {
+ char **avj;
+ jfound = 1;
+ argv++;
+ for (avj = argv; *avj; avj++)
+ cnt += strlen(*avj) + 1 + pad9314053;
+ break;
+ }
+ cnt += strlen(*bxp++ = *argv) + 1 + pad9314053;
+ } while (*++argv != NULL);
+ }
+
+ /*
+ * Set up begin/end/traversing pointers into the array. The -n
+ * count doesn't include the trailing NULL pointer, so the malloc
+ * added in an extra slot.
+ */
+ endxp = (xp = bxp) + nargs;
+
+ /*
+ * Allocate buffer space for the arguments read from stdin and the
+ * trailing NULL. Buffer space is defined as the default or specified
+ * space, minus the length of the utility name and arguments. Set up
+ * begin/end/traversing pointers into the array. The -s count does
+ * include the trailing NULL, so the malloc didn't add in an extra
+ * slot.
+ */
+ nline -= cnt;
+ if (nline <= 0)
+ errx(1, "insufficient space for command");
+
+ if ((bbp = malloc((size_t)(nline + 1))) == NULL)
+ errx(1, "malloc failed");
+ ebp = (argp = p = bbp) + nline - 1;
+ for (;;)
+ parse_input(argc, argv);
+}
+
+static void
+parse_input(int argc, char *argv[])
+{
+ int ch, foundeof;
+ char **avj;
+ int last_was_backslashed = 0;
+
+ foundeof = 0;
+
+ switch (ch = getchar()) {
+ case EOF:
+ /* No arguments since last exec. */
+ if (p == bbp)
+ xexit(*av, rval);
+ goto arg1;
+ case ' ':
+ last_was_blank = 1;
+ case '\t':
+ /* Quotes escape tabs and spaces. */
+ if (insingle || indouble || zflag)
+ goto addch;
+ goto arg2;
+ case '\0':
+ if (zflag) {
+ /*
+ * Increment 'count', so that nulls will be treated
+ * as end-of-line, as well as end-of-argument. This
+ * is needed so -0 works properly with -I and -L.
+ */
+ count++;
+ goto arg2;
+ }
+ goto addch;
+ case '\n':
+ if (zflag)
+ goto addch;
+ if (COMPAT_MODE("bin/xargs", "Unix2003")) {
+ if (last_was_newline) {
+ /* don't count empty line */
+ break;
+ }
+ if (!last_was_blank ) {
+ /* only count if NOT continuation line */
+ count++;
+ }
+ } else {
+ count++;
+ }
+ last_was_newline = 1;
+
+ /* Quotes do not escape newlines. */
+arg1: if (insingle || indouble) {
+ warnx("unterminated quote");
+ xexit(*av, 1);
+ }
+arg2:
+ foundeof = *eofstr != '\0' &&
+ strncmp(argp, eofstr, p - argp) == 0;
+
+#ifdef __APPLE__
+ /* 6591323: -I specifies that it processes the entire line,
+ * so only recognize eofstr at the end of a line. */
+ if (Iflag && !last_was_newline)
+ foundeof = 0;
+
+ /* 6591323: Essentially the same as the EOF handling above. */
+ if (foundeof && (p - strlen(eofstr) == bbp)) {
+ waitchildren(*argv, 1);
+ exit(rval);
+ }
+#endif
+
+ /* Do not make empty args unless they are quoted */
+ if ((argp != p || wasquoted) && !foundeof) {
+ *p++ = '\0';
+ *xp++ = argp;
+ if (Iflag) {
+ size_t curlen;
+
+ if (inpline == NULL)
+ curlen = 0;
+ else {
+ /*
+ * If this string is not zero
+ * length, append a space for
+ * separation before the next
+ * argument.
+ */
+ if ((curlen = strlen(inpline)))
+ strcat(inpline, " ");
+ }
+ curlen++;
+ /*
+ * Allocate enough to hold what we will
+ * be holding in a second, and to append
+ * a space next time through, if we have
+ * to.
+ */
+ inpline = realloc(inpline, curlen + 2 +
+ strlen(argp));
+ if (inpline == NULL) {
+ warnx("realloc failed");
+ xexit(*av, 1);
+ }
+ if (curlen == 1)
+ strcpy(inpline, argp);
+ else
+ strcat(inpline, argp);
+ }
+ }
+
+ /*
+ * If max'd out on args or buffer, or reached EOF,
+ * run the command. If xflag and max'd out on buffer
+ * but not on args, object. Having reached the limit
+ * of input lines, as specified by -L is the same as
+ * maxing out on arguments.
+ */
+ if (xp == endxp || p + (count * pad9314053) > ebp || ch == EOF ||
+ (Lflag <= count && xflag) || foundeof) {
+ if (xflag && xp != endxp && p + (count * pad9314053) > ebp) {
+ warnx("insufficient space for arguments");
+ xexit(*av, 1);
+ }
+ if (jfound) {
+ for (avj = argv; *avj; avj++)
+ *xp++ = *avj;
+ }
+ prerun(argc, av);
+ if (ch == EOF || foundeof)
+ xexit(*av, rval);
+ p = bbp;
+ xp = bxp;
+ count = 0;
+ }
+ argp = p;
+ wasquoted = 0;
+ break;
+ case '\'':
+ if (indouble || zflag)
+ goto addch;
+ insingle = !insingle;
+ wasquoted = 1;
+ break;
+ case '"':
+ if (insingle || zflag)
+ goto addch;
+ indouble = !indouble;
+ wasquoted = 1;
+ break;
+ case '\\':
+ last_was_backslashed = 1;
+ if (zflag)
+ goto addch;
+ /* Backslash escapes anything, is escaped by quotes. */
+ if (!insingle && !indouble && (ch = getchar()) == EOF) {
+ warnx("backslash at EOF");
+ xexit(*av, 1);
+ }
+ /* FALLTHROUGH */
+ default:
+addch: if (p < ebp) {
+ *p++ = ch;
+ break;
+ }
+
+ /* If only one argument, not enough buffer space. */
+ if (bxp == xp) {
+ warnx("insufficient space for argument");
+ xexit(*av, 1);
+ }
+ /* Didn't hit argument limit, so if xflag object. */
+ if (xflag) {
+ warnx("insufficient space for arguments");
+ xexit(*av, 1);
+ }
+
+ if (jfound) {
+ for (avj = argv; *avj; avj++)
+ *xp++ = *avj;
+ }
+ prerun(argc, av);
+ xp = bxp;
+ cnt = ebp - argp;
+ memcpy(bbp, argp, (size_t)cnt);
+ p = (argp = bbp) + cnt;
+ *p++ = ch;
+ break;
+ }
+ if (ch != ' ')
+ last_was_blank = 0;
+ if (ch != '\n' || last_was_backslashed)
+ last_was_newline = 0;
+}
+
+/*
+ * Do things necessary before run()'ing, such as -I substitution,
+ * and then call run().
+ */
+static void
+prerun(int argc, char *argv[])
+{
+ char **tmp, **tmp2, **avj;
+ int repls;
+
+ repls = Rflag;
+
+ if (argc == 0 || repls == 0) {
+ *xp = NULL;
+ run(argv);
+ return;
+ }
+
+ avj = argv;
+
+ /*
+ * Allocate memory to hold the argument list, and
+ * a NULL at the tail.
+ */
+ tmp = malloc((argc + 1) * sizeof(char *));
+ if (tmp == NULL) {
+ warnx("malloc failed");
+ xexit(*argv, 1);
+ }
+ tmp2 = tmp;
+
+ /*
+ * Save the first argument and iterate over it, we
+ * cannot do strnsubst() to it.
+ */
+ if ((*tmp++ = strdup(*avj++)) == NULL) {
+ warnx("strdup failed");
+ xexit(*argv, 1);
+ }
+
+ /*
+ * For each argument to utility, if we have not used up
+ * the number of replacements we are allowed to do, and
+ * if the argument contains at least one occurrence of
+ * replstr, call strnsubst(), else just save the string.
+ * Iterations over elements of avj and tmp are done
+ * where appropriate.
+ */
+ while (--argc) {
+ *tmp = *avj++;
+ if (repls && strstr(*tmp, replstr) != NULL) {
+ strnsubst(tmp++, replstr, inpline, (size_t)Sflag);
+ if (repls > 0)
+ repls--;
+ } else {
+ if ((*tmp = strdup(*tmp)) == NULL) {
+ warnx("strdup failed");
+ xexit(*argv, 1);
+ }
+ tmp++;
+ }
+ }
+
+ /*
+ * Run it.
+ */
+ *tmp = NULL;
+ run(tmp2);
+
+ /*
+ * Walk from the tail to the head, free along the way.
+ */
+ for (; tmp2 != tmp; tmp--)
+ free(*tmp);
+ /*
+ * Now free the list itself.
+ */
+ free(tmp2);
+
+ /*
+ * Free the input line buffer, if we have one.
+ */
+ if (inpline != NULL) {
+ free(inpline);
+ inpline = NULL;
+ }
+}
+
+static void
+run(char **argv)
+{
+ pid_t pid;
+ int fd;
+ char **avec;
+
+ /*
+ * If the user wants to be notified of each command before it is
+ * executed, notify them. If they want the notification to be
+ * followed by a prompt, then prompt them.
+ */
+ if (tflag || pflag) {
+ (void)fprintf(stderr, "%s", *argv);
+ for (avec = argv + 1; *avec != NULL; ++avec)
+ (void)fprintf(stderr, " %s", *avec);
+ /*
+ * If the user has asked to be prompted, do so.
+ */
+ if (pflag)
+ /*
+ * If they asked not to exec, return without execution
+ * but if they asked to, go to the execution. If we
+ * could not open their tty, break the switch and drop
+ * back to -t behaviour.
+ */
+ switch (prompt()) {
+ case 0:
+ return;
+ case 1:
+ goto exec;
+ case 2:
+ break;
+ }
+ (void)fprintf(stderr, "\n");
+ (void)fflush(stderr);
+ }
+exec:
+ childerr = 0;
+ switch (pid = vfork()) {
+ case -1:
+ warn("vfork");
+ xexit(*argv, 1);
+ case 0:
+ if (oflag) {
+ if ((fd = open(_PATH_TTY, O_RDONLY)) == -1)
+ err(1, "can't open /dev/tty");
+ } else {
+ fd = open(_PATH_DEVNULL, O_RDONLY);
+ }
+ if (fd > STDIN_FILENO) {
+ if (dup2(fd, STDIN_FILENO) != 0)
+ err(1, "can't dup2 to stdin");
+ close(fd);
+ }
+ execvp(argv[0], argv);
+ childerr = errno;
+ _exit(1);
+ }
+ pids_add(pid);
+ waitchildren(*argv, 0);
+}
+
+/*
+ * Wait for a tracked child to exit and return its pid and exit status.
+ *
+ * Ignores (discards) all untracked child processes.
+ * Returns -1 and sets errno to ECHILD if no tracked children exist.
+ * If block is set, waits indefinitely for a child process to exit.
+ * If block is not set and no children have exited, returns 0 immediately.
+ */
+static pid_t
+xwait(int block, int *status) {
+ pid_t pid;
+
+ if (pids_empty()) {
+ errno = ECHILD;
+ return (-1);
+ }
+
+ while ((pid = waitpid(-1, status, block ? 0 : WNOHANG)) > 0)
+ if (pids_remove(pid))
+ break;
+
+ return (pid);
+}
+
+static void
+xexit(const char *name, const int exit_code) {
+ waitchildren(name, 1);
+ exit(exit_code);
+}
+
+static void
+waitchildren(const char *name, int waitall)
+{
+ pid_t pid;
+ int status;
+ int cause_exit = 0;
+
+ while ((pid = xwait(waitall || pids_full(), &status)) > 0) {
+ /*
+ * If we couldn't invoke the utility or if utility exited
+ * because of a signal or with a value of 255, warn (per
+ * POSIX), and then wait until all other children have
+ * exited before exiting 1-125. POSIX requires us to stop
+ * reading if child exits because of a signal or with 255,
+ * but it does not require us to exit immediately; waiting
+ * is preferable to orphaning.
+ */
+ if (childerr != 0 && cause_exit == 0) {
+ errno = childerr;
+ waitall = 1;
+ cause_exit = errno == ENOENT ? 127 : 126;
+ warn("%s", name);
+ } else if (WIFSIGNALED(status)) {
+ waitall = cause_exit = 1;
+ warnx("%s: terminated with signal %d; aborting",
+ name, WTERMSIG(status));
+ } else if (WEXITSTATUS(status) == 255) {
+ waitall = cause_exit = 1;
+ warnx("%s: exited with status 255; aborting", name);
+ } else if (WEXITSTATUS(status))
+ rval = 1;
+ }
+
+ if (cause_exit)
+ exit(cause_exit);
+ if (pid == -1 && errno != ECHILD)
+ err(1, "waitpid");
+}
+
+#define NOPID (0)
+
+static void
+pids_init(void)
+{
+ int i;
+
+ if ((childpids = malloc(maxprocs * sizeof(*childpids))) == NULL)
+ errx(1, "malloc failed");
+
+ for (i = 0; i < maxprocs; i++)
+ clearslot(i);
+}
+
+static int
+pids_empty(void)
+{
+
+ return (curprocs == 0);
+}
+
+static int
+pids_full(void)
+{
+
+ return (curprocs >= maxprocs);
+}
+
+static void
+pids_add(pid_t pid)
+{
+ int slot;
+
+ slot = findfreeslot();
+ childpids[slot] = pid;
+ curprocs++;
+}
+
+static int
+pids_remove(pid_t pid)
+{
+ int slot;
+
+ if ((slot = findslot(pid)) < 0)
+ return (0);
+
+ clearslot(slot);
+ curprocs--;
+ return (1);
+}
+
+static int
+findfreeslot(void)
+{
+ int slot;
+
+ if ((slot = findslot(NOPID)) < 0)
+ errx(1, "internal error: no free pid slot");
+ return (slot);
+}
+
+static int
+findslot(pid_t pid)
+{
+ int slot;
+
+ for (slot = 0; slot < maxprocs; slot++)
+ if (childpids[slot] == pid)
+ return (slot);
+ return (-1);
+}
+
+static void
+clearslot(int slot)
+{
+
+ childpids[slot] = NOPID;
+}
+
+/*
+ * Prompt the user about running a command.
+ */
+static int
+prompt(void)
+{
+ regex_t cre;
+ size_t rsize;
+ int match;
+ char *response;
+ FILE *ttyfp;
+
+ if ((ttyfp = fopen(_PATH_TTY, "r")) == NULL)
+ return (2); /* Indicate that the TTY failed to open. */
+ (void)fprintf(stderr, "?...");
+ (void)fflush(stderr);
+ if ((response = fgetln(ttyfp, &rsize)) == NULL ||
+ regcomp(&cre, nl_langinfo(YESEXPR), REG_BASIC) != 0) {
+ (void)fclose(ttyfp);
+ return (0);
+ }
+ response[rsize - 1] = '\0';
+ match = regexec(&cre, response, 0, NULL, 0);
+ (void)fclose(ttyfp);
+ regfree(&cre);
+ return (match == 0);
+}
+
+static void
+usage(void)
+{
+
+ fprintf(stderr,
+"usage: xargs [-0opt] [-E eofstr] [-I replstr [-R replacements] [-S replsize]]\n"
+" [-J replstr] [-L number] [-n number [-x]] [-P maxprocs]\n"
+" [-s size] [utility [argument ...]]\n");
+ exit(1);
+}
diff --git a/shell_cmds/xcconfigs/base.xcconfig b/shell_cmds/xcconfigs/base.xcconfig
new file mode 100644
index 0000000..72c716a
--- /dev/null
+++ b/shell_cmds/xcconfigs/base.xcconfig
@@ -0,0 +1,59 @@
+// Build Options
+DEBUG_INFORMATION_FORMAT = dwarf-with-dsym
+
+// Code Signing
+CODE_SIGN_IDENTITY = -
+
+// Deployment
+COPY_PHASE_STRIP = YES
+
+// Packaging
+APPLY_RULES_IN_COPY_FILES = YES
+
+// Search Paths
+ALWAYS_SEARCH_USER_PATHS = NO
+USE_HEADERMAP = NO
+
+// Versioning
+CURRENT_PROJECT_VERSION = $(RC_ProjectSourceVersion)
+VERSIONING_SYSTEM = apple-generic
+VERSION_INFO_PREFIX = __
+
+// Warning Policies
+GCC_TREAT_WARNINGS_AS_ERRORS = YES
+
+// Warnings - All languages
+CLANG_WARN_ASSIGN_ENUM = YES
+CLANG_WARN_BOOL_CONVERSION = YES
+CLANG_WARN_CONSTANT_CONVERSION = YES
+CLANG_WARN_DOCUMENTATION_COMMENTS = YES
+CLANG_WARN_EMPTY_BODY = YES
+CLANG_WARN_ENUM_CONVERSION = YES
+CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES
+CLANG_WARN_INT_CONVERSION = YES
+CLANG_WARN_NULLABLE_TO_NONNULL_CONVERSION = YES
+CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES
+CLANG_WARN_UNREACHABLE_CODE = YES
+GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES
+GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES
+GCC_WARN_64_TO_32_BIT_CONVERSION = YES
+GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES
+GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES
+GCC_WARN_ABOUT_MISSING_NEWLINE = YES
+GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES
+GCC_WARN_ABOUT_POINTER_SIGNEDNESS = YES
+GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR
+GCC_WARN_CHECK_SWITCH_STATEMENTS = YES
+GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES
+GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES
+GCC_WARN_MISSING_PARENTHESES = YES
+GCC_WARN_SHADOW = YES
+GCC_WARN_SIGN_COMPARE = YES
+GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES
+GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE
+GCC_WARN_UNKNOWN_PRAGMAS = YES
+GCC_WARN_UNUSED_FUNCTION = YES
+GCC_WARN_UNUSED_LABEL = YES
+GCC_WARN_UNUSED_PARAMETER = YES
+GCC_WARN_UNUSED_VALUE = YES
+GCC_WARN_UNUSED_VARIABLE = YES
diff --git a/shell_cmds/xcconfigs/sh.xcconfig b/shell_cmds/xcconfigs/sh.xcconfig
new file mode 100644
index 0000000..f068b26
--- /dev/null
+++ b/shell_cmds/xcconfigs/sh.xcconfig
@@ -0,0 +1,33 @@
+#include "base.xcconfig"
+
+// TODO: change to /bin, sh, /usr
+SH_INSTALL_PATH = /usr/local/bin
+SH_PRODUCT_NAME = ash
+SH_MAN_PREFIX = /usr/local
+
+// Architectures
+SUPPORTED_PLATFORMS = iphoneos iphonesimulator macosx
+
+// Deployment
+INSTALL_PATH = $(SH_INSTALL_PATH)
+
+// Linking
+OTHER_LDFLAGS = -ledit
+
+// Packaging
+PRODUCT_NAME = $(SH_PRODUCT_NAME)
+
+// Search Paths
+USER_HEADER_SEARCH_PATHS = $(BUILT_PRODUCTS_DIR) $(SRCROOT)/sh
+
+// Preprocessing
+GCC_PREPROCESSOR_DEFINITIONS = SHELL
+
+// Warnings - All languages
+GCC_WARN_64_TO_32_BIT_CONVERSION = NO
+GCC_WARN_UNINITIALIZED_AUTOS = YES
+GCC_WARN_UNUSED_VARIABLE = NO
+CLANG_WARN_ASSIGN_ENUM = NO
+CLANG_WARN_EMPTY_BODY = NO
+CLANG_WARN_IMPLICIT_SIGN_CONVERSION = NO
+CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = NO
diff --git a/shell_cmds/xcodescripts/builtins-manpages.txt b/shell_cmds/xcodescripts/builtins-manpages.txt
new file mode 100644
index 0000000..ffc6f4e
--- /dev/null
+++ b/shell_cmds/xcodescripts/builtins-manpages.txt
@@ -0,0 +1,85 @@
+alias.1
+alloc.1
+bg.1
+bind.1
+bindkey.1
+break.1
+breaksw.1
+builtins.1
+case.1
+cd.1
+chdir.1
+command.1
+complete.1
+continue.1
+default.1
+dirs.1
+do.1
+done.1
+echotc.1
+elif.1
+else.1
+end.1
+endif.1
+endsw.1
+esac.1
+eval.1
+exec.1
+exit.1
+export.1
+fc.1
+fg.1
+fi.1
+filetest.1
+for.1
+foreach.1
+getopts.1
+glob.1
+goto.1
+hash.1
+hashstat.1
+history.1
+hup.1
+if.1
+jobid.1
+jobs.1
+limit.1
+logout.1
+ls-F.1
+notify.1
+onintr.1
+popd.1
+pushd.1
+read.1
+readonly.1
+rehash.1
+repeat.1
+return.1
+sched.1
+set.1
+setenv.1
+settc.1
+setty.1
+setvar.1
+shift.1
+source.1
+stop.1
+suspend.1
+switch.1
+telltc.1
+then.1
+times.1
+trap.1
+type.1
+ulimit.1
+umask.1
+unalias.1
+uncomplete.1
+unhash.1
+unlimit.1
+unset.1
+unsetenv.1
+until.1
+wait.1
+where.1
+while.1
diff --git a/shell_cmds/xcodescripts/builtins.txt b/shell_cmds/xcodescripts/builtins.txt
new file mode 100644
index 0000000..55cb408
--- /dev/null
+++ b/shell_cmds/xcodescripts/builtins.txt
@@ -0,0 +1,14 @@
+bg
+cd
+command
+fc
+fg
+getopts
+hash
+jobs
+read
+type
+ulimit
+umask
+unalias
+wait
diff --git a/shell_cmds/xcodescripts/install-files.sh b/shell_cmds/xcodescripts/install-files.sh
new file mode 100644
index 0000000..3710fcb
--- /dev/null
+++ b/shell_cmds/xcodescripts/install-files.sh
@@ -0,0 +1,66 @@
+#!/bin/sh
+set -e -x
+
+BINDIR="$DSTROOT"/usr/bin
+LIBEXECDIR="$DSTROOT"/usr/libexec
+MANDIR="$DSTROOT"/usr/share/man
+PAMDIR="$DSTROOT"/private/etc/pam.d
+
+ln -f "$BINDIR/hexdump" "$BINDIR/od"
+ln -f "$BINDIR/id" "$BINDIR/groups"
+ln -f "$BINDIR/id" "$BINDIR/whoami"
+ln -f "$BINDIR/w" "$BINDIR/uptime"
+ln -f "$DSTROOT/bin/test" "$DSTROOT/bin/["
+
+install -d -o root -g wheel -m 0755 "$BINDIR"
+install -d -o root -g wheel -m 0755 "$MANDIR"/man1
+install -d -o root -g wheel -m 0755 "$MANDIR"/man8
+
+install -c -o root -g wheel -m 0755 "$SRCROOT"/alias/generic.sh "$BINDIR"/alias
+install -c -o root -g wheel -m 0644 "$SRCROOT"/alias/builtin.1 "$MANDIR"/man1
+
+set +x
+for builtin in `cat "$SRCROOT/xcodescripts/builtins.txt"`; do
+ echo ... linking $builtin
+ ln -f "$BINDIR"/alias "$BINDIR/$builtin"
+done
+
+for manpage in `cat "$SRCROOT/xcodescripts/builtins-manpages.txt"`; do
+ echo ... linking $manpage
+ echo ".so man1/builtin.1" > "$MANDIR/man1/$manpage"
+done
+set -x
+
+install -d -o root -g wheel -m 0755 "$DSTROOT"/AppleInternal/Tests/shell_cmds
+install -o root -g wheel -m 0644 "$SRCROOT"/tests/regress.m4 \
+ "$DSTROOT"/AppleInternal/Tests/shell_cmds
+
+install -d -o root -g wheel -m 0755 \
+ "$DSTROOT"/AppleInternal/Tests/shell_cmds/time
+install -o root -g wheel -m 0644 "$SRCROOT"/time/tests/test_time.sh \
+ "$DSTROOT"/AppleInternal/Tests/shell_cmds/time
+
+install -d -o root -g wheel -m 0755 \
+ "$DSTROOT"/AppleInternal/CoreOS/BATS/unit_tests
+install -o root -g wheel -m 0644 "$SRCROOT"/tests/shell_cmds.plist \
+ "$DSTROOT"/AppleInternal/CoreOS/BATS/unit_tests
+
+# Skip locate and su targets for iOS
+if [ "$TARGET_NAME" = "All_iOS" ]; then
+ exit 0
+fi
+
+install -d -o root -g wheel -m 0755 "$LIBEXECDIR"
+install -c -o root -g wheel -m 0755 "$SRCROOT"/locate/locate/updatedb.sh \
+ "$LIBEXECDIR"/locate.updatedb
+install -c -o root -g wheel -m 0644 "$SRCROOT"/locate/locate/locate.updatedb.8 \
+ "$MANDIR"/man8
+install -c -o root -g wheel -m 0755 "$SRCROOT"/locate/locate/concatdb.sh \
+ "$LIBEXECDIR"/locate.concatdb
+echo ".so man8/locate.updatedb.8" > "$MANDIR"/man8/locate.concatdb.8
+install -c -o root -g wheel -m 0755 "$SRCROOT"/locate/locate/mklocatedb.sh \
+ "$LIBEXECDIR"/locate.mklocatedb
+echo ".so man8/locate.updatedb.8" > "$MANDIR"/man8/locate.mklocatedb.8
+
+install -d -o root -g wheel -m 0755 "$PAMDIR"
+install -c -o root -g wheel -m 0644 "$SRCROOT"/su/su.pam "$PAMDIR"/su
diff --git a/shell_cmds/yes/yes.1 b/shell_cmds/yes/yes.1
new file mode 100644
index 0000000..eab3795
--- /dev/null
+++ b/shell_cmds/yes/yes.1
@@ -0,0 +1,56 @@
+.\" $NetBSD: yes.1,v 1.4 1997/10/20 03:42:10 lukem Exp $
+.\"
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)yes.1 8.1 (Berkeley) 6/6/93
+.\"
+.Dd June 6, 1993
+.Dt YES 1
+.Os BSD 4
+.Sh NAME
+.Nm yes
+.Nd be repetitively affirmative
+.Sh SYNOPSIS
+.Nm
+.Op Ar expletive
+.Sh DESCRIPTION
+.Nm
+outputs
+.Ar expletive ,
+or, by default,
+.Dq y ,
+forever.
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.0 .
diff --git a/shell_cmds/yes/yes.c b/shell_cmds/yes/yes.c
new file mode 100644
index 0000000..863f363
--- /dev/null
+++ b/shell_cmds/yes/yes.c
@@ -0,0 +1,63 @@
+/* $NetBSD: yes.c,v 1.5 1997/10/19 14:28:27 mrg Exp $ */
+
+/*
+ * Copyright (c) 1987, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1987, 1993\n\
+ The Regents of the University of California. All rights reserved.\n");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)yes.c 8.1 (Berkeley) 6/6/93";
+#endif
+__RCSID("$NetBSD: yes.c,v 1.5 1997/10/19 14:28:27 mrg Exp $");
+#endif /* not lint */
+
+#include <stdio.h>
+
+int main __P((int, char **));
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ if (argc > 1)
+ for(;;)
+ (void)puts(argv[1]);
+ else for (;;)
+ (void)puts("y");
+}