/* * dup2 is not thread safe */ int dup2(int oldfd, int newfd) { struct fd_info *oldfdi, *newfdi; int ret; init_preload(); oldfdi = idm_lookup(&idm, oldfd); if (oldfdi) { if (oldfdi->state == fd_fork_passive) fork_passive(oldfd); else if (oldfdi->state == fd_fork_active) fork_active(oldfd); } newfdi = idm_lookup(&idm, newfd); if (newfdi) { /* newfd cannot have been dup'ed directly */ if (atomic_get(&newfdi->refcnt) > 1) return ERR(EBUSY); close(newfd); } ret = real.dup2(oldfd, newfd); if (!oldfdi || ret != newfd) return ret; newfdi = calloc(1, sizeof *newfdi); if (!newfdi) { close(newfd); return ERR(ENOMEM); } pthread_mutex_lock(&mut); idm_set(&idm, newfd, newfdi); pthread_mutex_unlock(&mut); newfdi->fd = oldfdi->fd; newfdi->type = oldfdi->type; if (oldfdi->dupfd != -1) { newfdi->dupfd = oldfdi->dupfd; oldfdi = idm_lookup(&idm, oldfdi->dupfd); } else { newfdi->dupfd = oldfd; } atomic_init(&newfdi->refcnt); atomic_set(&newfdi->refcnt, 1); atomic_inc(&oldfdi->refcnt); return newfd; }
static inline enum fd_type fd_fork_get(int index, int *fd) { struct fd_info *fdi; fdi = idm_lookup(&idm, index); if (fdi) { if (fdi->state == fd_fork_passive) fork_passive(index); else if (fdi->state == fd_fork_active) fork_active(index); *fd = fdi->fd; return fdi->type; } else { *fd = index; return fd_normal; } }