diff options
author | Konstantin Pereiaslov <perk11@perk11.info> | 2023-09-03 21:26:40 -0500 |
---|---|---|
committer | Konstantin Pereiaslov <perk11@perk11.info> | 2023-09-03 21:26:40 -0500 |
commit | d29b649b0705bc22f91734aea2329ecdabc0f3df (patch) | |
tree | 39af7f306b574f24ae1521a847281baaa5aeab37 | |
parent | d85a6c3e1180c18671fda223c033f92660a5bbf9 (diff) |
Implement handling the interruption signals: pass them to the underlying command and stop the idle checks0.3.0
-rw-r--r-- | README.md | 8 | ||||
-rw-r--r-- | main.c | 82 |
2 files changed, 70 insertions, 20 deletions
@@ -11,6 +11,10 @@ It then checks once per second if user activity has resumed, and once it is, pau runwhenidle uses XScreenSaverQueryInfo() to check when last user activity happened therefore a running X server is required. Wayland is not currently supported. +If runwhenidle receives an interruption signal (SIGINT or SIGTERM), it will pass that signal to the command it is +running, resume the command if it previously paused it, stop checking for user activity and will wait for the command +to handle the signal. + ## Installation **Ubuntu and Debian**: Download the deb file attached to the [latest release](https://github.com/perk11/runwhenidle/releases/latest). @@ -25,10 +29,10 @@ If you want to install it system-wide, run `sudo make install` or simply `sudo c ## Usage - runwhenidle [--timeout|-t timeout_value_in_seconds] [--verbose|-v] [--quiet|-q] shell_command_to_run + runwhenidle [--timeout|-t timeout_value_in_seconds] [--verbose|-v] [--debug] [--quiet|-q] [--version|-V] shell_command_to_run [shell_command_arguments] -`--timeout` or `-t` specifies how many seconds of user inactivity are enough to resume the command. Default value is 300/5 minutes. +`--timeout` or `-t` specifies how many seconds of user inactivity are enough to resume the command. Default value is 300/5 minutes. `--verbose` or `-v` adds additional debug output `--quiet` or `-q` suppresses all the output from `runwhenidle` and only displays output from the command that is running. @@ -27,6 +27,10 @@ Display *x_display; XScreenSaverInfo *xscreensaver_info; const long unsigned IDLE_TIME_NOT_AVAILABLE_VALUE = ULONG_MAX; +volatile sig_atomic_t interruption_received = 0; +int command_paused = 0; +pid_t pid; + void handle_kill_error(char *signal_name, pid_t pid) { const char *reason; if (errno == EPERM) { @@ -39,31 +43,31 @@ void handle_kill_error(char *signal_name, pid_t pid) { printf("Failed to send %s signal to PID %i: %s\n", signal_name, pid, reason); } - -void pause_command(pid_t pid) { - if (!quiet) { - printf("User activity is detected, pausing PID %i\n", pid); +void send_signal_to_pid(pid_t pid, int signal, char *signal_name) { + if (debug) { + printf("Sending %s to %i\n",signal_name, pid); } - int kill_result = kill(pid, SIGTSTP); + int kill_result = kill(pid, signal); if (kill_result == -1) { - handle_kill_error("SIGTSTP", pid); + handle_kill_error(signal_name, pid); exit(1); } else { - if (debug) fprintf(stderr, "kill function sending signal returned %i\n", kill_result); + if (debug) fprintf(stderr, "kill function sending %s returned %i\n",signal_name, kill_result); } } -void resume_command(pid_t pid) { +void pause_command(pid_t pid) { if (!quiet) { - printf("Lack of user activity is detected, resuming PID %i\n", pid); + printf("User activity is detected, pausing PID %i\n", pid); } - int kill_result = kill(pid, SIGCONT); - if (kill_result == -1) { - handle_kill_error("SIGCONT", pid); - exit(1); - } else { - if (debug) fprintf(stderr, "kill function sending signal returned %i\n", kill_result); + send_signal_to_pid(pid, SIGTSTP, "SIGTSTP"); +} + +void resume_command(pid_t pid) { + if (!quiet) { + printf("Resuming PID %i\n", pid); } + send_signal_to_pid(pid, SIGCONT, "SIGCONT"); } void print_usage(char *binary_name) { @@ -150,8 +154,43 @@ long unsigned query_user_idle_time() return IDLE_TIME_NOT_AVAILABLE_VALUE; } +int wait_for_pid_to_exit_synchronously(int pid) { + // Wait for the child process to complete + int status; + waitpid(pid, &status, 0); + int exit_code = WEXITSTATUS(status); + if (verbose) { + fprintf(stderr, "PID %i has finished with exit code %u\n", pid, exit_code); + } + + return exit_code; +} +int handle_interruption() { + if (command_paused) { + if (verbose) { + fprintf(stderr, + "Since command was previously paused, we will try to resume it now to be able to handle the interruption before exiting\n" + ); + } + resume_command(pid); + } + return wait_for_pid_to_exit_synchronously(pid); +} +void sigint_handler(int signum) { + if (!quiet) { + printf("Received SIGINT, sending SIGINT to the command and waiting for it to finish.\n"); + } + send_signal_to_pid(pid, signum, "SIGINT"); + interruption_received = 1; +} +void sigterm_handler(int signum) { + if (!quiet) { + printf("Received SIGTERM, sending SIGTERM to the command and waiting for it to finish.\n"); + } + send_signal_to_pid(pid, signum, "SIGTERM"); + interruption_received = 1; +} int main(int argc, char *argv[]) { - pid_t pid; long unsigned user_idle_timeout_ms = 300000; // Define command line options @@ -247,11 +286,15 @@ int main(int argc, char *argv[]) { long long polling_interval_ms = 1000; long long sleep_time_ms = polling_interval_ms; - int command_paused = 0; unsigned long user_idle_time_ms; + signal(SIGINT, sigint_handler); + signal(SIGTERM, sigterm_handler); // Monitor user activity while (1) { + if (interruption_received) { + return handle_interruption(); + } user_idle_time_ms = query_user_idle_time(); // Checking this after querying the screensaver timer so that the command is still running while @@ -266,7 +309,10 @@ int main(int argc, char *argv[]) { if (verbose) { fprintf(stderr, "Idle time: %lums, idle timeout: %lums, resuming command\n", user_idle_time_ms, user_idle_timeout_ms); } - + if (!quiet){ + printf("Lack of user activity detected. "); + //intentionally no new line here, resume_command will print the rest of the message. + } resume_command(pid); command_paused = 0; } |