Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 07 May 2009 20:07:46 -0700
From:      Tim Kientzle <kientzle@freebsd.org>
To:        "'freebsd-hackers@freebsd.org'" <freebsd-hackers@freebsd.org>
Subject:   fdescfs brokenness
Message-ID:  <4A03A202.2050101@freebsd.org>

next in thread | raw e-mail | index | archive | help
Colin Percival recently pointed out some issues
with tar and fdescfs.  Part of the problem
here is tar; I need to rethink some of the
traversal logic.

But fdescfs is really wonky:

  * This is a nit, but:  ls /dev/fd/18 should not
    return EBADF; it should return ENOENT, just
    like any other reference to a non-existent filename.
    (Just because a filename reflects a file descriptor
    does not mean it is a file descriptor.)

  * The fairly routine recursive directory walker
    below gets hung in fdescfs.  It appears that
    the two opendir() invocations active at the
    same time interfere with each other.

  * A similar chdir()-based version of the directory
    walker below breaks badly; you can chdir() into
    a directory under /dev/fd, but you can't chdir("..")
    to get back out of it.  (This is the particular
    problem that tar is running afoul of.)

  * Running "find /dev/fd" generates bogus ENOENT errors
    because you can opendir() a directory inside of /dev/fd,
    and read the entries, but you can't access those entries
    because path searches don't work through fdescfs.

I think the right solution here is to add a VOP_ACCESS
handler to fdescfs that bars all access to directory
nodes under /dev/fd.  Basically, if your program has a
directory open, that should be reflected as a directory
node that you can't do anything with.  The current implementation
allows you to chdir(), opendir(), etc, those directory
nodes, but the machinery to fully support those operations
is missing so they just screw things up.

I have a candidate vop_access handler partly written, but I'm
a little new to filesystem work, so it will take me
a little while to satisfy myself that it works.

/*
  *  Non-chdir directory walker.
  */
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <err.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
static char curpath[512];

void
visit(char *f, int depth)
{
	DIR *d;
	struct dirent *dp;
	size_t l = strlen(curpath);

	strcat(curpath, "/");
	strcat(curpath, f);
	printf("%3d: %s\n", depth, curpath);

	d = opendir(curpath);
	if (d != NULL) {
		while ((dp = readdir(d)) != NULL) {
			if (dp->d_name[0] == '.')
				continue;
			visit(dp->d_name, depth + 1);
		}
		closedir(d);
	}
	curpath[l] = '\0';
}

int
main(int argc, char **argv)
{
	visit("/dev/fd", 0);
	exit(0);
}



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?4A03A202.2050101>