Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

What happened to my /proc/curproc/file?

1 view
Skip to first unread message

Sam Varshavchik

unread,
Sep 3, 2012, 9:52:44 PM9/3/12
to freebsd...@freebsd.org
Am I the only one who's seeing this weirdness with procfs on 9.0-RELEASE-p3.
Unless I'm overlooking something stupid, a process that rmdir(2)s a
subdirectory of its current directory ends up with a broken
/proc/curproc/file symlink:

[mrsam@freebsd ~/stasher/stasher]$ cat t.c
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>

void dump(int n)
{
char buf[2048];

printf("Line %d, rc=%s\n", n,
(readlink("/proc/curproc/file", buf, 2048) < 0 ? "err":"ok"));
}

int main(int argc, char **argv)
{
dump(__LINE__);
mkdir("conftestdir.tst", 0777);
rmdir("conftestdir.tst");
dump(__LINE__);
}
[mrsam@freebsd ~/stasher/stasher]$ cc -o t t.c
[mrsam@freebsd ~/stasher/stasher]$ ./t
Line 15, rc=ok
Line 18, rc=err

???????

Konstantin Belousov

unread,
Sep 4, 2012, 6:15:59 AM9/4/12
to Sam Varshavchik, freebsd...@freebsd.org
The procfs links, as well as any other user of vn_fullpath(9) function,
can only translate a vnode to path if namecache contains useful data.
As such, the facilities are not guaranteed to success all the time.

In case of rmdir(2), UFS explicitely purges the cache for directory which
contained direntry of the removed directory. I suspect that you have
your test program binary located in the same directory which was the parent
of the removed one.

Similar purge is done by UFS for directories which are the sources or
destinations of the move.


Sam Varshavchik

unread,
Sep 4, 2012, 7:11:49 AM9/4/12
to freebsd...@freebsd.org
Konstantin Belousov writes:

> The procfs links, as well as any other user of vn_fullpath(9) function,
> can only translate a vnode to path if namecache contains useful data.
> As such, the facilities are not guaranteed to success all the time.
>
> In case of rmdir(2), UFS explicitely purges the cache for directory which
> contained direntry of the removed directory. I suspect that you have
> your test program binary located in the same directory which was the parent
> of the removed one.

Correct. Looks like the same thing applies if I try to use sysctl to get
KERN_PROC_PATHNAME.

I need some reliable way to get a process's executable file's name, as long
as it's meaningful (the executable file hasn't been removed).


John Baldwin

unread,
Sep 4, 2012, 3:19:19 PM9/4/12
to freebsd...@freebsd.org, Sam Varshavchik
There isn't one. What if the file is renamed, or what if it was executed via
a symlink that has been removed? What if there are multiple hard links, which
one is the "correct" path to return? The namecache bits are a best effort, but
if those are purged, the only approach are left with is a brute-force crawl of
the filesystem looking for a file whose stat() results match your executable.

--
John Baldwin
_______________________________________________
freebsd...@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-hackers
To unsubscribe, send any mail to "freebsd-hacke...@freebsd.org"

Sam Varshavchik

unread,
Sep 4, 2012, 7:47:26 PM9/4/12
to freebsd...@freebsd.org
John Baldwin writes:

> On Tuesday, September 04, 2012 7:10:42 am Sam Varshavchik wrote:
> > Konstantin Belousov writes:
> >
> > > The procfs links, as well as any other user of vn_fullpath(9) function,
> > > can only translate a vnode to path if namecache contains useful data.
> > > As such, the facilities are not guaranteed to success all the time.
> > >
> > > In case of rmdir(2), UFS explicitely purges the cache for directory which
> > > contained direntry of the removed directory. I suspect that you have
> > > your test program binary located in the same directory which was the
> parent
> > > of the removed one.
> >
> > Correct. Looks like the same thing applies if I try to use sysctl to get
> > KERN_PROC_PATHNAME.
> >
> > I need some reliable way to get a process's executable file's name, as long
> > as it's meaningful (the executable file hasn't been removed).
>
> There isn't one. What if the file is renamed, or what if it was executed via
> a symlink that has been removed?

If the file is renamed, shouldn't its new name be known? If I give the
file's supposed new name to realpath(3), its man page says I'll get back
the equivalent absolute pathname. Works for me.

And, I thought that the resolved pathname, in any case, would be the one
after all the symlink resolution takes place, like /proc shows on Linux: if,
say, I have /usr/local symlinked to /mnt/local-mnt,
exec("/usr/local/bin/furgle") gives me a process that, according to /proc,
is /mnt/local-mnt/bin/furgle.

> What if there are multiple hard links,
> which
> one is the "correct" path to return?

I would say whichever one of them was used to exec() the process. But either
one would be ok, I suppose.

> The namecache bits are a best effort,
> but
> if those are purged, the only approach are left with is a brute-force crawl
> of
> the filesystem looking for a file whose stat() results match your executable.

Well, for logging purposes, after I get a client process's credentials
passed through a domain socket, I was hoping to use the credentials' pid to
log the process's executable name. At least that's the code that I'm porting
is doing; but this is going to throw a big monkey wrench into the whole
thing.

Is the dev+ino of what was exec()ed known, for another process? I might be
able to get the client voluntarily submit its argv[0], then independently
have the server validate it by stat()ing that, and comparing the result
against what the kernel says the process's inode is.

John Baldwin

unread,
Sep 7, 2012, 11:10:44 AM9/7/12
to freebsd...@freebsd.org, Sam Varshavchik
On Tuesday, September 04, 2012 7:46:23 pm Sam Varshavchik wrote:
> John Baldwin writes:
>
> > On Tuesday, September 04, 2012 7:10:42 am Sam Varshavchik wrote:
> > > Konstantin Belousov writes:
> > >
> > > > The procfs links, as well as any other user of vn_fullpath(9) function,
> > > > can only translate a vnode to path if namecache contains useful data.
> > > > As such, the facilities are not guaranteed to success all the time.
> > > >
> > > > In case of rmdir(2), UFS explicitely purges the cache for directory which
> > > > contained direntry of the removed directory. I suspect that you have
> > > > your test program binary located in the same directory which was the parent
> > > > of the removed one.
> > >
> > > Correct. Looks like the same thing applies if I try to use sysctl to get
> > > KERN_PROC_PATHNAME.
> > >
> > > I need some reliable way to get a process's executable file's name, as long
> > > as it's meaningful (the executable file hasn't been removed).
> >
> > There isn't one. What if the file is renamed, or what if it was executed via
> > a symlink that has been removed?
>
> If the file is renamed, shouldn't its new name be known? If I give the
> file's supposed new name to realpath(3), its man page says I'll get back
> the equivalent absolute pathname. Works for me.

What if it was renamed by a different NFS client? :)

Also, files don't have backreferences to all their open file descriptors.
Even if they did they would have to have different sets for different paths.
That is a lot of overhead to maintain in the kernel, and it isn't maintained.
All the kernel effectively has internally is an i-node.

> And, I thought that the resolved pathname, in any case, would be the one
> after all the symlink resolution takes place, like /proc shows on Linux: if,
> say, I have /usr/local symlinked to /mnt/local-mnt,
> exec("/usr/local/bin/furgle") gives me a process that, according to /proc,
> is /mnt/local-mnt/bin/furgle.

That is what you would get by reverse-walking the name cache for
/proc/curproc/file as well.

> > The namecache bits are a best effort,
> > but
> > if those are purged, the only approach are left with is a brute-force crawl
> > of
> > the filesystem looking for a file whose stat() results match your executable.
>
> Well, for logging purposes, after I get a client process's credentials
> passed through a domain socket, I was hoping to use the credentials' pid to
> log the process's executable name. At least that's the code that I'm porting
> is doing; but this is going to throw a big monkey wrench into the whole
> thing.

Do you need the whole path or just the command name? The command name is
stored in the kernel, and if you know the other process' pid you can fetch
that via kvm_getprocs().

> Is the dev+ino of what was exec()ed known, for another process? I might be
> able to get the client voluntarily submit its argv[0], then independently
> have the server validate it by stat()ing that, and comparing the result
> against what the kernel says the process's inode is.

It's known in the kernel certainly. I don't think we currently have any way
of exporting that info to userland however.

Konstantin Belousov

unread,
Sep 7, 2012, 12:01:15 PM9/7/12
to John Baldwin, Sam Varshavchik, freebsd...@freebsd.org
It is, as KF_FD_TYPE_TEXT by sysctl kern.proc.filedesc.

John Baldwin

unread,
Sep 7, 2012, 12:26:14 PM9/7/12
to Konstantin Belousov, Sam Varshavchik, freebsd...@freebsd.org
That doesn't include stat info though IIRC. You can get a pathname that is
the same you would get from /proc/curproc/file (so it may fail and be empty),
but you don't get st_dev or st_ino.

I have thought that it might be useful for kinfo_file to include a full
'struct stat' and use the fo_stat() method of each file to fill it in, but
that is not present currently.

Konstantin Belousov

unread,
Sep 7, 2012, 12:40:57 PM9/7/12
to John Baldwin, Sam Varshavchik, freebsd...@freebsd.org
On Fri, Sep 07, 2012 at 12:23:54PM -0400, John Baldwin wrote:
> On Friday, September 07, 2012 11:59:36 am Konstantin Belousov wrote:
> > On Fri, Sep 07, 2012 at 10:33:52AM -0400, John Baldwin wrote:
> > > On Tuesday, September 04, 2012 7:46:23 pm Sam Varshavchik wrote:
> > > > Is the dev+ino of what was exec()ed known, for another process? I might be
> > > > able to get the client voluntarily submit its argv[0], then independently
> > > > have the server validate it by stat()ing that, and comparing the result
> > > > against what the kernel says the process's inode is.
> > >
> > > It's known in the kernel certainly. I don't think we currently have any way
> > > of exporting that info to userland however.
> >
> > It is, as KF_FD_TYPE_TEXT by sysctl kern.proc.filedesc.
>
> That doesn't include stat info though IIRC. You can get a pathname that is
> the same you would get from /proc/curproc/file (so it may fail and be empty),
> but you don't get st_dev or st_ino.
>
> I have thought that it might be useful for kinfo_file to include a full
> 'struct stat' and use the fo_stat() method of each file to fill it in, but
> that is not present currently.

ino is in kf_file_fileid, and rdev in kf_file_rdev. Also there is
fsid in kf_file_fsid.

John Baldwin

unread,
Sep 7, 2012, 2:21:38 PM9/7/12
to Konstantin Belousov, Sam Varshavchik, freebsd...@freebsd.org
Oh, foo. I was looking at the 'o' variants.
0 new messages