Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!mnetor!seismo!sundc!hadron!jsdy From: jsdy@hadron.UUCP (Joseph S. D. Yao) Newsgroups: comp.lang.c Subject: Re: pipe flushing Message-ID: <404@hadron.UUCP> Date: Fri, 2-Jan-87 06:46:10 EST Article-I.D.: hadron.404 Posted: Fri Jan 2 06:46:10 1987 Date-Received: Fri, 2-Jan-87 18:46:02 EST References: <523@bath63.bath.ac.uk> <721@dg_rtp.UUCP> <658@bath63.ux63.bath.ac.uk> Reply-To: jsdy@hadron.UUCP (Joseph S. D. Yao) Organization: Hadron, Inc., Fairfax, VA Lines: 151 Summary: LONG response, with some STYLE included. I am not the Throop, but here's how: In article <658@bath63.ux63.bath.ac.uk> ma6nrr@ux63.bath.ac.uk (Rashbrook) writes (to Wayne Throop): >a) mail me the fflush manual (I can't find it anywhere) Try 'man 3 fclose'. >b) show me what to do: In the below, some of what I say is flagged by '*' in the LHC. These lines have to do with style. This is not irrelevant, however anyone who wishes to flame those lines should be deprecated as a crashing boor. Style helps improve programming performance; but by its very name one should assume that there is more than one way to do each of these things. Some mangling of the program text bbelow has occured, in an attempt to convince inews (the real culprit) that more information is going out than came in. ... >#define lenu (unsigned)len >char buffer[128]; /* read/write buffer > arbitrary length */ * Should be local to parent() [see note on stop()]. >int pipe0[2],pipe1[2],tty,outfile,len; * Should be local as appropriate, and passed as parameters. >void exit(); /* this is for lint */ * Should be local to main() [see note on stop()]. >main(argc,argv,envp) ... >{ > if (argc!=3) > { /* bad no. of args */ ... What about programs with arguments? > fprintf(stderr,"Usage: %s file program\n",*argv); > exit(2); > } > if (outfile=creat(*++argv,0666),outfile==EOF) */2: I would have made the outfile = ... and if (...) two separate statements, to eschew confusion. Also, I never make files 0666: that way lies lack of data integrity. > { /* attempt to open file */ > fprintf(stderr,"%s: cannot open\n",*argv); > exit(1); > } > pipe(pipe0); /* pipe for i/p to program */ > pipe(pipe1); /* pipe for o/p from program */ ... MUST test these pipe()s for correct return! Either < 0 or == ERROR (if defined) to test for error. > if (fork()) parent(); else child(++argv,envp); ... Same. best is switch(fork()) ... > /* now execute required program */ > exit(0); /* this is for lint */ ... System 5 lint requires that these exit()s be return()s; I was unaware that any lint required exit()s. >} >stop() >{ ... (*/2) The only reliable thing to do in an interrupt handler is to set a flag. Best to set a flag here, and have parent() take notice of it and return to main(), which then exit()s [or return()s, per above]. > while ((len=read(pipe1[0],buffer,128))>0) > { /* clear output buffer */ ... > } >exit(0); >} >parent() /* parent writes to outfile */ >{ > int (*signal())(); /* this is for lint */ > close(pipe0[0]); /* enable read from pipe without waiting */ ... close(pipe1[1]); > fcntl(pipe1[0],F_SETFL,fcntl(pipe1[0],F_GETFL,0)|O_NDELAY); ... (*sigh*) Yes, this works for pipes, even though the docs say it only works for tty's. But (just because of the way it's defined) I'd rather have a real int than 0 as the arg. (man 2 fcntl) Also, O_NDELAY is for open() or ioctl(); FNDELAY is for fcntl(). (Yes, one is defined as the other in your include file. So what? Say What You Mean is the whole of the law!) > tty=open("/dev/tty",O_RDWR | O_NDELAY); /* open to console */ ... MUST check return values. > signal(18,stop); /* trap program's death */ ... Do you perchance mean SIGCHLD? Which is n o t 18! Always use symbolic constants. That way, you don't make silly mistakes like this. Also, if you should try to compile this on a machine which does not have SIGCHLD in its, you immediately know. > for (;;) > { /* transfer i/o until program dies */ > len=read(tty,buffer,128); ... Don't do the next two if lenu == 0 ! > write(pipe0[1],buffer,lenu); > write(outfile,buffer,lenu); ... This code seems to assume lockstep read-from-tty / write-to-tty performance on the part of the child. If that's the way it actually works (and if no message is >128 chars), fine. Otherwise, you should fork one process to funnel in each direction, OR use Berkeley's SIGIO (assuming BSD, but so do you) to sample reads, and read each one 'til dry; OR ... (The problem here is getting out of sync.) > len=read(pipe1[0],buffer,128); > if (len==EOF) stop(); /* so it's messy,but it's the > only way with O_NDELAY */ ... EOF is a stdio concept. It happens to be equal to what read() returns on error. Partly coincidence. This same value also happens to be what is returned on a possible delay! ... Again, don't do these if lenu == 0 . > write(tty,buffer,lenu); > write(outfile,buffer,lenu); > } >} >child(argv,envp) ... >{ > close(0); /* these aren't needed any more */ > close(1); > if (dup(pipe0[0])!=0 || dup(pipe1[1])!=1) > { /* connect pipes to stdin/out */ > fprintf(stderr,"error in pipes\n"); > exit(1); > } > close(pipe0[1]); > close(pipe1[0]); ... Also, close(pipe0[0]); close(pipe1[1]); since they're dup'd. > close(outfile); ... Should never have been opened before the fork(). > setbuf(stdout,(char *)0); ... Unfortunately, this does n o t affect any future exec'd program. (See below) >/* test lines */ >printf("Hit return:\n"); >while (getchar()!='\n'); >/* this correctly prints up prompt, > waits for return,then acts as > program options |tee file */ > if (execve(*argv,argv+1,envp)==EOF) fprintf(stderr,"%s: cannot execute\n",*argv); /* finally execute program (hopefully!) */ >} /* so I don't need an if,so what? */ An EOF is n o t the all-purpose error return. Stdio only. The setbuf() changes flags and elements in the iobuf structure in the current process image (program memory). When you exec a new program, that reads in new program memory. The structure would have to be re-initialised from within that program; or fflush() would have to be called every time you write: stdout is always buffered if it isn't hooked up to a tty. I think that's what you were asking about. There's more wrong with this, but I'm not sure what. -- Joe Yao hadron!jsdy@seismo.{CSS.GOV,ARPA,UUCP} jsdy@hadron.COM (not yet domainised)