diff options
author | Konstantin Pereiaslov <perk11@perk11.info> | 2024-01-04 00:03:55 -0600 |
---|---|---|
committer | Konstantin Pereiaslov <perk11@perk11.info> | 2024-01-04 00:03:55 -0600 |
commit | dc61e18ba48181d7517765a84157ef6695c5f9e5 (patch) | |
tree | 534ac86ee62dc32888cd6f1171bb135dedc528b3 | |
parent | 26925400bde36d9793581f78837be585c1aed562 (diff) |
Add support of managing an external pid
-rw-r--r-- | README.md | 1 | ||||
-rw-r--r-- | arguments_parsing.c | 37 | ||||
-rw-r--r-- | arguments_parsing.h | 5 | ||||
-rw-r--r-- | main.c | 14 | ||||
-rw-r--r-- | process_handling.c | 25 | ||||
-rwxr-xr-x | util/print_time.sh | 6 |
6 files changed, 73 insertions, 15 deletions
@@ -42,6 +42,7 @@ If you want to install it system-wide, run `sudo make install` or simply `sudo c | Option | Description | Default Value | |-----------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------| | `--timeout\| -t <seconds>` | Set the user idle time after which the command can run in seconds. | 300 seconds | +| `--pid\|-p <pid>` | Monitor an existing command rather than start a new one. When this option is used, shell_command_to_run should not be passed. | | | `--start-monitor-after\| -a <ms>` | Set an initial delay in milliseconds before monitoring starts. During this time command runs unrestricted. This helps to catch quick errors. | 300 ms | | `--pause-method\| -m <method>` | Specify method for pausing the command when the user is not idle. Available Options: SIGTSTP (can be ignored by the program), SIGSTOP (cannot be ignored). | SIGTSTP | | `--verbose\| -v` | Enable verbose output for monitoring. | Not verbose | diff --git a/arguments_parsing.c b/arguments_parsing.c index 4561f58..2448834 100644 --- a/arguments_parsing.c +++ b/arguments_parsing.c @@ -17,9 +17,10 @@ const long START_MONITOR_AFTER_MAX_SUPPORTED_VALUE = TIMEOUT_MAX_SUPPORTED_VALUE const long START_MONITOR_AFTER_MIN_SUPPORTED_VALUE = 0; void print_usage(char *binary_name) { - printf("Usage: %s [OPTIONS] shell_command_to_run [shell_command_arguments]\n", binary_name); + printf("Usage: %s [OPTIONS] [shell_command_to_run] [shell_command_arguments]\n", binary_name); printf("\nOptions:\n"); printf(" --timeout|-t <seconds> Set the user idle time after which the command can run in seconds (default: 300 seconds).\n"); + printf(" --pid|-p <pid> Monitor an existing command rather than start a new one. When this option is used, shell_command_to_run should not be passed.\n"); printf(" --start-monitor-after|-a <ms> Set an initial delay in milliseconds before monitoring starts. During this time command runs unrestricted. This helps to catch errors happening shortly after the execution has started. (default: 300 ms).\n"); printf(" --pause-method|-m <method> Specify method for pausing the command when user is not idle. Available parameters: SIGTSTP (can be ignored by the program), SIGSTOP (can not be ignored). (default: SIGTSTP).\n"); printf(" --verbose|-v Enable verbose output for monitoring.\n"); @@ -70,9 +71,10 @@ char *read_remaining_arguments_as_char(int argc, return remaining_arguments_string; } -char *parse_command_line_arguments(int argc, char *argv[]) { +void parse_command_line_arguments(int argc, char *argv[]) { struct option long_options[] = { {"timeout", required_argument, NULL, 't'}, + {"pid", required_argument, NULL, 'p'}, {"start-monitor-after", required_argument, NULL, 'a'}, {"pause-method", required_argument, NULL, 'm'}, {"verbose", no_argument, NULL, 'v'}, @@ -85,7 +87,7 @@ char *parse_command_line_arguments(int argc, char *argv[]) { // Parse command line options int option; - while ((option = getopt_long(argc, argv, "+hvqt:a:m:V", long_options, NULL)) != -1) { + while ((option = getopt_long(argc, argv, "+hvqp:t:a:m:V", long_options, NULL)) != -1) { switch (option) { case 't': { long timeout_arg_value = strtol(optarg, NULL, 10); @@ -99,6 +101,16 @@ char *parse_command_line_arguments(int argc, char *argv[]) { user_idle_timeout_ms = timeout_arg_value * 1000; break; } + case 'p': { + external_pid = strtol(optarg, NULL, 10); + if (external_pid < 1) { + fprintf_error("Invalid pid value: \"%s\".", optarg); + print_usage(argv[0]); + exit(1); + } + + break; + } case 'a': start_monitor_after_ms = strtol(optarg, NULL, 10); @@ -166,9 +178,21 @@ char *parse_command_line_arguments(int argc, char *argv[]) { user_idle_timeout_ms, start_monitor_after_ms ); - if (optind >= argc) { - print_usage(argv[0]); - exit(1); + if (external_pid) { + if (optind < argc) { + fprintf_error( + "Running command is not supported when -p option is used. Found unexpected \"%s\"\n", + read_remaining_arguments_as_char(argc, argv) + ); + print_usage(argv[0]); + exit(1); + } + } else { + if (optind >= argc) { + print_usage(argv[0]); + exit(1); + } + shell_command_to_run = read_remaining_arguments_as_char(argc, argv); } if (quiet && debug) { fprintf_error("Incompatible options --quiet|-q and --debug used\n"); @@ -181,5 +205,4 @@ char *parse_command_line_arguments(int argc, char *argv[]) { exit(1); } - return read_remaining_arguments_as_char(argc, argv); } diff --git a/arguments_parsing.h b/arguments_parsing.h index 1030f6a..ea31737 100644 --- a/arguments_parsing.h +++ b/arguments_parsing.h @@ -2,14 +2,15 @@ #define RUNWHENIDLE_ARGUMENTS_PARSING_H extern long start_monitor_after_ms; extern long unsigned user_idle_timeout_ms; +extern char *shell_command_to_run; +extern pid_t external_pid; /** * Parses command line arguments and sets relevant program options. * * @param argc The number of command line arguments. * @param argv An array of strings representing the command line arguments. - * @return A character pointer to the remaining command line arguments as a single string. */ -char *parse_command_line_arguments(int argc, char *argv[]); +void parse_command_line_arguments(int argc, char *argv[]); #endif //RUNWHENIDLE_ARGUMENTS_PARSING_H @@ -16,6 +16,8 @@ #define VERSION 'unkown' #endif +char *shell_command_to_run; +pid_t external_pid = 0; int verbose = 0; int quiet = 0; int debug = 0; @@ -59,6 +61,9 @@ int handle_interruption() { } resume_command_recursively(pid); } + if (external_pid) { + return 0; + } //Wait for the child process to complete return wait_for_pid_to_exit_synchronously(pid); } @@ -149,7 +154,7 @@ long long pause_or_resume_command_depending_on_user_activity( } int main(int argc, char *argv[]) { - char *shell_command_to_run = parse_command_line_arguments(argc, argv); + parse_command_line_arguments(argc, argv); //Open display and initialize XScreensaverInfo for querying idle time x_display = XOpenDisplay(NULL); @@ -169,8 +174,11 @@ int main(int argc, char *argv[]) { fprintf_error( "No available method for detecting user idle time on the system, user will be considered idle to allow the command to finish.\n"); } - - pid = run_shell_command(shell_command_to_run); + if (external_pid == 0) { + pid = run_shell_command(shell_command_to_run); + } else { + pid = external_pid; + } free(shell_command_to_run); struct timespec time_when_command_started; clock_gettime(CLOCK_MONOTONIC, &time_when_command_started); diff --git a/process_handling.c b/process_handling.c index 9a4573c..dd244c6 100644 --- a/process_handling.c +++ b/process_handling.c @@ -7,6 +7,8 @@ #include <sys/wait.h> #include <dirent.h> +#include "arguments_parsing.h" +#include "sleep_utils.h" #include "process_handling.h" #include "output_settings.h" #include "pause_methods.h" @@ -280,11 +282,28 @@ int wait_for_pid_to_exit_synchronously(int pid) { void exit_if_pid_has_finished(pid_t pid) { int status; + int finished = 0; + int exit_code; if (debug) fprintf(stderr, "Checking if PID %i has finished\n", pid); - if (waitpid(pid, &status, WNOHANG + WUNTRACED) == pid && WIFEXITED(status)) { - int exit_code = WEXITSTATUS(status); + if (external_pid) { + if (kill(pid, 0) == -1) { + finished = 1; + exit_code = 0; + } + } else { + if (waitpid(pid, &status, WNOHANG + WUNTRACED) == pid && WIFEXITED(status)) { + finished = 1; + exit_code = WEXITSTATUS(status); + } + } + + if (finished) { if (verbose) { - fprintf(stderr, "PID %i has finished with exit code %u\n", pid, exit_code); + fprintf(stderr, "PID %i has finished", pid); + if (!external_pid) { + fprintf(stderr, " with exit code %u", exit_code); + } + fprintf(stderr, "\n"); } exit(exit_code); } diff --git a/util/print_time.sh b/util/print_time.sh new file mode 100755 index 0000000..a388954 --- /dev/null +++ b/util/print_time.sh @@ -0,0 +1,6 @@ +#1/bin/sh +while true +do + date + sleep 1 +done
\ No newline at end of file |