[2.1.77] small patch for identifying sockets in /proc fs

Andrew Morgan (morgan@transmeta.com)
Sun, 4 Jan 1998 15:38:11 -0800 (PST)


Hi,

I've appended a small patch to reinstate the informative link to a
socket inode in the /proc/$PID/fd/* directory. This patch should work
against any recent kernel (the file it applies to has not changed
since July of last year).

Some time ago (before the dentry revolution) this directory listed a
set of symbolic links to inodes - something that was not particularly
intuitive for file/directory references. With dentries, we now get an
explicit link to the filename that the program opened: much nicer.
Unfortunately, for unnamed files, the link is listed as pointing to
"/" which is not very useful.

The reason I care about this is that I frequently need to be able to
work out which 'process' is talking to a given socket. Currently,
/proc/net/{tcp,udp,...} indicate the UID of the owner of the socket
and the inode number for the socket. With this patch it is once
again possible to identify processes that have a given socket open.

The appended patch only affects the readlink part of the link
resolution and not the filesystem's path completion. In other words,
you cannot follow the link, but you can identify a socket from it.

Sample 'ls -l' output [from /proc/$PID/fd/ of sshd]:

Before:

lr-x------ 1 root root 64 Jan 4 14:02 0 -> /dev/null
l-wx------ 1 root root 64 Jan 4 14:02 1 -> /dev/null
l-wx------ 1 root root 64 Jan 4 14:02 2 -> /dev/null
lrwx------ 1 root root 64 Jan 4 14:02 3 -> /
lrwx------ 1 root root 64 Jan 4 14:02 4 -> /dev/ptyp0
lrwx------ 1 root root 64 Jan 4 14:02 5 -> /
lrwx------ 1 root root 64 Jan 4 14:02 6 -> /dev/ptyp0

After:

lr-x------ 1 root root 64 Jan 4 14:02 0 -> /dev/null
l-wx------ 1 root root 64 Jan 4 14:02 1 -> /dev/null
l-wx------ 1 root root 64 Jan 4 14:02 2 -> /dev/null
lrwx------ 1 root root 64 Jan 4 14:02 3 -> socket:[236]
lrwx------ 1 root root 64 Jan 4 14:02 4 -> /dev/ptyp0
lrwx------ 1 root root 64 Jan 4 14:02 5 -> socket:[215]
lrwx------ 1 root root 64 Jan 4 14:02 6 -> /dev/ptyp0

The two sockets can now be identified from the contents of
/proc/net/*. In this case, inode 236 is recorded in /proc/net/unix
and 215 is recorded in /proc/net/tcp.

Linus: could you put this into 2.1.78? If nothing else, it resurrects
an old feature of 2.0.* .

Thanks

Andrew

--- linux/fs/proc/link.c Mon Jul 28 13:47:43 1997
+++ link.c.agm Sun Jan 4 11:41:14 1998
@@ -60,7 +60,16 @@
NULL /* permission */
};

-static struct dentry * proc_follow_link(struct inode *inode, struct dentry *base)
+/*
+ * here we are presented with an inode and this tells us what to probe
+ * out of the process' task structure. If the link is a file
+ * descriptor and 'inode_p' is set, we return the inode that the file
+ * descriptor refers to.
+ */
+
+static struct dentry * _proc_follow_link(struct inode *inode,
+ struct dentry *base,
+ const struct inode **inode_p)
{
struct task_struct *p;
struct dentry * result;
@@ -122,6 +131,9 @@
break;
if (!p->files->fd[ino]->f_dentry)
break;
+ if (inode_p)
+ *inode_p = p->files->fd[ino]->
+ f_dentry->d_inode;
result = dget(p->files->fd[ino]->f_dentry);
break;
}
@@ -129,10 +141,20 @@
return result;
}

+/* wrapper for real function. (We do not care about resolved inode.) */
+
+static struct dentry *proc_follow_link(struct inode *inode, struct dentry *base)
+{
+ return _proc_follow_link(inode, base, NULL);
+}
+
static int proc_readlink(struct inode * inode, char * buffer, int buflen)
{
int error;
- struct dentry * dentry = proc_follow_link(inode, NULL);
+ const struct inode *my_inode = NULL;
+ struct dentry * dentry;
+
+ dentry = _proc_follow_link(inode, NULL, &my_inode);

error = PTR_ERR(dentry);
if (!IS_ERR(dentry)) {
@@ -141,12 +163,21 @@
char * tmp = (char*)__get_free_page(GFP_KERNEL), *path;
int len;

+ /* default path ("/" => this may be 'special') */
path = d_path(dentry, tmp, PAGE_SIZE);
+ dput(dentry);
len = tmp + PAGE_SIZE - path;

+ /* handle special cases */
+ if (len == 2 && *path == '/' && my_inode) {
+ if (my_inode->i_sock) {
+ len = sprintf(path=tmp, "socket:[%lu]",
+ my_inode->i_ino);
+ }
+ }
+
if (len < buflen)
- buflen = len;
- dput(dentry);
+ buflen = len;
copy_to_user(buffer, path, buflen);
free_page((unsigned long)tmp);
error = buflen;