Skip to content

Commit 3a04ae2

Browse files
committed
Users (Linux): adds systemd fallback for user detection on Linux
Fixes #2064
1 parent dbaf8a3 commit 3a04ae2

File tree

1 file changed

+122
-2
lines changed

1 file changed

+122
-2
lines changed

src/detection/users/users_linux.c

Lines changed: 122 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
1+
#include "common/io/io.h"
2+
#include "common/properties.h"
13
#include "fastfetch.h"
24
#include "users.h"
35

6+
#include <unistd.h>
7+
48
#if FF_HAVE_UTMPX
59
#include <utmpx.h>
610
#else
@@ -15,7 +19,111 @@
1519
#include <arpa/inet.h>
1620
#endif
1721

18-
const char* ffDetectUsers(FFUsersOptions* options, FFlist* users)
22+
#if __linux__
23+
bool detectUserBySystemd(const FFstrbuf* pathUsers, FFlist* users)
24+
{
25+
FF_STRBUF_AUTO_DESTROY state = ffStrbufCreate();
26+
FF_STRBUF_AUTO_DESTROY userName = ffStrbufCreate();
27+
FF_STRBUF_AUTO_DESTROY loginTime = ffStrbufCreate();
28+
FF_STRBUF_AUTO_DESTROY sessions = ffStrbufCreate();
29+
30+
// WARNING: This is private data. Do not parse
31+
if (!ffParsePropFileValues(pathUsers->chars, 4, (FFpropquery[]) {
32+
{"NAME=", &userName},
33+
{"STATE=", &state},
34+
{"REALTIME=", &loginTime},
35+
{"ONLINE_SESSIONS=", &sessions},
36+
}) || !ffStrbufEqualS(&state, "active"))
37+
return false;
38+
39+
FFUserResult* user = FF_LIST_ADD(FFUserResult, *users);
40+
ffStrbufInitMove(&user->name, &userName);
41+
ffStrbufInit(&user->hostName);
42+
ffStrbufInit(&user->sessionName);
43+
ffStrbufInit(&user->clientIp);
44+
ffStrbufSubstrBefore(&loginTime, loginTime.length - 3); // converts us to ms
45+
user->loginTime = ffStrbufToUInt(&loginTime, 0);
46+
47+
FF_STRBUF_AUTO_DESTROY pathSessions = ffStrbufCreateS("/run/systemd/sessions/");
48+
const uint32_t pathSessionsBaseLen = pathSessions.length;
49+
50+
FF_STRBUF_AUTO_DESTROY tty = ffStrbufCreate();
51+
FF_STRBUF_AUTO_DESTROY remoteHost = ffStrbufCreate();
52+
FF_STRBUF_AUTO_DESTROY service = ffStrbufCreate();
53+
54+
char* token = NULL;
55+
size_t n = 0;
56+
while (ffStrbufGetdelim(&token, &n, ' ', &sessions))
57+
{
58+
ffStrbufSubstrBefore(&pathSessions, pathSessionsBaseLen);
59+
ffStrbufAppendS(&pathSessions, token);
60+
61+
ffStrbufClear(&remoteHost);
62+
ffStrbufClear(&service);
63+
ffStrbufClear(&tty);
64+
ffStrbufClear(&loginTime);
65+
66+
// WARNING: This is private data. Do not parse
67+
if (ffParsePropFileValues(pathSessions.chars, 4, (FFpropquery[]) {
68+
{"REMOTE_HOST=", &remoteHost},
69+
{"TTY=", &tty},
70+
{"SERVICE=", &service},
71+
{"REALTIME=", &loginTime},
72+
}) && !ffStrbufEqualS(&service, "systemd-user"))
73+
{
74+
if (remoteHost.length)
75+
{
76+
ffStrbufTrimRight(&remoteHost, ']');
77+
ffStrbufTrimLeft(&remoteHost, '[');
78+
ffStrbufInitMove(&user->hostName, &remoteHost);
79+
}
80+
else
81+
ffStrbufSetStatic(&user->hostName, "localhost");
82+
ffStrbufInitMove(&user->sessionName, tty.length ? &tty : &service);
83+
if (loginTime.length)
84+
{
85+
ffStrbufSubstrBefore(&loginTime, loginTime.length - 3); // converts us to ms
86+
user->loginTime = ffStrbufToUInt(&loginTime, 0);
87+
}
88+
break;
89+
}
90+
}
91+
92+
return true;
93+
}
94+
95+
const char* detectBySystemd(FFUsersOptions* options, FFlist* users)
96+
{
97+
// For some reason, debian/ubuntu no longer updates `/var/run/utmp` (#2064)
98+
// Query systemd instead
99+
FF_STRBUF_AUTO_DESTROY pathUsers = ffStrbufCreateS("/run/systemd/users/");
100+
101+
if (options->myselfOnly)
102+
{
103+
ffStrbufAppendUInt(&pathUsers, getuid());
104+
detectUserBySystemd(&pathUsers, users);
105+
}
106+
else
107+
{
108+
const uint32_t pathUsersBaseLen = pathUsers.length;
109+
FF_AUTO_CLOSE_DIR DIR* dirp = opendir(pathUsers.chars);
110+
if (!dirp) return "opendir(\"/run/systemd/users/\") failed";
111+
112+
struct dirent* entry;
113+
while ((entry = readdir(dirp)))
114+
{
115+
if (entry->d_type != DT_REG) continue;
116+
117+
ffStrbufAppendS(&pathUsers, entry->d_name);
118+
detectUserBySystemd(&pathUsers, users);
119+
ffStrbufSubstrBefore(&pathUsers, pathUsersBaseLen);
120+
}
121+
}
122+
return NULL;
123+
}
124+
#endif
125+
126+
const char* detectByUtmp(FFUsersOptions* options, FFlist* users)
19127
{
20128
struct utmpx* n = NULL;
21129
setutxent();
@@ -35,7 +143,7 @@ const char* ffDetectUsers(FFUsersOptions* options, FFlist* users)
35143
goto next;
36144
}
37145

38-
FFUserResult* user = (FFUserResult*) ffListAdd(users);
146+
FFUserResult* user = FF_LIST_ADD(FFUserResult, *users);
39147
ffStrbufInitS(&user->name, n->ut_user);
40148
ffStrbufInitS(&user->hostName, n->ut_host);
41149
ffStrbufInitS(&user->sessionName, n->ut_line);
@@ -68,3 +176,15 @@ const char* ffDetectUsers(FFUsersOptions* options, FFlist* users)
68176

69177
return NULL;
70178
}
179+
180+
const char* ffDetectUsers(FFUsersOptions* options, FFlist* users)
181+
{
182+
const char* err = detectByUtmp(options, users);
183+
if (err) return err;
184+
185+
#if __linux__
186+
if (users->length == 0) detectBySystemd(options, users);
187+
#endif
188+
189+
return NULL;
190+
}

0 commit comments

Comments
 (0)