draios / sysdig

Linux system exploration and troubleshooting tool with first class support for containers
http://www.sysdig.com/
Other
7.79k stars 728 forks source link

TTY as human readable #918

Open arossert opened 7 years ago

arossert commented 7 years ago

According to this #792, the TTY value of a thread is numeric (tty_nr). How can we convert this to a human readable value like /dev/pts/11? As far as I understand from the PR, we cannot use the thread FD's (0, 1 & 2) in order to get this value?

I want to create a fix for that (and submit a PR) but I can't find any information on how to achieve this online

gianlucaborello commented 7 years ago

That would be nice.

I can give you two inspiration points:

1) Since both ps and top show the TTY as a user friendly string, just look into their code and you'll find the function dev_to_tty() that does the resolution. Essentially they rely on a bunch of information in /proc/tty + stuff in /dev.

2) It might also be worth exploring what you can get on the kernel side. In particular, struct tty_driver has some strings in it that could be useful, I haven't checked very well.

arossert commented 7 years ago

Thanks for the information. I will try to take a look

arossert commented 7 years ago

@gianlucaborello I have looked in the struct tty_driver and I was able to get the tty by doing this:

snprintf(buf, buflen, "/dev/%s/%d", driver->name, tty->index);

I'm not sure that this will always work (it worked in my small test on Ubuntu 14.04, I will try to do more test).

Also I have a piece of code based on dev_to_tty() function:

static int guess_name(char *const buf, int maj, int min) {
    struct stat sbuf;
    int t0, t1;
    int tmpmin = min;
    switch (maj) {
        case 4:
            if (min < 64) {
                sprintf(buf, "/dev/tty%d", min);
                break;
            }
            if (min < 128) /* to 255 on newer systems */
            {
                sprintf(buf, "/dev/ttyS%d", min - 64);
                break;
            }
            tmpmin = min & 0x3f;  /* FALL THROUGH */
        case 3:      /* /dev/[pt]ty[p-za-o][0-9a-z] is 936 */
            t0 = "pqrstuvwxyzabcde"[tmpmin >> 4];
            t1 = "0123456789abcdef"[tmpmin & 0x0f];
            sprintf(buf, "/dev/tty%c%c", t0, t1);
            break;
        case 17:
            sprintf(buf, "/dev/ttyH%d", min);
            break;
        case 19:
            sprintf(buf, "/dev/ttyC%d", min);
            break;
        case 22:
            sprintf(buf, "/dev/ttyD%d", min);
            break; /* devices.txt */
        case 23:
            sprintf(buf, "/dev/ttyD%d", min);
            break; /* driver code */
        case 24:
            sprintf(buf, "/dev/ttyE%d", min);
            break;
        case 32:
            sprintf(buf, "/dev/ttyX%d", min);
            break;
        case 43:
            sprintf(buf, "/dev/ttyI%d", min);
            break;
        case 46:
            sprintf(buf, "/dev/ttyR%d", min);
            break;
        case 48:
            sprintf(buf, "/dev/ttyL%d", min);
            break;
        case 57:
            sprintf(buf, "/dev/ttyP%d", min);
            break;
        case 71:
            sprintf(buf, "/dev/ttyF%d", min);
            break;
        case 75:
            sprintf(buf, "/dev/ttyW%d", min);
            break;
        case 78:
            sprintf(buf, "/dev/ttyM%d", min);
            break; /* conflict */
        case 105:
            sprintf(buf, "/dev/ttyV%d", min);
            break;
        case 112:
            sprintf(buf, "/dev/ttyM%d", min);
            break; /* conflict */
            /* 136 ... 143 are /dev/pts/0, /dev/pts/1, /dev/pts/2 ... */
        case 136 ... 143:
            sprintf(buf, "/dev/pts/%d", min + (maj - 136) * 256);
            break;
        case 148:
            sprintf(buf, "/dev/ttyT%d", min);
            break;
        case 154:
            sprintf(buf, "/dev/ttySR%d", min);
            break;
        case 156:
            sprintf(buf, "/dev/ttySR%d", min + 256);
            break;
        case 164:
            sprintf(buf, "/dev/ttyCH%d", min);
            break;
        case 166:
            sprintf(buf, "/dev/ttyACM%d", min);
            break; /* bummer, 9-char */
        case 172:
            sprintf(buf, "/dev/ttyMX%d", min);
            break;
        case 174:
            sprintf(buf, "/dev/ttySI%d", min);
            break;
        case 188:
            sprintf(buf, "/dev/ttyUSB%d", min);
            break; /* bummer, 9-char */
        default:
            return 0;
    }

    if (stat(buf, &sbuf) < 0) {
        return 0;
    }
    if (min != minor(sbuf.st_rdev)) {
        return 0;
    }
    if (maj != major(sbuf.st_rdev)) {
        return 0;
    }

    return 1;
}

int tty_nr_to_tty(char *ret, int chop, int dev) {
    static char buf[PATH_MAX];
    char *tmp = buf;
    int i = 0;
    int c;
    if ((short) dev == (short) -1) {
        strcpy(ret, "?");
        return 1;
    }

    if (guess_name(tmp, major(dev), minor(dev)) != 1) {
        strcpy(ret, "?");
        return 1;
    }

    /* gotta check before we chop or we may chop someone else's memory */
    if (tmp + chop - buf <= sizeof(buf)) {
        tmp[chop] = '\0';
    }

    /* replace non-ASCII characters with '?' and return the number of chars */
    for (;;) {
        c = *tmp;
        tmp++;
        if (!c) { break; }
        i++;
        if (c <= ' ') {
            c = '?';
        }
        if (c > 126) {
            c = '?';
        }
        *ret = c;
        ret++;
    }
    *ret = '\0';

    return i;
}

I think that this is the only thing that we need to get the TTY device, what do you think? Do you think that it should be implemented in the kernel module or only in the userspace?

I will be happy to get your opinion on this.

arossert commented 7 years ago

@gianlucaborello after more investigation I think that the struct tty_driver and struct tty_struct have enoght information so the tty_nr_to_tty() is not neccecery.

I have a couple of questions on how to implement this feature:

  1. What information to extract:

    • Use struct tty_struct member char name[64] that will give the name in this format pts12 that represents /dev/pts/12.
    • As I mentioned in the previous comment we can use struct tty_driver to build the full path like so snprintf(buf, buflen, "/dev/%s/%d", driver->name, tty->index);
  2. Where to put this information:

    • Replace the current int_32 tty value that actully represent the tty_nr to char tty[SCAP_MAX_ENV_SIZE+1]
    • Rename the current int32_t tty to int32_t tty_nr and add a new char tty[SCAP_MAX_ENV_SIZE+1]
    • Add a new char ttyname[SCAP_MAX_ENV_SIZE+1]

After deciding on this 2 subject I will submit a PR for that.

gianlucaborello commented 7 years ago

Hi,

My non-educated check point list (because I haven't worked close enough to ttys) is:

Hope that helps somehow.

arossert commented 7 years ago

Hi,

Thanks for the input.

Regarding your comments:

I will work on that and submit a PR.

pqhais commented 3 years ago

Hi,

I'm a begginer.

I spent a while reading this post but as a non experienced user, I don't feel like editing the source code myself.

Looking into the PR, I've seen some errors but @arossert claimed that some of these solutions would work for most cases.

Should I try any of these?

Thanks.

github-actions[bot] commented 1 year ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.