aboutsummaryrefslogtreecommitdiff
path: root/src/Process.cpp
blob: a1e1e6c69b0858b765492705a1f5003c5a50a44b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#include "../include/Process.hpp"
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <sys/wait.h>
#include <limits.h>
#include <fcntl.h>
#include <dirent.h>
#include <stdlib.h>

namespace gsr {
    bool exec_program_daemonized(const char **args) {
        /* 1 argument */
        if(args[0] == nullptr)
            return false;

        pid_t pid = vfork();
        if(pid == -1) {
            perror("Failed to vfork");
            return false;
        } else if(pid == 0) { /* child */
            setsid();
            signal(SIGHUP, SIG_IGN);

            // Daemonize child to make the parent the init process which will reap the zombie child
            pid_t second_child = vfork();
            if(second_child == 0) { // child
                execvp(args[0], (char* const*)args);
                perror("execvp");
                _exit(127);
            } else if(second_child != -1) {
                // TODO:
                _exit(0);
            }
        } else { /* parent */
            waitpid(pid, nullptr, 0);
        }

        return true;
    }

    pid_t exec_program(const char **args) {
        /* 1 argument */
        if(args[0] == nullptr)
            return -1;

        pid_t pid = vfork();
        if(pid == -1) {
            perror("Failed to vfork");
            return -1;
        } else if(pid == 0) { /* child */
            execvp(args[0], (char* const*)args);
            perror("execvp");
            _exit(127);
        } else { /* parent */
            return pid;
        }
    }

    static bool is_number(const char *str) {
        while(*str) {
            char c = *str;
            if(c < '0' || c > '9')
                return false;
            ++str;
        }
        return true;
    }

    static bool read_cmdline(const char *filepath, char *output_buffer) {
        const char *arg0_end = NULL;
        int fd = open(filepath, O_RDONLY);
        if(fd == -1)
            return false;

        char buffer[PATH_MAX];
        ssize_t bytes_read = read(fd, buffer, sizeof(buffer));
        if(bytes_read == -1)
            goto err;

        arg0_end = (const char*)memchr(buffer, '\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;

        err:
        close(fd);
        return false;
    }

    static pid_t pidof(const char *process_name) {
        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(cmdline_filepath, arg0) && strcmp(process_name, arg0) == 0) {
                result = atoi(entry->d_name);
                break;
            }
        }

        closedir(dir);
        return result;
    }

    bool is_gpu_screen_recorder_running(pid_t &gsr_pid, GsrMode &mode) {
        // TODO: Set |mode| by checking cmdline
        gsr_pid = pidof("gpu-screen-recorder");
        if(gsr_pid == -1) {
            mode = GsrMode::Unknown;
            return false;
        } else {
            mode = GsrMode::Record;
            return true;
        }
    }
}