daisy
daisy

Reputation: 23501

How to find the owner process of an opened inode in Linux kernel?

Given an inode number (an opened socket), I want to find the process that opened the socket, is that possible?

Is there any function I could use?

Upvotes: 3

Views: 5563

Answers (3)

Alexis Wilke
Alexis Wilke

Reputation: 20730

I looked at the ss tool implementation to see how they get the information when we use the -p command line option.

The fact is that they read the user entries with the following function and generate a corresponding map. Then when displaying the list of sockets, they check the map to see whether they can find the inode, if so, they have the PID.

Note that the following function needs the user to be root to find all the inode. It detects files which name are of the form socket:[<inode>] (the files under /proc/<pid>/fd/<number> are softlinks, try listing them with ls -l ... to see the special socket & FIFO entries).

static void user_ent_hash_build(void)
{
    const char *root = getenv("PROC_ROOT") ? : "/proc/";
    struct dirent *d;
    char name[1024];
    int nameoff;
    DIR *dir;
    char *pid_context;
    char *sock_context;
    const char *no_ctx = "unavailable";
    static int user_ent_hash_build_init;

    /* If show_users & show_proc_ctx set only do this once */
    if (user_ent_hash_build_init != 0)
        return;

    user_ent_hash_build_init = 1;

    strlcpy(name, root, sizeof(name));

    if (strlen(name) == 0 || name[strlen(name)-1] != '/')
        strcat(name, "/");

    nameoff = strlen(name);

    dir = opendir(name);
    if (!dir)
        return;

    while ((d = readdir(dir)) != NULL) {
        struct dirent *d1;
        char process[16];
        char *p;
        int pid, pos;
        DIR *dir1;
        char crap;

        if (sscanf(d->d_name, "%d%c", &pid, &crap) != 1)
            continue;

        if (getpidcon(pid, &pid_context) != 0)
            pid_context = strdup(no_ctx);

        snprintf(name + nameoff, sizeof(name) - nameoff, "%d/fd/", pid);
        pos = strlen(name);
        if ((dir1 = opendir(name)) == NULL) {
            free(pid_context);
            continue;
        }

        process[0] = '\0';
        p = process;

        while ((d1 = readdir(dir1)) != NULL) {
            const char *pattern = "socket:[";
            unsigned int ino;
            char lnk[64];
            int fd;
            ssize_t link_len;
            char tmp[1024];

            if (sscanf(d1->d_name, "%d%c", &fd, &crap) != 1)
                continue;

            snprintf(name+pos, sizeof(name) - pos, "%d", fd);

            link_len = readlink(name, lnk, sizeof(lnk)-1);
            if (link_len == -1)
                continue;
            lnk[link_len] = '\0';

            if (strncmp(lnk, pattern, strlen(pattern)))
                continue;

            sscanf(lnk, "socket:[%u]", &ino);

            snprintf(tmp, sizeof(tmp), "%s/%d/fd/%s",
                    root, pid, d1->d_name);

            if (getfilecon(tmp, &sock_context) <= 0)
                sock_context = strdup(no_ctx);

            if (*p == '\0') {
                FILE *fp;

                snprintf(tmp, sizeof(tmp), "%s/%d/stat",
                    root, pid);
                if ((fp = fopen(tmp, "r")) != NULL) {
                    if (fscanf(fp, "%*d (%[^)])", p) < 1)
                        ; /* ignore */
                    fclose(fp);
                }
            }
            user_ent_add(ino, p, pid, fd,
                    pid_context, sock_context);
            free(sock_context);
        }
        free(pid_context);
        closedir(dir1);
    }
    closedir(dir);
}

So, in other words, the fact is that there doesn't seem to be an inode to PID function in the kernel (or it's not made accessible to the end users).

Upvotes: 0

Sunil Bojanapally
Sunil Bojanapally

Reputation: 12658

Two ways looking at /proc which you can find it but you need to grep with the inode you want to know. In the below case check the last column for th inode's.

$ cat /proc/net/tcp 
sl  local_address rem_address   st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout inode      


The value specified in the square brackets is inode again.

$ls -l /proc/5267/fd/10
lrwx------ 1 esunboj egi 64 Feb 18 12:07 /proc/5267/fd/10 -> socket:[19950]

Upvotes: 1

DusteD
DusteD

Reputation: 1410

There is the lsof tool which does this, you can also see this using the /proc/ filsystem as answered here. How to use lsof(List Opened Files) in a C/C++ application?

Upvotes: 1

Related Questions