[comp.unix.wizards] dup2 issue

stevesu@copper.UUCP (04/28/87)

Here's an interesting question: what is the correct behavior of
dup2 when both arguments are the same?  It appears to be a no-op
(on 4.2bsd, at least), but it's hardly a good idea to depend on
accidental, undocumented behavior.  In fact, a strict
interpretation of the man page ("If [the second] descriptor is
already in use, the descriptor is first deallocated as if a
_c_l_o_s_e(2) call had been done first") would imply that

	dup2(fd, fd);

should close fd before attempting to dup it, resulting in an
error and the loss of the file descriptor.

The question arises because of some code I have that sets up a
socket pair, forks, connects one end of the socket to fd's 0, 1,
and 2, and then exec's something.  I had (probably in a hurry,
since usually I know better) written

	close(sv[1]);
	close(0);
	close(1);
	close(2);
	dup(sv[0]);
	dup(sv[0]);
	dup(sv[0]);
	close(sv[0]);

(the two fd's returned by socketpair() were in the sv[] array.)
This code fails if it is invoked with 0, 1, or 2 already closed,
because then the low end of the socket ends up on 0, 1, or 2, and
gets closed before it can be dup'ed.

I changed the code to

	if(sv[0] != 0)
		dup2(sv[0], 0);
	if(sv[0] != 1)
		dup2(sv[0], 1);
	if(sv[0] != 2)
		dup2(sv[0], 2);
	if(sv[0] > 2)
		close(sv[0]);

but I wondered if the first three if's were strictly necessary.
(I'll definitely leave them in, even though it might work without
them.  By Murphy's law, since a version of Unix somewhere could
implement dup2(fd, fd) as closing fd, one will.)

Let me add a word of advice: be very careful when writing code
that tries to redefine fd's 0, 1, and/or 2.  It's extremely easy
to end up with code that fails mysteriously when, for instance,
open returns 0.  It's my belief that the opens of /dev/null that
daemon programs do, which have been discussed on this newsgroup,
are there in part to protect programs that have these
dependencies.  (In fact, the 4.x cpp has this property, and you
can break it by using make -f -, which inadvertently closes fd 0.)

                                           Steve Summit
                                           stevesu@copper.tek.com

mouse@mcgill-vision.UUCP (05/06/87)

In article <1004@copper.TEK.COM>, stevesu@copper.TEK.COM (Steve Summit) writes:
> [what does dup2 do with two identical arguments?  Question arises
> from something like]

> 	close(sv[1]);
> 	close(0);
> 	close(1);
> 	close(2);
> 	dup(sv[0]);
> 	dup(sv[0]);
> 	dup(sv[0]);
> 	close(sv[0]);

> This code fails if it is invoked with 0, 1, or 2 already closed,

> I changed the code to

> 	if(sv[0] != 0)
> 		dup2(sv[0], 0);
> 	if(sv[0] != 1)
> 		dup2(sv[0], 1);
> 	if(sv[0] != 2)
> 		dup2(sv[0], 2);
> 	if(sv[0] > 2)
> 		close(sv[0]);

> but I wondered if the first three if's were strictly necessary.

Well, I would suggest you write it as

	if (sv[0] != fileno(stdin))
	 { dup2(sv[0],fileno(stdin));
	   close(sv[0]);
	 }
	dup2(fileno(stdin),fileno(stdout));
	dup2(fileno(stdin),fileno(stderr));

[this line to patch around stupid counterproductive 50% rule]
[this line to patch around stupid counterproductive 50% rule]

					der Mouse

				(mouse@mcgill-vision.uucp)