• 1

One way to combat the leaked-fd problem...

In nash, we now have open() and friends set to use close-on-exec by default. This still doesn't help with libraries we link against, but it is a step in the right direction. For those who want to know how, here's the gest of it.

In the Makefile, do:
LDFLAGS += -Wl,--wrap,open,--wrap,fopen,--wrap,opendir,--wrap,socket,--wrap,pipe
OBJECTS = foo.o wrappers.o
$TARGET : $OBJECTS
        $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^
And then in wrappers.c do:
extern int __real_open(const char *path, int flags, ...);
extern FILE *__real_fopen(const char *path, const char *mode);
extern DIR *__real_opendir(const char *name);
extern int __real_socket(int domain, int type, int protocol);
extern int __real_pipe(int filedes[2]);

int
setFdCoe(int fd, int enable)
{
    int rc;
    long flags = 0;

    rc = fcntl(fd, F_GETFD, &flags);
    if (rc < 0)
        return rc;

    if (enable)
        flags |= FD_CLOEXEC;
    else
        flags &= ~FD_CLOEXEC;

    rc = fcntl(fd, F_SETFD, flags);
    return rc;
}

int
__wrap_open(const char *path, int flags, ...)
{
    int fd, rc, mode = 0;
    long errnum;

    if (flags & O_CREAT) {
        va_list arg;
        va_start(arg, flags);
        mode = va_arg(arg, int);
        va_end(arg);
    }

    fd = __real_open(path, flags);
    if (fd < 0)
        return fd;

    rc = setFdCoe(fd, 1);
    if (rc < 0) {
        errnum = errno;
        close(fd);
        errno = errnum;
        return rc;
    }

    return fd;
}

FILE *
__wrap_fopen(const char *path, const char *mode)
{
    FILE *f;
    int rc;
    long errnum;

    f = __real_fopen(path, mode);
    if (!f)
        return f;

    rc = setFdCoe(fileno(f), 1);
    if (rc < 0) {
        errnum = errno;
        fclose(f);
        errno = errnum;
        return NULL;
    }

    return f;
}

DIR *
__wrap_opendir(const char *name)
{
    DIR *d;
    int rc;
    long errnum;

    d = __real_opendir(name);
    if (!d)
        return d;

    rc = setFdCoe(dirfd(d), 1);
    if (rc < 0) {
        errnum = errno;
        closedir(d);
        errno = errnum;
        return NULL;
    }

    return d;
}

int
__wrap_socket(int domain, int type, int protocol)
{
    int fd;
    int rc;
    int errnum;

    fd = __real_socket(domain, type, protocol);
    if (fd < 0)
        return fd;

    rc = setFdCoe(fd, 1);
    if (rc < 0) {
        errnum = errno;
        close(fd);
        errno = errnum;
        return rc;
    }

    return fd;
}

int
__wrap_pipe(int filedes[2])
{
    int rc;
    int x;
    int fds[2];

    rc = __real_pipe(fds);
    if (rc < 0)
        return rc;

    for (x = 0; x < 2; x++) {
        int status;
        int errnum;

        status = setFdCoe(fds[x], 1);
        if (status < 0) {
            errnum = errno;
            close(fds[0]);
            close(fds[1]);
            errno = errnum;
            return status;
        }
    }
    filedes[0] = fds[0];
    filedes[1] = fds[1];

    return rc;
}

Re: One way to combat the leaked-fd problem...

(You also want to declare setFdCoe() in a header someplace, so functions that do depend on open-on-exec can mark Fds explicitly. Or they can use fcntl for it, but this API is simpler. If you always use fcntl elsewhere, then you'll want to mark setFdCoe() "static")

Re: One way to combat the leaked-fd problem...

... And for those who want to copy paste, that Makefile should be:
LDFLAGS += -Wl,--wrap,open,--wrap,fopen,--wrap,opendir,--wrap,socket,--wrap,pipe
OBJECTS = foo.o wrappers.o
$TARGET : $OBJECTS
	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^
(man, putting a tab character in a web form is harder than it shouold be)

# Integrating Ubuntu with a Windows-based network is harder than it should be *for end-users* Posted by: Anonymous [ip: .

Hey, that's a great new motto:

Ubuntu: Harder Than It Should Be.

  • 1
?

Log in