summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKonstantin Pereiaslov <perk11@perk11.info>2023-09-03 21:26:40 -0500
committerKonstantin Pereiaslov <perk11@perk11.info>2023-09-03 21:26:40 -0500
commitd29b649b0705bc22f91734aea2329ecdabc0f3df (patch)
tree39af7f306b574f24ae1521a847281baaa5aeab37
parentd85a6c3e1180c18671fda223c033f92660a5bbf9 (diff)
Implement handling the interruption signals: pass them to the underlying command and stop the idle checks0.3.0
-rw-r--r--README.md8
-rw-r--r--main.c82
2 files changed, 70 insertions, 20 deletions
diff --git a/README.md b/README.md
index 1c75a9b..4cf646a 100644
--- a/README.md
+++ b/README.md
@@ -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.
diff --git a/main.c b/main.c
index 630abfd..3db1071 100644
--- a/main.c
+++ b/main.c
@@ -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;
}