<commit_before>/*
 * Copyright (C) Tildeslash Ltd. All rights reserved.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License version 3.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * In addition, as a special exception, the copyright holders give
 * permission to link the code of portions of this program with the
 * OpenSSL library under certain conditions as described in each
 * individual source file, and distribute linked combinations
 * including the two.
 *
 * You must obey the GNU Affero General Public License in all respects
 * for all of the code used other than OpenSSL.
 */

#include "config.h"

#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif

#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif

#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif

#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif

#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif

#ifdef HAVE_TIME_H
#include <time.h>
#endif

#ifdef HAVE_STRING_H
#include <string.h>
#endif

#ifdef HAVE_STDIO_H
#include <stdio.h>
#endif

#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif

#include "monit.h"
#include "event.h"
#include "ProcessTree.h"
#include "process_sysdep.h"
#include "Box.h"
#include "Color.h"

// libmonit
#include "system/Time.h"


/**
 *  General purpose /proc methods.
 *
 *  @file
 */


/* ------------------------------------------------------------- Definitions */


static int ptreesize = 0;
static ProcessTree_T *ptree = NULL;


/* ----------------------------------------------------------------- Private */


static void _delete(ProcessTree_T **pt, int *size) {
        ASSERT(pt);
        ProcessTree_T *_pt = *pt;
        if (_pt) {
                for (int i = 0; i < *size; i++) {
                        FREE(_pt[i].cmdline);
                        FREE(_pt[i].children.list);
                }
                FREE(_pt);
                *pt = NULL;
                *size = 0;
        }
}


/**
 * Search a leaf in the processtree
 * @param pid  pid of the process
 * @param pt  processtree
 * @param treesize  size of the processtree
 * @return process index if succeeded otherwise -1
 */
static int _findProcess(int pid, ProcessTree_T *pt, int size) {
        if (size > 0) {
                for (int i = 0; i < size; i++)
                        if (pid == pt[i].pid)
                                return i;
        }
        return -1;
}


/**
 * Fill data in the process tree by recusively walking through it
 * @param pt process tree
 * @param i process index
 */
static void _fillProcessTree(ProcessTree_T *pt, int index) {
        if (! pt[index].visited) {
                pt[index].visited            = true;
                pt[index].children.total     = pt[index].children.count;
                pt[index].memory.usage_total = pt[index].memory.usage;
                pt[index].cpu.usage_total    = pt[index].cpu.usage;
                for (int i = 0; i < pt[index].children.count; i++)
                        _fillProcessTree(pt, pt[index].children.list[i]);
                if (pt[index].parent != -1 && pt[index].parent != index) {
                        ProcessTree_T *parent_pt       = &pt[pt[index].parent];
                        parent_pt->children.total     += pt[index].children.total;
                        parent_pt->memory.usage_total += pt[index].memory.usage_total;
                        parent_pt->cpu.usage_total    += pt[index].cpu.usage_total;
                }
        }
}


/**
 * Adjust the CPU usage based on the available system resources: number of CPU cores the application may utilize. Single threaded application may utilized only one CPU core, 4 threaded application 4 cores, etc.. If the application
 * has more threads then the machine has cores, it is limited by number of cores, not threads.
 * @param now Current process informations
 * @param prev Process informations from previous cycle
 * @param delta The delta of system time between current and previous cycle
 * @return Process' CPU usage [%] since last cycle
 */
static float _cpuUsage(ProcessTree_T *now, ProcessTree_T *prev, double delta) {
        if (systeminfo.cpus > 0 && delta > 0 && prev->cpu.time > 0 && now->cpu.time > prev->cpu.time) {
                int divisor;
                if (now->threads > 1) {
                        if (now->threads >= systeminfo.cpus) {
                                // Multithreaded application with more threads then CPU cores
                                divisor = systeminfo.cpus;
                        } else {
                                // Multithreaded application with less threads then CPU cores
                                divisor = now->threads;
                        }
                } else {
                        // Single threaded application
                        divisor = 1;
                }
                float usage = (100. * (now->cpu.time - prev->cpu.time) / delta) / divisor;
                return usage > 100. ? 100. : usage;
        }
        return 0.;
}


static boolean_t _match(regex_t *regex) {
        int found = -1;
        // Scan the whole process tree and find the oldest matching process whose parent doesn't match the pattern
        for (int i = 0; i < ptreesize; i++)
                if (regexec(regex, ptree[i].cmdline, 0, NULL, 0) == 0 && (i == ptree[i].parent || regexec(regex, ptree[ptree[i].parent].cmdline, 0, NULL, 0) != 0) && (found == -1 || ptree[found].uptime < ptree[i].uptime))
                        found = i;
        return found >= 0 ? ptree[found].pid : found;
}


/* ------------------------------------------------------------------ Public */


/**
 * Initialize the process tree
 * @return treesize >= 0 if succeeded otherwise < 0
 */
int ProcessTree_init(ProcessEngine_Flags pflags) {
        ProcessTree_T *oldptree = ptree;
        int oldptreesize = ptreesize;<commit_msg>check cmdline<commit_after>/*
 * Copyright (C) Tildeslash Ltd. All rights reserved.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License version 3.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * In addition, as a special exception, the copyright holders give
 * permission to link the code of portions of this program with the
 * OpenSSL library under certain conditions as described in each
 * individual source file, and distribute linked combinations
 * including the two.
 *
 * You must obey the GNU Affero General Public License in all respects
 * for all of the code used other than OpenSSL.
 */

#include "config.h"

#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif

#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif

#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif

#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif

#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif

#ifdef HAVE_TIME_H
#include <time.h>
#endif

#ifdef HAVE_STRING_H
#include <string.h>
#endif

#ifdef HAVE_STDIO_H
#include <stdio.h>
#endif

#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif

#include "monit.h"
#include "event.h"
#include "ProcessTree.h"
#include "process_sysdep.h"
#include "Box.h"
#include "Color.h"

// libmonit
#include "system/Time.h"


/**
 *  General purpose /proc methods.
 *
 *  @file
 */


/* ------------------------------------------------------------- Definitions */


static int ptreesize = 0;
static ProcessTree_T *ptree = NULL;


/* ----------------------------------------------------------------- Private */


static void _delete(ProcessTree_T **pt, int *size) {
        ASSERT(pt);
        ProcessTree_T *_pt = *pt;
        if (_pt) {
                for (int i = 0; i < *size; i++) {
                        FREE(_pt[i].cmdline);
                        FREE(_pt[i].children.list);
                }
                FREE(_pt);
                *pt = NULL;
                *size = 0;
        }
}


/**
 * Search a leaf in the processtree
 * @param pid  pid of the process
 * @param pt  processtree
 * @param treesize  size of the processtree
 * @return process index if succeeded otherwise -1
 */
static int _findProcess(int pid, ProcessTree_T *pt, int size) {
        if (size > 0) {
                for (int i = 0; i < size; i++)
                        if (pid == pt[i].pid)
                                return i;
        }
        return -1;
}


/**
 * Fill data in the process tree by recusively walking through it
 * @param pt process tree
 * @param i process index
 */
static void _fillProcessTree(ProcessTree_T *pt, int index) {
        if (! pt[index].visited) {
                pt[index].visited            = true;
                pt[index].children.total     = pt[index].children.count;
                pt[index].memory.usage_total = pt[index].memory.usage;
                pt[index].cpu.usage_total    = pt[index].cpu.usage;
                for (int i = 0; i < pt[index].children.count; i++)
                        _fillProcessTree(pt, pt[index].children.list[i]);
                if (pt[index].parent != -1 && pt[index].parent != index) {
                        ProcessTree_T *parent_pt       = &pt[pt[index].parent];
                        parent_pt->children.total     += pt[index].children.total;
                        parent_pt->memory.usage_total += pt[index].memory.usage_total;
                        parent_pt->cpu.usage_total    += pt[index].cpu.usage_total;
                }
        }
}


/**
 * Adjust the CPU usage based on the available system resources: number of CPU cores the application may utilize. Single threaded application may utilized only one CPU core, 4 threaded application 4 cores, etc.. If the application
 * has more threads then the machine has cores, it is limited by number of cores, not threads.
 * @param now Current process informations
 * @param prev Process informations from previous cycle
 * @param delta The delta of system time between current and previous cycle
 * @return Process' CPU usage [%] since last cycle
 */
static float _cpuUsage(ProcessTree_T *now, ProcessTree_T *prev, double delta) {
        if (systeminfo.cpus > 0 && delta > 0 && prev->cpu.time > 0 && now->cpu.time > prev->cpu.time) {
                int divisor;
                if (now->threads > 1) {
                        if (now->threads >= systeminfo.cpus) {
                                // Multithreaded application with more threads then CPU cores
                                divisor = systeminfo.cpus;
                        } else {
                                // Multithreaded application with less threads then CPU cores
                                divisor = now->threads;
                        }
                } else {
                        // Single threaded application
                        divisor = 1;
                }
                float usage = (100. * (now->cpu.time - prev->cpu.time) / delta) / divisor;
                return usage > 100. ? 100. : usage;
        }
        return 0.;
}


static boolean_t _match(regex_t *regex) {
        int found = -1;
        // Scan the whole process tree and find the oldest matching process whose parent doesn't match the pattern
        for (int i = 0; i < ptreesize; i++)
                if (ptree[i].cmdline && regexec(regex, ptree[i].cmdline, 0, NULL, 0) == 0 && (i == ptree[i].parent || ! ptree[ptree[i].parent].cmdline || regexec(regex, ptree[ptree[i].parent].cmdline, 0, NULL, 0) != 0) && (found == -1 || ptree[found].uptime < ptree[i].uptime))
                        found = i;
        return found >= 0 ? ptree[found].pid : found;
}


/* ------------------------------------------------------------------ Public */


/**
 * Initialize the process tree
 * @return treesize >= 0 if succeeded otherwise < 0
 */
int ProcessTree_init(ProcessEngine_Flags pflags) {
        ProcessTree_T *oldptree = ptree;
        int oldptreesize = ptreesize;
{'fraction_non_alphanumeric': 0.13206349206349208, 'fraction_numerical': 0.006190476190476191, 'mean_word_length': 1.8981140754369825, 'pattern_counts': {'":': 0, '<': 35, '<?xml version=': 0, '>': 65, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1174868', 'n_tokens_mistral': 3651, 'n_tokens_neox': 3439, 'n_words': 1192}