summaryrefslogtreecommitdiffstats
path: root/src/collectors/apps.plugin/apps_proc_pid_cmdline.c
blob: 75a60fa3a97406d3d2be246f1151dfdd43ba44f9 (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
// SPDX-License-Identifier: GPL-3.0-or-later

#include "apps_plugin.h"

#ifdef __APPLE__
bool get_cmdline_per_os(struct pid_stat *p, char *cmdline, size_t maxBytes) {
    int mib[3] = {CTL_KERN, KERN_PROCARGS2, p->pid};
    static char *args = NULL;
    static size_t size = 0;

    size_t new_size;
    if (sysctl(mib, 3, NULL, &new_size, NULL, 0) == -1) {
        return false;
    }

    if (new_size > size) {
        if (args)
            freez(args);

        args = (char *)mallocz(new_size);
        size = new_size;
    }

    memset(cmdline, 0, new_size < maxBytes ? new_size : maxBytes);

    size_t used_size = size;
    if (sysctl(mib, 3, args, &used_size, NULL, 0) == -1)
        return false;

    int argc;
    memcpy(&argc, args, sizeof(argc));
    char *ptr = args + sizeof(argc);
    used_size -= sizeof(argc);

    // Skip the executable path
    while (*ptr && used_size > 0) {
        ptr++;
        used_size--;
    }

    // Copy only the arguments to the cmdline buffer, skipping the environment variables
    size_t i = 0, copied_args = 0;
    bool inArg = false;
    for (; used_size > 0 && i < maxBytes - 1 && copied_args < argc; --used_size, ++ptr) {
        if (*ptr == '\0') {
            if (inArg) {
                cmdline[i++] = ' ';  // Replace nulls between arguments with spaces
                inArg = false;
                copied_args++;
            }
        } else {
            cmdline[i++] = *ptr;
            inArg = true;
        }
    }

    if (i > 0 && cmdline[i - 1] == ' ')
        i--;  // Remove the trailing space if present

    cmdline[i] = '\0'; // Null-terminate the string

    return true;
}
#endif // __APPLE__

#if defined(__FreeBSD__)
static inline bool get_cmdline_per_os(struct pid_stat *p, char *cmdline, size_t bytes) {
    size_t i, b = bytes - 1;
    int mib[4];

    mib[0] = CTL_KERN;
    mib[1] = KERN_PROC;
    mib[2] = KERN_PROC_ARGS;
    mib[3] = p->pid;
    if (unlikely(sysctl(mib, 4, cmdline, &b, NULL, 0)))
        return false;

    cmdline[b] = '\0';
    for(i = 0; i < b ; i++)
        if(unlikely(!cmdline[i])) cmdline[i] = ' ';

    return true;
}
#endif // __FreeBSD__

#if !defined(__FreeBSD__) && !defined(__APPLE__)
static inline bool get_cmdline_per_os(struct pid_stat *p, char *cmdline, size_t bytes) {
    if(unlikely(!p->cmdline_filename)) {
        char filename[FILENAME_MAX];
        snprintfz(filename, FILENAME_MAX, "%s/proc/%d/cmdline", netdata_configured_host_prefix, p->pid);
        p->cmdline_filename = strdupz(filename);
    }

    int fd = open(p->cmdline_filename, procfile_open_flags, 0666);
    if(unlikely(fd == -1))
        return false;

    ssize_t i, b = read(fd, cmdline, bytes - 1);
    close(fd);

    if(unlikely(b < 0))
        return false;

    cmdline[b] = '\0';
    for(i = 0; i < b ; i++)
        if(unlikely(!cmdline[i])) cmdline[i] = ' ';

    return true;
}
#endif // !__FreeBSD__ !__APPLE__

int read_proc_pid_cmdline(struct pid_stat *p) {
    static char cmdline[MAX_CMDLINE];

    if(unlikely(!get_cmdline_per_os(p, cmdline, sizeof(cmdline))))
        goto cleanup;

    if(p->cmdline) freez(p->cmdline);
    p->cmdline = strdupz(cmdline);

    debug_log("Read file '%s' contents: %s", p->cmdline_filename, p->cmdline);

    return 1;

cleanup:
    // copy the command to the command line
    if(p->cmdline) freez(p->cmdline);
    p->cmdline = strdupz(p->comm);
    return 0;
}