aboutsummaryrefslogtreecommitdiff
path: root/src/Process.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/Process.cpp')
-rw-r--r--src/Process.cpp158
1 files changed, 143 insertions, 15 deletions
diff --git a/src/Process.cpp b/src/Process.cpp
index e5886c0..c02753a 100644
--- a/src/Process.cpp
+++ b/src/Process.cpp
@@ -22,14 +22,33 @@ namespace gsr {
fprintf(stderr, "\n");
}
- bool exec_program_daemonized(const char **args) {
+ static bool is_number(const char *str) {
+ for(int i = 0; str[i]; ++i) {
+ char c = str[i];
+ if(c < '0' || c > '9')
+ return false;
+ }
+ return true;
+ }
+
+ static int count_num_args(const char **args) {
+ int num_args = 0;
+ while(*args) {
+ ++num_args;
+ ++args;
+ }
+ return num_args;
+ }
+
+ bool exec_program_daemonized(const char **args, bool debug) {
/* 1 argument */
if(args[0] == nullptr)
return false;
- debug_print_args(args);
+ if(debug)
+ debug_print_args(args);
- pid_t pid = vfork();
+ const pid_t pid = vfork();
if(pid == -1) {
perror("Failed to vfork");
return false;
@@ -38,10 +57,10 @@ namespace gsr {
signal(SIGHUP, SIG_IGN);
// Daemonize child to make the parent the init process which will reap the zombie child
- pid_t second_child = vfork();
+ const pid_t second_child = vfork();
if(second_child == 0) { // child
execvp(args[0], (char* const*)args);
- perror("execvp");
+ perror(args[0]);
_exit(127);
} else if(second_child != -1) {
// TODO:
@@ -54,7 +73,7 @@ namespace gsr {
return true;
}
- pid_t exec_program(const char **args, int *read_fd) {
+ pid_t exec_program(const char **args, int *read_fd, bool debug) {
if(read_fd)
*read_fd = -1;
@@ -66,9 +85,10 @@ namespace gsr {
if(pipe(fds) == -1)
return -1;
- debug_print_args(args);
+ if(debug)
+ debug_print_args(args);
- pid_t pid = vfork();
+ const pid_t pid = vfork();
if(pid == -1) {
close(fds[PIPE_READ]);
close(fds[PIPE_WRITE]);
@@ -80,7 +100,7 @@ namespace gsr {
close(fds[PIPE_WRITE]);
execvp(args[0], (char* const*)args);
- perror("execvp");
+ perror(args[0]);
_exit(127);
} else { /* parent */
close(fds[PIPE_WRITE]);
@@ -92,10 +112,85 @@ namespace gsr {
}
}
- bool read_cmdline_arg0(const char *filepath, char *output_buffer) {
+ int exec_program_get_stdout(const char **args, std::string &result, bool debug) {
+ result.clear();
+ int read_fd = -1;
+ const pid_t process_id = exec_program(args, &read_fd, debug);
+ if(process_id == -1)
+ return -1;
+
+ int exit_status = 0;
+ char buffer[8192];
+ for(;;) {
+ ssize_t bytes_read = read(read_fd, buffer, sizeof(buffer));
+ if(bytes_read == 0) {
+ break;
+ } else if(bytes_read == -1) {
+ fprintf(stderr, "Failed to read from pipe to program %s, error: %s\n", args[0], strerror(errno));
+ exit_status = -1;
+ break;
+ }
+ result.append(buffer, bytes_read);
+ }
+
+ if(exit_status != 0)
+ kill(process_id, SIGKILL);
+
+ int status = 0;
+ if(waitpid(process_id, &status, 0) == -1) {
+ perror("waitpid failed");
+ exit_status = -1;
+ }
+
+ if(!WIFEXITED(status))
+ exit_status = -1;
+
+ if(exit_status == 0)
+ exit_status = WEXITSTATUS(status);
+
+ close(read_fd);
+ return exit_status;
+ }
+
+ int exec_program_on_host_get_stdout(const char **args, std::string &result, bool debug) {
+ if(count_num_args(args) > 64 - 3) {
+ fprintf(stderr, "Error: too many arguments when trying to launch \"%s\"\n", args[0]);
+ return -1;
+ }
+
+ const bool inside_flatpak = getenv("FLATPAK_ID") != NULL;
+ if(inside_flatpak) {
+ // Assumes programs wont need more than 64 - 3 args
+ const char *modified_args[64] = { "flatpak-spawn", "--host", "--" };
+ for(int i = 3; i < 64; ++i) {
+ const char *arg = args[i - 3];
+ if(!arg) {
+ modified_args[i] = nullptr;
+ break;
+ }
+ modified_args[i] = arg;
+ }
+ return exec_program_get_stdout(modified_args, result, debug);
+ } else {
+ return exec_program_get_stdout(args, result, debug);
+ }
+ }
+
+ static const char *get_basename(const char *path, int size) {
+ for(int i = size - 1; i >= 0; --i) {
+ if(path[i] == '/')
+ return path + i + 1;
+ }
+ return path;
+ }
+
+ // |output_buffer| should be at least PATH_MAX in size
+ bool read_cmdline_arg0(const char *filepath, char *output_buffer, int output_buffer_size) {
output_buffer[0] = '\0';
+ const char *arg0_start = NULL;
const char *arg0_end = NULL;
+ int arg0_size = 0;
int fd = open(filepath, O_RDONLY);
if(fd == -1)
return false;
@@ -105,17 +200,50 @@ namespace gsr {
if(bytes_read == -1)
goto err;
- arg0_end = (const char*)memchr(buffer, '\0', bytes_read);
+ arg0_start = buffer;
+ arg0_end = (const char*)memchr(arg0_start, '\0', bytes_read);
if(!arg0_end)
goto err;
- memcpy(output_buffer, buffer, arg0_end - buffer);
- output_buffer[arg0_end - buffer] = '\0';
- close(fd);
- return true;
+ arg0_start = get_basename(arg0_start, arg0_end - arg0_start);
+ arg0_size = arg0_end - arg0_start;
+ if(arg0_size + 1 <= output_buffer_size) {
+ memcpy(output_buffer, arg0_start, arg0_size);
+ output_buffer[arg0_size] = '\0';
+ close(fd);
+ return true;
+ }
err:
close(fd);
return false;
}
+
+ pid_t pidof(const char *process_name, pid_t ignore_pid) {
+ pid_t result = -1;
+ DIR *dir = opendir("/proc");
+ if(!dir)
+ return -1;
+
+ char cmdline_filepath[PATH_MAX];
+ char arg0[PATH_MAX];
+
+ struct dirent *entry;
+ while((entry = readdir(dir)) != NULL) {
+ if(!is_number(entry->d_name))
+ continue;
+
+ snprintf(cmdline_filepath, sizeof(cmdline_filepath), "/proc/%s/cmdline", entry->d_name);
+ if(read_cmdline_arg0(cmdline_filepath, arg0, sizeof(arg0)) && strcmp(process_name, arg0) == 0) {
+ const pid_t pid = atoi(entry->d_name);
+ if(pid != ignore_pid) {
+ result = pid;
+ break;
+ }
+ }
+ }
+
+ closedir(dir);
+ return result;
+ }
} \ No newline at end of file