[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

es %dup



This is a long one that's probably mostly of interest to the authors.
I'll start off with what I think is probably a bug, no doubt already fixed
in versions following 0.67.

	;; ls gnatback >[1=2]
	;; ls gnatback
	gnatback: No such file or directory

Maybe rDup is supposed to lead to cpfd() instead of mvfd(), and in fact
that makes things work better.

OK, now, on to the fairly bizarre stuff, but it does happen to be
a matter of great personal interest.  My problem is that I need to be
able to dup2() file descriptors, without clobbering descriptors in use
within es.  Currently, if I have a descriptor 3 open for read, and I
dot-source a file that does "exec {<[0=3]}", when es returns from the
dot-sourced file it will begin to execute commands from what had been
unit 3.  As in (note that the results shown are from the tty, i.e. a
line buffered device):

	;; cat e3
	echo in third file
	;; cat e1
	exec {<[0=3]}
	echo in dot file
	;; let (prompt = '$ ') {./es}
	$ exec {<[3] e3}
	$ . ./e1
	in dot file
	in third file			< cmd input changed from tty to "e1"
	$ ;;

Whereas what I think is arguably right, or at least mighty convenient for
me, is for command input to return to the original source.  (Note that now
it doesn't matter, line buffered tty behaves the same as disk file.)

	$ . ./e1
	in dot file
	$ cat				< cmd input still on tty
	echo in third file		< (but the world sees "e1" on unit 0)
	$ exit
	;; 

Patches follow to that effect.  I can understand that this would be a
pretty grey area, and there's actually no other shell that does right
on this one.  The practical value of it comes from a user interface
front end, which sends commands to an rc back end through a pipe.
The back end shell needs 0 open on the tty, so that the commands it
execs will work, and I have been using hacks to the rc source to
specify an alternate descriptor in place of 0.  If es could do
"exec {<[0=3]}" without clobbering its internal descriptors, I could
have the read end of the pipe open on 0, the tty on 3, and then switch
them up front in the shell initialization once es has started.  And in
fact that works, with the following patches.  Perhaps there are other
ways to do the same thing.

Incidentally, the above examples work from DYNIX/ptx (SVR3 + POSIX), but
from RISC Ultrix 4.2 es craps out on the "exec {<[3] e3}", don't know why,
but anyway your mileage may vary.  The following patch doesn't affect that
problem one way or the other.  Patches are again to 0.67, on top of a
distributed patch to prim-io.c.

	Donn Cave, University Computing Services, University of Washington
	donn@cac.washington.edu
-------------------------------
*** input.c.dist	Thu Oct  1 00:25:38 1992
--- input.c	Thu Oct 15 23:24:29 1992
***************
*** 424,429 ****
--- 424,441 ----
  		}
  }
  
+ /* savefds -- before clobbering via dup2(), dup() old descriptors */
+ extern void savefds(int new) {
+ 	Input *i;
+ 	if (new < 0) return;
+ 	if (historyfd == new) {
+ 		historyfd = dup (historyfd);
+ 	}
+ 	for (i = istack; i != itop; --i)
+ 		if (i->t == iFd && i->fd == new)
+ 			i->fd = dup (i->fd);
+ }
+ 
  
  /*
   * initialization
*** util.c.dist	Thu Oct  1 00:25:38 1992
--- util.c	Thu Oct 15 23:27:48 1992
***************
*** 27,33 ****
  /* mvfd -- duplicate a fd and close the old */
  extern int mvfd(int old, int new) {
  	if (old != new) {
! 		int fd = dup2(old, new);
  		if (fd == -1)
  			fail("dup2: %s", strerror(errno));
  		assert(fd == new);
--- 27,35 ----
  /* mvfd -- duplicate a fd and close the old */
  extern int mvfd(int old, int new) {
  	if (old != new) {
! 		int fd;
! 		savefds (new);
! 		fd = dup2(old, new);
  		if (fd == -1)
  			fail("dup2: %s", strerror(errno));
  		assert(fd == new);
***************
*** 40,46 ****
  /* cpfd -- duplicate a fd keeping the old one open */
  extern int cpfd(int old, int new) {
  	if (old != new) {
! 		int fd = dup2(old, new);
  		if (fd == -1)
  			fail("dup2: %s", strerror(errno));
  		assert(fd == new);
--- 42,50 ----
  /* cpfd -- duplicate a fd keeping the old one open */
  extern int cpfd(int old, int new) {
  	if (old != new) {
! 		int fd;
! 		savefds (new);
! 		fd = dup2(old, new);
  		if (fd == -1)
  			fail("dup2: %s", strerror(errno));
  		assert(fd == new);
*** prim-io.c.dist2	Wed Oct 14 12:00:00 1992
--- prim-io.c	Fri Oct 16 01:09:32 1992
***************
*** 50,56 ****
  		close(dstfd);
  		break;
  	case rDup:
! 		mvfd(srcfd, dstfd);
  		break;
  	default:
  		panic("redirection not handled");
--- 50,56 ----
  		close(dstfd);
  		break;
  	case rDup:
! 		cpfd(srcfd, dstfd);
  		break;
  	default:
  		panic("redirection not handled");