sysdig
sysdig copied to clipboard
TTY as human readable
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
That would be nice.
I can give you two inspiration points:
-
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
. -
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:
- Use
struct tty_struct
memberchar name[64]
that will give the name in this formatpts12
that represents/dev/pts/12
. - As I mentioned in the previous comment we can use
struct tty_driver
to build the full path like sosnprintf(buf, buflen, "/dev/%s/%d", driver->name, tty->index);
- Use
-
Where to put this information:
- Replace the current
int_32 tty
value that actully represent thetty_nr
tochar tty[SCAP_MAX_ENV_SIZE+1]
- Rename the current
int32_t tty
toint32_t tty_nr
and add a newchar tty[SCAP_MAX_ENV_SIZE+1]
- Add a new
char ttyname[SCAP_MAX_ENV_SIZE+1]
- Replace the current
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:
- Prefer, if possible, a syntax consistent with
top
/w
/who
/...: that seems to bepts/0
,pts/1
, ... - Make sure everything works fine inside containers too.
- Make sure you not only get tty information at runtime from struct tty_driver like you mention, but also from /proc at startup during the initial state creation.
-
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 form_comm
and such) or build a map external to the thread table where you keep the mappingtty_nr
->tty_name
(assuming that makes sense, please check the logic).
Hope that helps somehow.
Hi,
Thanks for the input.
Regarding your comments:
- the syntax that usually is used is
/dev/pts/1
, I will do this usingsnprintf
but not sure if this is the best way to construct a string in the kernel. - I will test this with containers as well.
- I have extract the information from
/proc
using thestdin
(/proc/<pid>/fd/0). - The
SCAP_MAX_ENV_SIZE
was a mistake, it should beSCAP_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.