@@ -31,8 +31,14 @@ POSSIBILITY OF SUCH DAMAGE.
3131
3232#define _GNU_SOURCE
3333
34+ #include <common-helpers.h>
35+ #include <common-pidfds.h>
36+
3437#include <dbus/dbus.h>
38+ #include <errno.h>
3539#include <stdio.h>
40+ #include <stdlib.h>
41+ #include <string.h>
3642#include <sys/stat.h>
3743#include <sys/types.h>
3844#include <unistd.h>
@@ -54,6 +60,7 @@ POSSIBILITY OF SUCH DAMAGE.
5460#define _cleanup_bus_ _cleanup_(hop_off_the_bus)
5561#define _cleanup_msg_ _cleanup_(cleanup_msg)
5662#define _cleanup_dpc_ _cleanup_(cleanup_pending_call)
63+ #define _cleanup_fds_ _cleanup_(cleanup_fd_array)
5764
5865#ifdef NDEBUG
5966#define DEBUG (...)
@@ -73,6 +80,35 @@ static int log_error(const char *fmt, ...) __attribute__((format(printf, 1, 2)))
7380// Storage for error strings
7481static char error_string [512 ] = { 0 };
7582
83+ // memory helpers
84+ static void cleanup_fd_array (int * * fdlist )
85+ {
86+ if (fdlist == NULL || * fdlist == NULL )
87+ return ;
88+
89+ int errsave = errno ;
90+ for (int * fd = * fdlist ; * fd != -1 ; fd ++ ) {
91+ TRACE ("GM Closing fd %d\n" , * fd );
92+ (void )close (* fd );
93+ }
94+
95+ errno = errsave ;
96+ free (* fdlist );
97+ }
98+
99+ // Allocate a -1 termianted array of ints
100+ static inline int * alloc_fd_array (int n )
101+ {
102+ int * fds ;
103+
104+ size_t count = (size_t )n + 1 ; /* -1, terminated */
105+ fds = (int * )malloc (sizeof (int ) * count );
106+ for (size_t i = 0 ; i < count ; i ++ )
107+ fds [i ] = -1 ;
108+
109+ return fds ;
110+ }
111+
76112// Helper to check if we are running inside a flatpak
77113static int in_flatpak (void )
78114{
@@ -136,32 +172,62 @@ static DBusConnection *hop_on_the_bus(void)
136172/* cleanup functions */
137173static void cleanup_msg (DBusMessage * * msg )
138174{
139- if (msg == NULL )
175+ if (msg == NULL || * msg == NULL )
140176 return ;
141177
142178 dbus_message_unref (* msg );
143179}
144180
145181static void cleanup_pending_call (DBusPendingCall * * call )
146182{
147- if (call == NULL )
183+ if (call == NULL || * call == NULL )
148184 return ;
149185
150186 dbus_pending_call_unref (* call );
151187}
152188
153189/* internal API */
154- static int make_request (DBusConnection * bus ,
155- int native , const char * method ,
156- pid_t * pids , int npids ,
157- DBusError * error )
190+ static int make_request (DBusConnection * bus , int native , int use_pidfds , const char * method ,
191+ pid_t * pids , int npids , DBusError * error )
158192{
159193 _cleanup_msg_ DBusMessage * msg = NULL ;
160194 _cleanup_dpc_ DBusPendingCall * call = NULL ;
195+ _cleanup_fds_ int * fds = NULL ;
196+ char action [256 ] = {
197+ 0 ,
198+ };
161199 DBusError err ;
162200 DBusMessageIter iter ;
163201 int res = -1 ;
164202
203+ TRACE ("GM: Incoming request: %s, npids: %d, native: %d pifds: %d\n" ,
204+ method ,
205+ npids ,
206+ native ,
207+ use_pidfds );
208+
209+ if (use_pidfds ) {
210+ fds = alloc_fd_array (npids );
211+
212+ res = open_pidfds (pids , fds , npids );
213+ if (res != npids ) {
214+ dbus_set_error (error , DBUS_ERROR_FAILED , "Could not open pidfd for %d" , (int )pids [res ]);
215+ return -1 ;
216+ }
217+
218+ if (strstr (method , "ByPID" ))
219+ snprintf (action , sizeof (action ), "%sFd" , method );
220+ else
221+ snprintf (action , sizeof (action ), "%sByPIDFd" , method );
222+ method = action ;
223+ }
224+
225+ TRACE ("GM: Making request: %s, npids: %d, native: %d pifds: %d\n" ,
226+ method ,
227+ npids ,
228+ native ,
229+ use_pidfds );
230+
165231 // If we are inside a flatpak we need to talk to the portal instead
166232 const char * dest = native ? DAEMON_DBUS_NAME : PORTAL_DBUS_NAME ;
167233 const char * path = native ? DAEMON_DBUS_PATH : PORTAL_DBUS_PATH ;
@@ -170,15 +236,24 @@ static int make_request(DBusConnection *bus,
170236 msg = dbus_message_new_method_call (dest , path , iface , method );
171237
172238 if (!msg ) {
173- dbus_set_error_const (error , DBUS_ERROR_FAILED ,
174- "Could not create dbus message" );
239+ dbus_set_error_const (error , DBUS_ERROR_FAILED , "Could not create dbus message" );
175240 return -1 ;
176241 }
177242
178243 dbus_message_iter_init_append (msg , & iter );
244+
179245 for (int i = 0 ; i < npids ; i ++ ) {
180- dbus_int32_t p = (dbus_int32_t )pids [i ];
181- dbus_message_iter_append_basic (& iter , DBUS_TYPE_INT32 , & p );
246+ dbus_int32_t p ;
247+ int type ;
248+
249+ if (use_pidfds ) {
250+ type = DBUS_TYPE_UNIX_FD ;
251+ p = (dbus_int32_t )fds [i ];
252+ } else {
253+ type = DBUS_TYPE_INT32 ;
254+ p = (dbus_int32_t )pids [i ];
255+ }
256+ dbus_message_iter_append_basic (& iter , type , & p );
182257 }
183258
184259 dbus_connection_send_with_reply (bus , msg , & call , -1 );
@@ -190,21 +265,22 @@ static int make_request(DBusConnection *bus,
190265 msg = dbus_pending_call_steal_reply (call );
191266
192267 if (msg == NULL ) {
193- dbus_set_error_const (error , DBUS_ERROR_FAILED ,
194- "Did not receive a reply" );
268+ dbus_set_error_const (error , DBUS_ERROR_FAILED , "Did not receive a reply" );
195269 return -1 ;
196270 }
197271
198272 dbus_error_init (& err );
199-
273+ res = -1 ;
200274 if (dbus_set_error_from_message (& err , msg )) {
201- dbus_set_error (error , err .name ,
202- "Could not call method '%s' on '%s': %s" ,
203- method , dest , err .message );
275+ dbus_set_error (error ,
276+ err .name ,
277+ "Could not call method '%s' on '%s': %s" ,
278+ method ,
279+ dest ,
280+ err .message );
204281 } else if (!dbus_message_iter_init (msg , & iter ) ||
205- dbus_message_iter_get_arg_type (& iter ) != DBUS_TYPE_INT32 ) {
206- dbus_set_error (error , DBUS_ERROR_INVALID_SIGNATURE ,
207- "Failed to parse response" );
282+ dbus_message_iter_get_arg_type (& iter ) != DBUS_TYPE_INT32 ) {
283+ dbus_set_error (error , DBUS_ERROR_INVALID_SIGNATURE , "Failed to parse response" );
208284 } else {
209285 dbus_message_iter_get_basic (& iter , & res );
210286 }
@@ -219,14 +295,20 @@ static int make_request(DBusConnection *bus,
219295static int gamemode_request (const char * method , pid_t for_pid )
220296{
221297 _cleanup_bus_ DBusConnection * bus = NULL ;
298+ static int use_pidfs = 1 ;
222299 DBusError err ;
223- pid_t pids [2 ] = { 0 , for_pid } ;
300+ pid_t pids [2 ];
224301 int npids ;
225302 int native ;
226303 int res = -1 ;
227304
228305 native = !in_flatpak ();
306+
307+ /* we setup the array such that pids[1] will always be a
308+ * valid pid, either for_pid as given, or same as pid[0],
309+ * because that simplifies the logic in case of use_pidfs */
229310 pids [0 ] = getpid ();
311+ pids [1 ] = for_pid != 0 ? for_pid : pids [0 ];
230312
231313 TRACE ("GM: [%d] request '%s' received (for pid: %d) [portal: %s]\n" ,
232314 (int )pids [0 ],
@@ -239,12 +321,23 @@ static int gamemode_request(const char *method, pid_t for_pid)
239321 if (bus == NULL )
240322 return -1 ;
241323
242- npids = for_pid > 0 ? 2 : 1 ;
243-
244324 dbus_error_init (& err );
245- res = make_request (bus , native , method , pids , npids , & err );
325+ retry :
326+ if (for_pid != 0 || use_pidfs )
327+ npids = 2 ;
328+ else
329+ npids = 1 ;
330+
331+ res = make_request (bus , native , use_pidfs , method , pids , npids , & err );
332+
333+ if (res == -1 && use_pidfs && dbus_error_is_set (& err )) {
334+ TRACE ("GM: Request with pidfds failed (%s). Retrying.\n" , err .message );
335+ use_pidfs = 0 ;
336+ dbus_error_free (& err );
337+ goto retry ;
338+ }
246339
247- if (res == -1 )
340+ if (res == -1 && dbus_error_is_set ( & err ) )
248341 log_error ("D-Bus error: %s" , err .message );
249342
250343 TRACE ("GM: [%d] request '%s' done: %d\n" , (int )pids [0 ], method , res );
0 commit comments