[Toybox] Add remaining pwd options
Felix Janda
felix.janda at posteo.de
Thu Jan 17 11:09:07 PST 2013
On 01/13/13 at 09:57am, Rob Landley wrote:
> The kernel has two magic symlinks as part of each process's state:
>
> 1) "." which is set by chdir() and returned by getcwd().
>
> 2) "/" which is set by chroot() and not really returned by anything
> because it's what other paths are explained relative _to_.
>
> Inside the kernel, each points to a dentry, which is pinned by the
> reference so you don't have to worry about it going away. (It can be
> invalidated by deleting the dentry's attached inode, but I believe it's
> still around as a zombie until the reference count drops to zero. And
> there's a horrible magic syscall called switch_root that iterates
> through every process in the system and redirects the "." and "/" links
> of every process from one of these to another, but that does horrible
> latency spike locking.)
>
> Each dentry has a ".." link, which is not a process attribute, but a
> dentry attribute. (Or is it inode? The fact dentries aren't really
> independent of an underlying inode is half the reason you can't
> hardlink directories. Anyway, ".." is implemented by following the
> dentry parent pointer, with the exception that "/" pointing to the
> current dentry is treated the same as the dentry parent pointer being
> NULL. Yes, this means that if you go:
>
> mkdir("sub");
> chroot("sub");
> chdir("../../../../../../../../..");
> chroot(".");
>
> You can escape a chroot. Moving the "/" symlink _under_ "." means the
> .. test won't hit it, you see. There's no >= test here, just ==.
>
> Anyway, given a dentry the kernel can traverse up to the root (either
> equal to "/" or where the dentry parent pointer is NULL) to work out
> the absolute path to this dentry, and since each dentry only has one
> parent pointer there's only _one_ absolute path to a given dentry.
>
> Does that help?
Yes, it was really interesting.
> > Doesn't an unliked current working still exist for the processes
> > its the cwd of?
>
> You have a pointer to a zombie dentry, the parent pointer of which is
> NULL. It's been unlinked from the tree but won't be garbage collected
> until the reference count falls to zero. I'd guess the corresponding
> inode has been freed and thus the inode pointer is also NULL (thus
> freeing up actual disk space, unlike a filehandle to an open _file_),
> but I'd have to go look at the kernel source to know for sure.
That agrees with what I have observed. (Inside the zombie directory you
can't create files or directories. I didn't expect this at first since
I expected open dirs to act more like open files.)
> > (I was wrong about that 3) depends on whether pwd in
> > builtin or not since child processes inherit cwd.)
>
> Child processes inherit environment variables too, but a child process
> can't change the parent's attributes. (Ok, it could ptrace it but
> that's HORRIBLE and we're not doing that. Sorry, reflexive action
> anytime anyone, including me, says "you can't do X". There's usually a
> bad way to do it. I have a black belt in bad ways to do things, and a
> lot of experience in cleaning them up to look presentable. I do the
> "don't ask questions, post errors" thing to _myself_ all the time.)
As root one can of course also write to /dev/mem.
On to the $CDPATH discussion.
> > I just read
> >
> > http://landley.net/toybox/about.html:
>
> I read http://pubs.opengroup.org/onlinepubs/9699919799/utilities/cd.html
The "just" in the above quotation was of course not meant as an "only".
> > > And some things (like $CDPATH support in "cd") await a good
> > explanation
> > > of why to bother with them.
> >
> > and interpreted it as a reluctance to implement $CDPATH support.
>
> I am reluctant to implement $CDPATH support. Having a search path so
> that when you
> "cd frog" it finds /usr/ranunculus/diseases/frog is just _weird_. That
> said, someday an actual user of it might show up and change my mind.
Some days ago I read of $CDPATH for the first time in the standard. That
was a wtf moment... toybox's about page was one of the top search results.
Your stance on implementing it seems very sensible.
> > > > Then I think one can leave out step 5 on susv4's page on
> > > > cd, and "cd ." is no more special than "cd dir"; it does a chdir
> > to
> > > > "$PWD/."
> > > > or "$PWD/dir" respectively and then updates $PWD to its canonical
> > > > form. (and
> > > > modifies $OLDPWD also if necessary)
> > >
> > > Um, steps 4 and 8 are the ones that say cd . and .. are special?
> >
> > Step 4 means that $CDPATH shouldn't be taken into account when you do
> > something like "cd ./dir" or "cd ../dir".
>
> $CDPATH is not the same as $PWD. $CDPATH is a _search_path_ for cd. You
> know how when you run an executable it searches $PATH? Apparently when
> you cd to a directory it searches $CDPATH. Who knew? I didn't, and I've
> been using unix variants since the late 80's. (Well, if you count Vax
> Eunice on my father's work machine which had an amiga software library
> on it and xmodem. If you count _actual_ unix, more like 1992.)
It was just invented to make our lives more difficult.
> > In Step 8 the usual formal processes of simplifying a path (by
> > removing "."
> > dot components and so on) described.
> >
> > Of course here "." and ".." are treated specially, but this treatment
> > affects only $PWD, since chdir("/some/dir/.") should do the same as
> > chdir("/some/dir").
>
> I'm only talking about $PWD.
>
> > Step 9 looks like fun...
>
> I have an epic todo list for toysh. "cd" is a shell command, thus part
> of toysh.
Of course.
The algorithm in step 8 looks like suitable for being put into a function
in toybox/posix/sh.c.
Step 9 is new in POSIX 2008.1. It seems to exist because getcwd() may output
a path name longer than PATH_MAX bytes but chdir() might only accept path
names of size less than PATH_MAX. So Step 9 tries to convert an absolute path
name to a relative path name before passing it to chdir().
Felix
> Part of the reason I haven't been dinking at it in small amounts is
> there's so much context to keeps traight in your head I should probably
> buckle down and focus on just the shell for a couple months at some
> point, and right now the same effort completes multiple smaller
> commands.
>
> That said, I should do the basic cleanup pass (remove toybuf dependency
> that imposes command line length limitations), add basic environment
> variable support, start on conditionals (if/while/for)...
>
> But I need to finish the cleanup pass on cp. And finish the
> losetup/umount/mount chain. And review the pile of commands that are
> already in but not properly cleaned up. And figure out why current
> toolchains stopped doing proper dead function elimination (a toybox
> with just "true" on x86-64 is 15k! That's ridiculous. Admittedly a
> main() that does nothing but "return 1", built with -s -Os is 6k.
> That's gcc+glibc for you. But still, that extra 9k is sad. And if you
> objdump -d a toybox built with gcc 4.2.1 it hasn't got parse_optflags()
> in it, but one built with ubuntu's current gcc does. Yup, upstream
> toolchain regression in the ability to eliminiate dead code. The
> <strike>aristocrats</strike> free software foundation!
1358449747.0
More information about the Toybox
mailing list