[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