home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume25 / pdksh / part02 < prev    next >
Text File  |  1991-11-12  |  56KB  |  2,072 lines

  1. Newsgroups: comp.sources.misc
  2. From: sjg@zen.void.oz.au (Simon J. Gerraty)
  3. Subject:  v25i048:  pdksh - Public Domain Korn Shell, v4, Part02/09
  4. Message-ID: <1991Nov13.031036.15763@sparky.imd.sterling.com>
  5. X-Md4-Signature: 7c582cc4d925bcf5e285068e383734fd
  6. Date: Wed, 13 Nov 1991 03:10:36 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: sjg@zen.void.oz.au (Simon J. Gerraty)
  10. Posting-number: Volume 25, Issue 48
  11. Archive-name: pdksh/part02
  12. Environment: UNIX
  13.  
  14. #! /bin/sh
  15. # into a shell via "sh file" or similar.  To overwrite existing files,
  16. # type "sh file -c".
  17. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  18. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  19. # Contents:  ksh.1 sh/jobs.c sh/trace.c
  20. # Wrapped by kent@sparky on Tue Nov 12 20:44:32 1991
  21. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  22. echo If this archive is complete, you will see the following message:
  23. echo '          "shar: End of archive 2 (of 9)."'
  24. if test -f 'ksh.1' -a "${1}" != "-c" ; then 
  25.   echo shar: Will not clobber existing file \"'ksh.1'\"
  26. else
  27.   echo shar: Extracting \"'ksh.1'\" \(31646 characters\)
  28.   sed "s/^X//" >'ksh.1' <<'END_OF_FILE'
  29. X.\" $Header: /usr/local/src/nksh/sh/RCS/ksh.1,v 3.1 88/11/22 10:44:17 egisin Exp $
  30. X.nr OJ 1 \" Job Control
  31. X.nr OE 1 \" Command Editing
  32. X.nr OB 1 \" BSD enhanced ulimit options
  33. X.ds OK [\|
  34. X.ds CK \|]
  35. X.TH KSH 1 "January 1988"
  36. X.SH NAME
  37. Xksh \- Bourne / Korn Shell (Public Domain)
  38. X.SH SYNOPSIS
  39. X\fBksh\fP
  40. X[\fB\-st\fP] [\fB\-c\fP \fIcommand\fP]
  41. X[\fIfile\fP [\fIargument ...\fP]]
  42. X.SH INTRODUCTION
  43. XThis document only summarizes the System V, release 2 shell features.
  44. XAll of the System V features except for ``restricted mode''
  45. Xare implemented.
  46. XSee also the BUGS section.
  47. X.LP
  48. XFeatures of the Korn shell are described in more detail.
  49. XOnly a subset of the Korn shell features are currently implemented.
  50. X.SH DESCRIPTION
  51. X.SS Command syntax
  52. XThe ``#'' character begins a one-line comment,
  53. Xunless the ``#'' occurs inside a word.
  54. XThe tokens ``;'', ``|'', ``&'', ``;;'', ``||'', ``&&'', ``('', and ``)''
  55. Xstand by themselves.
  56. XA \fIword\fP is a sequence of any other non-whitespace characters,
  57. Xwhich may also contain quoted strings
  58. X(quote character are ``\''', ``"'', ``\`'',
  59. Xor a matching ``${ }'' or ``$( )'' pair).
  60. XA \fIname\fP is an unquoted word made up of letters, digits, or ``_''.
  61. XAny number of whitespace characters (space and tab) may separate words and tokens.
  62. X.LP
  63. XIn the following syntax, { ... }? indicates an optional thing,
  64. X{ ... }* indicates zero or more repetitions, { ... | ... } indicates alternatives.
  65. X.de S
  66. X.br
  67. X\\$1
  68. X.br
  69. X..
  70. X.IP statement:
  71. X.S "\fB(\fP list \fB)\fP"
  72. X.S "\fB{\fP list \fB;\fP \fB}\fP"
  73. X.S "\fBfor\fP name { \fBin\fP { word }* }? \fBdo\fP list \fB;\fP \fBdone\fP"
  74. X.S "{ \fBwhile\fP | \fBuntil\fP } list \fB;\fP \fBdo\fP list \fB;\fP \fBdone\fP"
  75. X.S "\fBif\fP list \fB;\fP \fBthen\fP list \fB;\fP { \fBelif\fP list \fB;\fP \fBthen\fP list \fB;\fP }* { \fBelse\fP list \fB;\fP }?\fBfi\fP"
  76. X.S "\fBcase\fP name \fBin\fP { \fB(\fP word { \fB|\fP word } \fB)\fP list \fB;;\fP }* \fBesac\fP"
  77. X.S "\fBfunction\fP name \fB{\fP list \fB;\fP \fB}\fP"
  78. X.S "name \fB() {\fP list \fB;\fP \fB}\fP"
  79. X.S "\fBtime\fP pipe"
  80. XThe opening parenthesis of the pattern is optional. 
  81. XRedirection may occur at the beginning or end of a statement.
  82. X.IP command:
  83. X.S "{ name=word }* { word }*"
  84. XRedirection may occur anywhere in a command.
  85. X.IP list:
  86. X.S "cond"
  87. X.S "cond \fB;\fP list"
  88. X.S "cond \fB&\fP list"
  89. X.IP cond:
  90. X.S "pipe"
  91. X.S "pipe \fB&&\fP cond"
  92. X.S "pipe \fB||\fP cond"
  93. X.IP pipe:
  94. X.S "statement { \fB|\fP statement }*"
  95. X.SS Alias expansion
  96. XAlias expansion occurs when the first word of a
  97. Xstatement is a defined alias,
  98. Xexcept when that alias is already being expanded.
  99. XIt also occurs after the expansion of an alias whose
  100. Xdefinition ends with a space.
  101. X.SS Shell variables
  102. XThe following standard special variables exist:
  103. X\fB!\fP, \fB#\fP, \fB$\fP, \fB\-\fP, \fB?\fP.
  104. X.IP "_"
  105. XIn interactive use this parameter is set to the last word of
  106. Xthe previous command.  When a command is executed this parameter
  107. Xis set to the full path of the command and placed in the environment
  108. Xfor the command.  See also \fBMAILPATH\fP.
  109. X.IP CDPATH
  110. XThe search path for the \fIcd\fP command.
  111. X.IP ENV
  112. XIf this variable is set at start-up
  113. X(after any profile files are executed),
  114. Xthe expanded value is used as shell start-up file.
  115. XIt typically contains function and alias definitions.
  116. X.IP FCEDIT
  117. XThe editor used by the \fIfc\fP command.
  118. X.IP IFS
  119. X\fIInternal field separator\fP,
  120. Xused during substitution and the \fIread\fP command.
  121. X.IP HOME
  122. XThe default directory for the \fIcd\fP command.
  123. X.IP MAIL
  124. XIf set, the user will be informed of the arrival of mail
  125. Xin the named file.  This variable is ignored if
  126. Xthe \fBMAILPATH\fP variable is set.
  127. X.IP MAILCHECK
  128. XHow often, in seconds, the shell will check for mail in the
  129. Xfile(s) specified by \fBMAIL\fP or \fBMAILPATH\fP.  If 0,
  130. Xthe shell checks before each prompt.  The default is 600
  131. Xseconds.
  132. X.IP MAILPATH
  133. XA list of files to be checked for mail.  The list is colon
  134. Xseparated, and each file may be followed by a \fB?\fP and
  135. Xa message to be printed if new mail has arrived.  Command
  136. Xand parameter substitution is performed on the message, and
  137. Xthe parameter \fB$_\fP is set to the name of the file.
  138. XThe default message is ``you have mail in $_''.
  139. X.IP PATH
  140. XThe search path for executable commands and \fB.\fP'd files.
  141. X.IP PPID
  142. XThe process number of the parent of the shell.
  143. X.IP "PS1 PS2"
  144. X\fBPS1\fP is the primary prompt for interactive shells.
  145. XDollar substitution is performed, and \fB!\fP is replaced
  146. Xwith the command number (see \fIfc\fP).
  147. X.IP "PWD OLDPWD"
  148. XThe current and previous working directories.
  149. X.IP RANDOM
  150. XA random integer.  The random number generator may be seeded
  151. Xby assigning an integer value to this variable.
  152. X.IP SECONDS
  153. XThe number of seconds since the shell timer was started or
  154. Xreset.  Assigning an integer value to this variable resets
  155. Xthe timer.
  156. X.SS Substitution
  157. XIn addition to the System Vr2 substitutions,
  158. Xthe following are available.
  159. X.IP "$(command)"
  160. XLike `command`, but no escapes are recognized.
  161. X.IP "$(<file)"
  162. XEquivalent to $(cat file), but without forking.
  163. X.IP "${#var}"
  164. XThe length of the string value of \fIvar\fP,
  165. Xor the number of arguments if \fIvar\fP is \fB*\fP or \fB@\fP.
  166. X.IP "${var#pattern} ${var##pattern}"
  167. XIf \fIpattern\fP matches the beginning of the value of \fIvar\fP,
  168. Xthe matched text is deleted from the result of substitution.
  169. XA single \fB#\fP results in the shortest match,
  170. Xtwo \fB#\fP's results in the longest match.
  171. X.IP "${var%pattern} ${var%%pattern}"
  172. XLike \fB#\fP substition, but deleting from the end of the value.
  173. X.SS Expressions
  174. XExpressions can be used with the \fBlet\fP command,
  175. Xas numeric arguments to the \fBtest\fP command,
  176. Xand as the value of an assignment to an integer variable.
  177. X.LP
  178. XExpression may contain alpha-numeric variable identifiers and integer constants
  179. Xand may be combined with the following operators:
  180. X.IP "== != <= < > >= + - * / % ! ( )"
  181. X.SS Command execution
  182. XAfter evaluation of keyword assignments and arguments,
  183. Xthe type of command is determined.
  184. XA command may execute a shell function, a shell built-in,
  185. Xor an executable file.
  186. X.LP
  187. XAny keyword assignments are then performed according to
  188. Xthe type of command.
  189. XIn function calls assignments are local to the function.
  190. XAssignments in built-in commands marked with a \(dg persist,
  191. Xotherwise they are temporary.
  192. XAssignments in executable commands are exported to the sub-process
  193. Xexecuting the command.
  194. X.LP
  195. XEven on systems where the exec() family does not support #!
  196. Xnotation for scripts, ksh can be configured to fake it.
  197. X.LP
  198. XThere are several built-in commands.
  199. X.IP ":"
  200. XOnly expansion and assignment are performed.
  201. XThis is the default if a command has no arguments.
  202. X.IP ". \fIfile\fP"
  203. XExecute the commands in \fIfile\fP without forking.
  204. XThe file is searched in the directories of $PATH.
  205. XPassing arguments is not implemented.
  206. X.IP "alias [\fIname\fB=\fIvalue\fI ...]\fR"
  207. XWithout arguments, \fBalias\fP lists all aliases and their values.
  208. XFor any name without a value, its value is listed.
  209. XAny name with a value defines an alias, see "Alias Expansion" above.
  210. XKorn's tracked aliases are not implemented,
  211. Xbut System V command hashing is (see "hash").
  212. X.IP "alias -d [\fIname\fB=\fIvalue\fI ...]\fR"
  213. XDirectory aliases for tilde expansion, eg.
  214. X.br
  215. Xalias -d fac=/usr/local/usr/facilities
  216. X.br
  217. Xcd ~fac/bin
  218. X.IP "break [\fIlevels\fP]"
  219. X.IP "builtin \fIcommand arg ...\fP"
  220. X\fICommand\fP is executed as a built-in command.
  221. X.IP "cd [\fIpath\fP]"
  222. XSet the working directory to \fIpath\fP.  If the parameter
  223. XCDPATH is set, it lists the search path for the directory
  224. Xcontaining \fIpath\fP.  A null path means the current directory.
  225. XIf \fIpath\fP is missing, the home directory ($HOME) is used.
  226. XIf \fIpath\fP is \fB\-\fP, the previous working directory is used.
  227. XIf \fIpath\fP is \fB..\fP, the shell changes directory to the
  228. Xparent directory, as determined from the value of PWD.
  229. XThe PWD and OLDPWD variables are reset.
  230. X.IP "cd \fIold new\fP"
  231. XThe string \fInew\fP is substituted for \fIold\fP in the current
  232. Xdirectory, and the shell attempts to change to the new directory.
  233. X.IP "continue [\fIlevels\fP]"
  234. X.IP "echo ..."
  235. X\fIEcho\fP is replaced with the alias echo='print' in the Korn shell.
  236. X.IP "eval \fIcommand ...\fP"
  237. X.IP "exec \fIcommand arg ...\fP"
  238. XThe executable command is executed without forking.
  239. XIf no arguments are given, any IO redirection is permanent.
  240. X.IP "exit [\fIstatus\fP]"
  241. X.IP "fc [\fB\-e\fP \fIeditor\fP] [\fB\-lnr\fP] [\fIfirst\fP [\fIlast\fP]]"
  242. X\fIFirst\fP and \fIlast\fP select commands.
  243. XCommands can be selected by history number,
  244. Xor a string specifing the most recent command starting with that string.
  245. XThe \fB\-l\fP option lists the command on stdout,
  246. Xand \fB\-n\fP inhibits the default command numbers.
  247. XThe \fB\-r\fP option reverses the order of the list.
  248. XWithout \fB\-l\fP, the selected commands can be edited by
  249. Xthe editor specified with the \fB\-e\fP option, or if no \fB\-e\fP
  250. Xis specified,
  251. Xthe \fB$FCEDIT\fP editor, then executed by the shell.
  252. X.IP "fc \fB\-e \-\fP [\fB\-g\fP] [\fIold\fB=\fInew\fR] [\fIcommand\fP]"
  253. XRe-execute the selected command (the previous command by default)
  254. Xafter performing the optional substitution of \fIold\fP with \fInew\fP.
  255. XIf \fB\-g\fP is specified, all occurrences of \fIold\fP are
  256. Xreplaced with \fInew\fP.
  257. XThis command is usually accessed with the predefined alias
  258. Xr=``fc \-e \-''.
  259. X.IP "getopts"
  260. XSee the attached manual page.
  261. X.IP "hash [\fB\-r\fP] [\fIname ...\fP]"
  262. XWithout arguments, any hashed executable command pathnames are listed.
  263. XThe \fB\-r\fP flag causes all hashed commands to be removed.
  264. XEach \fIname\fP is searched as if it were a command name
  265. Xand added to the hash table if it is an executable command.
  266. X.IP "kill [\fB\-\fIsignal\fR] \fIprocess\fP ..."
  267. XSend a signal (TERM by default) to the named process.
  268. XThe signal may be specified as a number or a mnemonic from <signal.h>
  269. Xwith the SIG prefix removed.
  270. X.IP "let [\fIexpression ...\fP]"
  271. XEach expression is evaluated, see "Expressions" above.
  272. XA zero status is returned if the last expression evaluates
  273. Xto a non-zero value, otherwise a non-zero status is returned.
  274. XSince may expressions need to be quoted, \fI(( expr ))\fP is
  275. Xsyntactic sugar for \fIlet "expr"\fP.
  276. X.IP "print [\fB\-nreu\fIn\fR] [\fIargument ...\fP]"
  277. X\fBPrint\fP prints its arguments on the standard output,
  278. Xseparated by spaces, and terminated with a newline.
  279. XThe \fB\-n\fP option eliminates the newline.
  280. X.IP
  281. XBy default, certain C escapes are translated.
  282. XThese include \eb, \ef, \en, \er, \et, \ev, and \e### (# is an octal digit).
  283. X\ec is equivalent to the \fB\-n\fP option.
  284. XThis expansion may be inhibitted with the \fB\-r\fP option,
  285. Xand may be re-enabled with the addition of the \fB\-e\fP option.
  286. X.IP "read [\fB\-ru\fIn\fR] \fIname ...\fP"
  287. XThe first variable name may be of the form \fIname\fB?\fIprompt\fR.
  288. X.IP "readonly [\fIname ...\fP]"
  289. X.IP "return [\fIstatus\fP]"
  290. X.ta 5n 10n 30n
  291. X.de O
  292. X.br
  293. X\t\\$1\t\\$2\t\\$3
  294. X..
  295. X.IP "set [\fB\(+-\fP\fI[a-z]\fP] [\fB\(+-o\fP \fIkeyword\fP] ..."
  296. XSet (\fB\-\fP) or clear (\fB+\fP) a shell option:
  297. X.O \-a allexport "all new variable are created with export attribute"
  298. X.O \-e errexit "exit on non-zero status [incorrect]"
  299. X.O "" bgnice "background jobs are run with lower priority"
  300. X.if \n(OE \{
  301. X.O "" emacs "BRL emacs-like line editing"\}
  302. X.O "" ignoreeof "shell will not exit of EOF, must use \fIexit\fP"
  303. X.O \-k keyword "variable assignments are recognized anywhere in command"
  304. X.O "" markdirs "[not implemented]"
  305. X.O \-m monitor "job control enabled (default for interactive shell)"
  306. X.O \-n noexec "compile input but do not execute (ignored if interactive)"
  307. X.O \-f noglob "don't expand filenames"
  308. X.O \-u nounset "dollar expansion of unset variables is an error"
  309. X.O \-v verbose "echo shell commands on stdout when compiling"
  310. X.O \-h trackall "add command pathnames to hash table"
  311. X.O "" vi "VI-like line editing"
  312. X.O \-x xtrace "echo simple commands while executing"
  313. X.IP "set [\fB\-\-\fP] \fIarg ...\fP"
  314. XSet shell arguments.
  315. X.IP "shift [\fInumber\fP]"
  316. X.IP "test"
  317. XSee the attached manual page.
  318. X.IP "times"
  319. X.IP "trap [\fIhandler\fP] [\fIsignal ...\fP]"
  320. X.IP "typeset [\fB\(+-irtx\fP] [\fIname\fP[\fB=\fIvalue\fR] ...]"
  321. XIf no arguments are given, lists all variables and their attributes.
  322. X.PP
  323. XIf options but no names are given, lists variables with specified
  324. Xattributes, and their values if unless ``+'' is used.
  325. X.PP
  326. XIf names are given, set the attributes of the named variables.
  327. XVariables may also be assigned a value.
  328. XIf used inside a function, the created variable are local to the function.
  329. X.PP
  330. XThe attributes are as follows.
  331. X.ta 5n 10n
  332. X\t\-i\tThe variable's value is stored as an integer.
  333. X.br
  334. X\t\-x\tThe variable is exported to the enviroment.
  335. X.br
  336. X\t\-r\tThe variable is read-only cannot be reassigned a value.
  337. X.br
  338. X\t\-t\tTrace (not implemented).
  339. X.br
  340. X\t\-f\tList functions instead of variable.
  341. X.\".IP "ulimit [\fB\-f\fP] [\fIvalue\fP]"
  342. X.ds OZ <OZ>
  343. X.IP "\fBulimit\fP \*(OK \fB\-\*(OZ\fP \*(CK \*(OK \fIn\fP \*(CK"
  344. X.RS
  345. X.TP "\w'\fB\-\-\ \ \ 'u"
  346. X.if \n(OB \{.B \-c
  347. XImpose a size limit of
  348. X.I n\^
  349. Xblocks on the size of core dumps.
  350. X.TP
  351. X.B \-d
  352. XImpose a size limit of
  353. X.I n\^
  354. Xblocks on the size of the data area.\}
  355. X.TP
  356. X.B \-f
  357. XImpose a size limit of
  358. X.I n
  359. Xblocks on files written by the shell
  360. Xand its child processes (files of any size may be read).
  361. X.if \n(OB \{.TP
  362. X.B \-m
  363. XImpose a soft limit of
  364. X.I n\^
  365. Xblocks on the size of physical memory.
  366. X.TP
  367. X.B \-t
  368. XImpose a time limit of
  369. X.I n\^
  370. Xseconds to be used by each process.\}
  371. X.PP
  372. XIf no option is given,
  373. X.B \-f
  374. Xis assumed.
  375. XIf
  376. X.I n
  377. Xis omitted, the current limit is printed.
  378. XAs far as
  379. X.B ulimit
  380. Xis concerned, a ``block'' is 512 bytes.
  381. X.PP
  382. XYou may lower your own resource limit,
  383. Xbut only a super-user (see
  384. X.IR su (1M))
  385. Xcan raise a limit.
  386. X.RE
  387. X.IP "umask [\fIvalue\fP]"
  388. X.IP "unalias \fIname ...\fP"
  389. XThe aliases for the given names are removed.
  390. X.IP "unset [\fB\-f\fP] \fIname ...\fP"
  391. X.IP "wait [\fIprocess-id\fP]"
  392. X.IP "whence [\fB\-v\fP] name ..."
  393. XFor each name, the type of command is listed.
  394. XThe \fB\-v\fP flag causes function and alias values to be listed.
  395. X.SS Job Control
  396. XJob control features are enabled by the
  397. X\fB\-m\fP or \fB\-o monitor\fP flags.
  398. XWhen job control is enabled, and the system supports job control,
  399. Xbackground commands and foreground commands that have been stopped
  400. X(usually by a
  401. X.SM SIGTSTP
  402. Xsignal generated by typing
  403. X.IR ^Z\^ )
  404. Xare placed into separate individual
  405. X.IR "process groups" .
  406. XThe following commands are used to manipulate these process groups:
  407. X.PP
  408. X.PD 0
  409. X.TP "\w'\fBkill\fP \*(OK \fIjob\fP \*(CK\ \ \ 'u"
  410. X\fBjobs\fP
  411. XDisplay information about the controlled jobs.
  412. XThe job number is given preceeded by a percent sign,
  413. Xfollowed by a plus sign if it is the ``current job'',
  414. Xor by a minus sign if it is the ``previous job'',
  415. Xthen the process group number for the job,
  416. Xthen the command.
  417. X.TP
  418. X\fBkill\fP [\fB\-\fIsignal\fR] \fIjob\fP ...
  419. XSend a signal (TERM by default) to the named job process group.
  420. X.TP
  421. X\fBfg\fP \*(OK \fIjob\fP \*(CK
  422. XResume the stopped foreground job in the foreground.
  423. XIf the process group
  424. X.I n
  425. Xis not specified then the ``current job'' is resumed.
  426. X.TP
  427. X\fBbg\fP \*(OK \fIjob\fP \*(CK
  428. XResume the stopped foreground job in the background.
  429. XIf the process group
  430. X.I n
  431. Xis not specified then the ``current job'' is resumed.
  432. X.PD
  433. X.PP
  434. XThe \fBfg\fP, \fBbg\fP, \fBkill\fP, and \fBwait\fP commands
  435. Xmay refer to jobs with the following ``percent'' sequences.
  436. XThe percent sign is optional with the fg and bg commands.
  437. X.PP
  438. X.PD 0
  439. X.TP "\w'\fBbg\fP \*(OK \fIn\fP \*(CK\ \ \ 'u"
  440. X.BR %+ ( %\- )
  441. XIf there is a ``current job'' (``previous job''),
  442. Xthen that job is selected.
  443. X.TP
  444. X.BI % n
  445. XIf the specified job number is one of the known jobs,
  446. Xthen that job is selected.
  447. X.TP
  448. X.BI % string
  449. XIf the string matches the initial part of a job's command,
  450. Xthen that job is selected.
  451. X.TP
  452. X.BI %? string
  453. XAs above, but the string may match any portion of the command.
  454. X.sp
  455. X.PP
  456. XIf the system does not support job control, monitor mode enables
  457. Xjob reporting.  The jobs and kill commands
  458. Xfunctions as above, and you will
  459. Xbe informed when background jobs complete.  Fg and bg are not 
  460. Xavailiable.
  461. X.PD
  462. X.br
  463. X.SS "Interactive Input Line Editing"
  464. XWhen the
  465. X.B emacs
  466. Xoption is set,
  467. Xinteractive input line editing is enabled.
  468. XThis mode is slightly different from the emacs mode in AT&T's KornShell.
  469. XIn this mode various
  470. X.I "editing commands"
  471. X(typically bound to one or more control characters)
  472. Xcause immediate actions without waiting for a new-line.
  473. XSeveral
  474. X.I "editing commands"
  475. Xare bound to particular control characters
  476. Xwhen the shell is invoked;
  477. Xthese bindings can be changed using the following commands:
  478. X.br
  479. X.PP
  480. X.PD 0
  481. X.TP 2i
  482. X\fBbind\fP
  483. XThe current bindings are listed.
  484. X.TP
  485. X\fBbind\fP \*(OK \fIstring\fP \*(CK = \*(OK \fIediting-command\fP \*(CK
  486. XThe specified
  487. X.I "editing command\^"
  488. Xis bound to the given
  489. X.IR string ,
  490. Xwhich should consist of a control character
  491. X(which may be written using ``caret notation'' \fB^\fP\fIx\fP\|),
  492. Xoptionally preceded by one of the two prefix characters.
  493. XFuture input of the
  494. X.I string
  495. Xwill cause the
  496. X.I "editing command\^"
  497. Xto be immediately invoked.
  498. X.br
  499. XNote that although only two prefix characters (normal ESC and ^X)
  500. Xare supported, some multi-character sequences can be supported:
  501. X.br
  502. Xbind '^[['=prefix-2
  503. X.br
  504. Xbind '^XA'=up-history
  505. X.br
  506. Xbind '^XB'=down-history
  507. X.br
  508. Xbind '^XC'=forward-char
  509. X.br
  510. Xbind '^XC'=backward-char
  511. X.br
  512. Xwill bind the arrow keys on an ANSI terminal.  Of course some escape
  513. Xsequences won't work out quite that nicely.
  514. X.TP
  515. X\fBbind -m\fP \*(OK \fIstring\fP \*(CK = \*(OK \fIsubstitute\fP \*(CK
  516. XThe specified input
  517. X.I string
  518. Xwill afterwards be immediately replaced by the given
  519. X.I substitute
  520. Xstring,
  521. Xwhich may contain
  522. X.IR "editing commands" .
  523. X.PD
  524. X.PP
  525. XThe following
  526. X.I "editing commands"
  527. Xare available;
  528. Xfirst the command name is given
  529. Xfollowed by its default binding (if any)
  530. Xusing caret notation
  531. X(note that the ASCII
  532. X.SM ESC
  533. Xcharacter is written as \s-1^[\s0\|),
  534. Xthen the editing function performed is decribed.
  535. XNote that
  536. X.I "editing command"
  537. Xnames are used only with the
  538. X.B bind
  539. Xcommand.
  540. XFurthermore,
  541. Xmany
  542. X.I "editing commands"
  543. Xare useful only on terminals with a visible cursor.
  544. XThe default bindings were chosen to resemble corresponding EMACS key bindings.
  545. XThe users tty characters (eg. erase) are bound to reasonable
  546. Xsubstitutes.
  547. X.br
  548. X.PP
  549. X.PD 0
  550. X.TP "\w'\fBdelete-word-backward\ \ ^[\|ERASE\fP\ \ \ 'u"
  551. X\fBabort\ \ ^G\fP
  552. XUseful as a response to a request for a
  553. X.B search-history
  554. Xpattern in order to abort the search.
  555. X.br
  556. X.TP
  557. X\fBauto-insert\fP
  558. XSimply causes the character to appear as literal input.
  559. X(Most ordinary characters are bound to this.)
  560. X.br
  561. X.TP
  562. X\fBbackward-char\ \ ^B\fP
  563. XMoves the cursor backward one character.
  564. X.br
  565. X.TP
  566. X\fBbackward-word\ \ ^[\|b\fP
  567. XMoves the cursor backward to the beginning of a word.
  568. X.br
  569. X.TP
  570. X\fBbeginning-of-line\ \ ^A\fP
  571. XMoves the cursor to the beginning of the input line
  572. X(after the prompt string).
  573. X.br
  574. X.TP
  575. X\fBcomplete\ \ ^[\|^[\fP
  576. XAutomatically completes as much as is unique of the hashed command name
  577. Xor the file name containing the cursor.
  578. XIf the entire remaining command or file name is unique
  579. Xa space is printed after its completion,
  580. Xunless it is a directory name in which case
  581. X.B /
  582. Xis postpended.
  583. XIf there is no hashed command or file name with the current partial word
  584. Xas its prefix,
  585. Xa bell character is output (usually causing a ``beep'').
  586. X.br
  587. X.TP
  588. X\fBcomplete-command\ \ ^X^[\fP
  589. XAutomatically completes as much as is unique of the hashed command name
  590. Xhaving the partial word up to the cursor as its prefix,
  591. Xas in the
  592. X.B complete
  593. Xcommand described above.
  594. XOnly command and function names seen since the last
  595. X.B "hash \-r"
  596. Xcommand are available for completion;
  597. Xthe
  598. X.B "hash"
  599. Xcommand may be used to register additional names.
  600. X.br
  601. X.TP
  602. X\fBcomplete-file\ \ ^[\|^X\fP
  603. XAutomatically completes as much as is unique of the file name
  604. Xhaving the partial word up to the cursor as its prefix,
  605. Xas in the
  606. X.B complete
  607. Xcommand described above.
  608. X.br
  609. X.TP
  610. X\fBcopy-last-arg\ \ ^[\|_\fP
  611. XThe last word of the previous command is inserted at the
  612. Xcursor.  Note I/O redirections do not count as words of
  613. Xthe command.
  614. X.br
  615. X.TP
  616. X\fBdelete-char-backward\ \ ERASE\fP
  617. XDeletes the character before the cursor.
  618. X.br
  619. X.TP
  620. X\fBdelete-char-forward\fP
  621. XDeletes the character after the cursor.
  622. X.br
  623. X.TP
  624. X\fBdelete-word-backward\ \ ^[\|ERASE\fP
  625. XDeletes characters before the cursor back to the beginning of a word.
  626. X.br
  627. X.TP
  628. X\fBdelete-word-forward\ \ ^[\|d\fP
  629. XDeletes characters after the cursor up to the end of a word.
  630. X.br
  631. X.TP
  632. X\fBdown-history\ \ ^N\fP
  633. XScrolls the history buffer forward one line (later).
  634. XEach input line originally starts just after
  635. Xthe last entry in the history buffer,
  636. Xso
  637. X.B down-history
  638. Xis not useful until either
  639. X.B search-history
  640. Xor
  641. X.B up-history
  642. Xhas been performed.
  643. X.br
  644. X.TP
  645. X\fBend-of-line\ \ ^E\fP
  646. XMoves the cursor to the end of the input line.
  647. X.br
  648. X.TP
  649. X\fBeot\ \ ^_\fP
  650. XActs as an end-of-file;
  651. Xthis is useful because edit-mode input
  652. Xdisables normal terminal input canonicalization.
  653. X.br
  654. X.TP
  655. X\fBeot-or-delete\ \ ^D\fP
  656. XActs as eot if alone on a line;
  657. Xotherwise acts as delete-char-forward.
  658. X.br
  659. X.TP
  660. X\fBexchange-point-and-mark\ \ ^X\|^X\fP
  661. XPlaces the cursor where the mark is, and sets the
  662. Xmark to where the cursor was.
  663. X.br
  664. X.TP
  665. X\fBforward-char\ \ ^F\fP
  666. XMoves the cursor forward one position.
  667. X.br
  668. X.TP
  669. X\fBforward-word\ \ ^[\|f\fP
  670. XMoves the cursor forward to the end of a word.
  671. X.br
  672. X.TP
  673. X\fBkill-line\ \ KILL\fP
  674. XDeletes the entire input line.
  675. X.br
  676. X.TP
  677. X\fBkill-to-eol\ \ ^K\fP
  678. XDeletes the input from the cursor to the end of the line.
  679. X.br
  680. X.TP
  681. X\fBkill-region\ \ ^W\fP
  682. XDeletes the input between the cursor and the mark.
  683. X.br
  684. X.TP
  685. X\fBlist\ \ ^[\|?\fP
  686. XPrints a sorted, columnated list of hashed command names or file names
  687. X(if any) that can complete the partial word containing the cursor.
  688. XDirectory names have
  689. X.B /
  690. Xpostpended to them,
  691. Xand executable file names are followed by
  692. X.BR \(** .
  693. X.br
  694. X.TP
  695. X\fBlist-command\ \ ^X\|?\fP
  696. XPrints a sorted, columnated list of hashed command names
  697. X(if any) that can complete the partial word containing the cursor.
  698. X.br
  699. X.TP
  700. X\fBlist-file\fP
  701. XPrints a sorted, columnated list of file names
  702. X(if any) that can complete the partial word containing the cursor.
  703. XFile type indicators are postpended as described under
  704. X.B list
  705. Xabove.
  706. X.br
  707. X.TP
  708. X\fBnewline\ \ ^J\ \fP\fIand\^\fP\fB\ ^M\fP
  709. XCauses the current input line to be processed by the shell.
  710. X(The current cursor position may be anywhere on the line.)
  711. X.br
  712. X.TP
  713. X\fBnewline-and-next\ \ ^O\fP
  714. XCauses the current input line to be processed by the shell, and
  715. Xthe next line from history becomes the current line.  This is
  716. Xonly useful after an up-history or search-history.
  717. X.br
  718. X.TP
  719. X\fBno-op\ \ QUIT\fP
  720. XDoes nothing.
  721. X.br
  722. X.TP
  723. X\fBprefix-1\ \ ^[\fP
  724. XIntroduces a 2-character command sequence.
  725. X.br
  726. X.TP
  727. X\fBprefix-2\ \ ^X\fP
  728. XIntroduces a 2-character command sequence.
  729. X.br
  730. X.TP
  731. X\fBquote\ \ ^^\fP
  732. XThe following character is taken literally
  733. Xrather than as an
  734. X.IR "editing command" .
  735. X.br
  736. X.TP
  737. X\fBredraw\ \ ^L\fP
  738. XReprints the prompt string and the current input line.
  739. X.br
  740. X.TP
  741. X\fBsearch-character\ \ ^]\fP
  742. XSearch forward in the current line for the next keyboard character.
  743. X.br
  744. X.TP
  745. X\fBsearch-history\ \ ^R\fP
  746. XEnter incremental search mode.
  747. XThe internal history list is searched backwards for commands matching the input.
  748. XAn initial ``^'' in the search string anchors the search.
  749. XThe escape key will leave search mode.
  750. XOther commands will be executed after leaving search mode (unless
  751. Xof course they are prefixed by escape, in which case they will
  752. Xalmost certainly do the wrong thing).
  753. XSuccessive
  754. X.B search-history
  755. Xcommands continue searching backward
  756. Xto the next previous occurrence of the pattern.
  757. XThe history buffer retains only a finite number of lines;
  758. Xthe oldest are discarded as necessary.
  759. X.br
  760. X.TP
  761. X\fBset-mark-command\ \ ^]\|<space>\fP
  762. XSearch forward in the current line for the next keyboard character.
  763. X.br
  764. X.ie \n(OX \{.TP
  765. X\fBstuff\ \ ^T\fP\}
  766. X.el \{.TP
  767. X\fBstuff\fP\}
  768. XOn systems supporting it,
  769. Xpushes the bound character back onto the terminal input
  770. Xwhere it may receive special processing by the terminal handler.
  771. X.if \n(OX \{This is useful for the BRL
  772. X.B ^T
  773. X``mini-systat'' feature,
  774. Xfor example.\}
  775. X.br
  776. X.TP
  777. X\fBstuff-reset\fP
  778. XActs like
  779. X.BR stuff\^ ,
  780. Xthen aborts input the same as an interrupt.
  781. X.br
  782. X.ie \n(OX \{.TP
  783. X\fBtranspose-chars\fP\}
  784. X.el \{.TP
  785. X\fBtranspose-chars\ \ ^T\fP\}
  786. XExchanges the two characters on either side of the cursor, or
  787. Xthe two previous characters if the cursor is at end of line.
  788. X.br
  789. X.TP
  790. X\fBup-history\ \ ^P\fP
  791. XScrolls the history buffer backward one line (earlier).
  792. X.br
  793. X.TP
  794. X\fByank\ \ ^Y\fP
  795. XInserts the most recently killed text string at the current cursor position.
  796. X.br
  797. X.TP
  798. X\fByank-pop\ \ ^[\|y\fP
  799. XImmediately after a
  800. X.BR yank ,
  801. Xreplaces the inserted text string with the
  802. Xnext previous killed text string.
  803. X.PD
  804. X.br
  805. X.SH FILES
  806. X~/.profile
  807. X.br
  808. X/etc/profile
  809. X.SH SEE ALSO
  810. XSh(1) on System V or Sun OS.
  811. X.LP
  812. X.I "UNIX Shell Programming,"
  813. XStephan G. Kochan,
  814. XPatrick H. Wood,
  815. XHayden.
  816. X.LP
  817. X.I "KornShell: Command and Programming Language (not yet published),"
  818. XMorris Bolsky and David Korn.
  819. X.SH AUTHORS
  820. XBased on the public domain 7th edition Bourne shell.
  821. X.LP
  822. XSystem V and Korn modifications by Eric Gisin,
  823. Xwith contributions by
  824. XRon Natalie, Arnold Robbins, Doug Gwyn, Erik Baalbergen, AT&T (getopt(3)).
  825. X.SH DIFFERENCES FROM AT&T VERSION
  826. XVi editing mode is not implemented.
  827. XThe \fBselect\fP statement is not implemented.
  828. XVariable arrays are not implemented.
  829. XVariable attributes other than integer are not implemented.
  830. XThe \fBERR\fP and \fBEXIT\fP traps are not implemented for functions.
  831. XAlias expansion is inhibited at the beginning of an alias definition
  832. Xin the AT&T version.
  833. XKorn evaluates expressions differently [elaborate].
  834. X.SH BUGS
  835. XInteractive shells will occasionally hang while waiting for a job
  836. Xin the BSD version.
  837. X.LP
  838. XThe 8th bit is stripped in emacs mode.
  839. X.LP
  840. XQuoting double-quote (") characters inside back-quote (`) inside
  841. Xdouble-quotes does not behave properly.  Why are you doing this?
  842. X.LP
  843. XJob control on System V is not really job control.  In fact it is
  844. Xnot much of anything.
  845. X.LP
  846. XThe emacs mode can ``lose'' stty command done by the user.
  847. X.LP
  848. XUnsetting special variables
  849. Xmay cause unexpected results.
  850. X.LP
  851. XFunctions declared as having local scope really have global scope.
  852. X.LP
  853. XHere documents inside functions do not work correctly.
  854. X.LP
  855. XExit on error (\fBset \-e\fP or \fBset -o errexit\fP) does not work
  856. Xcorrectly.
  857. X.TH TEST 1 "January 1988" "Korn shell"
  858. X.ta 30n
  859. X.de X
  860. X.br
  861. X\\$1\t\\$2
  862. X..
  863. X.SH NAME
  864. Xtest \- test condition (Korn and 8th edition)
  865. X.SH SYNOPSIS
  866. X\fBtest\fP \fIexpression\fP
  867. X.br
  868. X\fB[\fP \fIexpression\fP \fB]\fP
  869. X.SH DESCRIPTION
  870. X\fBTest\f evalutates the \fIexpression\fP and returns zero status if true,
  871. Xand non-zero status otherwise.
  872. XIt is normally used as the controlling command of the \fBif\fP and \fBwhile\fP statements.
  873. X.LP
  874. XThe following basic expressions are available.
  875. X.IP
  876. X.X "-r file" "file exists and is readable"
  877. X.X "-w file" "file exists and is writable"
  878. X.X "-x file" "file exists and is executable"
  879. X.X "-f file" "file is a regular file"
  880. X.X "-d file" "file is a directory"
  881. X.X "-c file" "file is a character special device"
  882. X.X "-b file" "file is a block special device"
  883. X.X "-p file" "file is a named pipe"
  884. X.X "-u file" "file mode has setuid bit"
  885. X.X "-g file" "file mode has setgid bit"
  886. X.X "-k file" "file mode has sticky bit"
  887. X.X "-s file" "file is not empty"
  888. X.X "-L file" "file is a symbolic link"
  889. X.X "-S file" "file is a socket"
  890. X.X "file -nt file" "first file is newer than second file"
  891. X.X "file -ot file" "first file is older than second file"
  892. X.X "file -ef file" "first file is the same file as second file"
  893. X.X "-t filedes" "file descriptor is a tty device"
  894. X.IP
  895. X.X "string" "string is not null"
  896. X.X "-z string" "string is null"
  897. X.X "-n string" "string is not null"
  898. X.X "string = string" "strings are equal"
  899. X.X "string != string" "strings are not equal"
  900. X.IP
  901. X.X "number -eq number" "numbers compare equal"
  902. X.X "number -ne number" "numbers compare not equal"
  903. X.X "number -ge number" "numbers compare greater than or equal"
  904. X.X "number -gt number" "numbers compare greater than"
  905. X.X "number -le number" "numbers compare less than or equal"
  906. X.X "number -lt number" "numbers compare less than"
  907. X.LP
  908. XThe above basic expressions may be combined with the following operators.
  909. X.IP
  910. X.X "expr -o expr" "logical or"
  911. X.X "expr -a expr" "logical and"
  912. X.X "! expr" "logical not"
  913. X.X "( expr )" "grouping"
  914. X.SH AUTHOR
  915. XErik Baalbergen. Modified by Arnold Robbins.
  916. X.rn LP P
  917. X.TH GETOPTS 1 "January 1988" "Korn shell"
  918. X.SH NAME
  919. Xgetopts \- parse command options
  920. X.SH SYNOPSIS
  921. X.B getopts
  922. Xoptstring name [arg ...]
  923. X.SH DESCRIPTION
  924. X.I getopts
  925. Xis used by shell procedures
  926. Xto parse positional parameters and to check for legal options.
  927. XIt supports all applicable rules of the command syntax standard
  928. X(see Rules 3-10,
  929. X.IR intro (1)).
  930. XIt should be used in place of the
  931. X.IR getopt (1)
  932. Xcommand.
  933. X(See the
  934. X.BR \s-1WARNING\s0 ,
  935. Xbelow.)
  936. X.PP
  937. X.I optstring
  938. Xmust contain the option letters the command using
  939. X.I getopts
  940. Xwill recognize;
  941. Xif a letter is followed by a colon,
  942. Xthe option is expected to have an argument
  943. Xwhich should be separated from it by white space.
  944. X.PP
  945. XEach time it is invoked,
  946. X.I getopts
  947. Xwill place the next option in the shell variable
  948. X.I name
  949. Xand the index of the next argument to be processed in the shell variable
  950. X.BR \s-1OPTIND\s0 .
  951. XWhenever the shell or a shell procedure is invoked,
  952. X.B \s-1OPTIND\s0
  953. Xis initialized to
  954. X.BR 1 .
  955. X.PP
  956. XWhen an option requires an option-argument,
  957. X.I getopts
  958. Xplaces it in the shell variable
  959. X.BR \s-1OPTARG\s0 .
  960. X.P
  961. XIf an illegal option is encountered,
  962. X.B ?\&
  963. Xwill be placed in
  964. X.IR name .
  965. X.P
  966. XWhen the end of the options is encountered,
  967. X.I getopts
  968. Xexits with a non-zero exit status.
  969. XThe special option
  970. X.RB `` \-\- ''
  971. Xmay be used to delimit the end of the options.
  972. X.P
  973. XBy default,
  974. X.I getopts
  975. Xparses the positional parameters.
  976. XIf extra arguments
  977. X.RI ( arg
  978. X\&...) are given on the
  979. X.I getopts
  980. Xcommand line,
  981. X.I getopts
  982. Xwill parse them instead.
  983. X.PP
  984. XSo all new commands will adhere to the command syntax standard described in
  985. X.IR intro (1),
  986. Xthey should use
  987. X.IR getopts (1)
  988. Xor
  989. X.IR getopt (3C)
  990. Xto parse positional parameters
  991. Xand check for options that are legal for that command
  992. X(see
  993. X.BR \s-1WARNINGS\s0 ,
  994. Xbelow).
  995. X.SH EXAMPLE
  996. XThe following fragment of a shell program
  997. Xshows how one might process the arguments
  998. Xfor a command that can take the options
  999. X.B a
  1000. Xor
  1001. X.BR b ,
  1002. Xas well as the option
  1003. X.BR o ,
  1004. Xwhich requires an option-argument:
  1005. X.PP
  1006. X.RS
  1007. X.nf
  1008. X.ss 18
  1009. X.ta +.5i +1i
  1010. X\fBwhile getopts abo: c
  1011. Xdo
  1012. X    case $c in
  1013. X    a\(bvb)    FLAGS=$FLAGS$c;;
  1014. X    o)    OARG=$OPTARG;;
  1015. X    \e?)    echo $USAGE 1>&2
  1016. X        exit 2;;
  1017. X    esac
  1018. Xdone
  1019. Xshift OPTIND\-1\fP
  1020. X.fi
  1021. X.ta
  1022. X.ss 12
  1023. X.RE
  1024. X.PP
  1025. XThis code will accept any of the following as equivalent:
  1026. X.PP
  1027. X.RS
  1028. X.nf
  1029. X.ss 18
  1030. X\fBcmd \-a \-b \-o "xxx z yy" file
  1031. Xcmd \-a \-b \-o "xxx z yy" \-\- file
  1032. Xcmd \-ab \-o "xxx z yy" file
  1033. Xcmd \-ab \-o "xxx z yy" \-\- file\fP
  1034. X.fi
  1035. X.ss 12
  1036. X.RE
  1037. X.SH SEE ALSO
  1038. Xintro(1),
  1039. Xsh(1).
  1040. X.br
  1041. Xgetopt(3C)
  1042. Xin the
  1043. X.IR "Programmer's Reference Manual" .
  1044. X.br
  1045. X.IR "UNIX System V Release 3.0 Release Notes" .
  1046. X.SH WARNING
  1047. XAlthough the following command syntax rule (see
  1048. X.IR intro (1))
  1049. Xrelaxations are permitted under the current implementation,
  1050. Xthey should not be used because they may not be supported
  1051. Xin future releases of the system.
  1052. XAs in the
  1053. X.B \s-1EXAMPLE\s0
  1054. Xsection above,
  1055. X.B a
  1056. Xand
  1057. X.B b
  1058. Xare options,
  1059. Xand the option
  1060. X.B o
  1061. Xrequires an option-argument:
  1062. X.PP
  1063. X.RS
  1064. X.nf
  1065. X.ta +1i +1.5i
  1066. X\fBcmd \-aboxxx file\fP    (Rule 5 violation: options with
  1067. X    option-arguments must not be grouped with other options)
  1068. X\fBcmd \-ab \-oxxx file\fP    (Rule 6 violation: there must be
  1069. X    white space after an option that takes an option-argument)
  1070. X.fi
  1071. X.ta
  1072. X.RE
  1073. X.PP
  1074. XChanging the value of the shell variable
  1075. X.B \s-1OPTIND\s0
  1076. Xor parsing different sets of arguments
  1077. Xmay lead to unexpected results.
  1078. X.SH DIAGNOSTICS
  1079. X.I getopts
  1080. Xprints an error message on the standard error output
  1081. Xwhen it encounters an option letter not included in
  1082. X.IR optstring .
  1083. END_OF_FILE
  1084.   if test 31646 -ne `wc -c <'ksh.1'`; then
  1085.     echo shar: \"'ksh.1'\" unpacked with wrong size!
  1086.   fi
  1087.   # end of 'ksh.1'
  1088. fi
  1089. if test -f 'sh/jobs.c' -a "${1}" != "-c" ; then 
  1090.   echo shar: Will not clobber existing file \"'sh/jobs.c'\"
  1091. else
  1092.   echo shar: Extracting \"'sh/jobs.c'\" \(16759 characters\)
  1093.   sed "s/^X//" >'sh/jobs.c' <<'END_OF_FILE'
  1094. X/*
  1095. X * Process and job control
  1096. X */
  1097. X#ifndef lint
  1098. Xstatic char *RCSid = "$Id: jobs.c,v 3.5 89/03/27 15:51:01 egisin Exp $";
  1099. Xstatic char  sccs_id[] = "@(#)jobs.c     1.4  91/08/16  17:36:59  (sjg)";
  1100. X#endif
  1101. X
  1102. X/*
  1103. X * based on version by Ron Natalie, BRL
  1104. X * modified by Simon J. Gerraty <sjg@melb.bull.oz.au>
  1105. X *
  1106. X * TODO:
  1107. X *    change Proc table to Job table, with array of pids.
  1108. X *    make %+ be jobs, %- be jobs->next.
  1109. X *    do not JFREE members of pipeline.
  1110. X *    consider procs[] related critical sections.
  1111. X *    signal(SIGCHLD, j_sigchld) should be
  1112. X *    sigaction(SIGCHLD, sigchld, NULL),
  1113. X *    with sigchld.sa_flags = SA_RESTART.
  1114. X *    There is a simple work-around if there is no SA_RESTART.
  1115. X */
  1116. X
  1117. X#include <stddef.h>
  1118. X#include <string.h>
  1119. X#include <stdio.h>
  1120. X#include <errno.h>
  1121. X#include <unistd.h>
  1122. X#include <signal.h>
  1123. X#include <setjmp.h>
  1124. X#include <sys/types.h>
  1125. X#include <sys/times.h>
  1126. X#include <sys/wait.h>
  1127. X#include "sh.h"
  1128. X#include "tree.h"
  1129. X#ifdef JOBS
  1130. X#ifdef _BSD
  1131. X#include <sys/ioctl.h>
  1132. X#else
  1133. X#include "termios.h"
  1134. X#endif
  1135. X#endif
  1136. X
  1137. X#ifndef WIFCORED
  1138. X#define    WIFCORED(x)    (!!((x)&0x80)) /* non-standard */
  1139. X#endif
  1140. X
  1141. X/* as of P1003.1 Draft 12.3:
  1142. X *    pid_t getpgrp(void);        // Get process group id
  1143. X *    pid_t setsid(void);        // Create session and Set process group id
  1144. X *    int setpgid(pid_t pid, pid_t pgid); // Set process group id for job control
  1145. X */
  1146. X
  1147. Xstatic int sigchld_caught;    /* for recording child terminations */
  1148. X
  1149. X#ifdef JOBS
  1150. X#ifdef _BSD            /* _BSD 4.* */
  1151. X#define    setpgid(p, pg)    setpgrp(p, pg)
  1152. X#define    getpgid(p)    getpgrp(p)
  1153. X#define    tcsetpgrp(fd,p)    ioctl(fd, TIOCSPGRP, &(p))
  1154. X#else                /* POSIX-compatible */
  1155. X#define    getpgid(p)    getpgrp() /* 1003.1 stupidity */
  1156. X#define    killpg(p, s)    kill(-(p), s)
  1157. X#endif
  1158. X#endif
  1159. X
  1160. X#ifndef    SIGCHLD
  1161. X#define    SIGCHLD    SIGCLD
  1162. X#endif
  1163. X
  1164. Xtypedef struct Proc Proc;
  1165. Xstruct Proc {
  1166. X    Proc   *next;        /* `procs' list link */
  1167. X    int    job;        /* job number: %n */
  1168. X    short    Volatile state;    /* proc state */
  1169. X    short    Volatile notify; /* proc state has changed */
  1170. X    Proc   *prev;        /* prev member of pipeline */
  1171. X    pid_t    proc;        /* process id */
  1172. X    pid_t    pgrp;        /* process group if flag[FMONITOR] */
  1173. X    short    flags;        /* execute flags */
  1174. X    int    status;        /* wait status */
  1175. X    clock_t    utime, stime;    /* user/system time when JDONE */
  1176. X    char    com [48];    /* command */
  1177. X};
  1178. X
  1179. X/* proc states */
  1180. X#define    JFREE    0        /* unused proc */
  1181. X#define    JRUN    1        /* foreground */
  1182. X#define JEXIT    2        /* exit termination */
  1183. X#define    JSIGNAL    3        /* signal termination */
  1184. X#define    JSTOP    4        /* stopped */
  1185. X
  1186. Xstatic    Proc *procs = NULL;    /* job/process table */
  1187. X
  1188. Xclock_t    j_utime, j_stime;    /* user and system time for last job a-waited */
  1189. X#ifdef JOBS
  1190. Xstatic    int    sm_default, sm_sigchld;    /* signal masks */
  1191. Xstatic    int    our_pgrp;        /* shell's pgrp */
  1192. X#endif
  1193. Xstatic    Proc   *j_lastj;        /* last proc created by exchild */
  1194. Xstatic    int    j_lastjob = 0;        /* last created job */
  1195. Xstatic    int    j_current = 0;        /* current job */
  1196. Xstatic    int    j_previous = 0;        /* previous job */
  1197. X
  1198. Xstatic    int    j_newjob ARGS((void));
  1199. Xstatic    void    j_print ARGS((Proc *j));
  1200. Xstatic    Proc   *j_search ARGS((int job));
  1201. Xstatic    int    j_waitj ARGS((Proc *j, int intr));
  1202. Xstatic    void    j_sigchld ARGS((int sig));
  1203. X    
  1204. X/* initialize job control */
  1205. Xvoid
  1206. Xj_init()
  1207. X{
  1208. X#ifdef JOBS
  1209. X#ifdef NTTYDISC
  1210. X    int ldisc = NTTYDISC;    /* BSD brain damage */
  1211. X
  1212. X    if (ttyfd >= 0)
  1213. X        ioctl(ttyfd, TIOCSETD, &ldisc);
  1214. X#endif
  1215. X    our_pgrp = getpgid(0);
  1216. X    sigchld_caught = 0;
  1217. X    sm_default = 0;
  1218. X    sm_sigchld = sigmask(SIGCHLD);
  1219. X    _TRACE(5, ("j_init: sm_sigchld == 0x%x", sm_sigchld));
  1220. X#endif
  1221. X#if defined(_SYSV) && !defined(JOBS)
  1222. X    signal(SIGCHLD, SIG_DFL);    /* necessary ??? */
  1223. X#endif
  1224. X}
  1225. X
  1226. X/* job cleanup before shell exit */
  1227. Xvoid
  1228. Xj_exit()
  1229. X{
  1230. X    register Proc *j;
  1231. X    int killed = 0;
  1232. X
  1233. X#ifdef JOBS
  1234. X    /* kill stopped jobs */
  1235. X    for (j = procs; j != NULL; j = j->next)
  1236. X        if (j->state == JSTOP) {
  1237. X            killed ++;
  1238. X            killpg(j->pgrp, SIGHUP);
  1239. X            killpg(j->pgrp, SIGCONT);
  1240. X        }
  1241. X    if (killed)
  1242. X        sleep(1);
  1243. X#endif
  1244. X    j_notify();
  1245. X
  1246. X#ifdef JOBS
  1247. X    if (flag[FMONITOR]) {
  1248. X        flag[FMONITOR] = 0;
  1249. X        j_change();
  1250. X    }
  1251. X#endif
  1252. X}
  1253. X
  1254. X#ifdef JOBS
  1255. X/* turn job control on or off according to flag[FMONITOR] */
  1256. Xvoid
  1257. Xj_change()
  1258. X{
  1259. X    static handler_t old_tstp, old_ttin, old_ttou;
  1260. X
  1261. X    if (flag[FMONITOR]) {
  1262. X        if (ttyfd < 0) {
  1263. X            flag[FMONITOR] = 0;
  1264. X            shellf("job control requires tty\n");
  1265. X            return;
  1266. X        }
  1267. X        (void) signal(SIGCHLD, j_sigchld);
  1268. X        sigtraps[SIGCHLD].sig_dfl = 1; /* restore on fork */
  1269. X        old_tstp = signal(SIGTSTP, SIG_IGN);
  1270. X        sigtraps[SIGTSTP].sig_dfl = 1;
  1271. X        old_ttin = signal(SIGTTIN, SIG_IGN);
  1272. X        sigtraps[SIGTTIN].sig_dfl = 1;
  1273. X        old_ttou = signal(SIGTTOU, SIG_IGN);
  1274. X        sigtraps[SIGTTOU].sig_dfl = 1;
  1275. X        sigsetmask(sm_default);
  1276. X        tcsetpgrp(ttyfd, our_pgrp);
  1277. X    } else {
  1278. X        (void) signal(SIGCHLD, SIG_DFL);
  1279. X        (void) signal(SIGTSTP, old_tstp);
  1280. X        sigtraps[SIGTSTP].sig_dfl = 0;
  1281. X        (void) signal(SIGTTIN, old_ttin);
  1282. X        sigtraps[SIGTTIN].sig_dfl = 0;
  1283. X        (void) signal(SIGTTOU, old_ttou);
  1284. X        sigtraps[SIGTTOU].sig_dfl = 0;
  1285. X    }
  1286. X}
  1287. X#endif
  1288. X
  1289. X/* execute tree in child subprocess */
  1290. Xint
  1291. Xexchild(t, flags)
  1292. X    struct op *t;
  1293. X    int flags;
  1294. X{
  1295. X    register int i;
  1296. X    register Proc *j;
  1297. X    int rv = 0;
  1298. X    int forksleep;
  1299. X
  1300. X    flags &= ~XFORK;
  1301. X    if ((flags&XEXEC))
  1302. X        return execute(t, flags);
  1303. X
  1304. X    /* get free Proc entry */
  1305. X    for (j = procs; j != NULL; j = j->next)
  1306. X        if (j->state == JFREE)
  1307. X            goto Found;
  1308. X    j = (Proc*) alloc(sizeof(Proc), APERM);
  1309. X    j->next = procs;
  1310. X    j->state = JFREE;
  1311. X    procs = j;
  1312. X  Found:
  1313. X
  1314. X    j->prev = ((flags&XPIPEI)) ? j_lastj : NULL;
  1315. X    j->proc = j->pgrp = 0;
  1316. X    j->flags = flags;
  1317. X    j->job = (flags&XPIPEI) ? j_lastjob : j_newjob();
  1318. X    snptreef(j->com, sizeof(j->com), "%T", t); /* save proc's command */
  1319. X    j->com[sizeof(j->com)-1] = '\0';
  1320. X    j->state = JRUN;
  1321. X
  1322. X    /* stdio buffer must be flushed and invalidated */
  1323. X    for (i = 0; i < NUFILE; i++)
  1324. X        flushshf(i);
  1325. X
  1326. X    /* create child process */
  1327. X    forksleep = 0;
  1328. X    while ((i = fork()) < 0 && errno == EAGAIN && forksleep < 32) {
  1329. X        if (forksleep) {
  1330. X            sleep(forksleep);
  1331. X            forksleep <<= 1;
  1332. X        } else
  1333. X            forksleep = 1;
  1334. X    }
  1335. X    if (i < 0) {
  1336. X        j->state = JFREE;
  1337. X        errorf("cannot fork - try again\n");
  1338. X    }
  1339. X    j->proc = (i != 0) ? i : getpid();
  1340. X
  1341. X#ifdef JOBS
  1342. X    /* job control set up */
  1343. X    if (flag[FMONITOR] && !(flags&XXCOM)) {
  1344. X        j->pgrp = !(flags&XPIPEI) ? j->proc : j_lastj->pgrp;
  1345. X        /* do in both parent and child to avoid fork race condition */
  1346. X        if (!(flags&XBGND))
  1347. X            tcsetpgrp(ttyfd, j->pgrp); /* could be trouble */
  1348. X        setpgid(j->proc, j->pgrp);
  1349. X    }
  1350. X#endif
  1351. X    j_lastj = j;
  1352. X
  1353. X    if (i == 0) {        /* child */
  1354. X        e.oenv = NULL;
  1355. X        if (flag[FTALKING])
  1356. X            restoresigs();
  1357. X        if ((flags&XBGND) && !flag[FMONITOR]) {
  1358. X            signal(SIGINT, SIG_IGN);
  1359. X            signal(SIGQUIT, SIG_IGN);
  1360. X            if (flag[FTALKING])
  1361. X                signal(SIGTERM, SIG_DFL);
  1362. X            if (!(flags&XPIPEI)) {
  1363. X                i = open("/dev/null", 0);
  1364. X                (void) dup2(i, 0);
  1365. X                close(i);
  1366. X            }
  1367. X        }
  1368. X        for (j = procs; j != NULL; j = j->next)
  1369. X            j->state = JFREE;
  1370. X        ttyfd = -1;
  1371. X        flag[FMONITOR] = flag[FTALKING] = 0;
  1372. X        cleartraps();
  1373. X        execute(t, flags|XEXEC); /* no return */
  1374. X        /* NOTREACHED */
  1375. X    }
  1376. X
  1377. X    /* shell (parent) stuff */
  1378. X    if ((flags&XBGND)) { /* async statement */
  1379. X        async = j->proc;
  1380. X        j_previous = j_current;
  1381. X        j_current = j->job;
  1382. X        if (flag[FTALKING])
  1383. X            j_print(j);
  1384. X    } else {        /* sync statement */
  1385. X        if (!(flags&XPIPE))
  1386. X            rv = j_waitj(j, 0);
  1387. X    }
  1388. X
  1389. X    return rv;
  1390. X}
  1391. X
  1392. X/* wait for last job: pipeline or $() sub-process */
  1393. Xint
  1394. Xwaitlast()
  1395. X{
  1396. X    return j_waitj(j_lastj, 0);
  1397. X}
  1398. X
  1399. X/* wait for job to complete or change state */
  1400. Xstatic int
  1401. Xj_waitj(aj, intr)
  1402. X    Proc *aj;
  1403. X    int intr;        /* interruptable */
  1404. X{
  1405. X    register Proc *j;
  1406. X    int rv = 1;
  1407. X    int ttysig = 0;
  1408. X
  1409. X#ifdef JOBS
  1410. X    if (flag[FMONITOR])
  1411. X    {
  1412. X      _TRACE(5, ("j_waitj: sigsetmask(sm_sigchld==0x%x)", sm_sigchld));
  1413. X      sigsetmask(sm_sigchld);
  1414. X    }
  1415. X#endif
  1416. X    /* wait for all members of pipeline */
  1417. X    for (j = aj; j != NULL; j = j->prev) {
  1418. X        /* wait for job to finish, stop, or ^C of built-in wait */
  1419. X        while (j->state == JRUN) {
  1420. X#ifdef JOBS
  1421. X            if (flag[FMONITOR])
  1422. X            {
  1423. X              /*
  1424. X               * 91-07-07 <sjg@sun0>
  1425. X               * we don't want to wait for a signal
  1426. X               * that has already arrived :-)
  1427. X               */
  1428. X              if (!sigchld_caught)
  1429. X              {
  1430. X                _TRACE(4, ("j_waitj: sigpause(%d), sigchld_caught==%d", sm_default, sigchld_caught));
  1431. X                sigpause(sm_default);
  1432. X                _TRACE(4, ("j_waitj: sigpause() returned %d, sigchld_caught==%d", errno, sigchld_caught));
  1433. X              }
  1434. X            }
  1435. X            else
  1436. X#endif
  1437. X                j_sigchld(0);
  1438. X            /*
  1439. X             * Children to reap
  1440. X             */
  1441. X            if (sigchld_caught)
  1442. X              j_reapchld();
  1443. X            _TRACE(4, ("j_waitj: j->proc==%d, j->com=='%s', j->state==0x%hx, j->status==0x%x, j->notify==%hd", j->proc, j->com, j->state, j->status, j->notify));
  1444. X            
  1445. X            if (sigtraps[SIGINT].set && intr)
  1446. X                goto Break;
  1447. X        }
  1448. X        if (j->state == JEXIT) { /* exit termination */
  1449. X            if (!(j->flags&XPIPEO))
  1450. X                rv = WEXITSTATUS(j->status);
  1451. X            j->notify = 0;
  1452. X        } else
  1453. X        if (j->state == JSIGNAL) { /* signalled to death */
  1454. X            if (!(j->flags&XPIPEO))
  1455. X                rv = 0x80 + WTERMSIG(j->status);
  1456. X            if (WTERMSIG(j->status) == SIGINT ||
  1457. X                WTERMSIG(j->status) == SIGPIPE && (j->flags&XPIPEO))
  1458. X                j->notify = 0;
  1459. X            if (WTERMSIG(j->status) == SIGINT ||
  1460. X                WTERMSIG(j->status) == SIGQUIT)
  1461. X                ttysig = 1;
  1462. X        } else
  1463. X#ifdef JOBS
  1464. X        if (j->state == JSTOP)
  1465. X            if (WSTOPSIG(j->status) == SIGTSTP)
  1466. X                ttysig = 1;
  1467. X#else
  1468. X        ;
  1469. X#endif
  1470. X    }
  1471. X
  1472. X    /* compute total child time for time statement */
  1473. X    for (j = aj; j != NULL; j = j->prev)
  1474. X        j_utime += j->utime, j_stime += j->stime;
  1475. X
  1476. X    /* find new current job */
  1477. X#ifdef JOBS
  1478. X    if (aj->state == JSTOP) {
  1479. X        j_previous = j_current;
  1480. X        j_current = aj->job;
  1481. X    } else {
  1482. X#else
  1483. X    if (1) {
  1484. X#endif
  1485. X        int hijob = 0;
  1486. X
  1487. X        /* todo: this needs to be done in j_notify */
  1488. X        /* todo: figure out what to do with j_previous */
  1489. X        j_current = 0;
  1490. X        for (j = procs; j != NULL; j = j->next)
  1491. X            if ((j->state == JRUN || j->state == JSTOP)
  1492. X                && j->job > hijob) {
  1493. X                hijob = j->job;
  1494. X                j_current = j->job;
  1495. X            }
  1496. X    }
  1497. X
  1498. X  Break:
  1499. X#ifdef JOBS
  1500. X    if (flag[FMONITOR]) {
  1501. X        /* reset shell job control state */
  1502. X        sigsetmask(sm_default);
  1503. X        tcsetpgrp(ttyfd, our_pgrp);
  1504. X    }
  1505. X#endif
  1506. X    if (ttysig)
  1507. X        fputc('\n', shlout);
  1508. X    j_notify();
  1509. X
  1510. X    return rv;
  1511. X}
  1512. X
  1513. X/* SIGCHLD handler to reap children */
  1514. X/*
  1515. X * 91-07-07 <sjg@sun0>
  1516. X * On the Sun SS2 this appears to get called
  1517. X * too quickly!
  1518. X * So just record the event and process later.
  1519. X */
  1520. Xstatic void
  1521. Xj_sigchld(sig)
  1522. X    int sig;
  1523. X{
  1524. X    sigchld_caught++;    /* acknowledge it */
  1525. X#if defined(_SYSV) && !defined(JOBS)
  1526. X    /* non-zero sig means called as handler */
  1527. X    /* 5.2 handlers must reinstate themselves */
  1528. X    if (sig) signal(SIGCHLD, j_sigchld);
  1529. X#endif
  1530. X}
  1531. X
  1532. X/*
  1533. X * 91-07-07 <sjg@sun0>
  1534. X * This now gets called when j_sigchld()
  1535. X * has recorded some signals...
  1536. X */
  1537. Xj_reapchld()
  1538. X{
  1539. X    struct tms t0, t1;
  1540. X#ifdef JOBS
  1541. X    int sm_old;
  1542. X
  1543. X    sm_old = sigblock(0);    /* just get current mask */
  1544. X#endif
  1545. X    _TRACE(5, ("j_reapchld: sm_old==0x%x, sigchld_caught==%d", sm_old, sigchld_caught));
  1546. X    (void) times(&t0);
  1547. X
  1548. X    do {
  1549. X        register Proc *j;
  1550. X        int pid, status;
  1551. X#ifdef JOBS
  1552. X        if (flag[FMONITOR])
  1553. X            pid = waitpid(-1, &status, (WNOHANG|WUNTRACED));
  1554. X        else
  1555. X#endif
  1556. X            pid = wait(&status);
  1557. X        if (pid <= 0)    /* return if would block (0) ... */
  1558. X            break;    /* ... or no children or interrupted (-1) */
  1559. X        (void) times(&t1);
  1560. X
  1561. X        _TRACE(5, ("j_reapchld: looking for pid==%d", pid));
  1562. X
  1563. X        for (j = procs; j != NULL; j = j->next)
  1564. X        {
  1565. X          _TRACE(6, ("j_reapchld: j->proc==%d, j->com=='%s', j->state==0x%hx, j->status==0x%x, j->notify==%hd", j->proc, j->com, j->state, j->status, j->notify));
  1566. X          if (j->state != JFREE && j->proc == pid)
  1567. X            goto Found;
  1568. X        }
  1569. X        _TRACE(5, ("j_reapchld: did not find pid==%d", pid));
  1570. X        continue;
  1571. X      Found:
  1572. X        _TRACE(5, ("j_reapchld: found pid==%d", pid));
  1573. X        j->notify = 1;
  1574. X        j->status = status;
  1575. X#ifdef JOBS
  1576. X        if (WIFSTOPPED(status))
  1577. X            j->state = JSTOP;
  1578. X        else
  1579. X#endif
  1580. X        if (WIFEXITED(status))
  1581. X            j->state = JEXIT;
  1582. X        else
  1583. X        if (WIFSIGNALED(status))
  1584. X            j->state = JSIGNAL;
  1585. X
  1586. X        /* compute child's time */
  1587. X        /* todo: what does a stopped job do? */
  1588. X        j->utime = t1.tms_cutime - t0.tms_cutime;
  1589. X        j->stime = t1.tms_cstime - t0.tms_cstime;
  1590. X        t0 = t1;
  1591. X#ifdef JOBS
  1592. X        sigblock(sm_sigchld);
  1593. X#endif
  1594. X        if (--sigchld_caught < 0) /* reduce the count */
  1595. X          sigchld_caught = 0;
  1596. X#ifdef JOBS
  1597. X        _TRACE(5, ("j_reapchld: j->proc==%d, j->com=='%s', j->state==0x%hx, j->status==0x%x, j->notify==%hd", j->proc, j->com, j->state, j->status, j->notify));
  1598. X        sigsetmask(sm_old); /* restore old mask */
  1599. X#endif
  1600. X#ifdef JOBS
  1601. X    } while (flag[FMONITOR]);
  1602. X#else
  1603. X    } while (0);        /* only once if wait()ing */
  1604. X#endif
  1605. X}
  1606. X
  1607. Xj_reap()
  1608. X{
  1609. X  if (sigchld_caught)
  1610. X    j_reapchld();
  1611. X#if defined(_SYSV) && !defined(JOBS)
  1612. X    signal(SIGCHLD, j_sigchld);
  1613. X    signal(SIGCLD, SIG_DFL);
  1614. X#endif
  1615. X    return(0);
  1616. X}
  1617. X
  1618. X/* wait for child, interruptable */
  1619. Xint
  1620. Xwaitfor(job)
  1621. X    int job;
  1622. X{
  1623. X    register Proc *j;
  1624. X
  1625. X    if (job == 0 && j_current == 0)
  1626. X        errorf("no current job\n");
  1627. X    j = j_search((job == 0) ? j_current : job);
  1628. X    if (j == NULL)
  1629. X        errorf("no such job: %d\n", job);
  1630. X    if (flag[FTALKING])
  1631. X        j_print(j);
  1632. X    if (e.interactive) {    /* flush stdout, shlout */
  1633. X        fflush(shf[1]);
  1634. X        fflush(shf[2]);
  1635. X    }
  1636. X    return j_waitj(j, 1);
  1637. X}
  1638. X
  1639. X/* kill (built-in) a job */
  1640. Xvoid
  1641. Xj_kill(job, sig)
  1642. X    int job;
  1643. X    int sig;
  1644. X{
  1645. X    register Proc *j;
  1646. X
  1647. X    j = j_search(job);
  1648. X    if (j == NULL)
  1649. X        errorf("cannot find job\n");
  1650. X    if (j->pgrp == 0) {    /* !flag[FMONITOR] */
  1651. X        if (kill(j->proc, sig) < 0) /* todo: all member of pipeline */
  1652. X            errorf("kill: %s\n", strerror(errno));
  1653. X#ifdef JOBS
  1654. X    } else {
  1655. X        if (sig == SIGTERM || sig == SIGHUP)
  1656. X            (void) killpg(j->pgrp, SIGCONT);
  1657. X        if (killpg(j->pgrp, sig) < 0)
  1658. X            errorf("killpg: %s\n", strerror(errno));
  1659. X#endif
  1660. X    }
  1661. X}
  1662. X
  1663. X#ifdef JOBS
  1664. X
  1665. X/* fg and bg built-ins */
  1666. Xint
  1667. Xj_resume(job, bg)
  1668. X    int job;
  1669. X    int bg;
  1670. X{
  1671. X    register Proc *j; 
  1672. X    
  1673. X    j = j_search((job == 0) ? j_current : job);
  1674. X    if (j == NULL)
  1675. X        errorf("cannot find job\n", job);
  1676. X    if (j->pgrp == 0)
  1677. X        errorf("job not job-controlled\n");
  1678. X
  1679. X    j->state = JRUN;
  1680. X    j_print(j);
  1681. X    flushshf(2);
  1682. X
  1683. X    if (!bg)
  1684. X          tcsetpgrp(ttyfd, j->pgrp); /* attach shell to job */
  1685. X    if (killpg(j->pgrp, SIGCONT) < 0)
  1686. X        errorf("cannot continue job %%%d\n", job);
  1687. X    if (!bg)
  1688. X        return j_waitj(j, 0);
  1689. X    return 0;
  1690. X}
  1691. X
  1692. X#endif
  1693. X
  1694. X/* list jobs for jobs built-in */
  1695. Xvoid
  1696. Xj_jobs()
  1697. X{
  1698. X    register Proc *j; 
  1699. X
  1700. X    for (j = procs; j != NULL; j = j->next)
  1701. X        if (j->state != JFREE)
  1702. X            j_print(j);
  1703. X}
  1704. X
  1705. X/* list jobs for top-level notification */
  1706. Xvoid
  1707. Xj_notify()
  1708. X{
  1709. X    register Proc *j; 
  1710. X
  1711. X    /*
  1712. X     * since reaping is no longer done in the signal handler
  1713. X     * we had better try here...
  1714. X     */
  1715. X    if (sigchld_caught)
  1716. X      j_reapchld();
  1717. X    
  1718. X    for (j = procs; j != NULL; j = j->next) {
  1719. X        if (j->state == JEXIT && !flag[FTALKING])
  1720. X            j->notify = 0;
  1721. X        if (j->state != JFREE && j->notify)
  1722. X            j_print(j);
  1723. X        if (j->state == JEXIT || j->state == JSIGNAL)
  1724. X            j->state = JFREE;
  1725. X        j->notify = 0;
  1726. X    }
  1727. X}
  1728. X
  1729. Xstatic void
  1730. Xj_print(j)
  1731. X    register Proc *j;
  1732. X{
  1733. X    char buf [64], *s = buf;
  1734. X
  1735. X    switch (j->state) {
  1736. X      case JRUN:
  1737. X        s = "Running";
  1738. X        break;
  1739. X
  1740. X#ifdef JOBS
  1741. X      case JSTOP:
  1742. X        strcpy(buf, "Stopped ");
  1743. X        s = strchr(sigtraps[WSTOPSIG(j->status)].mess, '(');
  1744. X        if (s != NULL)
  1745. X            strcat(buf, s);
  1746. X        s = buf;
  1747. X        break;
  1748. X#endif
  1749. X
  1750. X      case JEXIT: {
  1751. X        int rv;
  1752. X        rv = WEXITSTATUS(j->status);
  1753. X        sprintf(buf, "Done (%d)", rv);
  1754. X        if (rv == 0)
  1755. X            *strchr(buf, '(') = 0;
  1756. X        j->state = JFREE;
  1757. X        } break;
  1758. X
  1759. X      case JSIGNAL: {
  1760. X        int sig = WTERMSIG(j->status);
  1761. X        char *n = sigtraps[sig].mess;
  1762. X        if (n != NULL)
  1763. X            sprintf(buf, "%s", n);
  1764. X        else
  1765. X            sprintf(buf, "Signal %d", sig);
  1766. X        if (WIFCORED(j->status))
  1767. X            strcat(buf, " - core dumped");
  1768. X        j->state = JFREE;
  1769. X        } break;
  1770. X
  1771. X      default:
  1772. X        s = "Hideous job state";
  1773. X        j->state = JFREE;
  1774. X        break;
  1775. X    }
  1776. X    shellf("%%%-2d%c %5d %-20s %s%s\n", j->job,
  1777. X           (j_current==j->job) ? '+' : (j_previous==j->job) ? '-' : ' ',
  1778. X           j->proc, s, j->com, (j->flags&XPIPEO) ? "|" : "");
  1779. X}
  1780. X
  1781. X/* convert % sequence to job number */
  1782. Xint
  1783. Xj_lookup(cp)
  1784. X    char *cp;
  1785. X{
  1786. X    register Proc *j;
  1787. X    int len, job = 0;
  1788. X
  1789. X    if (*cp == '%')        /* leading % is optional */
  1790. X        cp++;
  1791. X    switch (*cp) {
  1792. X      case '\0':
  1793. X      case '+':
  1794. X        job = j_current;
  1795. X        break;
  1796. X
  1797. X      case '-':
  1798. X        job = j_previous;
  1799. X        break;
  1800. X
  1801. X      case '0': case '1': case '2': case '3': case '4':
  1802. X      case '5': case '6': case '7': case '8': case '9': 
  1803. X        job = atoi(cp);
  1804. X        break;
  1805. X
  1806. X      case '?':        /* %?string */
  1807. X        for (j = procs; j != NULL; j = j->next)
  1808. X            if (j->state != JFREE && strstr(j->com, cp+1) != NULL)
  1809. X                job = j->job;
  1810. X        break;
  1811. X
  1812. X      default:        /* %string */
  1813. X        len = strlen(cp);
  1814. X        for (j = procs; j != NULL; j = j->next)
  1815. X            if (j->state != JFREE && strncmp(cp, j->com, len) == 0)
  1816. X                job = j->job;
  1817. X        break;
  1818. X    }
  1819. X    if (job == 0)
  1820. X        errorf("%s: no such job\n", cp);
  1821. X    return job;
  1822. X}
  1823. X
  1824. X/* are any stopped jobs ? */
  1825. X#ifdef JOBS
  1826. Xint
  1827. Xj_stopped()
  1828. X{
  1829. X    register Proc *j; 
  1830. X
  1831. X    for (j = procs; j != NULL; j = j->next)
  1832. X        if (j->state == JSTOP)
  1833. X            return 1;
  1834. X    return 0;
  1835. X}
  1836. X#endif
  1837. X
  1838. X/* create new job number */
  1839. Xstatic int
  1840. Xj_newjob()
  1841. X{
  1842. X    register Proc *j; 
  1843. X    register int max = 0;
  1844. X    
  1845. X    j_lastjob ++;
  1846. X    for (j = procs; j != NULL; j = j->next)
  1847. X        if (j->state != JFREE && j->job)
  1848. X            if (j->job > max)
  1849. X                max = j->job;
  1850. X    if (j_lastjob > max)
  1851. X        j_lastjob = max + 1;
  1852. X    return j_lastjob;
  1853. X}
  1854. X
  1855. X/* search for job by job number */
  1856. Xstatic Proc *
  1857. Xj_search(job)
  1858. X    int job;
  1859. X{
  1860. X    register Proc *j;
  1861. X
  1862. X    for (j = procs; j != NULL; j = j->next)
  1863. X        if (j->state != JFREE && job == j->job && !(j->flags&XPIPEO))
  1864. X            return j;
  1865. X    return NULL;
  1866. X}
  1867. X
  1868. END_OF_FILE
  1869.   if test 16759 -ne `wc -c <'sh/jobs.c'`; then
  1870.     echo shar: \"'sh/jobs.c'\" unpacked with wrong size!
  1871.   fi
  1872.   # end of 'sh/jobs.c'
  1873. fi
  1874. if test -f 'sh/trace.c' -a "${1}" != "-c" ; then 
  1875.   echo shar: Will not clobber existing file \"'sh/trace.c'\"
  1876. else
  1877.   echo shar: Extracting \"'sh/trace.c'\" \(3039 characters\)
  1878.   sed "s/^X//" >'sh/trace.c' <<'END_OF_FILE'
  1879. X/* NAME:
  1880. X *      trace.c - a simple trace facility
  1881. X *
  1882. X * SYNOPSIS:
  1883. X *      TRACE(level, (fmt [, ...]));
  1884. X *
  1885. X * DESCRIPTION:
  1886. X *      This module provides a simple trace facility via
  1887. X *      a call to checkpoint() which opens a log file and writes 
  1888. X *      an entry and closes the log (so that process crashes 
  1889. X *      won't destroy the log :-).  checkpoint() takes options 
  1890. X *      like printf().  If Trace_log is not initialized then
  1891. X *      stderr is used.
  1892. X *      
  1893. X *      The header file trace.h defines a macro TRACE() which 
  1894. X *      is useful in that it allows checkpoint to be called 
  1895. X *      based on the value of Trace_level, and the calls can be 
  1896. X *      eliminated by undefining USE_TRACE.
  1897. X *
  1898. X * RETURN VALUE:
  1899. X *      None.
  1900. X *
  1901. X * FILES:
  1902. X *      None.
  1903. X *
  1904. X * SEE ALSO:
  1905. X *      
  1906. X *
  1907. X * BUGS:
  1908. X *      
  1909. X *
  1910. X * AMENDED:
  1911. X *      %E%  %U%  (%Y%)
  1912. X *
  1913. X * RELEASED:
  1914. X *      %D%  %T%  v%I%
  1915. X *
  1916. X *      @(#)Copyright (c) 1990 Simon J. Gerraty.
  1917. X */
  1918. X#ifdef USE_TRACE
  1919. X
  1920. X#ifndef lint
  1921. Xstatic char  sccs_id[] = "%Z%%M%     %I%  %E%  %U%  (%Y%)";
  1922. X#endif
  1923. X
  1924. X/* include files */
  1925. X#include <stdio.h>
  1926. X#ifdef __STDC__
  1927. X# include <stdlib.h>
  1928. X#endif
  1929. X
  1930. X#define EXTERN
  1931. X#include "trace.h"
  1932. X#undef EXTERN
  1933. X
  1934. X/* some useful #defines */
  1935. X#ifndef ENTRY
  1936. X# define ENTRY
  1937. X# define LOCAL static
  1938. X# define BOOLEAN int
  1939. X#endif
  1940. X#ifndef TRUE
  1941. X# define TRUE  1
  1942. X# define FALSE 0
  1943. X#endif
  1944. X#ifndef _P_
  1945. X# if defined(__STDC__) || defined(PROTO)
  1946. X#   define _P_(p) p
  1947. X# else
  1948. X#   define _P_(p) ()
  1949. X# endif
  1950. X#endif
  1951. X
  1952. X
  1953. X/* NAME:
  1954. X *      checkpoint - write a logfile entry
  1955. X *
  1956. X * SYNOPSIS:
  1957. X *      checkpoint(fmt, ...)
  1958. X *
  1959. X * DESCRIPTION:
  1960. X *      This function takes a variable number or args  
  1961. X *      like the printf(3S) family of functions.
  1962. X *
  1963. X * RETURN VALUE:
  1964. X *      None
  1965. X */
  1966. Xextern char * _CDECL strdup    _P_((char *s));
  1967. X  
  1968. X#ifdef __STDC__
  1969. X# include <stdarg.h>
  1970. X
  1971. XENTRY void _CDECL
  1972. Xcheckpoint(fmt)
  1973. X    char *fmt;
  1974. X{
  1975. X  int c;
  1976. X  va_list arg_ptr;
  1977. X  FILE *fp;
  1978. X  register char *rcp;
  1979. X  char  *mode;
  1980. X  static  setup;
  1981. X  
  1982. X  va_start(arg_ptr, fmt);
  1983. X#else  /* __STDC__ */
  1984. X# include <varargs.h>
  1985. X  
  1986. XENTRY void _CDECL
  1987. Xcheckpoint(va_alist)
  1988. X  va_dcl
  1989. X{
  1990. X  extern char *getenv    _P_((char *var));
  1991. X  char *fmt;
  1992. X  int c;
  1993. X  va_list arg_ptr;
  1994. X  FILE *fp;
  1995. X  register char *rcp;
  1996. X  char  *mode;
  1997. X  static  setup;
  1998. X  
  1999. X  va_start(arg_ptr);
  2000. X  fmt = va_arg(arg_ptr, char *);
  2001. X#endif /* __STDC__ */
  2002. X  
  2003. X  /* 42 is a "magic" number */
  2004. X  if (setup == 42)
  2005. X    mode = "a";
  2006. X  else
  2007. X  {
  2008. X    if (Trace_level == 0 && (rcp = getenv("TRACE_LEVEL")))
  2009. X      Trace_level = atoi(rcp);
  2010. X    if (Trace_log == NULL || *Trace_log == '\0')
  2011. X    {
  2012. X      if (rcp = getenv("TRACE_LOG"))
  2013. X    Trace_log = strdup(rcp);
  2014. X      else
  2015. X    Trace_log = NULL;
  2016. X    }
  2017. X    setup = 42;
  2018. X    mode= "w";
  2019. X  }
  2020. X  if (Trace_log)
  2021. X    fp = fopen(Trace_log, mode);
  2022. X  else
  2023. X    fp = stderr;
  2024. X  if (fp != (FILE *)NULL)
  2025. X  {
  2026. X    vfprintf(fp, fmt, arg_ptr);
  2027. X    fputc('\n', fp);
  2028. X    if (fp == stderr)
  2029. X      fflush(fp);
  2030. X    else
  2031. X      fclose(fp);
  2032. X  }
  2033. X}
  2034. X
  2035. X#endif /* USE_TRACE */
  2036. X
  2037. X/* This lot (for GNU-Emacs) goes at the end of the file. */
  2038. X/* 
  2039. X * Local Variables:
  2040. X * version-control:t
  2041. X * comment-column:40
  2042. X * End:
  2043. X */
  2044. END_OF_FILE
  2045.   if test 3039 -ne `wc -c <'sh/trace.c'`; then
  2046.     echo shar: \"'sh/trace.c'\" unpacked with wrong size!
  2047.   fi
  2048.   # end of 'sh/trace.c'
  2049. fi
  2050. echo shar: End of archive 2 \(of 9\).
  2051. cp /dev/null ark2isdone
  2052. MISSING=""
  2053. for I in 1 2 3 4 5 6 7 8 9 ; do
  2054.     if test ! -f ark${I}isdone ; then
  2055.     MISSING="${MISSING} ${I}"
  2056.     fi
  2057. done
  2058. if test "${MISSING}" = "" ; then
  2059.     echo You have unpacked all 9 archives.
  2060.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2061. else
  2062.     echo You still must unpack the following archives:
  2063.     echo "        " ${MISSING}
  2064. fi
  2065. exit 0
  2066. exit 0 # Just in case...
  2067. -- 
  2068. Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
  2069. Sterling Software, IMD           UUCP:     uunet!sparky!kent
  2070. Phone:    (402) 291-8300         FAX:      (402) 291-4362
  2071. Please send comp.sources.misc-related mail to kent@uunet.uu.net.
  2072.