Subject: Re: emul vs. symlinks
To: Quentin Garnier <cube@NetBSD.org>
From: Bill Studenmund <wrstuden@netbsd.org>
List: tech-kern
Date: 07/12/2004 13:13:40
--4Ckj6UjgE2iN1+kY
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable

On Sat, Jul 10, 2004 at 11:05:25AM +0200, Quentin Garnier wrote:
> Le Fri, 9 Jul 2004 19:00:44 -0700
> Bill Studenmund a ecrit :
> > I think the thing to do is either teach namei about emulations or have=
=20
> > your lookup routine enforce NOFOLLOW (i.e. clear FOLLOW) and handle=20
> > symlinks yourself.
>=20
> There is the issue der Mouse pointed out, but it's not that important in
> the general case.

I think we can address that case, and probably should.

> > Actually, since the emulation code already does the "/emul/foo/path"
> > then "/path" stuff, you just need to put a symlink handling wrapper
> > outside of that.
>=20
> No.  emul_find() only looks up in the emulation root if the target exists,
> and returns with the prefixed path in that case, and returns with the
> non-prefixed path in the other case.  That's just that.

Hmm...

> > I really think that you don't need to add your own namei() routine.
> > Since you can tell namei() to not follow symlinks and the symlink
> > following isn't hard, just do it yourself.
>=20
> Well, what namei() does is exactly that:  call lookup() and handle
> symlinks when it returns.  As ugly as it might be, it's easier to start
> from namei() than from scratch.

Yes, but namei() does more than that.

My main objection is to having two almost-the-same copies of the same=20
code. While I'd rather not tweak namei() much, I think I'd rather shuffle=
=20
the code around than make two copies of it.

Hmm... I've sat here a few minutes thinking myself in circles. So I'll=20
write my thoughts and see what you think.

My suspicion is that we want to change all calls to namei() into calls=20
that indirect off of a pointer in the emulation. The NetBSD emulation=20
points to namei(), while all emulations that play with pathing point to=20
emul_namei().

emul_namei() looks at the first four bytes of the path. If they are=20
"/../" then it does "return namei(ndp);".

Then it does a namei lookup of "/emul/foo". If this lookup fails,=20
emul_namei() just does a "return namei(ndp);". i.e. if you don't have=20
/emul/foo, then we short-circuit the special path lookup.

Then what I want us to do (which I admit needs some work) is to try the=20
namei() lookup with the result of the above lookup ("/emul/foo") as a=20
temporary process root (the fact it should really be a call-specific root=
=20
is what needs work). If it fails, then perform the lookup with the real=20
process root. Oh, we do the above namei() lookup with the "don't follow=20
any symlinks" flag set.

If we found a symlink and either it wasn't terminal or we are following=20
symlinks then we do:

	while (we found a symlink) {
		numsymlinks++;
		if (too many symlinks)
			return ELOOP;
		set "chroot" to "/emul/foo" result
		error =3D namei(ndp);
		if ((is absolute path) && (error =3D=3D ENOENT)) {
			set "chroot" to normal chroot
			error =3D namei(ndp);
		}
	}

A similar option would be to leave namei() alone, but turn it into namei()=
=20
and namei1(). namei() would do some setup, then in the normal case just=20
call namei1(). In the emulation case, it would call namei_emul() which=20
would do the above dance (changed slightly as needed) and call namei1().

Hmmm... Maybe having two versions is what we need.

I think if we do this right, we can get rid of emul_find().

Take care,

Bill

--4Ckj6UjgE2iN1+kY
Content-Type: application/pgp-signature
Content-Disposition: inline

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.3 (NetBSD)

iD8DBQFA8vDzWz+3JHUci9cRAivbAKCQDTxJMXsDLr2wmgAuaQjcWdZg6wCfT/ub
D6oJfmCPmKtmawaaAtCrIAA=
=apM4
-----END PGP SIGNATURE-----

--4Ckj6UjgE2iN1+kY--