schmidt@bastille.ics.uci.edu (Doug Schmidt) (02/08/91)
Hi, I'm curious, is it possible to implement the dup2() system call using only routines available in the standard C library and other existing system calls? Thanks, Doug -- As flies to wanton boys | Douglas C. Schmidt Are we to th' gods, | (schmidt@ics.uci.edu) They kill us for their sport. | (714) 856-4101
pfalstad@phoenix.Princeton.EDU (Paul Falstad) (02/08/91)
schmidt@ics.uci.edu (Doug Schmidt) wrote: > I'm curious, is it possible to implement the dup2() system >call using only routines available in the standard C library and other >existing system calls? Two ways, at least. 1: close and dup only int dup2(int fd1,int fd2) { close(fd2); fd1 = dup(fd1); if (fd1 != fd2) fd1 = movefd(fd1,fd2); return fd1; } int movefd(int fd1,int fd2) { int fe; if (fd1 == -1) return -1; if ((fe = dup(fd1)) != fd2) fe = movefd(fe); close(fd1); return fe; } 2: fcntl int dup2(int fd1,int fd2) { close(fd2); return(fcntl(fd1,F_DUPFD,fd2)); } -- Paul Falstad, pfalstad@phoenix.princeton.edu PLink:HYPNOS GEnie:P.FALSTAD 10 PRINT "PRINCETON CS" | #include <std.disclaimer.h> 20 GOTO 10 | [Your blood pressure just went up.] Princeton University would like to apologize to everyone for this article.
chet@odin.INS.CWRU.Edu (Chet Ramey) (02/08/91)
Doug Schmidt writes: > I'm curious, is it possible to implement the dup2() system >call using only routines available in the standard C library and other >existing system calls? When you really get down to it. the kernel is going to have to do the nitty-gritty duplication for you, otherwise it gets tricky. If you have an fcntl(..., F_DUPFD, ...), it's straightforward. Here's how we do it in bash: dup2 (fd1, fd2) int fd1, fd2; { if (fcntl (fd1, F_GETFL, 0) == -1) /* fd1 is an invalid fd */ return (-1); if (fd2 < 0 || fd2 >= getdtablesize ()) { errno = EBADF; return (-1); } if (fd1 == fd2) return (0); (void) close (fd2); return (fcntl (fd1, F_DUPFD, fd2)); } (getdtablesize() can be replaced with: sysconf(_SC_OPEN_MAX) Posix ulimit(4, 0L) System V.3 and up NOFILE just about anything else and of course the value can be fetched once into a static variable and cached.) Chet -- Chet Ramey ``There's just no surf in Network Services Group Cleveland, U.S.A. ...'' Case Western Reserve University chet@ins.CWRU.Edu My opinions are just those, and mine alone.
rbj@uunet.uu.net (Root Boy Jim) (02/08/91)
--text follows this line-- In article <1991Feb8.002436.21328@usenet.ins.cwru.edu> chet@po.CWRU.Edu writes: >Doug Schmidt writes: > >> I'm curious, is it possible to implement the dup2() system >>call using only routines available in the standard C library and other >>existing system calls? > >When you really get down to it. the kernel is going to have to do the >nitty-gritty duplication for you, otherwise it gets tricky. If you have >an fcntl(..., F_DUPFD, ...), it's straightforward. > >Here's how we do it in bash: Hmmmm. The two left feet don't know what the right hand is doing. Go check your emacs sources, src/sysdep.c. It's trivial once you realize the recursive solution. First, the one from emacs: OOPS! It doesn't work! And I feel really stupid cuz I sent it to Larry Wall. Oh well, I just tested this: dup2(old,new) { register int fd, ret; close(new); fd = dup(old); if (fd == -1) return(-1); if (fd == new) return(new); ret = dup2(old,new); close(fd); return(ret); } If you want to try it out, here's a driver program: main(c,v) char **v; { int a,b; (c > 2) || (printf("usage: %s srcfd dstfd\n",v[0]), exit(1)); a = atoi(v[1]); b = atoi(v[2]); printf("dup2(%d,%d) = %d\n",a,b,dup2(a,b)), exit(0); } -- Root Boy Jim Cottrell <rbj@uunet.uu.net> I got a head full of ideas They're driving me insane
rbj@uunet.UU.NET (Root Boy Jim) (02/08/91)
In article <1991Feb8.002436.21328@usenet.ins.cwru.edu> chet@po.CWRU.Edu writes: >Doug Schmidt writes: > >> I'm curious, is it possible to implement the dup2() system >>call using only routines available in the standard C library and other >>existing system calls? > >When you really get down to it. the kernel is going to have to do the >nitty-gritty duplication for you, otherwise it gets tricky. If you have >an fcntl(..., F_DUPFD, ...), it's straightforward. > >Here's how we do it in bash: [You may see this twice. Sorry if you do] Well, a clear case of two left feet not knowing what the right hand is doing. The solution is trivial once you grasp the recursive nature of it. I was gonna tell y'all to look in ~emacs/src/sysdep.c, but the version there is broken! I feel like a fool, as I sent it off to Larry Wall. Dup and dup2 can fail, altho people treat it as if it can't. I just debugged the following routine. Appended is a test driver. dup2(old,new) { #ifdef F_DUPFD close(new); return(fcntl(old, F_DUPFD, new)); #else register int fd, ret; close(new); fd = dup(old); if (fd == -1) return(-1); if (fd == new) return(new); ret = dup2(old,new); close(fd); return(ret); #endif } main(c,v) char *v[]; { register int a,b; (c > 2) || (printf("usage: %s srcfd dstfd\n",v[0]),exit(1)); a = atoi(v[1]); b = atoi(v[2]); printf("dup2(%d,%d) = %d\n",a,b,dup2(a,b)); } -- Root Boy Jim Cottrell <rbj@uunet.uu.net> I got a head full of ideas They're driving me insane
jpr@jpradley.jpr.com (Jean-Pierre Radley) (02/09/91)
In article <27B1CA1C.22559@ics.uci.edu> schmidt@ics.uci.edu (Doug Schmidt) writes: > I'm curious, is it possible to implement the dup2() system >call using only routines available in the standard C library and other >existing system calls? From the xcmalt sources: #if !DUP2 /* For those that do not have dup2() */ #include <fcntl.h> dup2(oldfd, newfd) int oldfd, newfd; { if (fcntl(oldfd, F_GETFL, 0) == -1) /* Valid file descriptor? */ return (-1); /* No, return an error */ close(newfd); /* Ensure newfd is closed */ return (fcntl(oldfd, F_DUPFD, newfd)); /* Dup oldfd into newfd */ } #endif /* !DUP2Thanks to Bill Allie CIS: 76703,2061 */ Jean-Pierre Radley NYC Public Unix jpr@jpradley.jpr.com CIS: 72160,1341
gwyn@smoke.brl.mil (Doug Gwyn) (02/09/91)
In article <27B1CA1C.22559@ics.uci.edu> schmidt@ics.uci.edu (Doug Schmidt) writes: > I'm curious, is it possible to implement the dup2() system >call using only routines available in the standard C library and other >existing system calls? /* dup2 -- 7th Edition UNIX system call emulation for UNIX System V last edit: 11-Feb-1987 D A Gwyn */ #include <errno.h> #include <fcntl.h> extern int close(), fcntl(); int dup2( oldfd, newfd ) int oldfd; /* already-open file descriptor */ int newfd; /* desired duplicate descriptor */ { register int ret; /* for fcntl() return value */ register int save; /* for saving entry errno */ if ( oldfd == newfd ) return oldfd; /* be careful not to close() */ save = errno; /* save entry errno */ (void) close( newfd ); /* in case newfd is open */ /* (may have just clobbered the original errno value) */ ret = fcntl( oldfd, F_DUPFD, newfd ); /* dupe it */ if ( ret >= 0 ) errno = save; /* restore entry errno */ else /* fcntl() returned error */ if ( errno == EINVAL ) errno = EBADF; /* we think of everything */ return ret; /* return file descriptor */ }
rbj@uunet.UU.NET (Root Boy Jim) (02/12/91)
In article <15136@smoke.brl.mil> gwyn@smoke.brl.mil (Doug Gwyn) writes: >/* > dup2 -- 7th Edition UNIX system call emulation for UNIX System V >*/ Do you mean that V7 had dup2 but System V doesn't? And what about systems that don't have fcntl? BTW, folks, I missed the case where newfd==oldfd. My (mis)reading of the manual led me to believe that you should get nothing but an error. In any case, it's a trivial fix. -- Root Boy Jim Cottrell <rbj@uunet.uu.net> I got a head full of ideas They're driving me insane
richard@locus.com (Richard M. Mathews) (02/12/91)
I have not yet seen a correct version of code for dup2() posted. The
versions posted by Paul Falsted, Doug Gwyn, and Root Boy Jim all fail
the following test case because they close "fd2" too soon:
main()
{
dup2(-1,fileno(stdout)); /* this returns -1 as expected */
printf("stdout *should* still be OK\n");
}
Only the version posted by Chet Ramey gets this right, but only Doug
Gwyn's version does everything right with errno, including mapping
EINVAL to EBADF.
I would post what I consider to be the right answer, but I have licensing
problems. I can recommend taking ideas from both Gwyn and Ramey; perhaps
one of them would be willing to post the result of such a merge.
Richard M. Mathews Freedom for Lithuania
richard@locus.com Laisve!
lcc!richard@seas.ucla.edu
...!{uunet|ucla-se|turnkey}!lcc!richard
guy@auspex.auspex.com (Guy Harris) (02/13/91)
>Do you mean that V7 had dup2 but System V doesn't? Yes. For whatever reason, that particular branch of the family didn't have "dup2()"; it did, however, have "fcntl()" and the F_DUPFD subfunction thereof, at least as far back as S3 (I don't remember whether earlier members of that branch had it). S5R3 picked up "dup2()", which is in POSIX; 4.2BSD picked up "fcntl()", which is also in POSIX. >And what about systems that don't have fcntl? If you have neither "fcntl()" nor "dup2()", you're not dealing with a UNIX, or lookalike, that does a reasonable job of looking like a modern UNIX (it's not as modern as V7, even), in which case 1) you may have a problem if you need "dup2()"-like functionality (you might have to repeatedly "dup()" the file descriptor until it reaches the desired value, and then close all the intermediate descriptors) and 2) you probably have a bunch of other problems as well.
chet@odin.INS.CWRU.Edu (Chet Ramey) (02/13/91)
In article <richard.666334818@fafnir.la.locus.com> richard@locus.com (Richard M. Mathews) writes: >I would post what I consider to be the right answer, but I have licensing >problems. I can recommend taking ideas from both Gwyn and Ramey; perhaps >one of them would be willing to post the result of such a merge. How about this (apologies for the Gnu coding style)? (As an aside, I do not think that the second fcntl will ever return EINVAL, since it only returns that error for out-of-range values (< 0 or >= getdtablesize()), and that case is already handled explicitly.) dup2 (fd1, fd2) int fd1, fd2; { int saved_errno, r; if (fcntl (fd1, F_GETFL, 0) == -1) /* fd1 is an invalid fd */ return (-1); if (fd2 < 0 || fd2 >= getdtablesize ()) /* This could be removed. */ { errno = EBADF; return (-1); } if (fd1 == fd2) return (0); saved_errno = errno; (void) close (fd2); r = fcntl (fd1, F_DUPFD, fd2); if (r >= 0) errno = saved_errno; else { if (errno == EINVAL) errno = EBADF; } return (r); } Chet -- Chet Ramey ``There's just no surf in Network Services Group Cleveland, U.S.A. ...'' Case Western Reserve University chet@ins.CWRU.Edu My opinions are just those, and mine alone.
gwyn@smoke.brl.mil (Doug Gwyn) (02/14/91)
In article <122373@uunet.UU.NET> rbj@uunet.UU.NET (Root Boy Jim) writes: -In article <15136@smoke.brl.mil> gwyn@smoke.brl.mil (Doug Gwyn) writes: ->/* -> dup2 -- 7th Edition UNIX system call emulation for UNIX System V ->*/ -Do you mean that V7 had dup2 but System V doesn't? -And what about systems that don't have fcntl? Geez, what do you think the comment means, anyway?
sbs@ciara.Frame.COM (Steven Sargent) (02/20/91)
dup2(old, new)
{
return dup(old+64, new);
}
... depends on an undocumented interface; your mileage may
vary; guaranteed to lose in SunOS 4.1 (but you can use real
dup2 there); doubtless will lose other places that have wide
u.u_ofile; but amusing nonetheless.
--
Steven Sargent sbs@frame.com "Frame's phone bill, my opinions."
forrie@morwyn.UUCP (Forrie Aldrich) (04/17/91)
Brandon S. Allbery writes: | | As quoted from <2180@estevax.UUCP> by iain@estevax.UUCP (Hr Iain Lea): | +--------------- | | I am porting a program from BSD to a Sys5r2 ish derivative and need the | | dup2() function call. | +--------------- | | Is this one in the FAQ? | | /* | * Near-duplicate for dup2(). ("Near"? We discussed this for a whole bloody | * month --- I don't want to discuss it any more. BSD and System V have | * enough differing errno values that that part is pointless anyway.) | * | * Caveats: doesn't necessarily return the same errno values on failure; does | * not leave f2 open if the dup fails. | */ | | #include <ioctl.h> | #include <errno.h> | | #define dup2(f1,f2) (close(f2),fcntl(f1,F_DUPFD,f2)) | | ++Brandon [...] Well, for reference's sake, here's another version that I caught off the net a little while ago... hope it helps. /* dup2 -- 7th Edition UNIX system call emulation for UNIX System V last edit: 11-Feb-1987 D A Gwyn */ #include <errno.h> #include <fcntl.h> extern int close(), fcntl(); int dup2( oldfd, newfd ) int oldfd; /* already-open file descriptor */ int newfd; /* desired duplicate descriptor */ { register int ret; /* for fcntl() return value */ register int save; /* for saving entry errno */ if ( oldfd == newfd ) return oldfd; /* be careful not to close() */ save = errno; /* save entry errno */ (void) close( newfd ); /* in case newfd is open */ /* (may have just clobbered the original errno value) */ ret = fcntl( oldfd, F_DUPFD, newfd ); /* dupe it */ if ( ret >= 0 ) errno = save; /* restore entry errno */ else /* fcntl() returned error */ if ( errno == EINVAL ) errno = EBADF; /* we think of everything */ return ret; /* return file descriptor */ } --------------------=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-------------------- Forrest Aldrich, Jr.| ...uunet!eci!morwyn!forrie |forrie@morywn.UUCP | <email paths> | CREATIVE CONNECTIONS| ...uunet!zinn!eci!morwyn!forrie |Graphic Illustration ------------------\-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=/------------------ \___ PO Box 1541 - Dover, NH 03820 ___/ -- --------------------=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-------------------- Forrest Aldrich, Jr.| ...uunet!eci!morwyn!forrie |forrie@morywn.UUCP | <email paths> | CREATIVE CONNECTIONS| ...uunet!zinn!eci!morwyn!forrie |Graphic Illustration ------------------\-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=/------------------ \___ PO Box 1541 - Dover, NH 03820 ___/
allbery@NCoast.ORG (Brandon S. Allbery KB8JRR/AA) (04/21/91)
As quoted from <85@morwyn.UUCP> by forrie@morwyn.UUCP (Forrie Aldrich): +--------------- | Well, for reference's sake, here's another version that I caught off the net | a little while ago... hope it helps. +--------------- (Doug Gwyn's dup2() omitted) Reference's sake, yes --- but that was one that got some remarks about differing errno values. (Which is why I had that remark in my comments.) For almost every use of dup2() I've ever encountered, the macro does the job. If you absolutely NEED 100% V7 compatibility, use Doug's by all means. ++Brandon -- Me: Brandon S. Allbery Ham: KB8JRR/AA on 2m, 220, 440, 1200 Internet: allbery@NCoast.ORG (QRT on HF until local problems fixed) America OnLine: KB8JRR // Delphi: ALLBERY AMPR: kb8jrr.AmPR.ORG [44.70.4.88] uunet!usenet.ins.cwru.edu!ncoast!allbery KB8JRR @ WA8BXN.OH
richard@locus.com (Richard M. Mathews) (04/23/91)
allbery@NCoast.ORG (Brandon S. Allbery KB8JRR/AA) writes: >(Doug Gwyn's dup2() omitted) >Reference's sake, yes --- but that was one that got some remarks about >differing errno values. (Which is why I had that remark in my comments.) Actually, the problem with Gwyn's version is the behavior when, on entry to the routine, newfd is a valid descriptor for an open file oldfd is not a valid descriptor for an open file A real dup2 (as on V7) will return EBADF and leave newfd alone. Gwyn's will return EBADF and close newfd. >For almost every use of dup2() I've ever encountered, the macro does the job. >If you absolutely NEED 100% V7 compatibility, use Doug's by all means. I had problems with the super-simple-minded version of dup2 when porting the BSD4.1 C Shell. I don't remember if it was the above problem or the problem with newfd==oldfd (I think it was the latter, and Gwyn's addresses that). Richard M. Mathews Lietuva laisva = Free Lithuania richard@locus.com Brivu Latviju = Free Latvia lcc!richard@seas.ucla.edu Eesti vabaks = Free Estonia ...!{uunet|ucla-se|turnkey}!lcc!richard