Browse Source

Implement game_mode_query_status_for as well

Marc Di Luzio 6 years ago
parent
commit
c2f7e971c6
5 changed files with 99 additions and 0 deletions
  1. 23 0
      daemon/dbus_messaging.c
  2. 32 0
      daemon/gamemode.c
  3. 11 0
      daemon/gamemode.h
  4. 6 0
      lib/client_impl.c
  5. 27 0
      lib/gamemode_client.h

+ 23 - 0
daemon/dbus_messaging.c

@@ -162,6 +162,27 @@ static int method_unregister_game_by_pid(sd_bus_message *m, void *userdata,
 	return sd_bus_reply_method_return(m, "i", reply);
 }
 
+/**
+ * Handles the QueryStatus D-BUS Method
+ */
+static int method_query_status_for(sd_bus_message *m, void *userdata,
+                                   __attribute__((unused)) sd_bus_error *ret_error)
+{
+	int callerpid = 0;
+	int gamepid = 0;
+	GameModeContext *context = userdata;
+
+	int ret = sd_bus_message_read(m, "ii", &callerpid, &gamepid);
+	if (ret < 0) {
+		LOG_ERROR("Failed to parse input parameters: %s\n", strerror(-ret));
+		return ret;
+	}
+
+	int status = game_mode_context_query_status_for(context, (pid_t)callerpid, (pid_t)gamepid);
+
+	return sd_bus_reply_method_return(m, "i", status);
+}
+
 /**
  * D-BUS vtable to dispatch virtual methods
  */
@@ -174,6 +195,8 @@ static const sd_bus_vtable gamemode_vtable[] =
 	                SD_BUS_VTABLE_UNPRIVILEGED),
 	  SD_BUS_METHOD("UnregisterGameByPID", "ii", "i", method_unregister_game_by_pid,
 	                SD_BUS_VTABLE_UNPRIVILEGED),
+	  SD_BUS_METHOD("QueryStatusFor", "ii", "i", method_query_status_for,
+	                SD_BUS_VTABLE_UNPRIVILEGED),
 	  SD_BUS_VTABLE_END };
 
 /**

+ 32 - 0
daemon/gamemode.c

@@ -568,6 +568,38 @@ error_cleanup:
 	return status;
 }
 
+/**
+ * Request status on behalf of caller
+ */
+int game_mode_context_query_status_for(GameModeContext *self, pid_t callerpid, pid_t gamepid)
+{
+	int status = 0;
+
+	/* Lookup the executable first */
+	char *executable = game_mode_context_find_exe(callerpid);
+	if (!executable) {
+		status = -1;
+		goto error_cleanup;
+	}
+
+	/* Check our blacklist and whitelist */
+	if (!config_get_supervisor_whitelisted(self->config, executable)) {
+		LOG_MSG("Supervisor [%s] was rejected (not in whitelist)\n", executable);
+		status = -2;
+		goto error_cleanup;
+	} else if (config_get_supervisor_blacklisted(self->config, executable)) {
+		LOG_MSG("Supervisor [%s] was rejected (in blacklist)\n", executable);
+		status = -2;
+		goto error_cleanup;
+	}
+	/* Checks cleared, call the original query */
+	return game_mode_context_query_status(self, gamepid);
+
+error_cleanup:
+	free(executable);
+	return status;
+}
+
 /**
  * Construct a new GameModeClient for the given process ID
  *

+ 11 - 0
daemon/gamemode.h

@@ -111,6 +111,17 @@ int game_mode_context_register_by_pid(GameModeContext *self, pid_t callerpid, pi
  */
 int game_mode_context_unregister_by_pid(GameModeContext *self, pid_t callerpid, pid_t gamepid);
 
+/**
+ * Query the current status of gamemode for another process
+ *
+ * @param pid Process ID for the remote client
+ * @returns Positive if gamemode is active
+ *          1 if gamemode is active but the client is not registered
+ *          2 if gamemode is active and the client is registered
+ *          -2 if this supervisor was rejected
+ */
+int game_mode_context_query_status_for(GameModeContext *self, pid_t callerpid, pid_t gamepid);
+
 /**
  * Query the config of a gamemode context
  *

+ 6 - 0
lib/client_impl.c

@@ -124,3 +124,9 @@ extern int real_gamemode_register_end_for(pid_t pid)
 {
 	return gamemode_request("UnregisterGameByPID", pid);
 }
+
+// Wrapper to call QueryStatusFor
+extern int real_gamemode_query_status_for(pid_t pid)
+{
+	return gamemode_request("QueryStatusFor", pid);
+}

+ 27 - 0
lib/gamemode_client.h

@@ -58,6 +58,10 @@ POSSIBILITY OF SUCH DAMAGE.
  *   -1 if the request failed
  *   -2 if the request was rejected
  *
+ * int gamemode_query_status_for(pid_t pid) - Query the current status of gamemode for another
+ * process 0 if gamemode is inactive 1 if gamemode is active 2 if gamemode is active and this client
+ * is registered -1 if the query failed
+ *
  * const char* gamemode_error_string() - Get an error string
  *   returns a string describing any of the above errors
  */
@@ -95,6 +99,7 @@ static api_call_return_int REAL_internal_gamemode_query_status = NULL;
 static api_call_return_cstring REAL_internal_gamemode_error_string = NULL;
 static api_call_pid_return_int REAL_internal_gamemode_request_start_for = NULL;
 static api_call_pid_return_int REAL_internal_gamemode_request_end_for = NULL;
+static api_call_pid_return_int REAL_internal_gamemode_query_status_for = NULL;
 
 /**
  * Internal helper to perform the symbol binding safely.
@@ -166,6 +171,10 @@ __attribute__((always_inline)) static inline int internal_load_libgamemode(void)
 		  (void **)&REAL_internal_gamemode_request_end_for,
 		  sizeof(REAL_internal_gamemode_request_end_for),
 		  false },
+		{ "real_gamemode_query_status_for",
+		  (void **)&REAL_internal_gamemode_query_status_for,
+		  sizeof(REAL_internal_gamemode_query_status_for),
+		  false },
 	};
 
 	void *libgamemode = NULL;
@@ -330,4 +339,22 @@ __attribute__((always_inline)) static inline int gamemode_request_end_for(pid_t
 	return REAL_internal_gamemode_request_end_for(pid);
 }
 
+/* Redirect to the real libgamemode */
+__attribute__((always_inline)) static inline int gamemode_query_status_for(pid_t pid)
+{
+	/* Need to load gamemode */
+	if (internal_load_libgamemode() < 0) {
+		return -1;
+	}
+
+	if (REAL_internal_gamemode_query_status_for == NULL) {
+		snprintf(internal_gamemode_client_error_string,
+		         sizeof(internal_gamemode_client_error_string),
+		         "gamemode_query_status_for missing (older host?)");
+		return -1;
+	}
+
+	return REAL_internal_gamemode_query_status_for(pid);
+}
+
 #endif // CLIENT_GAMEMODE_H