diff --git a/sys/man/2/dup b/sys/man/2/dup index cd3414106..1eca0a713 100644 --- a/sys/man/2/dup +++ b/sys/man/2/dup @@ -32,6 +32,19 @@ requires that .I newfd be no greater than 20 more than the highest file descriptor ever used by the program. +.PP +.I Dup +does not copy the per file descriptor +.B OCEXEC +flag, +meaning that +.I newfd +will not be closed on +.IR exec(2) +syscall, +when +.I oldfd +had been previously opend with it. .SH SOURCE .B /sys/src/libc/9syscall .SH SEE ALSO diff --git a/sys/src/9/port/auth.c b/sys/src/9/port/auth.c index 2cc54c657..b6b19bd63 100644 --- a/sys/src/9/port/auth.c +++ b/sys/src/9/port/auth.c @@ -97,13 +97,12 @@ sysfauth(va_list list) nexterror(); } - fd = newfd(ac); + /* always mark it close on exec */ + fd = newfd(ac, OCEXEC); if(fd < 0) error(Enofd); poperror(); /* ac */ - /* always mark it close on exec */ - ac->flag |= CCEXEC; return (uintptr)fd; } diff --git a/sys/src/9/port/chan.c b/sys/src/9/port/chan.c index 58a47cc83..e60561d1a 100644 --- a/sys/src/9/port/chan.c +++ b/sys/src/9/port/chan.c @@ -1468,9 +1468,6 @@ namec(char *aname, int amode, int omode, ulong perm) saveregisters(); c = devtab[c->type]->open(c, omode&~OCEXEC); - - if(omode & OCEXEC) - c->flag |= CCEXEC; if(omode & ORCLOSE) c->flag |= CRCLOSE; break; @@ -1571,11 +1568,9 @@ namec(char *aname, int amode, int omode, ulong perm) incref(cnew->path); cnew = devtab[cnew->type]->create(cnew, e.elems[e.nelems-1], omode&~(OEXCL|OCEXEC), perm); - poperror(); - if(omode & OCEXEC) - cnew->flag |= CCEXEC; if(omode & ORCLOSE) cnew->flag |= CRCLOSE; + poperror(); putmhead(m); cclose(c); c = cnew; diff --git a/sys/src/9/port/devdup.c b/sys/src/9/port/devdup.c index 2ba718729..79c7d90ff 100644 --- a/sys/src/9/port/devdup.c +++ b/sys/src/9/port/devdup.c @@ -63,6 +63,8 @@ dupopen(Chan *c, int omode) Chan *f; int fd, twicefd; + if(omode & ORCLOSE) + error(Eperm); if(c->qid.type & QTDIR){ if(omode != 0) error(Eisdir); diff --git a/sys/src/9/port/devshr.c b/sys/src/9/port/devshr.c index 96e319221..225ba6c93 100644 --- a/sys/src/9/port/devshr.c +++ b/sys/src/9/port/devshr.c @@ -396,6 +396,8 @@ shropen(Chan *c, int omode) case Qcmpt: if(omode&OTRUNC) error(Eexist); + if(omode&ORCLOSE) + error(Eperm); shr = sch->shr; mpt = sch->mpt; devpermcheck(mpt->owner, mpt->perm, mode); diff --git a/sys/src/9/port/devsrv.c b/sys/src/9/port/devsrv.c index 193fa6c8b..8128569a1 100644 --- a/sys/src/9/port/devsrv.c +++ b/sys/src/9/port/devsrv.c @@ -135,6 +135,8 @@ srvopen(Chan *c, int omode) if(omode&OTRUNC) error(Eexist); + if(omode&ORCLOSE) + error(Eperm); if(openmode(omode)!=sp->chan->mode && sp->chan->mode!=ORDWR) error(Eperm); devpermcheck(sp->owner, sp->perm, omode); @@ -338,8 +340,6 @@ srvwrite(Chan *c, void *va, long n, vlong) cclose(c1); nexterror(); } - if(c1->flag & (CCEXEC|CRCLOSE)) - error("posted fd has remove-on-close or close-on-exec"); if(c1->qid.type & QTAUTH) error("cannot post auth file in srv"); sp = srvlookup(nil, c->qid.path); diff --git a/sys/src/9/port/lib.h b/sys/src/9/port/lib.h index 1f7bf7d1d..06b423d9d 100644 --- a/sys/src/9/port/lib.h +++ b/sys/src/9/port/lib.h @@ -176,7 +176,7 @@ extern void qsort(void*, long, long, int (*)(void*, void*)); #define ORDWR 2 /* read and write */ #define OEXEC 3 /* execute, == read but check execute permission */ #define OTRUNC 16 /* or'ed in (except for exec), truncate file first */ -#define OCEXEC 32 /* or'ed in, close on exec */ +#define OCEXEC 32 /* or'ed in (per file descriptor), close on exec */ #define ORCLOSE 64 /* or'ed in, remove on close */ #define OEXCL 0x1000 /* or'ed in, exclusive create */ diff --git a/sys/src/9/port/pgrp.c b/sys/src/9/port/pgrp.c index 5576acc57..408370d35 100644 --- a/sys/src/9/port/pgrp.c +++ b/sys/src/9/port/pgrp.c @@ -140,7 +140,8 @@ dupfgrp(Fgrp *f) new = smalloc(sizeof(Fgrp)); if(f == nil){ - new->fd = smalloc(DELTAFD*sizeof(Chan*)); + new->flag = smalloc(DELTAFD*sizeof(new->flag[0])); + new->fd = smalloc(DELTAFD*sizeof(new->fd[0])); new->nfd = DELTAFD; new->ref = 1; return new; @@ -152,12 +153,19 @@ dupfgrp(Fgrp *f) i = new->nfd%DELTAFD; if(i != 0) new->nfd += DELTAFD - i; - new->fd = malloc(new->nfd*sizeof(Chan*)); + new->fd = malloc(new->nfd*sizeof(new->fd[0])); if(new->fd == nil){ unlock(f); free(new); error("no memory for fgrp"); } + new->flag = malloc(new->nfd*sizeof(new->flag[0])); + if(new->flag == nil){ + unlock(f); + free(new->fd); + free(new); + error("no memory for fgrp"); + } new->ref = 1; new->maxfd = f->maxfd; @@ -165,6 +173,7 @@ dupfgrp(Fgrp *f) if((c = f->fd[i]) != nil){ incref(c); new->fd[i] = c; + new->flag[i] = f->flag[i]; } } unlock(f); @@ -194,6 +203,7 @@ closefgrp(Fgrp *f) up->closingfgrp = nil; free(f->fd); + free(f->flag); free(f); } diff --git a/sys/src/9/port/portdat.h b/sys/src/9/port/portdat.h index 7c9aa7193..a5cdafa6a 100644 --- a/sys/src/9/port/portdat.h +++ b/sys/src/9/port/portdat.h @@ -125,7 +125,7 @@ enum COPEN = 0x0001, /* for i/o */ CMSG = 0x0002, /* the message channel for a mount */ /*rsc CCREATE = 0x0004, /* permits creation if c->mnt */ - CCEXEC = 0x0008, /* close on exec */ + CCEXEC = 0x0008, /* close on exec (per file descriptor) */ CFREE = 0x0010, /* not in use */ CRCLOSE = 0x0020, /* remove on close */ CCACHE = 0x0080, /* client cache */ @@ -509,6 +509,7 @@ struct Fgrp Ref; Lock; Chan **fd; + uchar *flag; /* per file-descriptor flags (CCEXEC) */ int nfd; /* number allocated */ int maxfd; /* highest fd in use */ int exceed; /* debugging */ diff --git a/sys/src/9/port/portfns.h b/sys/src/9/port/portfns.h index 04550987f..00c7e8b96 100644 --- a/sys/src/9/port/portfns.h +++ b/sys/src/9/port/portfns.h @@ -201,7 +201,7 @@ Chan* namec(char*, int, int, ulong); void nameerror(char*, char*); int needpages(void*); Chan* newchan(void); -int newfd(Chan*); +int newfd(Chan*, int); Mhead* newmhead(Chan*); Mount* newmount(Chan*, int, char*); Page* newpage(int, Segment **, uintptr); diff --git a/sys/src/9/port/sysfile.c b/sys/src/9/port/sysfile.c index ed8e5c7ad..a503b2cca 100644 --- a/sys/src/9/port/sysfile.c +++ b/sys/src/9/port/sysfile.c @@ -25,33 +25,45 @@ int growfd(Fgrp *f, int fd) /* fd is always >= 0 */ { Chan **newfd, **oldfd; + uchar *newflag, *oldflag; + int nfd; - if(fd < f->nfd) + nfd = f->nfd; + if(fd < nfd) return 0; - if(fd >= f->nfd+DELTAFD) + if(fd >= nfd+DELTAFD) return -1; /* out of range */ /* * Unbounded allocation is unwise; besides, there are only 16 bits * of fid in 9P */ - if(f->nfd >= 5000){ + if(nfd >= 5000){ Exhausted: print("no free file descriptors\n"); return -1; } - newfd = malloc((f->nfd+DELTAFD)*sizeof(Chan*)); + oldfd = f->fd; + oldflag = f->flag; + newfd = malloc((nfd+DELTAFD)*sizeof(newfd[0])); if(newfd == nil) goto Exhausted; - oldfd = f->fd; - memmove(newfd, oldfd, f->nfd*sizeof(Chan*)); + memmove(newfd, oldfd, nfd*sizeof(newfd[0])); + newflag = malloc((nfd+DELTAFD)*sizeof(newflag[0])); + if(newflag == nil){ + free(newfd); + goto Exhausted; + } + memmove(newflag, oldflag, nfd*sizeof(newflag[0])); f->fd = newfd; - free(oldfd); - f->nfd += DELTAFD; + f->flag = newflag; + f->nfd = nfd+DELTAFD; if(fd > f->maxfd){ if(fd/100 > f->maxfd/100) f->exceed = (fd/100)*100; f->maxfd = fd; } + free(oldfd); + free(oldflag); return 1; } @@ -72,9 +84,9 @@ findfreefd(Fgrp *f, int start) } int -newfd(Chan *c) +newfd(Chan *c, int mode) { - int fd; + int fd, flag; Fgrp *f; f = up->fgrp; @@ -87,6 +99,13 @@ newfd(Chan *c) if(fd > f->maxfd) f->maxfd = fd; f->fd[fd] = c; + + /* per file-descriptor flags */ + flag = 0; + if(mode & OCEXEC) + flag |= CCEXEC; + f->flag[fd] = flag; + unlockfgrp(f); return fd; } @@ -112,6 +131,8 @@ newfd2(int fd[2], Chan *c[2]) f->maxfd = fd[1]; f->fd[fd[0]] = c[0]; f->fd[fd[1]] = c[1]; + f->flag[fd[0]] = 0; + f->flag[fd[1]] = 0; unlockfgrp(f); return 0; } @@ -247,6 +268,7 @@ sysdup(va_list list) oc = f->fd[fd]; f->fd[fd] = c; + f->flag[fd] = 0; unlockfgrp(f); if(oc != nil) cclose(oc); @@ -255,7 +277,7 @@ sysdup(va_list list) cclose(c); nexterror(); } - fd = newfd(c); + fd = newfd(c, 0); if(fd < 0) error(Enofd); poperror(); @@ -280,7 +302,7 @@ sysopen(va_list list) cclose(c); nexterror(); } - fd = newfd(c); + fd = newfd(c, mode); if(fd < 0) error(Enofd); poperror(); @@ -295,7 +317,7 @@ fdclose(int fd, int flag) lock(f); c = fd <= f->maxfd ? f->fd[fd] : nil; - if(c == nil || (flag != 0 && (c->flag&flag) == 0)){ + if(c == nil || (flag != 0 && ((f->flag[fd]|c->flag)&flag) == 0)){ unlock(f); return; } @@ -1166,7 +1188,7 @@ syscreate(va_list list) cclose(c); nexterror(); } - fd = newfd(c); + fd = newfd(c, mode); if(fd < 0) error(Enofd); poperror();