Open arossert opened 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.
Thanks for the information. I will try to take a look
@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.
@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:
What information to extract:
struct tty_struct
member char name[64]
that will give the name in this format pts12
that represents /dev/pts/12
.struct tty_driver
to build the full path like so snprintf(buf, buflen, "/dev/%s/%d", driver->name, tty->index);
Where to put this information:
int_32 tty
value that actully represent the tty_nr
to char tty[SCAP_MAX_ENV_SIZE+1]
int32_t tty
to int32_t tty_nr
and add a new char tty[SCAP_MAX_ENV_SIZE+1]
char ttyname[SCAP_MAX_ENV_SIZE+1]
After deciding on this 2 subject I will submit a PR for that.
Hi,
My non-educated check point list (because I haven't worked close enough to ttys) is:
top
/w
/who
/...: that seems to be pts/0
, pts/1
, ...ttyname
as field is fine, but don't add a 4KB (SCAP_MAX_ENV_SIZE
) string to each thread in sinsp, the cost of that would be prohibitive. Either keep a small string (like we do for m_comm
and such) or build a map external to the thread table where you keep the mapping tty_nr
-> tty_name
(assuming that makes sense, please check the logic).Hope that helps somehow.
Hi,
Thanks for the input.
Regarding your comments:
/dev/pts/1
, I will do this using snprintf
but not sure if this is the best way to construct a string in the kernel./proc
using the stdin
(/proc/\<pid>/fd/0).SCAP_MAX_ENV_SIZE
was a mistake, it should be SCAP_MAX_PATH_SIZE
(can be smaller if we know that the syntax will be /dev/pts/...
).I will work on that and submit a PR.
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.
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.
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