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
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