From: Aleksinski, MichalX Date: Wed, 20 Feb 2019 12:32:50 +0000 (+0000) Subject: utils_proc_pids: moved to utils directory X-Git-Url: https://git.octo.it/?a=commitdiff_plain;h=bcb9e8252f192560195b4faa5c79a84ea31df4f6;p=collectd.git utils_proc_pids: moved to utils directory Change-Id: Ia7c9bf5dca2b871b05c9ed3876059e6d34bd943e --- diff --git a/Makefile.am b/Makefile.am index b4195c13..7a64fbfd 100644 --- a/Makefile.am +++ b/Makefile.am @@ -378,7 +378,7 @@ test_utils_config_cores_SOURCES = \ test_utils_config_cores_LDADD = libplugin_mock.la test_utils_proc_pids_SOURCES = \ - src/utils_proc_pids_test.c \ + src/utils/proc_pids/proc_pids_test.c \ src/testing.h test_utils_proc_pids_LDADD = libplugin_mock.la @@ -1071,8 +1071,8 @@ if BUILD_PLUGIN_INTEL_RDT pkglib_LTLIBRARIES += intel_rdt.la intel_rdt_la_SOURCES = \ src/intel_rdt.c \ - src/utils_proc_pids.c \ - src/utils_proc_pids.h \ + src/utils/proc_pids/proc_pids.c \ + src/utils/proc_pids/proc_pids.h \ src/utils/config_cores/config_cores.h \ src/utils/config_cores/config_cores.c intel_rdt_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBPQOS_CPPFLAGS) @@ -1082,7 +1082,7 @@ intel_rdt_la_LIBADD = $(BUILD_WITH_LIBPQOS_LIBS) test_plugin_intel_rdt_SOURCES = \ src/intel_rdt_test.c \ src/utils/config_cores/config_cores.c \ - src/utils_proc_pids.c \ + src/utils/proc_pids/proc_pids.c \ src/daemon/configfile.c \ src/daemon/types_list.c test_plugin_intel_rdt_CPPFLAGS = $(AM_CPPFLAGS) diff --git a/src/intel_rdt.c b/src/intel_rdt.c index 73648208..003f71ab 100644 --- a/src/intel_rdt.c +++ b/src/intel_rdt.c @@ -31,7 +31,7 @@ #include "collectd.h" #include "utils/common/common.h" #include "utils/config_cores/config_cores.h" -#include "utils_proc_pids.h" +#include "utils/proc_pids/proc_pids.h" #include #define RDT_PLUGIN "intel_rdt" @@ -526,7 +526,7 @@ static int rdt_config_ngroups(rdt_ctx_t *rdt, const oconfig_item_t *item) { name_idx++) { DEBUG(RDT_PLUGIN ": checking process name [%zu]: %s", name_idx, rdt->ngroups[group_idx].names[name_idx]); - if (!is_proc_name_valid(rdt->ngroups[group_idx].names[name_idx])) { + if (!proc_pids_is_name_valid(rdt->ngroups[group_idx].names[name_idx])) { ERROR(RDT_PLUGIN ": Process name group '%s' contains invalid name '%s'", rdt->ngroups[group_idx].desc, rdt->ngroups[group_idx].names[name_idx]); @@ -798,7 +798,7 @@ static int read_pids_data() { #endif /* COLLECT_DEBUG */ groups_refresh: - ret = update_proc_pids(RDT_PROC_PATH, g_rdt->proc_pids, g_rdt->num_proc_pids); + ret = proc_pids_update(RDT_PROC_PATH, g_rdt->proc_pids, g_rdt->num_proc_pids); if (0 != ret) { ERROR(RDT_PLUGIN ": Initial update of proc pids failed"); return ret; @@ -839,8 +839,8 @@ static void rdt_init_pids_monitoring() { * PIDs statistics detection. */ rdt_name_group_t *ng = &g_rdt->ngroups[group_idx]; - int init_result = initialize_proc_pids((const char **)ng->names, - ng->num_names, &ng->proc_pids); + int init_result = + proc_pids_init((const char **)ng->names, ng->num_names, &ng->proc_pids); if (0 != init_result) { ERROR(RDT_PLUGIN ": Initialization of proc_pids for group %zu failed. Error: %d", @@ -865,7 +865,7 @@ static void rdt_init_pids_monitoring() { } int update_result = - update_proc_pids(RDT_PROC_PATH, g_rdt->proc_pids, g_rdt->num_proc_pids); + proc_pids_update(RDT_PROC_PATH, g_rdt->proc_pids, g_rdt->num_proc_pids); if (0 != update_result) ERROR(RDT_PLUGIN ": Initial update of proc pids failed"); diff --git a/src/utils/proc_pids/proc_pids.c b/src/utils/proc_pids/proc_pids.c new file mode 100644 index 00000000..336a9964 --- /dev/null +++ b/src/utils/proc_pids/proc_pids.c @@ -0,0 +1,361 @@ +/** + * collectd - src/utils/proc_pids/proc_pids.c + * + * Copyright(c) 2018-2019 Intel Corporation. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Authors: + * Starzyk, Mateusz + * Wojciech Andralojc + * Michał Aleksiński + **/ + +#include "collectd.h" +#include "utils/common/common.h" +#include "utils/proc_pids/proc_pids.h" + +#define UTIL_NAME "utils_proc_pids" + +void pids_list_free(pids_list_t *list) { + assert(list); + + sfree(list->pids); + sfree(list); +} + +int proc_pids_is_name_valid(const char *name) { + + if (name != NULL) { + unsigned len = strlen(name); + if (len > 0 && len <= MAX_PROC_NAME_LEN) + return 1; + else { + DEBUG(UTIL_NAME + ": Process name \'%s\' is too long. Max supported len is %d chars.", + name, MAX_PROC_NAME_LEN); + } + } + + return 0; +} + +int pids_list_add_pid(pids_list_t *list, const pid_t pid) { + assert(list); + + if (list->allocated == list->size) { + size_t new_allocated = list->allocated + 1 + list->allocated / 10; + pid_t *new_pids = realloc(list->pids, sizeof(pid_t) * new_allocated); + + if (NULL == new_pids) { + ERROR(UTIL_NAME ": Alloc error\n"); + return -1; + } + + list->pids = new_pids; + list->allocated = new_allocated; + } + + list->pids[list->size] = pid; + list->size++; + + return 0; +} + +int pids_list_add_list(pids_list_t *dst, pids_list_t *src) { + assert(dst); + assert(src); + + if (dst->allocated < dst->size + src->size) { + pid_t *new_pids = + realloc(dst->pids, sizeof(pid_t) * (dst->size + src->size)); + + if (NULL == new_pids) { + ERROR(UTIL_NAME ": Alloc error\n"); + return -1; + } + + dst->allocated = dst->size + src->size; + dst->pids = new_pids; + } + + memcpy(dst->pids + dst->size, src->pids, src->size * sizeof(*(src->pids))); + dst->size += src->size; + + return 0; +} + +int pids_list_clear(pids_list_t *list) { + assert(list); + + if (list->pids != NULL) + sfree(list->pids); + + list->size = 0; + list->allocated = 0; + + return 0; +} + +int pids_list_contains_pid(pids_list_t *list, const pid_t pid) { + assert(list); + + for (int i = 0; i < list->size; i++) + if (list->pids[i] == pid) + return 1; + + return 0; +} + +/* + * NAME + * read_proc_name + * + * DESCRIPTION + * Reads process name from given pid directory. + * Strips new-line character (\n). + * + * PARAMETERS + * `procfs_path' Path to systems proc directory (e.g. /proc) + * `pid_entry' Dirent for PID directory + * `name' Output buffer for process name, recommended proc_comm. + * `out_size' Output buffer size, recommended sizeof(proc_comm) + * + * RETURN VALUE + * On success, the number of read bytes (includes stripped \n). + * -1 on file open error +*/ +static int read_proc_name(const char *procfs_path, + const struct dirent *pid_entry, char *name, + const size_t out_size) { + assert(pid_entry); + assert(name); + assert(out_size); + memset(name, 0, out_size); + + const char *comm_file_name = "comm"; + + char *path = ssnprintf_alloc("%s/%s/%s", procfs_path, pid_entry->d_name, + comm_file_name); + if (path == NULL) + return -1; + FILE *f = fopen(path, "r"); + if (f == NULL) { + ERROR(UTIL_NAME ": Failed to open comm file, error: %d\n", errno); + sfree(path); + return -1; + } + size_t read_length = fread(name, sizeof(char), out_size, f); + name[out_size - 1] = '\0'; + fclose(f); + sfree(path); + /* strip new line ending */ + char *newline = strchr(name, '\n'); + if (newline) { + *newline = '\0'; + } + + return read_length; +} + +/* + * NAME + * get_pid_number + * + * DESCRIPTION + * Gets pid number for given /proc/pid directory entry or + * returns error if input directory does not hold PID information. + * + * PARAMETERS + * `entry' Dirent for PID directory + * `pid' PID number to be filled + * + * RETURN VALUE + * 0 on success. -1 on error. + */ +static int get_pid_number(struct dirent *entry, pid_t *pid) { + char *tmp_end; /* used for strtoul error check*/ + + if (pid == NULL || entry == NULL) + return -1; + + if (entry->d_type != DT_DIR) + return -1; + + /* trying to get pid number from directory name*/ + *pid = strtoul(entry->d_name, &tmp_end, 10); + if (*tmp_end != '\0') { + return -1; /* conversion failed, not proc-pid */ + } + /* all checks passed, marking as success */ + return 0; +} + +int proc_pids_init(const char **procs_names_array, + const size_t procs_names_array_size, + proc_pids_t **proc_pids[]) { + + proc_pids_t **proc_pids_array; + assert(proc_pids); + assert(NULL == *proc_pids); + + /* Copy procs names to output array. Initialize pids list with NULL value. */ + proc_pids_array = calloc(procs_names_array_size, sizeof(*proc_pids_array)); + + if (NULL == proc_pids_array) + return -1; + + for (size_t i = 0; i < procs_names_array_size; ++i) { + proc_pids_array[i] = calloc(1, sizeof(**proc_pids_array)); + if (NULL == proc_pids_array[i]) + goto proc_pids_init_error; + + sstrncpy(proc_pids_array[i]->process_name, procs_names_array[i], + STATIC_ARRAY_SIZE(proc_pids_array[i]->process_name)); + proc_pids_array[i]->prev = NULL; + proc_pids_array[i]->curr = NULL; + } + + *proc_pids = proc_pids_array; + + return 0; +proc_pids_init_error: + if (NULL != proc_pids_array) { + for (size_t i = 0; i < procs_names_array_size; ++i) { + free(proc_pids_array[i]); + } + free(proc_pids_array); + } + return -1; +} + +static void swap_proc_pids(proc_pids_t **proc_pids, size_t proc_pids_num) { + for (size_t i = 0; i < proc_pids_num; i++) { + pids_list_t *swap = proc_pids[i]->prev; + proc_pids[i]->prev = proc_pids[i]->curr; + proc_pids[i]->curr = swap; + } +} + +int proc_pids_update(const char *procfs_path, proc_pids_t **proc_pids, + size_t proc_pids_num) { + assert(procfs_path); + assert(proc_pids); + + DIR *proc_dir = opendir(procfs_path); + if (proc_dir == NULL) { + ERROR(UTIL_NAME ": Could not open %s directory, error: %d", procfs_path, + errno); + return -1; + } + + swap_proc_pids(proc_pids, proc_pids_num); + + for (size_t i = 0; i < proc_pids_num; i++) { + if (NULL == proc_pids[i]->curr) + proc_pids[i]->curr = calloc(1, sizeof(*(proc_pids[i]->curr))); + + if (NULL == proc_pids[i]->curr) { + ERROR(UTIL_NAME ": Alloc error\n"); + goto update_error; + } + + proc_pids[i]->curr->size = 0; + } + + /* Go through procfs and find PIDS and their comms */ + struct dirent *entry; + while ((entry = readdir(proc_dir)) != NULL) { + pid_t pid; + int pid_conversion = get_pid_number(entry, &pid); + if (pid_conversion < 0) + continue; + + proc_comm_t comm; + int read_result = + read_proc_name(procfs_path, entry, comm, sizeof(proc_comm_t)); + if (read_result <= 0) + continue; + + /* Try to find comm in input procs array */ + for (size_t i = 0; i < proc_pids_num; ++i) { + if (0 == + strncmp(comm, proc_pids[i]->process_name, STATIC_ARRAY_SIZE(comm))) + pids_list_add_pid(proc_pids[i]->curr, pid); + } + } + + int close_result = closedir(proc_dir); + if (0 != close_result) { + ERROR(UTIL_NAME ": failed to close /proc directory, error: %d", errno); + goto update_error; + } + return 0; + +update_error: + swap_proc_pids(proc_pids, proc_pids_num); + return -1; +} + +int pids_list_diff(proc_pids_t *proc, pids_list_t *added, + pids_list_t *removed) { + assert(proc); + assert(added); + assert(removed); + + added->size = 0; + removed->size = 0; + + if (NULL == proc->prev || 0 == proc->prev->size) { + /* append all PIDs from curr to added*/ + return pids_list_add_list(added, proc->curr); + } else if (NULL == proc->curr || 0 == proc->curr->size) { + /* append all PIDs from prev to removed*/ + return pids_list_add_list(removed, proc->prev); + } + + for (int i = 0; i < proc->prev->size; i++) + if (0 == pids_list_contains_pid(proc->curr, proc->prev->pids[i])) { + int add_result = pids_list_add_pid(removed, proc->prev->pids[i]); + if (add_result < 0) + return add_result; + } + + for (int i = 0; i < proc->curr->size; i++) + if (0 == pids_list_contains_pid(proc->prev, proc->curr->pids[i])) { + int add_result = pids_list_add_pid(added, proc->curr->pids[i]); + if (add_result < 0) + return add_result; + } + + return 0; +} + +int proc_pids_free(proc_pids_t *proc_pids[], size_t proc_pids_num) { + for (size_t i = 0; i < proc_pids_num; i++) { + if (NULL != proc_pids[i]->curr) + pids_list_free(proc_pids[i]->curr); + if (NULL != proc_pids[i]->prev) + pids_list_free(proc_pids[i]->prev); + sfree(proc_pids[i]); + } + sfree(proc_pids); + + return 0; +} diff --git a/src/utils/proc_pids/proc_pids.h b/src/utils/proc_pids/proc_pids.h new file mode 100644 index 00000000..8b19497c --- /dev/null +++ b/src/utils/proc_pids/proc_pids.h @@ -0,0 +1,226 @@ +/** + * collectd - src/utils/proc_pids/proc_pids.h + * + * Copyright(c) 2018-2019 Intel Corporation. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Authors: + * Starzyk, Mateusz + * Wojciech Andralojc + * Michał Aleksiński + **/ + +#include +#include + +/* + * Process name inside comm file is limited to 16 chars. + * More info here: http://man7.org/linux/man-pages/man5/proc.5.html + */ +#define MAX_PROC_NAME_LEN 16 + +/* Helper typedef for process name array + * Extra 1 char is added for string null termination. + */ +typedef char proc_comm_t[MAX_PROC_NAME_LEN + 1]; + +/* List of pids. */ +typedef struct pids_list_s { + pid_t *pids; + size_t size; + size_t allocated; +} pids_list_t; + +/* Holds process name and list of pids assigned to that name */ +typedef struct proc_pids_s { + proc_comm_t process_name; + pids_list_t *prev; + pids_list_t *curr; +} proc_pids_t; + +/* + * NAME + * pids_list_free + * + * DESCRIPTION + * Free all elements of given pids list + * + * PARAMETERS + * `list' Head of target pids_list. + */ +void pids_list_free(pids_list_t *list); + +/* + * NAME + * pids_list_add_pid + * + * DESCRIPTION + * Adds pid at the end of the pids array. + * Reallocates memory for new pid element, it is up to user to free it. + * + * PARAMETERS + * `list' Target pids_list. + * `pid' Pid to be added. + * + * RETURN VALUE + * On success, returns 0. + * -1 on memory allocation error. + */ +int pids_list_add_pid(pids_list_t *list, const pid_t pid); + +/* + * NAME + * pids_list_clear + * + * DESCRIPTION + * Remove all pids from the list + * + * PARAMETERS + * `list' Target pids_list. + * + * RETURN VALUE + * On success, return 0 + */ +int pids_list_clear(pids_list_t *list); + +/* + * NAME + * pids_list_add_list + * + * DESCRIPTION + * Adds pids list at the end of the pids list. + * Allocates memory for new pid elements, it is up to user to free it. + * + * PARAMETERS + * `dst' Target PIDs list. + * `src' Source PIDs list. + * + * RETURN VALUE + * On success, returns 0. + * -1 on memory allocation error. + */ +int pids_list_add_list(pids_list_t *dst, pids_list_t *src); + +/* + * NAME + * pids_list_contains_pid + * + * DESCRIPTION + * Tests if pids list contains specific pid. + * + * PARAMETERS + * `list' pids_list to check. + * `pid' Pid to be searched for. + * + * RETURN VALUE + * If PID found in list, returns 1, + * Otherwise returns 0. + */ +int pids_list_contains_pid(pids_list_t *list, const pid_t pid); + +/* + * NAME + * pids_list_diff + * + * DESCRIPTION + * Searches for differences in two given lists + * + * PARAMETERS + * `proc' List of pids + * `added' New pids which appeared + * `removed' Result array storing pids which disappeared + * RETURN VALUE + * 0 on success. Negative number on error. + */ +int pids_list_diff(proc_pids_t *proc, pids_list_t *added, pids_list_t *removed); + +/* + * NAME + * proc_pids_is_name_valid + * + * DESCRIPTION + * Checks if given string is valid process name. + * + * PARAMETERS + * `name' null-terminated char array + * + * RETURN VALUE + * If given name is a valid process name, returns 1, + * Otherwise returns 0. + */ +int proc_pids_is_name_valid(const char *name); + +/* + * NAME + * proc_pids_init + * + * DESCRIPTION + * Helper function to properly initialize array of proc_pids. + * Allocates memory for proc_pids structs. + * + * PARAMETERS + * `procs_names_array' Array of null-terminated strings with + * process' names to be copied to new array + * `procs_names_array_size' procs_names_array element count + * `proc_pids' Address of pointer, under which new + * array of proc_pids will be allocated. + * Must be NULL. + * RETURN VALUE + * 0 on success. Negative number on error: + * -1: allocation error + */ +int proc_pids_init(const char **procs_names_array, + const size_t procs_names_array_size, + proc_pids_t **proc_pids[]); + +/* + * NAME + * proc_pids_update + * + * DESCRIPTION + * Updates PIDs matching processes's names. + * Searches all PID directories in /proc fs and updates current pids_list. + * + * PARAMETERS + * `procfs_path' Path to systems proc directory (e.g. /proc) + * `proc_pids' Array of proc_pids pointers to be updated. + * `proc_pids_num' proc_pids element count + * + * RETURN VALUE + * 0 on success. -1 on error. + */ +int proc_pids_update(const char *procfs_path, proc_pids_t *proc_pids[], + size_t proc_pids_num); + +/* + * NAME + * proc_pids_free + * + * DESCRIPTION + * Releses memory allocatd for proc_pids + * + * PARAMETERS + * `proc_pids' Array of proc_pids + * `proc_pids_num' proc_pids element count + * + * RETURN VALUE + * 0 on success. -1 on error. + */ +int proc_pids_free(proc_pids_t *proc_pids[], size_t proc_pids_num); diff --git a/src/utils/proc_pids/proc_pids_test.c b/src/utils/proc_pids/proc_pids_test.c new file mode 100644 index 00000000..06b8d39b --- /dev/null +++ b/src/utils/proc_pids/proc_pids_test.c @@ -0,0 +1,505 @@ +#include "testing.h" +#include "utils/proc_pids/proc_pids.c" /* sic */ +#include + +/*************************************************************************** + * helper functions + */ + +typedef struct stub_proc_pid { + proc_comm_t comm; + pid_t pid; +} stub_proc_pid_t; + +static const char *proc_fs = "/tmp/procfs_stub"; + +/* + * NAME + * stub_procfs_setup + * + * DESCRIPTION + * Prepares testing environment by creating temporary + * PID/comm file structure. + * + * PARAMETERS + * `proc_pids_array' Array of stub_proc_pid_t structs. Represents + * which PIDs should hold given process name. + * `proc_pids_array_length' Element count of input array. + * + * RETURN VALUE + * 0 on success. + * -1 on base dir creation error. + * -2 on comm file creation error. + * -3 on comm file write error. + */ +int stub_procfs_setup(const stub_proc_pid_t *proc_pids_array, + const size_t proc_pids_array_length) { + if (mkdir(proc_fs, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0) + return -1; + char path[256]; + + for (size_t i = 0; i < proc_pids_array_length; ++i) { + memset(path, 0, sizeof(path)); + snprintf(path, STATIC_ARRAY_SIZE(path), "%s/%d", proc_fs, + proc_pids_array[i].pid); + mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); + strncat(path, "/comm", STATIC_ARRAY_SIZE(path) - strlen(path) - 1); + + FILE *fp = fopen(path, "w"); + if (!fp) + return -2; + + size_t slen = strlen(proc_pids_array[i].comm); + size_t wlen = fwrite(proc_pids_array[i].comm, sizeof(char), slen, fp); + fclose(fp); + + if (slen != wlen) + return -3; + } + return 0; +} + +/* + * NAME + * stub_procfs_teardown + * + * DESCRIPTION + * Clears testing environment: removes stub proc files. + * NOTE - This function could be implemented by usage of nftw, but this + * would require #define _XOPEN_SOURCE 500, which + * messes up intel_rdt includes. + * + * RETURN VALUE + * system command result + */ +int stub_procfs_teardown() { + char cmd[256]; + sstrncpy(cmd, "rm -rf ", STATIC_ARRAY_SIZE(cmd)); + strncat(cmd, proc_fs, STATIC_ARRAY_SIZE(cmd) - strlen(cmd) - 1); + return system(cmd); +} + +/* Max PID value. More info: + * http://web.archive.org/web/20111209081734/http://research.cs.wisc.edu/condor/condorg/linux_scalability.html + */ +#define MAX_PID 4194304 +#define MAX_PID_STR "4194304" + +/*************************************************************************** + * tests + */ +DEF_TEST(proc_pids_init__on_nullptr) { + /* setup */ + const char *procs_names_array[] = {"proc1", "proc2", "proc3"}; + const size_t procs_names_array_size = STATIC_ARRAY_SIZE(procs_names_array); + proc_pids_t **proc_pids_array = NULL; + + /* check */ + int result = proc_pids_init(procs_names_array, procs_names_array_size, + &proc_pids_array); + EXPECT_EQ_INT(0, result); + for (size_t i = 0; i < procs_names_array_size; ++i) + EXPECT_EQ_STR(procs_names_array[i], proc_pids_array[i]->process_name); + + /* cleanup */ + proc_pids_free(proc_pids_array, procs_names_array_size); + return 0; +} + +DEF_TEST(pid_list_add_pid__empty_list) { + /* setup */ + pids_list_t *proc_pids_instance = calloc(1, sizeof(*proc_pids_instance)); + pid_t pid = 1234; + + /* check */ + pids_list_add_pid(proc_pids_instance, pid); + EXPECT_EQ_INT(pid, proc_pids_instance->pids[0]); + + /* cleanup */ + pids_list_free(proc_pids_instance); + return 0; +} + +DEF_TEST(pid_list_add_pid__non_empty_list) { + /* setup */ + pids_list_t *proc_pids_instance = calloc(1, sizeof(*proc_pids_instance)); + pid_t pids[] = {1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007}; + + /* check */ + for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids); ++i) + pids_list_add_pid(proc_pids_instance, pids[i]); + + for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids); ++i) { + EXPECT_EQ_INT(pids[i], proc_pids_instance->pids[i]); + } + + /* cleanup */ + pids_list_free(proc_pids_instance); + return 0; +} + +DEF_TEST(pids_list_add_pids_list__non_empty_lists) { + /* setup */ + pid_t pids_array_1[] = {1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007}; + pid_t pids_array_2[] = {2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007}; + pids_list_t *pids_list_1 = calloc(1, sizeof(*pids_list_1)); + pids_list_t *pids_list_2 = calloc(1, sizeof(*pids_list_2)); + for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids_array_1); ++i) { + pids_list_add_pid(pids_list_1, pids_array_1[i]); + pids_list_add_pid(pids_list_2, pids_array_2[i]); + } + + /* check */ + int result = pids_list_add_list(pids_list_1, pids_list_2); + EXPECT_EQ_INT(0, result); + EXPECT_EQ_INT(STATIC_ARRAY_SIZE(pids_array_2) + + STATIC_ARRAY_SIZE(pids_array_1), + pids_list_1->size); + + for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids_array_1); ++i) { + EXPECT_EQ_INT(1, pids_list_contains_pid(pids_list_1, pids_array_1[i])); + EXPECT_EQ_INT(1, pids_list_contains_pid(pids_list_1, pids_array_2[i])); + } + + /* setup */ + pids_list_free(pids_list_1); + pids_list_free(pids_list_2); + return 0; +} + +DEF_TEST(pids_list_add_pids_list__add_to_empty) { + /* setup */ + pid_t pids_array[] = {2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007}; + pids_list_t *pids_list_1 = calloc(1, sizeof(*pids_list_1)); + pids_list_t *pids_list_2 = calloc(1, sizeof(*pids_list_2)); + for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids_array); ++i) + pids_list_add_pid(pids_list_2, pids_array[i]); + + /* check */ + int result = pids_list_add_list(pids_list_1, pids_list_2); + EXPECT_EQ_INT(0, result); + EXPECT_EQ_INT(STATIC_ARRAY_SIZE(pids_array), pids_list_1->size); + + for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids_array); ++i) + EXPECT_EQ_INT(1, pids_list_contains_pid(pids_list_1, pids_array[i])); + + /* setup */ + pids_list_free(pids_list_1); + pids_list_free(pids_list_2); + return 0; +} + +DEF_TEST(get_pid_number__valid_dir) { + /* setup */ + struct dirent d; + sstrncpy(d.d_name, MAX_PID_STR, STATIC_ARRAY_SIZE(d.d_name)); + d.d_type = DT_DIR; + pid_t pid = 0; + + /* check */ + int pid_conversion = get_pid_number(&d, &pid); + + EXPECT_EQ_INT(0, pid_conversion); + EXPECT_EQ_INT(MAX_PID, pid); + + /* cleanup */ + return 0; +} + +DEF_TEST(get_pid_number__invalid_dir_name) { + /* setup */ + struct dirent d; + sstrncpy(d.d_name, "invalid", STATIC_ARRAY_SIZE(d.d_name)); + d.d_type = DT_DIR; + pid_t pid = 0; + + /* check */ + int pid_conversion = get_pid_number(&d, &pid); + + EXPECT_EQ_INT(-1, pid_conversion); + EXPECT_EQ_INT(0, pid); + + /* cleanup */ + return 0; +} + +DEF_TEST(read_proc_name__valid_name) { + /* setup */ + stub_proc_pid_t pp_stubs[] = {{"proc1", MAX_PID}}; + stub_procfs_setup(pp_stubs, STATIC_ARRAY_SIZE(pp_stubs)); + struct dirent d; + sstrncpy(d.d_name, MAX_PID_STR, STATIC_ARRAY_SIZE(d.d_name)); + d.d_type = DT_DIR; + + /* check */ + proc_comm_t comm; + int read_result = read_proc_name(proc_fs, &d, comm, STATIC_ARRAY_SIZE(comm)); + + EXPECT_EQ_INT(strlen(pp_stubs[0].comm), read_result); + EXPECT_EQ_STR(pp_stubs[0].comm, comm); + + /* cleanup */ + stub_procfs_teardown(); + return 0; +} + +DEF_TEST(read_proc_name__invalid_name) { + /* setup */ + struct dirent d; + sstrncpy(d.d_name, MAX_PID_STR, STATIC_ARRAY_SIZE(d.d_name)); + d.d_type = DT_DIR; + + /* check */ + proc_comm_t comm; + int read_result = read_proc_name(proc_fs, &d, comm, STATIC_ARRAY_SIZE(comm)); + + EXPECT_EQ_INT(-1, read_result); + + /* cleanup */ + return 0; +} + +DEF_TEST(proc_pids_update__one_proc_many_pid) { + /* setup */ + const char *proc_names[] = {"proc1"}; + stub_proc_pid_t pp_stubs[] = {{"proc1", 1007}, + {"proc1", 1008}, + {"proc1", 1009}, + {"proc2", 1010}, + {"proc3", 1011}}; + proc_pids_t **proc_pids = NULL; + int result; + stub_procfs_setup(pp_stubs, STATIC_ARRAY_SIZE(pp_stubs)); + + result = + proc_pids_init(proc_names, STATIC_ARRAY_SIZE(proc_names), &proc_pids); + EXPECT_EQ_INT(0, result); + + /* check */ + result = proc_pids_update(proc_fs, proc_pids, STATIC_ARRAY_SIZE(proc_names)); + EXPECT_EQ_INT(0, result); + + /* proc name check */ + EXPECT_EQ_STR(proc_names[0], proc_pids[0]->process_name); + + for (size_t i = 0; i < STATIC_ARRAY_SIZE(pp_stubs); ++i) { + if (0 == strcmp(pp_stubs[i].comm, proc_names[0])) + /* check if proc struct has correct pids */ + EXPECT_EQ_INT(pids_list_contains_pid(proc_pids[0]->curr, pp_stubs[i].pid), + 1); + else + /* check if proc struct has no incorrect pids */ + EXPECT_EQ_INT(pids_list_contains_pid(proc_pids[0]->curr, pp_stubs[i].pid), + 0); + } + + /* cleanup */ + proc_pids_free(proc_pids, STATIC_ARRAY_SIZE(proc_names)); + stub_procfs_teardown(); + return 0; +} + +DEF_TEST(proc_pids_update__many_proc_many_pid) { + /* setup */ + const char *proc_names[] = {"proc1", "proc2", "proc3"}; + stub_proc_pid_t pp_stubs[] = { + {"proc1", 1007}, {"proc1", 1008}, {"proc1", 1009}, {"proc2", 2007}, + {"proc2", 2008}, {"proc2", 2009}, {"proc3", 3007}, {"proc3", 3008}, + {"proc3", 3009}, {"proc4", 4007}, {"proc4", 4008}, {"proc4", 4009}, + {"proc5", 5007}, {"proc5", 5008}, {"proc5", 5009}}; + proc_pids_t **proc_pids = NULL; + int result; + stub_procfs_setup(pp_stubs, STATIC_ARRAY_SIZE(pp_stubs)); + + result = + proc_pids_init(proc_names, STATIC_ARRAY_SIZE(proc_names), &proc_pids); + EXPECT_EQ_INT(0, result); + + /* check */ + result = proc_pids_update(proc_fs, proc_pids, STATIC_ARRAY_SIZE(proc_names)); + EXPECT_EQ_INT(0, result); + + for (size_t i = 0; i < STATIC_ARRAY_SIZE(proc_names); ++i) { + + /* proc name check */ + EXPECT_EQ_STR(proc_names[i], proc_pids[i]->process_name); + + for (size_t j = 0; j < STATIC_ARRAY_SIZE(pp_stubs); ++j) { + if (0 == strcmp(pp_stubs[j].comm, proc_names[i])) + /* check if proc struct has correct pids */ + EXPECT_EQ_INT( + pids_list_contains_pid(proc_pids[i]->curr, pp_stubs[j].pid), 1); + else + /* check if proc struct has no incorrect pids */ + EXPECT_EQ_INT( + pids_list_contains_pid(proc_pids[i]->curr, pp_stubs[j].pid), 0); + } + } + + /* cleanup */ + proc_pids_free(proc_pids, STATIC_ARRAY_SIZE(proc_names)); + stub_procfs_teardown(); + return 0; +} + +DEF_TEST(pids_list_diff__all_changed) { + /* setup */ + pid_t pids_array_before[] = {1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007}; + pid_t pids_array_after[] = {2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007}; + proc_pids_t proc_pids; + pids_list_t curr; + pids_list_t prev; + + prev.pids = pids_array_before; + prev.size = STATIC_ARRAY_SIZE(pids_array_before); + prev.allocated = prev.size; + curr.pids = pids_array_after; + curr.size = STATIC_ARRAY_SIZE(pids_array_after); + curr.allocated = curr.size; + proc_pids.curr = &curr; + proc_pids.prev = &prev; + + pids_list_t *new_pids = calloc(1, sizeof(*new_pids)); + pids_list_t *lost_pids = calloc(1, sizeof(*lost_pids)); + + /* check */ + int result = pids_list_diff(&proc_pids, new_pids, lost_pids); + EXPECT_EQ_INT(0, result); + EXPECT_EQ_INT(STATIC_ARRAY_SIZE(pids_array_before), lost_pids->size); + EXPECT_EQ_INT(STATIC_ARRAY_SIZE(pids_array_after), new_pids->size); + + for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids_array_before); ++i) { + EXPECT_EQ_INT(1, pids_list_contains_pid(new_pids, pids_array_after[i])); + EXPECT_EQ_INT(1, pids_list_contains_pid(lost_pids, pids_array_before[i])); + } + + /* cleanup */ + pids_list_free(new_pids); + pids_list_free(lost_pids); + + return 0; +} + +DEF_TEST(pids_list_diff__nothing_changed) { + /* setup */ + pid_t pids_array_before[] = {1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007}; + proc_pids_t proc_pids; + pids_list_t curr; + pids_list_t prev; + + prev.pids = pids_array_before; + prev.size = STATIC_ARRAY_SIZE(pids_array_before); + prev.allocated = prev.size; + curr.pids = pids_array_before; + curr.size = STATIC_ARRAY_SIZE(pids_array_before); + curr.allocated = curr.size; + proc_pids.curr = &curr; + proc_pids.prev = &prev; + + pids_list_t *new_pids = calloc(1, sizeof(*new_pids)); + pids_list_t *lost_pids = calloc(1, sizeof(*lost_pids)); + + /* check */ + int result = pids_list_diff(&proc_pids, new_pids, lost_pids); + EXPECT_EQ_INT(0, result); + EXPECT_EQ_INT(0, lost_pids->size); + EXPECT_EQ_INT(0, new_pids->size); + + /* cleanup */ + pids_list_free(lost_pids); + pids_list_free(new_pids); + + return 0; +} + +DEF_TEST(pids_list_diff__one_added) { + /* setup */ + pid_t pids_array_before[] = {1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007}; + pid_t pids_array_after[] = {1000, 1001, 1002, 1003, 1004, + 1005, 1006, 1007, 1008}; + proc_pids_t proc_pids; + pids_list_t curr; + pids_list_t prev; + + prev.pids = pids_array_before; + prev.size = STATIC_ARRAY_SIZE(pids_array_before); + prev.allocated = prev.size; + curr.pids = pids_array_after; + curr.size = STATIC_ARRAY_SIZE(pids_array_after); + curr.allocated = curr.size; + proc_pids.curr = &curr; + proc_pids.prev = &prev; + + pids_list_t *new_pids = calloc(1, sizeof(*new_pids)); + pids_list_t *lost_pids = calloc(1, sizeof(*lost_pids)); + + /* check */ + int result = pids_list_diff(&proc_pids, new_pids, lost_pids); + EXPECT_EQ_INT(0, result); + EXPECT_EQ_INT(0, lost_pids->size); + EXPECT_EQ_INT(1, new_pids->size); + EXPECT_EQ_INT(1008, new_pids->pids[0]); + + /* cleanup */ + pids_list_free(lost_pids); + pids_list_free(new_pids); + + return 0; +} + +DEF_TEST(pids_list_diff__one_removed) { + /* setup */ + pid_t pids_array_before[] = {1000, 1001, 1002, 1003, 1004, + 1005, 1006, 1007, 1008}; + pid_t pids_array_after[] = {1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007}; + + proc_pids_t proc_pids; + pids_list_t curr; + pids_list_t prev; + + prev.pids = pids_array_before; + prev.size = STATIC_ARRAY_SIZE(pids_array_before); + prev.allocated = prev.size; + curr.pids = pids_array_after; + curr.size = STATIC_ARRAY_SIZE(pids_array_after); + curr.allocated = curr.size; + proc_pids.curr = &curr; + proc_pids.prev = &prev; + + pids_list_t *new_pids = calloc(1, sizeof(*new_pids)); + pids_list_t *lost_pids = calloc(1, sizeof(*lost_pids)); + + /* check */ + int result = pids_list_diff(&proc_pids, new_pids, lost_pids); + EXPECT_EQ_INT(0, result); + EXPECT_EQ_INT(0, new_pids->size); + EXPECT_EQ_INT(1, lost_pids->size); + EXPECT_EQ_INT(1008, lost_pids->pids[0]); + + /* cleanup */ + pids_list_free(lost_pids); + pids_list_free(new_pids); + + return 0; +} + +int main(void) { + stub_procfs_teardown(); + RUN_TEST(proc_pids_init__on_nullptr); + RUN_TEST(pid_list_add_pid__empty_list); + RUN_TEST(pid_list_add_pid__non_empty_list); + RUN_TEST(pids_list_add_pids_list__non_empty_lists); + RUN_TEST(pids_list_add_pids_list__add_to_empty); + RUN_TEST(get_pid_number__valid_dir); + RUN_TEST(get_pid_number__invalid_dir_name); + RUN_TEST(read_proc_name__valid_name); + RUN_TEST(read_proc_name__invalid_name); + RUN_TEST(proc_pids_update__one_proc_many_pid); + RUN_TEST(proc_pids_update__many_proc_many_pid); + RUN_TEST(pids_list_diff__all_changed); + RUN_TEST(pids_list_diff__nothing_changed); + RUN_TEST(pids_list_diff__one_added); + RUN_TEST(pids_list_diff__one_removed); + stub_procfs_teardown(); + END_TEST; +} diff --git a/src/utils_proc_pids.c b/src/utils_proc_pids.c deleted file mode 100644 index 0fbea530..00000000 --- a/src/utils_proc_pids.c +++ /dev/null @@ -1,327 +0,0 @@ -/** - * collectd - src/utils_config_pids.c - * - * Copyright(c) 2018-2019 Intel Corporation. All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * Authors: - * Starzyk, Mateusz - * Wojciech Andralojc - * Michał Aleksiński - **/ - -#include "collectd.h" -#include "utils/common/common.h" -#include "utils_proc_pids.h" - -#define UTIL_NAME "utils_proc_pids" - -void pids_list_free(pids_list_t *list) { - assert(list); - - sfree(list->pids); - sfree(list); -} - -int is_proc_name_valid(const char *name) { - - if (name != NULL) { - unsigned len = strlen(name); - if (len > 0 && len <= MAX_PROC_NAME_LEN) - return 1; - else { - DEBUG(UTIL_NAME - ": Process name \'%s\' is too long. Max supported len is %d chars.", - name, MAX_PROC_NAME_LEN); - } - } - - return 0; -} - -int pids_list_add_pid(pids_list_t *list, const pid_t pid) { - assert(list); - - if (list->allocated == list->size) { - size_t new_allocated = list->allocated + 1 + list->allocated / 10; - pid_t *new_pids = realloc(list->pids, sizeof(pid_t) * new_allocated); - - if (NULL == new_pids) { - ERROR(UTIL_NAME ": Alloc error\n"); - return -1; - } - - list->pids = new_pids; - list->allocated = new_allocated; - } - - list->pids[list->size] = pid; - list->size++; - - return 0; -} - -int pids_list_add_list(pids_list_t *dst, pids_list_t *src) { - assert(dst); - assert(src); - - if (dst->allocated < dst->size + src->size) { - pid_t *new_pids = - realloc(dst->pids, sizeof(pid_t) * (dst->size + src->size)); - - if (NULL == new_pids) { - ERROR(UTIL_NAME ": Alloc error\n"); - return -1; - } - - dst->allocated = dst->size + src->size; - dst->pids = new_pids; - } - - memcpy(dst->pids + dst->size, src->pids, src->size * sizeof(*(src->pids))); - dst->size += src->size; - - return 0; -} - -int pids_list_clear(pids_list_t *list) { - assert(list); - - if (list->pids != NULL) - sfree(list->pids); - - list->size = 0; - list->allocated = 0; - - return 0; -} - -int pids_list_contains_pid(pids_list_t *list, const pid_t pid) { - assert(list); - - for (int i = 0; i < list->size; i++) - if (list->pids[i] == pid) - return 1; - - return 0; -} - -int read_proc_name(const char *procfs_path, const struct dirent *pid_entry, - char *name, const size_t out_size) { - assert(pid_entry); - assert(name); - assert(out_size); - memset(name, 0, out_size); - - const char *comm_file_name = "comm"; - - char *path = ssnprintf_alloc("%s/%s/%s", procfs_path, pid_entry->d_name, - comm_file_name); - if (path == NULL) - return -1; - FILE *f = fopen(path, "r"); - if (f == NULL) { - ERROR(UTIL_NAME ": Failed to open comm file, error: %d\n", errno); - sfree(path); - return -1; - } - size_t read_length = fread(name, sizeof(char), out_size, f); - name[out_size - 1] = '\0'; - fclose(f); - sfree(path); - /* strip new line ending */ - char *newline = strchr(name, '\n'); - if (newline) { - *newline = '\0'; - } - - return read_length; -} - -int get_pid_number(struct dirent *entry, pid_t *pid) { - char *tmp_end; /* used for strtoul error check*/ - - if (pid == NULL || entry == NULL) - return -1; - - if (entry->d_type != DT_DIR) - return -1; - - /* trying to get pid number from directory name*/ - *pid = strtoul(entry->d_name, &tmp_end, 10); - if (*tmp_end != '\0') { - return -1; /* conversion failed, not proc-pid */ - } - /* all checks passed, marking as success */ - return 0; -} - -int initialize_proc_pids(const char **procs_names_array, - const size_t procs_names_array_size, - proc_pids_t **proc_pids[]) { - - proc_pids_t **proc_pids_array; - assert(proc_pids); - assert(NULL == *proc_pids); - - /* Copy procs names to output array. Initialize pids list with NULL value. */ - proc_pids_array = calloc(procs_names_array_size, sizeof(*proc_pids_array)); - - if (NULL == proc_pids_array) - return -1; - - for (size_t i = 0; i < procs_names_array_size; ++i) { - proc_pids_array[i] = calloc(1, sizeof(**proc_pids_array)); - if (NULL == proc_pids_array[i]) - goto initialize_proc_pids_error; - - sstrncpy(proc_pids_array[i]->process_name, procs_names_array[i], - STATIC_ARRAY_SIZE(proc_pids_array[i]->process_name)); - proc_pids_array[i]->prev = NULL; - proc_pids_array[i]->curr = NULL; - } - - *proc_pids = proc_pids_array; - - return 0; -initialize_proc_pids_error: - if (NULL != proc_pids_array) { - for (size_t i = 0; i < procs_names_array_size; ++i) { - free(proc_pids_array[i]); - } - free(proc_pids_array); - } - return -1; -} - -static void swap_proc_pids(proc_pids_t **proc_pids, size_t proc_pids_num) { - for (size_t i = 0; i < proc_pids_num; i++) { - pids_list_t *swap = proc_pids[i]->prev; - proc_pids[i]->prev = proc_pids[i]->curr; - proc_pids[i]->curr = swap; - } -} - -int update_proc_pids(const char *procfs_path, proc_pids_t **proc_pids, - size_t proc_pids_num) { - assert(procfs_path); - assert(proc_pids); - - DIR *proc_dir = opendir(procfs_path); - if (proc_dir == NULL) { - ERROR(UTIL_NAME ": Could not open %s directory, error: %d", procfs_path, - errno); - return -1; - } - - swap_proc_pids(proc_pids, proc_pids_num); - - for (size_t i = 0; i < proc_pids_num; i++) { - if (NULL == proc_pids[i]->curr) - proc_pids[i]->curr = calloc(1, sizeof(*(proc_pids[i]->curr))); - - if (NULL == proc_pids[i]->curr) { - ERROR(UTIL_NAME ": Alloc error\n"); - goto update_error; - } - - proc_pids[i]->curr->size = 0; - } - - /* Go through procfs and find PIDS and their comms */ - struct dirent *entry; - while ((entry = readdir(proc_dir)) != NULL) { - pid_t pid; - int pid_conversion = get_pid_number(entry, &pid); - if (pid_conversion < 0) - continue; - - proc_comm_t comm; - int read_result = - read_proc_name(procfs_path, entry, comm, sizeof(proc_comm_t)); - if (read_result <= 0) - continue; - - /* Try to find comm in input procs array */ - for (size_t i = 0; i < proc_pids_num; ++i) { - if (0 == - strncmp(comm, proc_pids[i]->process_name, STATIC_ARRAY_SIZE(comm))) - pids_list_add_pid(proc_pids[i]->curr, pid); - } - } - - int close_result = closedir(proc_dir); - if (0 != close_result) { - ERROR(UTIL_NAME ": failed to close /proc directory, error: %d", errno); - goto update_error; - } - return 0; - -update_error: - swap_proc_pids(proc_pids, proc_pids_num); - return -1; -} - -int pids_list_diff(proc_pids_t *proc, pids_list_t *added, - pids_list_t *removed) { - assert(proc); - assert(added); - assert(removed); - - added->size = 0; - removed->size = 0; - - if (NULL == proc->prev || 0 == proc->prev->size) { - /* append all PIDs from curr to added*/ - return pids_list_add_list(added, proc->curr); - } else if (NULL == proc->curr || 0 == proc->curr->size) { - /* append all PIDs from prev to removed*/ - return pids_list_add_list(removed, proc->prev); - } - - for (int i = 0; i < proc->prev->size; i++) - if (0 == pids_list_contains_pid(proc->curr, proc->prev->pids[i])) { - int add_result = pids_list_add_pid(removed, proc->prev->pids[i]); - if (add_result < 0) - return add_result; - } - - for (int i = 0; i < proc->curr->size; i++) - if (0 == pids_list_contains_pid(proc->prev, proc->curr->pids[i])) { - int add_result = pids_list_add_pid(added, proc->curr->pids[i]); - if (add_result < 0) - return add_result; - } - - return 0; -} - -int proc_pids_free(proc_pids_t *proc_pids[], size_t proc_pids_num) { - for (size_t i = 0; i < proc_pids_num; i++) { - if (NULL != proc_pids[i]->curr) - pids_list_free(proc_pids[i]->curr); - if (NULL != proc_pids[i]->prev) - pids_list_free(proc_pids[i]->prev); - sfree(proc_pids[i]); - } - sfree(proc_pids); - - return 0; -} diff --git a/src/utils_proc_pids.h b/src/utils_proc_pids.h deleted file mode 100644 index a2a668dd..00000000 --- a/src/utils_proc_pids.h +++ /dev/null @@ -1,265 +0,0 @@ -/** - * collectd - src/utils_config_pids.h - * - * Copyright(c) 2018-2019 Intel Corporation. All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * Authors: - * Starzyk, Mateusz - * Wojciech Andralojc - * Michał Aleksiński - **/ - -#include -#include - -/* - * Process name inside comm file is limited to 16 chars. - * More info here: http://man7.org/linux/man-pages/man5/proc.5.html - */ -#define MAX_PROC_NAME_LEN 16 - -/* Helper typedef for process name array - * Extra 1 char is added for string null termination. - */ -typedef char proc_comm_t[MAX_PROC_NAME_LEN + 1]; - -/* List of pids. */ -typedef struct pids_list_s { - pid_t *pids; - size_t size; - size_t allocated; -} pids_list_t; - -/* Holds process name and list of pids assigned to that name */ -typedef struct proc_pids_s { - proc_comm_t process_name; - pids_list_t *prev; - pids_list_t *curr; -} proc_pids_t; - -/* - * NAME - * pids_list_free - * - * DESCRIPTION - * Free all elements of given pids list - * - * PARAMETERS - * `list' Head of target pids_list. - */ -void pids_list_free(pids_list_t *list); - -/* - * NAME - * is_proc_name_valid - * - * DESCRIPTION - * Checks if given string as valid process name. - * - * PARAMETERS - * `name' null-terminated char array - * - * RETURN VALUE - * If given name is a valid process name, returns 1, - * Otherwise returns 0. - */ -int is_proc_name_valid(const char *name); - -/* - * NAME - * pids_list_add_pid - * - * DESCRIPTION - * Adds pid at the end of the pids array. - * Reallocates memory for new pid element, it is up to user to free it. - * - * PARAMETERS - * `list' Target pids_list. - * `pid' Pid to be added. - * - * RETURN VALUE - * On success, returns 0. - * -1 on memory allocation error. - */ -int pids_list_add_pid(pids_list_t *list, const pid_t pid); - -/* - * NAME - * pids_list_clear - * - * DESCRIPTION - * Remove all pids from the list - * - * PARAMETERS - * `list' Target pids_list. - * - * RETURN VALUE - * On success, return 0 - */ -int pids_list_clear(pids_list_t *list); - -/* - * NAME - * pids_list_add_list - * - * DESCRIPTION - * Adds pids list at the end of the pids list. - * Allocates memory for new pid elements, it is up to user to free it. - * - * PARAMETERS - * `dst' Target PIDs list. - * `src' Source PIDs list. - * - * RETURN VALUE - * On success, returns 0. - * -1 on memory allocation error. - */ -# -int pids_list_add_list(pids_list_t *dst, pids_list_t *src); - -/* - * NAME - * pids_list_contains_pid - * - * DESCRIPTION - * Tests if pids list contains specific pid. - * - * PARAMETERS - * `list' pids_list to check. - * `pid' Pid to be searched for. - * - * RETURN VALUE - * If PID found in list, returns 1, - * Otherwise returns 0. - */ -int pids_list_contains_pid(pids_list_t *list, const pid_t pid); - -/* - * NAME - * read_proc_name - * - * DESCRIPTION - * Reads process name from given pid directory. - * Strips new-line character (\n). - * - * PARAMETERS - * `procfs_path' Path to systems proc directory (e.g. /proc) - * `pid_entry' Dirent for PID directory - * `name' Output buffer for process name, recommended proc_comm. - * `out_size' Output buffer size, recommended sizeof(proc_comm) - * - * RETURN VALUE - * On success, the number of read bytes (includes stripped \n). - * -1 on file open error - */ -int read_proc_name(const char *procfs_path, const struct dirent *pid_entry, - char *name, const size_t out_size); - -/* - * NAME - * get_pid_number - * - * DESCRIPTION - * Gets pid number for given /proc/pid directory entry or - * returns error if input directory does not hold PID information. - * - * PARAMETERS - * `entry' Dirent for PID directory - * `pid' PID number to be filled - * - * RETURN VALUE - * 0 on success. -1 on error. - */ -int get_pid_number(struct dirent *entry, pid_t *pid); - -/* - * NAME - * initialize_proc_pids - * - * DESCRIPTION - * Helper function to properly initialize array of proc_pids. - * Allocates memory for proc_pids structs. - * - * PARAMETERS - * `procs_names_array' Array of null-terminated strings with - * process' names to be copied to new array - * `procs_names_array_size' procs_names_array element count - * `proc_pids' Address of pointer, under which new - * array of proc_pids will be allocated. - * Must be NULL. - * RETURN VALUE - * 0 on success. Negative number on error: - * -1: allocation error - */ -int initialize_proc_pids(const char **procs_names_array, - const size_t procs_names_array_size, - proc_pids_t **proc_pids[]); - -/* - * NAME - * update_proc_pids - * - * DESCRIPTION - * Updates PIDs matching processes's names. - * Searches all PID directories in /proc fs and updates current pids_list. - * - * PARAMETERS - * `procfs_path' Path to systems proc directory (e.g. /proc) - * `proc_pids' Array of proc_pids pointers to be updated. - * `proc_pids_num' proc_pids element count - * - * RETURN VALUE - * 0 on success. -1 on error. - */ -int update_proc_pids(const char *procfs_path, proc_pids_t *proc_pids[], - size_t proc_pids_num); - -/* - * NAME - * pids_list_diff - * - * DESCRIPTION - * Searches for differences in two given lists - * - * PARAMETERS - * `proc' List of pids - * `added' New pids which appeared - * `removed' Result array storing pids which disappeared - * RETURN VALUE - * 0 on success. Negative number on error. - */ -int pids_list_diff(proc_pids_t *proc, pids_list_t *added, pids_list_t *removed); - -/* - * NAME - * proc_pids_free - * - * DESCRIPTION - * Releses memory allocatd for proc_pids - * - * PARAMETERS - * `proc_pids' Array of proc_pids - * `proc_pids_num' proc_pids element count - * - * RETURN VALUE - * 0 on success. -1 on error. - */ -int proc_pids_free(proc_pids_t *proc_pids[], size_t proc_pids_num); diff --git a/src/utils_proc_pids_test.c b/src/utils_proc_pids_test.c deleted file mode 100644 index 21c8b349..00000000 --- a/src/utils_proc_pids_test.c +++ /dev/null @@ -1,505 +0,0 @@ -#include "testing.h" -#include "utils_proc_pids.c" /* sic */ -#include - -/*************************************************************************** - * helper functions - */ - -typedef struct stub_proc_pid { - proc_comm_t comm; - pid_t pid; -} stub_proc_pid_t; - -static const char *proc_fs = "/tmp/procfs_stub"; - -/* - * NAME - * stub_procfs_setup - * - * DESCRIPTION - * Prepares testing environment by creating temporary - * PID/comm file structure. - * - * PARAMETERS - * `proc_pids_array' Array of stub_proc_pid_t structs. Represents - * which PIDs should hold given process name. - * `proc_pids_array_length' Element count of input array. - * - * RETURN VALUE - * 0 on success. - * -1 on base dir creation error. - * -2 on comm file creation error. - * -3 on comm file write error. - */ -int stub_procfs_setup(const stub_proc_pid_t *proc_pids_array, - const size_t proc_pids_array_length) { - if (mkdir(proc_fs, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0) - return -1; - char path[256]; - - for (size_t i = 0; i < proc_pids_array_length; ++i) { - memset(path, 0, sizeof(path)); - snprintf(path, STATIC_ARRAY_SIZE(path), "%s/%d", proc_fs, - proc_pids_array[i].pid); - mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); - strncat(path, "/comm", STATIC_ARRAY_SIZE(path) - strlen(path) - 1); - - FILE *fp = fopen(path, "w"); - if (!fp) - return -2; - - size_t slen = strlen(proc_pids_array[i].comm); - size_t wlen = fwrite(proc_pids_array[i].comm, sizeof(char), slen, fp); - fclose(fp); - - if (slen != wlen) - return -3; - } - return 0; -} - -/* - * NAME - * stub_procfs_teardown - * - * DESCRIPTION - * Clears testing environment: removes stub proc files. - * NOTE - This function could be implemented by usage of nftw, but this - * would require #define _XOPEN_SOURCE 500, which - * messes up intel_rdt includes. - * - * RETURN VALUE - * system command result - */ -int stub_procfs_teardown() { - char cmd[256]; - sstrncpy(cmd, "rm -rf ", STATIC_ARRAY_SIZE(cmd)); - strncat(cmd, proc_fs, STATIC_ARRAY_SIZE(cmd) - strlen(cmd) - 1); - return system(cmd); -} - -/* Max PID value. More info: - * http://web.archive.org/web/20111209081734/http://research.cs.wisc.edu/condor/condorg/linux_scalability.html - */ -#define MAX_PID 4194304 -#define MAX_PID_STR "4194304" - -/*************************************************************************** - * tests - */ -DEF_TEST(initialize_proc_pids__on_nullptr) { - /* setup */ - const char *procs_names_array[] = {"proc1", "proc2", "proc3"}; - const size_t procs_names_array_size = STATIC_ARRAY_SIZE(procs_names_array); - proc_pids_t **proc_pids_array = NULL; - - /* check */ - int result = initialize_proc_pids(procs_names_array, procs_names_array_size, - &proc_pids_array); - EXPECT_EQ_INT(0, result); - for (size_t i = 0; i < procs_names_array_size; ++i) - EXPECT_EQ_STR(procs_names_array[i], proc_pids_array[i]->process_name); - - /* cleanup */ - proc_pids_free(proc_pids_array, procs_names_array_size); - return 0; -} - -DEF_TEST(pid_list_add_pid__empty_list) { - /* setup */ - pids_list_t *proc_pids_instance = calloc(1, sizeof(*proc_pids_instance)); - pid_t pid = 1234; - - /* check */ - pids_list_add_pid(proc_pids_instance, pid); - EXPECT_EQ_INT(pid, proc_pids_instance->pids[0]); - - /* cleanup */ - pids_list_free(proc_pids_instance); - return 0; -} - -DEF_TEST(pid_list_add_pid__non_empty_list) { - /* setup */ - pids_list_t *proc_pids_instance = calloc(1, sizeof(*proc_pids_instance)); - pid_t pids[] = {1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007}; - - /* check */ - for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids); ++i) - pids_list_add_pid(proc_pids_instance, pids[i]); - - for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids); ++i) { - EXPECT_EQ_INT(pids[i], proc_pids_instance->pids[i]); - } - - /* cleanup */ - pids_list_free(proc_pids_instance); - return 0; -} - -DEF_TEST(pids_list_add_pids_list__non_empty_lists) { - /* setup */ - pid_t pids_array_1[] = {1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007}; - pid_t pids_array_2[] = {2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007}; - pids_list_t *pids_list_1 = calloc(1, sizeof(*pids_list_1)); - pids_list_t *pids_list_2 = calloc(1, sizeof(*pids_list_2)); - for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids_array_1); ++i) { - pids_list_add_pid(pids_list_1, pids_array_1[i]); - pids_list_add_pid(pids_list_2, pids_array_2[i]); - } - - /* check */ - int result = pids_list_add_list(pids_list_1, pids_list_2); - EXPECT_EQ_INT(0, result); - EXPECT_EQ_INT(STATIC_ARRAY_SIZE(pids_array_2) + - STATIC_ARRAY_SIZE(pids_array_1), - pids_list_1->size); - - for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids_array_1); ++i) { - EXPECT_EQ_INT(1, pids_list_contains_pid(pids_list_1, pids_array_1[i])); - EXPECT_EQ_INT(1, pids_list_contains_pid(pids_list_1, pids_array_2[i])); - } - - /* setup */ - pids_list_free(pids_list_1); - pids_list_free(pids_list_2); - return 0; -} - -DEF_TEST(pids_list_add_pids_list__add_to_empty) { - /* setup */ - pid_t pids_array[] = {2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007}; - pids_list_t *pids_list_1 = calloc(1, sizeof(*pids_list_1)); - pids_list_t *pids_list_2 = calloc(1, sizeof(*pids_list_2)); - for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids_array); ++i) - pids_list_add_pid(pids_list_2, pids_array[i]); - - /* check */ - int result = pids_list_add_list(pids_list_1, pids_list_2); - EXPECT_EQ_INT(0, result); - EXPECT_EQ_INT(STATIC_ARRAY_SIZE(pids_array), pids_list_1->size); - - for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids_array); ++i) - EXPECT_EQ_INT(1, pids_list_contains_pid(pids_list_1, pids_array[i])); - - /* setup */ - pids_list_free(pids_list_1); - pids_list_free(pids_list_2); - return 0; -} - -DEF_TEST(get_pid_number__valid_dir) { - /* setup */ - struct dirent d; - sstrncpy(d.d_name, MAX_PID_STR, STATIC_ARRAY_SIZE(d.d_name)); - d.d_type = DT_DIR; - pid_t pid = 0; - - /* check */ - int pid_conversion = get_pid_number(&d, &pid); - - EXPECT_EQ_INT(0, pid_conversion); - EXPECT_EQ_INT(MAX_PID, pid); - - /* cleanup */ - return 0; -} - -DEF_TEST(get_pid_number__invalid_dir_name) { - /* setup */ - struct dirent d; - sstrncpy(d.d_name, "invalid", STATIC_ARRAY_SIZE(d.d_name)); - d.d_type = DT_DIR; - pid_t pid = 0; - - /* check */ - int pid_conversion = get_pid_number(&d, &pid); - - EXPECT_EQ_INT(-1, pid_conversion); - EXPECT_EQ_INT(0, pid); - - /* cleanup */ - return 0; -} - -DEF_TEST(read_proc_name__valid_name) { - /* setup */ - stub_proc_pid_t pp_stubs[] = {{"proc1", MAX_PID}}; - stub_procfs_setup(pp_stubs, STATIC_ARRAY_SIZE(pp_stubs)); - struct dirent d; - sstrncpy(d.d_name, MAX_PID_STR, STATIC_ARRAY_SIZE(d.d_name)); - d.d_type = DT_DIR; - - /* check */ - proc_comm_t comm; - int read_result = read_proc_name(proc_fs, &d, comm, STATIC_ARRAY_SIZE(comm)); - - EXPECT_EQ_INT(strlen(pp_stubs[0].comm), read_result); - EXPECT_EQ_STR(pp_stubs[0].comm, comm); - - /* cleanup */ - stub_procfs_teardown(); - return 0; -} - -DEF_TEST(read_proc_name__invalid_name) { - /* setup */ - struct dirent d; - sstrncpy(d.d_name, MAX_PID_STR, STATIC_ARRAY_SIZE(d.d_name)); - d.d_type = DT_DIR; - - /* check */ - proc_comm_t comm; - int read_result = read_proc_name(proc_fs, &d, comm, STATIC_ARRAY_SIZE(comm)); - - EXPECT_EQ_INT(-1, read_result); - - /* cleanup */ - return 0; -} - -DEF_TEST(update_proc_pids__one_proc_many_pid) { - /* setup */ - const char *proc_names[] = {"proc1"}; - stub_proc_pid_t pp_stubs[] = {{"proc1", 1007}, - {"proc1", 1008}, - {"proc1", 1009}, - {"proc2", 1010}, - {"proc3", 1011}}; - proc_pids_t **proc_pids = NULL; - int result; - stub_procfs_setup(pp_stubs, STATIC_ARRAY_SIZE(pp_stubs)); - - result = initialize_proc_pids(proc_names, STATIC_ARRAY_SIZE(proc_names), - &proc_pids); - EXPECT_EQ_INT(0, result); - - /* check */ - result = update_proc_pids(proc_fs, proc_pids, STATIC_ARRAY_SIZE(proc_names)); - EXPECT_EQ_INT(0, result); - - /* proc name check */ - EXPECT_EQ_STR(proc_names[0], proc_pids[0]->process_name); - - for (size_t i = 0; i < STATIC_ARRAY_SIZE(pp_stubs); ++i) { - if (0 == strcmp(pp_stubs[i].comm, proc_names[0])) - /* check if proc struct has correct pids */ - EXPECT_EQ_INT(pids_list_contains_pid(proc_pids[0]->curr, pp_stubs[i].pid), - 1); - else - /* check if proc struct has no incorrect pids */ - EXPECT_EQ_INT(pids_list_contains_pid(proc_pids[0]->curr, pp_stubs[i].pid), - 0); - } - - /* cleanup */ - proc_pids_free(proc_pids, STATIC_ARRAY_SIZE(proc_names)); - stub_procfs_teardown(); - return 0; -} - -DEF_TEST(update_proc_pids__many_proc_many_pid) { - /* setup */ - const char *proc_names[] = {"proc1", "proc2", "proc3"}; - stub_proc_pid_t pp_stubs[] = { - {"proc1", 1007}, {"proc1", 1008}, {"proc1", 1009}, {"proc2", 2007}, - {"proc2", 2008}, {"proc2", 2009}, {"proc3", 3007}, {"proc3", 3008}, - {"proc3", 3009}, {"proc4", 4007}, {"proc4", 4008}, {"proc4", 4009}, - {"proc5", 5007}, {"proc5", 5008}, {"proc5", 5009}}; - proc_pids_t **proc_pids = NULL; - int result; - stub_procfs_setup(pp_stubs, STATIC_ARRAY_SIZE(pp_stubs)); - - result = initialize_proc_pids(proc_names, STATIC_ARRAY_SIZE(proc_names), - &proc_pids); - EXPECT_EQ_INT(0, result); - - /* check */ - result = update_proc_pids(proc_fs, proc_pids, STATIC_ARRAY_SIZE(proc_names)); - EXPECT_EQ_INT(0, result); - - for (size_t i = 0; i < STATIC_ARRAY_SIZE(proc_names); ++i) { - - /* proc name check */ - EXPECT_EQ_STR(proc_names[i], proc_pids[i]->process_name); - - for (size_t j = 0; j < STATIC_ARRAY_SIZE(pp_stubs); ++j) { - if (0 == strcmp(pp_stubs[j].comm, proc_names[i])) - /* check if proc struct has correct pids */ - EXPECT_EQ_INT( - pids_list_contains_pid(proc_pids[i]->curr, pp_stubs[j].pid), 1); - else - /* check if proc struct has no incorrect pids */ - EXPECT_EQ_INT( - pids_list_contains_pid(proc_pids[i]->curr, pp_stubs[j].pid), 0); - } - } - - /* cleanup */ - proc_pids_free(proc_pids, STATIC_ARRAY_SIZE(proc_names)); - stub_procfs_teardown(); - return 0; -} - -DEF_TEST(pids_list_diff__all_changed) { - /* setup */ - pid_t pids_array_before[] = {1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007}; - pid_t pids_array_after[] = {2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007}; - proc_pids_t proc_pids; - pids_list_t curr; - pids_list_t prev; - - prev.pids = pids_array_before; - prev.size = STATIC_ARRAY_SIZE(pids_array_before); - prev.allocated = prev.size; - curr.pids = pids_array_after; - curr.size = STATIC_ARRAY_SIZE(pids_array_after); - curr.allocated = curr.size; - proc_pids.curr = &curr; - proc_pids.prev = &prev; - - pids_list_t *new_pids = calloc(1, sizeof(*new_pids)); - pids_list_t *lost_pids = calloc(1, sizeof(*lost_pids)); - - /* check */ - int result = pids_list_diff(&proc_pids, new_pids, lost_pids); - EXPECT_EQ_INT(0, result); - EXPECT_EQ_INT(STATIC_ARRAY_SIZE(pids_array_before), lost_pids->size); - EXPECT_EQ_INT(STATIC_ARRAY_SIZE(pids_array_after), new_pids->size); - - for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids_array_before); ++i) { - EXPECT_EQ_INT(1, pids_list_contains_pid(new_pids, pids_array_after[i])); - EXPECT_EQ_INT(1, pids_list_contains_pid(lost_pids, pids_array_before[i])); - } - - /* cleanup */ - pids_list_free(new_pids); - pids_list_free(lost_pids); - - return 0; -} - -DEF_TEST(pids_list_diff__nothing_changed) { - /* setup */ - pid_t pids_array_before[] = {1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007}; - proc_pids_t proc_pids; - pids_list_t curr; - pids_list_t prev; - - prev.pids = pids_array_before; - prev.size = STATIC_ARRAY_SIZE(pids_array_before); - prev.allocated = prev.size; - curr.pids = pids_array_before; - curr.size = STATIC_ARRAY_SIZE(pids_array_before); - curr.allocated = curr.size; - proc_pids.curr = &curr; - proc_pids.prev = &prev; - - pids_list_t *new_pids = calloc(1, sizeof(*new_pids)); - pids_list_t *lost_pids = calloc(1, sizeof(*lost_pids)); - - /* check */ - int result = pids_list_diff(&proc_pids, new_pids, lost_pids); - EXPECT_EQ_INT(0, result); - EXPECT_EQ_INT(0, lost_pids->size); - EXPECT_EQ_INT(0, new_pids->size); - - /* cleanup */ - pids_list_free(lost_pids); - pids_list_free(new_pids); - - return 0; -} - -DEF_TEST(pids_list_diff__one_added) { - /* setup */ - pid_t pids_array_before[] = {1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007}; - pid_t pids_array_after[] = {1000, 1001, 1002, 1003, 1004, - 1005, 1006, 1007, 1008}; - proc_pids_t proc_pids; - pids_list_t curr; - pids_list_t prev; - - prev.pids = pids_array_before; - prev.size = STATIC_ARRAY_SIZE(pids_array_before); - prev.allocated = prev.size; - curr.pids = pids_array_after; - curr.size = STATIC_ARRAY_SIZE(pids_array_after); - curr.allocated = curr.size; - proc_pids.curr = &curr; - proc_pids.prev = &prev; - - pids_list_t *new_pids = calloc(1, sizeof(*new_pids)); - pids_list_t *lost_pids = calloc(1, sizeof(*lost_pids)); - - /* check */ - int result = pids_list_diff(&proc_pids, new_pids, lost_pids); - EXPECT_EQ_INT(0, result); - EXPECT_EQ_INT(0, lost_pids->size); - EXPECT_EQ_INT(1, new_pids->size); - EXPECT_EQ_INT(1008, new_pids->pids[0]); - - /* cleanup */ - pids_list_free(lost_pids); - pids_list_free(new_pids); - - return 0; -} - -DEF_TEST(pids_list_diff__one_removed) { - /* setup */ - pid_t pids_array_before[] = {1000, 1001, 1002, 1003, 1004, - 1005, 1006, 1007, 1008}; - pid_t pids_array_after[] = {1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007}; - - proc_pids_t proc_pids; - pids_list_t curr; - pids_list_t prev; - - prev.pids = pids_array_before; - prev.size = STATIC_ARRAY_SIZE(pids_array_before); - prev.allocated = prev.size; - curr.pids = pids_array_after; - curr.size = STATIC_ARRAY_SIZE(pids_array_after); - curr.allocated = curr.size; - proc_pids.curr = &curr; - proc_pids.prev = &prev; - - pids_list_t *new_pids = calloc(1, sizeof(*new_pids)); - pids_list_t *lost_pids = calloc(1, sizeof(*lost_pids)); - - /* check */ - int result = pids_list_diff(&proc_pids, new_pids, lost_pids); - EXPECT_EQ_INT(0, result); - EXPECT_EQ_INT(0, new_pids->size); - EXPECT_EQ_INT(1, lost_pids->size); - EXPECT_EQ_INT(1008, lost_pids->pids[0]); - - /* cleanup */ - pids_list_free(lost_pids); - pids_list_free(new_pids); - - return 0; -} - -int main(void) { - stub_procfs_teardown(); - RUN_TEST(initialize_proc_pids__on_nullptr); - RUN_TEST(pid_list_add_pid__empty_list); - RUN_TEST(pid_list_add_pid__non_empty_list); - RUN_TEST(pids_list_add_pids_list__non_empty_lists); - RUN_TEST(pids_list_add_pids_list__add_to_empty); - RUN_TEST(get_pid_number__valid_dir); - RUN_TEST(get_pid_number__invalid_dir_name); - RUN_TEST(read_proc_name__valid_name); - RUN_TEST(read_proc_name__invalid_name); - RUN_TEST(update_proc_pids__one_proc_many_pid); - RUN_TEST(update_proc_pids__many_proc_many_pid); - RUN_TEST(pids_list_diff__all_changed); - RUN_TEST(pids_list_diff__nothing_changed); - RUN_TEST(pids_list_diff__one_added); - RUN_TEST(pids_list_diff__one_removed); - stub_procfs_teardown(); - END_TEST; -}