aboutsummaryrefslogtreecommitdiff
path: root/src/plugins/utils/UniqueProcess.cpp
blob: 76b9cb15169a3947423787537308dd21c508bac0 (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
#include "../../../plugins/utils/UniqueProcess.hpp"
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>

namespace QuickMedia {
    static bool is_process_running_program(pid_t pid, const char *program_name) {
        char filepath[256];
        snprintf(filepath, sizeof(filepath), "/proc/%ld/cmdline", (long)pid);

        int fd = open(filepath, O_RDONLY);
        if(fd == -1)
            return false;
        
        char buffer[PATH_MAX + 1];
        ssize_t bytes_read = read(fd, buffer, sizeof(buffer) - 1);
        if(bytes_read == -1) {
            close(fd);
            return false;
        }
        buffer[bytes_read] = '\0';

        char resolved_path[PATH_MAX + 1];
        if(!realpath(buffer, resolved_path)) {
            close(fd);
            return false;
        }
        bytes_read = strlen(resolved_path);
        resolved_path[bytes_read] = '\0';

        const char *end = resolved_path + bytes_read;
        const char *start = (const char*)memrchr(resolved_path, '/', bytes_read);
        if(start)
            start += 1;
        else
            start = buffer;

        const size_t cmd_arg0_len = end - start;
        const size_t program_name_len = strlen(program_name);
        bool running = (cmd_arg0_len == program_name_len && memcmp(start, program_name, program_name_len) == 0);
        close(fd);
        return running;
    }

    bool is_quickmedia_instance_already_running(const char *pid_file_dir, const char *plugin_name) {
        char pid_file[PATH_MAX];
        snprintf(pid_file, sizeof(pid_file), "%s/quickmedia.%s.pid", pid_file_dir, plugin_name);

        char buffer[256];
        int fd = open(pid_file, O_RDONLY);
        if(fd == -1)
            return false;

        ssize_t bytes_read = read(fd, buffer, sizeof(buffer) - 1);
        if(bytes_read < 0) {
            perror("failed to read quickmedia pid file");
            close(fd);
            return false;
        }
        buffer[bytes_read] = '\0';
        close(fd);

        bool running = false;
        long pid = 0;
        if(sscanf(buffer, "%ld", &pid) == 1) {
            if(is_process_running_program(pid, "quickmedia")) {
                fprintf(stderr, "Error: quickmedia %s is already running\n", plugin_name);
                running = true;
            }
        } else {
            fprintf(stderr, "Warning: quickmedia pid file is in incorrect format, it's possible that its corrupt. Replacing file and continuing...\n");
            running = false;
        }

        if(!running)
            unlink(pid_file);

        return running;
    }

    bool set_quickmedia_instance_unique(const char *pid_file_dir, const char *plugin_name) {
        char pid_file[PATH_MAX];
        snprintf(pid_file, sizeof(pid_file), "%s/quickmedia.%s.pid", pid_file_dir, plugin_name);

        int fd = open(pid_file, O_WRONLY|O_CREAT|O_TRUNC, 0777);
        if(fd == -1) {
            perror("failed to create quickmedia pid file");
            return false;
        }

        bool success = true;
        char buffer[256];
        const int buffer_size = snprintf(buffer, sizeof(buffer), "%ld", (long)getpid());
        if(write(fd, buffer, buffer_size) == -1) {
            perror("failed to write quickmedia pid file");
            success = false;
        }

        close(fd);
        if(!success)
            unlink(pid_file);
        return success;
    }

    void remove_quickmedia_instance_lock(const char *pid_file_dir, const char *plugin_name) {
        char pid_file[PATH_MAX];
        snprintf(pid_file, sizeof(pid_file), "%s/quickmedia.%s.pid", pid_file_dir, plugin_name);
        unlink(pid_file);
    }
}