[net.unix-wizards] Command substitution and daemons - Request for help

mbr@aoa.UUCP (Mark Rosenthal) (08/23/85)

Although our site has been receiving articles for the past few months,
articles posted to the net have not been getting distributed until recently.
The following is a reposting of an article I sent out quite some time ago.
I believe it never made it to the net at large.  Apologies if you have seen
this before.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


I am having trouble using comand substitution from either /bin/sh or csh.
I can find no mention in the man pages for either shell of the interaction
of `` and programs that place themselves in the background.

I am trying to create a set of C programs which can be called from a shell
script.  There is a daemon ('dmn') which controls a device, and a user
interface ('ifc') which sends commands to 'dmn' via a queue.  I want 'dmn'
to be able to put the queue identifier into the environment where
'ifc' can find it.  In other words, the script should look like:

	setenv ID `dmn`
	    or
	ID=`dmn`; export ID
	 .
	 .
	 .
	ifc

'ifc' is simply coded to look in the environment variable ID.

The following code is the relevant section of 'dmn'.  Note that it writes
the queue identifier to stdout, before it backgrounds itself.

- - - - - - - - - - - - - - - - - -beg dmn- - - - - - - - - - - - - - - - - - -
#include <stdio.h>

main()
{
    printf("01\n");
    fflush(stdout);

    background();

    fprintf(stderr, "Background pid = %d\n", getpid());
    fflush(stderr);

    for (;;)		/* Simulate computation in the background */
	{ }
}

background()
{
    int pid;

    pid = fork();
    if (pid < 0)	/* fork failed */
    {
	fprintf(stderr, "background(): Fork failed\n", 0);
	fflush(stderr);
	exit(-1);
    }
    if (pid > 0)	/* parent exits */
    {
	fprintf(stderr, "Foreground exiting, pid = %d\n", getpid());
	fflush(stderr);
	exit(0);
    }
    /* child gets inherited by init */
}
- - - - - - - - - - - - - - - - - -end dmn- - - - - - - - - - - - - - - - - - -

Now for the problem.  When I run 'dmn' from either shell as:

	% dmn

it operates as expected.  It outputs "01" and leaves a process running
whose parent is init (process 1).  The foreground process is gone.
However when I try:

	% setenv ID `dmn`
	    or
	$ ID=`dmn`
	    or
	% echo `dmn`
	    etc.

it hangs.  Running 'ps' shows the background process with init as its parent
(as before), but now the foreground process shows as <exiting>.  Anybody
know what the shells are waiting for?  Is the problem that they think they're
dealing with a pipeline?  I don't have source available to check for myself.

Additional (possibly relevant) info: this is on a Masscomp MC500, which
runs Sys V w/some 4.2 enhancements.  Please send mail.  When responses
dwindle, I'll post whatever answer(s) appear to be correct.

-- 

	Mark of the Valley of Roses
	...!{decvax,linus,ima,ihnp4}!bbncca!aoa!mbr

mbr@aoa.UUCP (Mark Rosenthal) (09/03/85)

In article <257@aoa.UUCP> I asked for help with a background process
which outputs to stdout and then computes forever.  I was trying to
use backquote evaluation to assign the output of the process to a
shell variable, but the shell appeared to hang during the evaluation.

It turns out to be the result of my failing to close stdout.  I enclose
herewith one of the responses I received.  Many thanks to all who responded.  
BTW, as John suggests, I too was bitten by this in my days as a fledgling
Unix programmer.  Guess I should have seen it myself.  But then, what
is the net for?  Also, thanks to everybody for responding by mail rather
than adding to the already immense load on usenet.

John Macklin writes:
>
> I have to admit that it took me a few minutes to work out the answer
> to your problem.  I'm ashamed, I should have known at once, but this
> is truly ``old wine in a new bottle'' -- I think almost every serious
> UNIX systems programmer must have been bitten by this exactly once in
> his/her career, BUT in a very different guise.  Usually you see it the
> first time you try to make significant use of pipes.  You're doing that
> here but it's well hidden and takes a while to spot.
> 
> The Answer (no, not 42):
> 
> A process which reads a pipe will not see EOF on the pipe as long
> as ANY OTHER PROCESS has the write end of the pipe open.
> 
> So, in your case, the shell will keep reading the pipe it created
> to be dmn's standard output, due to the fact that dmn's child still
> has the write end of the pipe open.  The shell cannot know that there
> isn't more output coming.  The fix is simple, just do a close(1) in
> the child after you fork.
> 
> John Mackin, Basser Department of Computer Science,
> 	     University of Sydney, Sydney, Australia
-- 

	Mark of the Valley of Roses
	...!{decvax,linus,ima,ihnp4}!bbncca!aoa!mbr