giampaolo / psutil

Cross-platform lib for process and system monitoring in Python
BSD 3-Clause "New" or "Revised" License
10.3k stars 1.39k forks source link

[Linux] psutil.users() always produces "host=localhost", not expected IP #2470

Closed Ixtalo closed 1 week ago

Ixtalo commented 1 week ago

Summary

Description

For python3 -c "import psutil; print(psutil.users())" it gives always "host=localhost":

suser(name='user', terminal='pts/1', host='localhost', started=..., pid=13535)

But, the expected is an IP (as long as getutent() doesn't produce ":0"/":0.0"), e.g.:

suser(name='user', terminal='pts/1', host='192.168.56.1', started=..., pid=13535)

With psutil version 5.9.0 I get the correct host='192.168.56.1'. With 6.1.0 it's always "localhost".

Is it possible that the strcmp could be the problem?

IS:

SHOULD:

I would expect the IF to check whether host is ":0" or ":0.0".

giampaolo commented 1 week ago

I think I'm misinterpreting what your saying here but here goes. Are you saying that you expect "127.0.0.1" instead of "localhost"? Current doc doesn't say that it will always be an IP, so "localhost" technically is correct. You can later use gethostbyname to resolve it to either an IPv4 or IPv6 address:

>>> socket.gethostbyname("localhost")
'127.0.0.1'
Ixtalo commented 1 week ago

Thanks @giampaolo for your response.

Yes, I'm afraid we're talking about different things here.

My issue is not with the name resolution, nor regarding localhost/127.0.0.1. I am concerned about a possibly improper use of “strcmp”.

The described problem here is that with psutil.users the host-field is always set to "localhost" - even if there is a remote connection (e.g., 192.168.56.1). This is because strcmp(..) || strcmp(...) is always 1/true.

I think, the intention of the referenced code line (for Linux X Window System check) is: IF host equals to ":0"/":0.0" THEN "localhost" ELSE host.

But, IMHO, for this to work as intended you would need (because of the lexicographical comparison done by strcmp):

if (strcmp(ut->ut_host, ":0") == 0 || strcmp(ut->ut_host, ":0.0") == 0)

A small code example:

// g++ ut_strcmp.cc -o ut_strcmp
// ./ut_strcmp :0
// ./ut_strcmp foobar
#include <iostream>
#include <cstring>

int main(int argn, char** args) {
    if (argn < 2) {
        std::cerr << "... <arg>" << std::endl;
        return 1;
    }
    const char* host = args[1];
    std::cout << "strcmp(host, :0): " << strcmp(host, ":0") << std::endl;
    std::cout << "strcmp(host, :0.0): " << strcmp(host, ":0:0") << std::endl;
    std::cout << "strcmp(..) || strcmp(...): " << (strcmp(host, ":0") || strcmp(host, ":0:0")) << std::endl;

    // incorrect
    if (strcmp(host, ":0") || strcmp(host, ":0.0"))
        std::cout << "(with no check for == 0, host this is always)  " << "localhost" << std::endl;
    else
    // never happens
        std::cout << "this never happens :(" << host << std::endl;

    // correct
    if (strcmp(host, ":0") == 0 || strcmp(host, ":0.0") == 0)
        // host is a standard X Window identifier
        std::cout << "(this is correct) " << "localhost" << std::endl;
    else
        std::cout << host << std::endl;

    return 0;
}
$ g++ ut_strcmp.cc -o ut_strcmp && ./ut_strcmp :0
strcmp(host, :0): 0
strcmp(host, :0.0): -58
strcmp(..) || strcmp(...): 1
with no check for == 0, host this is always: localhost
host: localhost

$ g++ ut_strcmp.cc -o ut_strcmp && ./ut_strcmp 192.168.56.1
strcmp(host, :0): 44
strcmp(host, :0.0): 44
strcmp(..) || strcmp(...): 1
with no check for == 0, host this is always: localhost
host: 192.168.56.1
giampaolo commented 1 week ago

Oh I get it now. And now that I re-read your first message it was clear already, but my brain malfunctioned. :) Yeah it seems we should check strcmp return code as you suggest. Feel free to make a PR or I will do it later on.

Ixtalo commented 1 week ago

@giampaolo thanks a lot! I just wanted to start the PR... ;-)

However, I can confirm that it now works (again) as expected.

I tested it with a VM with 1 login on console (tty7) and 1 remote SSH login (pts/1).

Now, fixed, correct (687695c289a84585b20f2037eee84fa11ca49b81):

In [3]: psutil.users()
Out[3]: 
[suser(name='user', terminal='tty7', host='localhost', started=1731328029.0, pid=1273),
 suser(name='user', terminal='pts/1', host='192.168.56.1', started=1731328170.0, pid=3439)]

=> host='192.168.56.1' is now correct :smile:

For comparison, before, incorrect, with bug (3d12e67a9e4af3328660d4b3a81966555d7c98bf):

In [2]: psutil.users()
Out[2]: 
[suser(name='user', terminal='tty7', host='localhost', started=1731328029.0, pid=1273),
 suser(name='user', terminal='pts/1', host='localhost', started=1731328170.0, pid=3439)]