summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKonstantin Pereiaslov <perk11@perk11.info>2024-01-04 00:03:55 -0600
committerKonstantin Pereiaslov <perk11@perk11.info>2024-01-04 00:03:55 -0600
commitdc61e18ba48181d7517765a84157ef6695c5f9e5 (patch)
tree534ac86ee62dc32888cd6f1171bb135dedc528b3
parent26925400bde36d9793581f78837be585c1aed562 (diff)
Add support of managing an external pid
-rw-r--r--README.md1
-rw-r--r--arguments_parsing.c37
-rw-r--r--arguments_parsing.h5
-rw-r--r--main.c14
-rw-r--r--process_handling.c25
-rwxr-xr-xutil/print_time.sh6
6 files changed, 73 insertions, 15 deletions
diff --git a/README.md b/README.md
index b2022fa..872d52f 100644
--- a/README.md
+++ b/README.md
@@ -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
diff --git a/main.c b/main.c
index ff71b34..c781d44 100644
--- a/main.c
+++ b/main.c
@@ -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