diff --git a/daemon/gamemode.c b/daemon/gamemode.c index 4f53b64..ca1c143 100644 --- a/daemon/gamemode.c +++ b/daemon/gamemode.c @@ -103,7 +103,7 @@ static GameModeContext instance = { 0 }; */ static volatile bool had_context_init = false; -static GameModeClient *game_mode_client_new(pid_t pid); +static GameModeClient *game_mode_client_new(pid_t pid, char *exe); static void game_mode_client_free(GameModeClient *client); static bool game_mode_context_has_client(GameModeContext *self, pid_t client); static int game_mode_context_num_clients(GameModeContext *self); @@ -442,6 +442,7 @@ bool game_mode_context_register(GameModeContext *self, pid_t client) { /* Construct a new client if we can */ GameModeClient *cl = NULL; + char *executable = NULL; /* Cap the total number of active clients */ if (game_mode_context_num_clients(self) + 1 > MAX_GAMES) { @@ -449,11 +450,7 @@ bool game_mode_context_register(GameModeContext *self, pid_t client) return false; } - cl = game_mode_client_new(client); - if (!cl) { - fputs("OOM\n", stderr); - return false; - } + errno = 0; /* Check the PID first to spare a potentially expensive lookup for the exe */ if (game_mode_context_has_client(self, client)) { @@ -461,20 +458,27 @@ bool game_mode_context_register(GameModeContext *self, pid_t client) goto error_cleanup; } - /* Lookup the executable */ - cl->executable = game_mode_context_find_exe(client); - if (!cl->executable) + /* Lookup the executable first */ + executable = game_mode_context_find_exe(client); + if (!executable) goto error_cleanup; /* Check our blacklist and whitelist */ - if (!config_get_client_whitelisted(self->config, cl->executable)) { - LOG_MSG("Client [%s] was rejected (not in whitelist)\n", cl->executable); + if (!config_get_client_whitelisted(self->config, executable)) { + LOG_MSG("Client [%s] was rejected (not in whitelist)\n", executable); goto error_cleanup; - } else if (config_get_client_blacklisted(self->config, cl->executable)) { - LOG_MSG("Client [%s] was rejected (in blacklist)\n", cl->executable); + } else if (config_get_client_blacklisted(self->config, executable)) { + LOG_MSG("Client [%s] was rejected (in blacklist)\n", executable); goto error_cleanup; } + /* From now on we depend on the client, initialize it */ + cl = game_mode_client_new(client, executable); + if (cl) + executable = NULL; // ownership has been delegated + else + goto error_cleanup; + /* Begin a write lock now to insert our new client at list start */ pthread_rwlock_wrlock(&self->rwlock); @@ -497,7 +501,11 @@ bool game_mode_context_register(GameModeContext *self, pid_t client) game_mode_apply_ioprio(self, client); return true; + error_cleanup: + if (errno != 0) + LOG_ERROR("Failed to register client [%d]: %s\n", client, strerror(errno)); + free(executable); game_mode_client_free(cl); return false; } @@ -585,9 +593,10 @@ int game_mode_context_query_status(GameModeContext *self, pid_t client) * * This is deliberately OOM safe */ -static GameModeClient *game_mode_client_new(pid_t pid) +static GameModeClient *game_mode_client_new(pid_t pid, char *executable) { GameModeClient c = { + .executable = executable, .next = NULL, .pid = pid, };