Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add RestartGamemode command #521

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions daemon/gamemode-context.c
Original file line number Diff line number Diff line change
Expand Up @@ -857,6 +857,49 @@ int game_mode_context_query_status(GameModeContext *self, pid_t client, pid_t re
return ret;
}

int game_mode_context_restart(GameModeContext *self, pid_t client, pid_t requester)
{
/* First check the requester settings */
{
char *executable = game_mode_context_find_exe(requester);
if (!executable) {
return -1;
}

/* Check our blacklist and whitelist */
if (!config_get_supervisor_whitelisted(self->config, executable)) {
LOG_MSG("Supervisor [%s] was rejected (not in whitelist)\n", executable);
free(executable);
return -2;
} else if (config_get_supervisor_blacklisted(self->config, executable)) {
LOG_MSG("Supervisor [%s] was rejected (in blacklist)\n", executable);
free(executable);
return -2;
}

free(executable);
}

/*
* Check the current refcount on gamemode, this equates to whether gamemode is active or not,
* see game_mode_context_register and game_mode_context_unregister
*/
if (!atomic_load_explicit(&self->refcount, memory_order_seq_cst)) {
return 1;
}

/* Requires locking. */
pthread_rwlock_rdlock(&self->rwlock);

game_mode_context_leave(self);
game_mode_context_enter(self);

/* Unlock here, potentially yielding */
pthread_rwlock_unlock(&self->rwlock);

return 0;
}

/**
* Construct a new GameModeClient for the given process ID
*
Expand Down
21 changes: 21 additions & 0 deletions daemon/gamemode-dbus.c
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,26 @@ static int method_query_status(sd_bus_message *m, void *userdata,
return sd_bus_reply_method_return(m, "i", status);
}

/**
* Handles the RestartGamemode D-BUS Method
*/
static int method_restart_gamemode(sd_bus_message *m, void *userdata,
__attribute__((unused)) sd_bus_error *ret_error)
{
int pid = 0;
GameModeContext *context = userdata;

int ret = sd_bus_message_read(m, "i", &pid);
if (ret < 0) {
LOG_ERROR("Failed to parse input parameters: %s\n", strerror(-ret));
return ret;
}

int status = game_mode_context_restart(context, (pid_t)pid, (pid_t)pid);

return sd_bus_reply_method_return(m, "i", status);
}

/**
* Handles the RegisterGameByPID D-BUS Method
*/
Expand Down Expand Up @@ -402,6 +422,7 @@ static const sd_bus_vtable gamemode_vtable[] = {
SD_BUS_METHOD("RegisterGame", "i", "i", method_register_game, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("UnregisterGame", "i", "i", method_unregister_game, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("QueryStatus", "i", "i", method_query_status, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("RestartGamemode", "i", "i", method_restart_gamemode, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("RegisterGameByPID", "ii", "i", method_register_game_by_pid,
SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("UnregisterGameByPID", "ii", "i", method_unregister_game_by_pid,
Expand Down
10 changes: 10 additions & 0 deletions daemon/gamemode.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,16 @@ int game_mode_context_unregister(GameModeContext *self, pid_t pid, pid_t request
*/
int game_mode_context_query_status(GameModeContext *self, pid_t pid, pid_t requester);

/**
* Restart gamemode if it is running
*
* @param pid Process ID for the remote client
* @returns 0 if gamemode was restarted
* 1 if gamemode was already deactivated
* -2 if this request was rejected
*/
int game_mode_context_restart(GameModeContext *self, pid_t pid, pid_t requester);

/**
* Query the config of a gamemode context
*
Expand Down
30 changes: 25 additions & 5 deletions daemon/gamemoded.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ POSSIBILITY OF SUCH DAMAGE.
" When no PID given, requests gamemode and pauses\n" \
" -s[PID], --status=[PID] Query the status of gamemode for process\n" \
" When no PID given, queries the status globally\n" \
" -R, --reset If gamemode is currently running, stop it, then restart\n" \
" -d, --daemonize Daemonize self after launch\n" \
" -l, --log-to-syslog Log to syslog\n" \
" -t, --test Run tests\n" \
Expand Down Expand Up @@ -158,12 +159,17 @@ int main(int argc, char *argv[])

/* Options struct for getopt_long */
static struct option long_options[] = {
{ "daemonize", no_argument, 0, 'd' }, { "log-to-syslog", no_argument, 0, 'l' },
{ "request", optional_argument, 0, 'r' }, { "test", no_argument, 0, 't' },
{ "status", optional_argument, 0, 's' }, { "help", no_argument, 0, 'h' },
{ "version", no_argument, 0, 'v' }, { NULL, 0, NULL, 0 },
{ "daemonize", no_argument, 0, 'd' },
{ "log-to-syslog", no_argument, 0, 'l' },
{ "request", optional_argument, 0, 'r' },
{ "test", no_argument, 0, 't' },
{ "status", optional_argument, 0, 's' },
{ "reset", no_argument, 0, 'R' },
{ "help", no_argument, 0, 'h' },
{ "version", no_argument, 0, 'v' },
{ NULL, 0, NULL, 0 },
};
static const char *short_options = "dls::r::tvh";
static const char *short_options = "dls::r::tvhR";

while ((opt = getopt_long(argc, argv, short_options, long_options, 0)) != -1) {
switch (opt) {
Expand Down Expand Up @@ -289,6 +295,20 @@ int main(int argc, char *argv[])

exit(EXIT_SUCCESS);

case 'R':
switch (gamemode_request_restart()) {
case 0: /* success */
LOG_MSG("gamemode restart succeeded\n");
exit(EXIT_SUCCESS);
case 1: /* already off */
LOG_ERROR("gamemode was already deactivated\n");
break;
case -1: /* error */
LOG_ERROR("gamemode_request_restart failed: %s\n", gamemode_error_string());
break;
}
exit(EXIT_FAILURE);

case 't': {
int status = game_mode_run_client_tests();
exit(status);
Expand Down
6 changes: 6 additions & 0 deletions lib/client_impl.c
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,12 @@ extern int real_gamemode_query_status(void)
{
return gamemode_request("QueryStatus", 0);
}
//
// Wrapper to call RestartGamemode
extern int real_gamemode_request_restart(void)
{
return gamemode_request("RestartGamemode", 0);
}

// Wrapper to call RegisterGameByPID
extern int real_gamemode_request_start_for(pid_t pid)
Expand Down
23 changes: 23 additions & 0 deletions lib/gamemode_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ typedef int (*api_call_pid_return_int)(pid_t);
static api_call_return_int REAL_internal_gamemode_request_start = NULL;
static api_call_return_int REAL_internal_gamemode_request_end = NULL;
static api_call_return_int REAL_internal_gamemode_query_status = NULL;
static api_call_return_int REAL_internal_gamemode_request_restart = 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;
Expand Down Expand Up @@ -166,6 +167,10 @@ __attribute__((always_inline)) static inline int internal_load_libgamemode(void)
(void **)&REAL_internal_gamemode_query_status,
sizeof(REAL_internal_gamemode_query_status),
false },
{ "real_gamemode_request_restart",
(void **)&REAL_internal_gamemode_request_restart,
sizeof(REAL_internal_gamemode_request_restart),
false },
{ "real_gamemode_error_string",
(void **)&REAL_internal_gamemode_error_string,
sizeof(REAL_internal_gamemode_error_string),
Expand Down Expand Up @@ -319,6 +324,24 @@ __attribute__((always_inline)) static inline int gamemode_query_status(void)
return REAL_internal_gamemode_query_status();
}

/* Redirect to the real libgamemode */
__attribute__((always_inline)) static inline int gamemode_request_restart(void)
{
/* Need to load gamemode */
if (internal_load_libgamemode() < 0) {
return -1;
}

if (REAL_internal_gamemode_request_restart == NULL) {
snprintf(internal_gamemode_client_error_string,
sizeof(internal_gamemode_client_error_string),
"gamemode_request_restart missing (older host?)");
return -1;
}

return REAL_internal_gamemode_request_restart();
}

/* Redirect to the real libgamemode */
__attribute__((always_inline)) static inline int gamemode_request_start_for(pid_t pid)
{
Expand Down
Loading