[comp.unix.questions] rsh hangs until command is over

phil@ux1.cso.uiuc.edu (09/13/90)

> I've got a shell command followed by "&" in a script.  When called on the
> UNIX machine itself, the script returns promptly.  However, when it is
> rshelled from the PC, it disregards the "&" and waits till the command is
> over.
> 
> I tried redirecting the stdin and stdout of the command to null.
> That didn't work.

You need to do more than that.  You need to spawn the command off AND make
the parent believe the child exited.

> Then I tried putting the command automatically to background with a
> fork() and exit() in the parent.  That didn't work either.  The PC rsh
> seems to wait till the child exits.

You need to do a combination of these things.  In this example I will
execute the "sleep 300" command.  I don't know the syntax of your PC
rsh so I will give the UNIX equivalent.

rsh remotehost 'csh -fc "sleep 300 &" < /dev/null >& /dev/null'

Note that you must do ALL of these things:
1.  be sure stdin gets closed
2.  be sure stdout gets closed
3.  be sure stderr gets closed
4.  be sure the child (csh above) exits so the parent (login shell)
    exits and the network file descriptor gets closed in cases 1-3.
5.  be sure it spawns the command (sleep) into the background first

Doing the above is complicated enough.  Doing it from another UNIX system
and getting the rsh to go into the background quickly is tougher still.
After a couple months of hack-hack-hack I finally got the following shell
script, which ASSUMES YOU USE csh FOR YOUR LOGIN SHELL (more hacking to do
if not), to effectively "launch" a process on another machine.  I call it
"rlaunch".  Note the hairy quoting and DNFW it.

#!/bin/csh -f
set h = $1
shift
exec csh -fc "rsh $h exec csh -fc "'"'"'$* &' < /dev/null >& /dev/null"'" &' < /dev/null > /dev/null
#
# this version of rlaunch is for remote login shell = csh
# hack the inner null redirects to match syntax of other shells
#
# first csh: (executed in same process as shell script)
# stdin = /dev/null [needed by rsh]
# stdout= /dev/null [this flushes the background job number]
# stderr= /dev/tty
# arg[1]: -fc
# arg[2]: rsh host exec csh -c "'cmd and args &' < /dev/null >& /dev/null" &
# this csh forks rsh as a child then exits to parent (interactive shell)
# the interactive shell sees child exit, so resumes normal sequence
#
# rsh: (forked)
# stdin = /dev/null [this prevent stopping for tty input]
# stdout= /dev/null
# stderr= /dev/tty
# arg[1]: host
# arg[2]: exec
# arg[3]: csh
# arg[4]: -fc
# arg[5]: 'cmd and args &' < /dev/null >& /dev/null
# rsh will fork a child to read from stdin (null) and write to connection
# this child rsh will become defunct until parent rsh waits or exits
#
# remote login csh: (forked by rshd)
# stdin = |net
# stdout= |net
# stderr= |net2
# arg[1]: -c
# arg[2]: exec csh -fc 'cmd and args &' < /dev/null >& /dev/null
#
# remote second csh: (executed in same process as login csh)
# stdin = /dev/null [prevents child from having network connection open]
# stdout= /dev/null [as above]
# stderr= /dev/null [as above]
# arg[1]: -fc
# arg[2]: cmd and args &
#
# null redirects cannot be given to last csh so they can be in cmd string
# last csh forks cmd as a child then exits to parent (rshd)
# rshd sees child exit, so it closes connection and exits
# rsh on local host gets eof on connection, waits for the
# defunct rsh that was reading input, and exits