[comp.unix.questions] csh Rerouting stderr

penneyj@servio.UUCP (D. Jason Penney) (05/11/89)

I have a question that some one with Unix source should be able to
easily answer for me.

THE ENVIRONMENT: SunOS (or AIX) Unix.

THE SCENARIO: my program is fork()'ing another process which eventually
execve()'s a shell script.  Before the execve(), the program reroutes
stdout and stderr to a disk file:

fork();
...
setpgrp(0, getpid());
close(1); /* stdout */
close(2); /* stderr */
dup(creat("logfile", 0644); /* points 1 and 2 at logfile */
...
execve("script", argv, envp);

THE PROBLEM:

If script is as follows,

#! /bin/sh
frob

logfile contains
frob: not found

(Other more sophisticated tests show that stderr is indeed being
rerouted properly.)
If script is as follows,

#! /bin/csh
frob

nothing appears! (Other tests indicate that the writes to stderr are
trashing my address space!)

Workaround:  If script is as follows,

#! /bin/csh
(frob) |& cat

logfile contains
frob: Command not found.

THE QUESTION:  csh is obviously doing something "smart" with stderr.
Just what is going on?

Please reply directly to me -- if results are interesting enough, I
may post a followup.  Thank you in advance...

-- 
D. Jason Penney                  Ph: (503) 629-8383
Beaverton, OR 97006              uucp: ...ogccse!servio!penneyj
STANDARD DISCLAIMER:  Should I or my opinions be caught or killed, the
company will disavow any knowledge of my actions...

penneyj@servio.UUCP (D. Jason Penney) (05/16/89)

I've found my problem!  The answer is interesting enough that I'm posting
this follow-up, as I threatened I would.

To recap the problem description:  In a fork()'d and execve()'d task,
stderr was not getting printed, and in fact programs were trashing their
address space in an odd way.  This ONLY happened under csh -- Bourne shell
worked properly.

Here is what I did wrong: before doing the execve() I closed stdin so that
the forked process would not share stdin with the parent process:

close(0);

What csh is evidently doing is closing stderr and then re-opening it,
thus leaving descriptor 2 uninitialized.

Thus, if you want to bit-bucket stdin in a forked process, the correct
approach is,

close(0);
open("/dev/null", O_RDONLY);

so that csh will get file descriptor 2 when it reopens stderr.

Many thanks to Maarten Litmaath @ VU Amsterdam, who encouraged me
to keep looking until I found the problem.

-- 
D. Jason Penney                  Ph: (503) 629-8383
Beaverton, OR 97006              uucp: ...ogccse!servio!penneyj
STANDARD DISCLAIMER:  Should I or my opinions be caught or killed, the
company will disavow any knowledge of my actions...