[net.unix-wizards] Unix standard output buffer problem

PUPPY%clemson.csnet@csnet-relay.arpa (03/01/86)

   I am looking for a little help in solving a rather interesting problem
with SYSTEM V Unix.  Here are the symptoms:

	I set the standard output flag byte to indicated no buffering:
		stdout -> _flag |= _IONBF;  /* Declared in stdio.h */

	The code then does a fork() call.  At this point the child and
	parent process both report that the stdout -> _flag has the
	correct value (I.E. buffering is turned off).

	The child process does an exec() type call.  The execed pgm
	reports that the stdout -> _flag has mysteriously been reinitialized
	to indicate buffering.

  I have checked the C run-time startup routines (crt0.c) and it does not
appear to mess with this flag setting.

  I have check the printf code and it does not harm the flag as best I 
could tell.
  
 I have checked the exec source and it does not appear to mess with it either.

 I have checked the kernel's expand () source (exec does an expand) and it
to does'nt seem to do anything with this flag setting.

 
 My problem is that I need to turn off this buffering so that the execed
program has buffering initially turned off.  Because of the nature of the
application I cannot use stty's or ioctl's to accomplish this. This problem
is also an annoyance if one trys to set up a pipe to a program (such
as mail) to work with its standard input and output. (Mailx will put
"Command?" into the pipe but because of buffering the parent process will
not receive this because there is no \n in the prompt).  I have found
this problem to be on a VAX 11/780 running Ultrix, several NCR Towers and
a Perkin Elmer 3200 running Xelos.  I would appreciate any help you could
be in locating the source of the problem as well as any suggestions on
how to correct or circumvent the problem.

Please send responses directly to:  puppy@clemson.csnet

William Faulkner

has experienced this problem

mjs@sfsup.UUCP (M.J.Shannon) (03/03/86)

> 
>    I am looking for a little help in solving a rather interesting problem
> with SYSTEM V Unix.  Here are the symptoms:
> 
> 	I set the standard output flag byte to indicated no buffering:
> 		stdout -> _flag |= _IONBF;  /* Declared in stdio.h */
> 
> 	The code then does a fork() call.  At this point the child and
> 	parent process both report that the stdout -> _flag has the
> 	correct value (I.E. buffering is turned off).
> 
> 	The child process does an exec() type call.  The execed pgm
> 	reports that the stdout -> _flag has mysteriously been reinitialized
> 	to indicate buffering.
> 

First, you shouldn't mess with stdio's flags; to achieve the proper effect, use:
	setbuf(stdout, NULL);
Second, you need to understand what happens when your code executes an exec().
What happens is this: the current process image is abandoned (thrown away) and
a new process image is created (bearing NO relationship to what was there
before the exec() (well, not quite technically true; some kernel data
associated with the process is inherited)).  But, since stdio is not
implemented in the kernel, the new process does its own stdio initialization,
which includes setting up some buffering.
-- 
	Marty Shannon
UUCP:	ihnp4!attunix!mjs
Phone:	+1 (201) 522 6063

Disclaimer: I speak for no one.

"If I never loved, I never would have cried." -- Simon & Garfunkel

throopw@dg_rtp.UUCP (03/07/86)

> I have checked the exec source and it does not appear to mess
> with it [alter the whether-to-buffer flag] either.

Uh.... yeah.  I'm not sure what you think "exec" does, but on most
Unix(*)-like operating systems it does indeed "mess with" *all* the
globally persistant variables in the executable image it creates.  In
particular, it *creates* them all, giving them the values assigned them
at link-time.

To answer your question directly, there is *no* *way* to do what you
said you wanted to do.  Altering an address space before an exec had
*better* *not* have any effect on the address space seen after the exec,
or exec just isn't doing it's job.  The only way to alter the address
space gotten by execing an executable image is to patch the image on
disk (or link a new one).

> William Faulkner
--
* Unix is a trademark of ATT
-- 
Wayne Throop at Data General, RTP, NC
<the-known-world>!mcnc!rti-sel!dg_rtp!throopw

jdz@wucec2.UUCP (03/13/86)

In article <203@dg_rtp.UUCP> throopw@dg_rtp.UUCP writes:
>To answer your question directly, there is *no* *way* to do what you
>said you wanted to do.  Altering an address space before an exec had
>*better* *not* have any effect on the address space seen after the exec,
>or exec just isn't doing it's job.  The only way to alter the address
>space gotten by execing an executable image is to patch the image on
>disk (or link a new one).

Well, on machines that implement ptrace(3) or some equivalent/variant,
one can start-up the child to be traced, poke the new bits in, and then
let it run. Yeah, I know, slow, ugly, unportable, etc.

But not impossible.

I wouldn't recommend it, for most of the reasons mentioned above. But if you
have to have it, there you go. I shudder at the thought of poking around
the namelist of the child executable to find the appropriate virtual address
of the particular word to be poked... And it will never work on stripped
images (for this reason). Yuck!

The beauty of Un*x is that almost nothing is impossible. The biggest drawback
to Un*x is that those "impossible elsewhere" functions are UGLY!!!!!
-- 
Jason D. Zions			...!{seismo,cbosgd,ihnp4}!wucs!wucec2!jdz
Box 1045 Washington University
St. Louis MO 63130  USA		(314) 889-6160
Nope, I didn't say nothing. Just random noise.

jsdy@hadron.UUCP (Joseph S. D. Yao) (03/16/86)

In article <1421@brl-smoke.ARPA> PUPPY%clemson.csnet@csnet-relay.arpa writes:
>	I set the standard output flag byte to indicated no buffering:
>		stdout -> _flag |= _IONBF;  /* Declared in stdio.h */
>	The code then does a fork() call.  ...
>	The child process does an exec() type call.  The execed pgm
>	reports that the stdout -> _flag has mysteriously been reinitialized
>	to indicate buffering.

The problem is, that local states aren't carried over in an exec().
When a program is exec'ed, the entire memory of the process being
run is wiped clean, and then the image of the new program is overlaid
on top of it.  So, you see, unfortunately, no status information can
be passed down except via command-line arguments or other, non-
standard techniques (like using IPC's: pipes, sockets, shared memory,
mailboxes, et alii).

Stdout is always unbuffered if and only if it is connected to a tty;
otherwise it defaults to buffered.  You may set it to unbuffered for
the duration of your program with setbuf(stdout, (char *) NULL); but
this does not last past exec()'s.  You may alternatively (and should,
if leaving stdout buffered) do an fflush(stdout) every time that you
think you want output to appear.  This, unfortunately, doesn't help
you if what you want to do is run a binary program thorugh a pipe.
There were, once upon a time, various kernel mods to associate a
pipe with a tty, so that stat's and ioctl's got passed through.  I'm
afraid I don't have any references here and now.

BTW:  for future reference, the stdio routines are given to you so
that you don't have to mess with FILE internals.  Don't do it: it'll
turn around and bite you some day when you least expect it ...
-- 

	Joe Yao		hadron!jsdy@seismo.{CSS.GOV,ARPA,UUCP}