/* ** Zabbix ** Copyright (C) 2001-2023 Zabbix SIA ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2 of the License, or ** (at your option) any later version. ** ** 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 General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. **/ #include "zbxsysinfo.h" #include "../sysinfo.h" #include "zbxregexp.h" #include "log.h" #include "zbxjson.h" #include "zbxstr.h" #include <sys/sysctl.h> /* in OpenBSD 5.1 KERN_PROC2 became KERN_PROC and structure kinfo_proc2 became kinfo_proc */ #if OpenBSD >= 201205 /* OpenBSD 5.1 version as year and month */ # ifndef KERN_PROC2 # define KERN_PROC2 KERN_PROC # endif # ifndef kinfo_proc2 # define kinfo_proc2 kinfo_proc # endif #endif #ifdef KERN_PROC2 # define ZBX_P_COMM p_comm # define ZBX_P_FLAG p_flag # define ZBX_P_PID p_pid # define ZBX_P_PPID p_ppid # define ZBX_P_TID p_tid # define ZBX_P_STAT p_stat # define ZBX_P_VM_RSSIZE p_vm_rssize # define ZBX_P_VM_VSIZE p_vm_map_size # define ZBX_P_VM_TSIZE p_vm_tsize # define ZBX_P_VM_DSIZE p_vm_dsize # define ZBX_P_VM_SSIZE p_vm_ssize # define ZBX_P_MAJFLT p_uru_majflt # define ZBX_P_SWAP p_uru_nswap # define ZBX_P_INBLOCK p_uru_inblock # define ZBX_P_OUBLOCK p_uru_oublock # define ZBX_P_NVCSW p_uru_nvcsw # define ZBX_P_NIVCSW p_uru_nivcsw # define ZBX_P_UTIME p_uutime_sec # define ZBX_P_STIME p_ustime_sec # define ZBX_P_UID p_ruid # define ZBX_P_GID p_rgid # define ZBX_STRUCT_KINFO_PROC kinfo_proc2 # define ZBX_KINFO_MIBS_NUM 6 #else # define ZBX_P_COMM kp_proc.p_comm # define ZBX_P_FLAG kp_proc.p_flag # define ZBX_P_PID kp_proc.p_pid # define ZBX_P_PPID kp_eproc.e_ppid # define ZBX_P_TID kp_proc.p_tid # define ZBX_P_STAT kp_proc.p_stat # define ZBX_P_VM_RSSIZE kp_eproc.e_vm.vm_rssize # define ZBX_P_VM_VSIZE kp_eproc.e_vm.vm_map.size # define ZBX_P_VM_TSIZE kp_eproc.e_vm.vm_tsize # define ZBX_P_VM_DSIZE kp_eproc.e_vm.vm_dsize # define ZBX_P_VM_SSIZE kp_eproc.e_vm.vm_ssize # define ZBX_P_MAJFLT kp_eproc.e_pstats.p_ru.ru_majflt # define ZBX_P_SWAP kp_eproc.e_pstats.p_ru.ru_nswap # define ZBX_P_INBLOCK kp_eproc.e_pstats.p_ru.ru_inblock # define ZBX_P_OUBLOCK kp_eproc.e_pstats.p_ru.ru_oublock # define ZBX_P_NVCSW kp_eproc.e_pstats.p_ru.ru_nvcsw # define ZBX_P_NIVCSW kp_eproc.e_pstats.p_ru.ru_nivcsw # define ZBX_P_UTIME kp_eproc.e_pstats.p_ru.ru_utime.tv_sec # define ZBX_P_STIME kp_eproc.e_pstats.p_ru.ru_stime.tv_sec # define ZBX_P_UID kp_proc.p_ruid # define ZBX_P_GID kp_proc.p_rgid # define ZBX_STRUCT_KINFO_PROC kinfo_proc # define ZBX_KINFO_MIBS_NUM 4 #endif typedef struct { int pid; int ppid; int tid; char *name; char *cmdline; char *state; char *tname; zbx_uint64_t processes; char *user; char *group; zbx_uint64_t uid; zbx_uint64_t gid; zbx_uint64_t cputime_user; zbx_uint64_t cputime_system; zbx_uint64_t ctx_switches; zbx_int64_t threads; zbx_uint64_t page_faults; zbx_int64_t fds; zbx_uint64_t io_read_op; zbx_uint64_t io_write_op; zbx_uint64_t vsize; zbx_uint64_t rss; zbx_uint64_t size; zbx_uint64_t tsize; zbx_uint64_t dsize; zbx_uint64_t ssize; zbx_uint64_t swap; } proc_data_t; ZBX_PTR_VECTOR_DECL(proc_data_ptr, proc_data_t *) ZBX_PTR_VECTOR_IMPL(proc_data_ptr, proc_data_t *) /****************************************************************************** * * * Purpose: frees process data structure * * * ******************************************************************************/ static void proc_data_free(proc_data_t *proc_data) { zbx_free(proc_data->name); zbx_free(proc_data->cmdline); zbx_free(proc_data->state); zbx_free(proc_data->tname); zbx_free(proc_data->user); zbx_free(proc_data->group); zbx_free(proc_data); } #define ARGS_START_SIZE 64 static int proc_argv(pid_t pid, char ***argv, size_t *argv_alloc, int *argc) { size_t sz; int mib[4], nargv = 0; if (NULL == *argv) { *argv_alloc = ARGS_START_SIZE; *argv = zbx_malloc(*argv, *argv_alloc); } mib[0] = CTL_KERN; mib[1] = KERN_PROC_ARGS; mib[2] = (int)pid; mib[3] = KERN_PROC_ARGV; retry: sz = *argv_alloc; if (0 != sysctl(mib, 4, *argv, &sz, NULL, 0)) { if (errno == ENOMEM) { *argv_alloc *= 2; *argv = zbx_realloc(*argv, *argv_alloc); goto retry; } return FAIL; } while (NULL != (*argv)[nargv]) nargv++; *argc = nargv; return SUCCEED; } static void collect_args(char **argv, int argc, char **args, size_t *args_alloc) { int i; size_t args_offset = 0; if (0 == *args_alloc) { *args_alloc = ARGS_START_SIZE; *args = zbx_malloc(*args, *args_alloc); } for (i = 0; i < argc; i++) zbx_snprintf_alloc(args, args_alloc, &args_offset, "%s ", argv[i]); if (0 != args_offset) args_offset--; /* ' ' */ (*args)[args_offset] = '\0'; } #undef ARGS_START_SIZE int proc_mem(AGENT_REQUEST *request, AGENT_RESULT *result) { char *procname, *proccomm, *param; int do_task, pagesize, count, i, proccount = 0, invalid_user = 0, proc_ok, comm_ok; double value = 0.0, memsize = 0; size_t sz; struct passwd *usrinfo; #ifdef KERN_PROC2 int mib[6]; struct kinfo_proc2 *proc = NULL; #else int mib[4]; struct kinfo_proc *proc = NULL; #endif char **argv = NULL, *args = NULL; size_t argv_alloc = 0, args_alloc = 0; int argc; if (4 < request->nparam) { SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters.")); return SYSINFO_RET_FAIL; } procname = get_rparam(request, 0); param = get_rparam(request, 1); if (NULL != param && '\0' != *param) { errno = 0; if (NULL == (usrinfo = getpwnam(param))) { if (0 != errno) { SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain user information: %s", zbx_strerror(errno))); return SYSINFO_RET_FAIL; } invalid_user = 1; } } else usrinfo = NULL; param = get_rparam(request, 2); if (NULL == param || '\0' == *param || 0 == strcmp(param, "sum")) do_task = ZBX_DO_SUM; else if (0 == strcmp(param, "avg")) do_task = ZBX_DO_AVG; else if (0 == strcmp(param, "max")) do_task = ZBX_DO_MAX; else if (0 == strcmp(param, "min")) do_task = ZBX_DO_MIN; else { SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid third parameter.")); return SYSINFO_RET_FAIL; } proccomm = get_rparam(request, 3); if (1 == invalid_user) /* handle 0 for non-existent user after all parameters have been parsed and validated */ goto out; pagesize = getpagesize(); mib[0] = CTL_KERN; if (NULL != usrinfo) { mib[2] = KERN_PROC_UID; mib[3] = usrinfo->pw_uid; } else { mib[2] = KERN_PROC_ALL; mib[3] = 0; } #ifdef KERN_PROC2 mib[1] = KERN_PROC2; mib[4] = sizeof(struct kinfo_proc2); mib[5] = 0; sz = 0; if (0 != sysctl(mib, 6, NULL, &sz, NULL, 0)) { SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain necessary buffer size from system: %s", zbx_strerror(errno))); return SYSINFO_RET_FAIL; } proc = (struct kinfo_proc2 *)zbx_malloc(proc, sz); mib[5] = (int)(sz / sizeof(struct kinfo_proc2)); if (0 != sysctl(mib, 6, proc, &sz, NULL, 0)) { zbx_free(proc); SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain process information: %s", zbx_strerror(errno))); return SYSINFO_RET_FAIL; } count = sz / sizeof(struct kinfo_proc2); #else mib[1] = KERN_PROC; sz = 0; if (0 != sysctl(mib, 4, NULL, &sz, NULL, 0)) { SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain necessary buffer size from system: %s", zbx_strerror(errno))); return SYSINFO_RET_FAIL; } proc = (struct kinfo_proc *)zbx_malloc(proc, sz); if (0 != sysctl(mib, 4, proc, &sz, NULL, 0)) { zbx_free(proc); SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain process information: %s", zbx_strerror(errno))); return SYSINFO_RET_FAIL; } count = sz / sizeof(struct kinfo_proc); #endif for (i = 0; i < count; i++) { proc_ok = 0; comm_ok = 0; if (NULL == procname || '\0' == *procname || 0 == strcmp(procname, proc[i].ZBX_P_COMM)) proc_ok = 1; if (NULL != proccomm && '\0' != *proccomm) { if (SUCCEED == proc_argv(proc[i].ZBX_P_PID, &argv, &argv_alloc, &argc)) { collect_args(argv, argc, &args, &args_alloc); if (NULL != zbx_regexp_match(args, proccomm, NULL)) comm_ok = 1; } } else comm_ok = 1; if (proc_ok && comm_ok) { value = proc[i].ZBX_P_VM_TSIZE + proc[i].ZBX_P_VM_DSIZE + proc[i].ZBX_P_VM_SSIZE; value *= pagesize; if (0 == proccount++) memsize = value; else { if (ZBX_DO_MAX == do_task) memsize = MAX(memsize, value); else if (ZBX_DO_MIN == do_task) memsize = MIN(memsize, value); else memsize += value; } } } zbx_free(proc); zbx_free(argv); zbx_free(args); out: if (ZBX_DO_AVG == do_task) SET_DBL_RESULT(result, 0 == proccount ? 0 : memsize / proccount); else SET_UI64_RESULT(result, memsize); return SYSINFO_RET_OK; } int proc_num(AGENT_REQUEST *request, AGENT_RESULT *result) { char *procname, *proccomm, *param; int proccount = 0, invalid_user = 0, zbx_proc_stat, count, i, proc_ok, stat_ok, comm_ok; size_t sz; struct passwd *usrinfo; #ifdef KERN_PROC2 int mib[6]; struct kinfo_proc2 *proc = NULL; #else int mib[4]; struct kinfo_proc *proc = NULL; #endif char **argv = NULL, *args = NULL; size_t argv_alloc = 0, args_alloc = 0; int argc; if (4 < request->nparam) { SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters.")); return SYSINFO_RET_FAIL; } procname = get_rparam(request, 0); param = get_rparam(request, 1); if (NULL != param && '\0' != *param) { errno = 0; if (NULL == (usrinfo = getpwnam(param))) { if (0 != errno) { SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain user information: %s", zbx_strerror(errno))); return SYSINFO_RET_FAIL; } invalid_user = 1; } } else usrinfo = NULL; param = get_rparam(request, 2); if (NULL == param || '\0' == *param || 0 == strcmp(param, "all")) zbx_proc_stat = ZBX_PROC_STAT_ALL; else if (0 == strcmp(param, "run")) zbx_proc_stat = ZBX_PROC_STAT_RUN; else if (0 == strcmp(param, "sleep")) zbx_proc_stat = ZBX_PROC_STAT_SLEEP; else if (0 == strcmp(param, "zomb")) zbx_proc_stat = ZBX_PROC_STAT_ZOMB; else if (0 == strcmp(param, "disk")) zbx_proc_stat = ZBX_PROC_STAT_DISK; else if (0 == strcmp(param, "trace")) zbx_proc_stat = ZBX_PROC_STAT_TRACE; else { SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid third parameter.")); return SYSINFO_RET_FAIL; } proccomm = get_rparam(request, 3); if (1 == invalid_user) /* handle 0 for non-existent user after all parameters have been parsed and validated */ goto out; mib[0] = CTL_KERN; if (NULL != usrinfo) { mib[2] = KERN_PROC_UID; mib[3] = usrinfo->pw_uid; } else { mib[2] = KERN_PROC_ALL; mib[3] = 0; } #ifdef KERN_PROC2 mib[1] = KERN_PROC2; mib[4] = sizeof(struct kinfo_proc2); mib[5] = 0; sz = 0; if (0 != sysctl(mib, 6, NULL, &sz, NULL, 0)) { SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain necessary buffer size from system: %s", zbx_strerror(errno))); return SYSINFO_RET_FAIL; } proc = (struct kinfo_proc2 *)zbx_malloc(proc, sz); mib[5] = (int)(sz / sizeof(struct kinfo_proc2)); if (0 != sysctl(mib, 6, proc, &sz, NULL, 0)) { zbx_free(proc); SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain process information: %s", zbx_strerror(errno))); return SYSINFO_RET_FAIL; } count = sz / sizeof(struct kinfo_proc2); #else mib[1] = KERN_PROC; sz = 0; if (0 != sysctl(mib, 4, NULL, &sz, NULL, 0)) { SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain necessary buffer size from system: %s", zbx_strerror(errno))); return SYSINFO_RET_FAIL; } proc = (struct kinfo_proc *)zbx_malloc(proc, sz); if (0 != sysctl(mib, 4, proc, &sz, NULL, 0)) { zbx_free(proc); SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain process information: %s", zbx_strerror(errno))); return SYSINFO_RET_FAIL; } count = sz / sizeof(struct kinfo_proc); #endif for (i = 0; i < count; i++) { proc_ok = 0; stat_ok = 0; comm_ok = 0; if (NULL == procname || '\0' == *procname || 0 == strcmp(procname, proc[i].ZBX_P_COMM)) proc_ok = 1; if (ZBX_PROC_STAT_ALL != zbx_proc_stat) { switch (zbx_proc_stat) { case ZBX_PROC_STAT_RUN: if (SRUN == proc[i].ZBX_P_STAT || SONPROC == proc[i].ZBX_P_STAT) stat_ok = 1; break; case ZBX_PROC_STAT_SLEEP: if (SSLEEP == proc[i].ZBX_P_STAT && 0 != (proc[i].ZBX_P_FLAG & P_SINTR)) stat_ok = 1; break; case ZBX_PROC_STAT_ZOMB: if (SZOMB == proc[i].ZBX_P_STAT || SDEAD == proc[i].ZBX_P_STAT) stat_ok = 1; break; case ZBX_PROC_STAT_DISK: if (SSLEEP == proc[i].ZBX_P_STAT && 0 == (proc[i].ZBX_P_FLAG & P_SINTR)) stat_ok = 1; break; case ZBX_PROC_STAT_TRACE: if (SSTOP == proc[i].ZBX_P_STAT) stat_ok = 1; break; } } else stat_ok = 1; if (NULL != proccomm && '\0' != *proccomm) { if (SUCCEED == proc_argv(proc[i].ZBX_P_PID, &argv, &argv_alloc, &argc)) { collect_args(argv, argc, &args, &args_alloc); if (NULL != zbx_regexp_match(args, proccomm, NULL)) comm_ok = 1; } } else comm_ok = 1; if (proc_ok && stat_ok && comm_ok) proccount++; } zbx_free(proc); zbx_free(argv); zbx_free(args); out: SET_UI64_RESULT(result, proccount); return SYSINFO_RET_OK; } static zbx_int64_t get_fds(int pid) { int mib[ZBX_KINFO_MIBS_NUM], num; size_t sz; struct kinfo_file *kf = NULL; mib[0] = CTL_KERN; mib[1] = KERN_FILE; mib[2] = KERN_FILE_BYPID; mib[3] = pid; #ifdef KERN_PROC2 mib[4] = sizeof(struct kinfo_file); mib[5] = 0; #endif if (0 != sysctl(mib, ZBX_KINFO_MIBS_NUM, NULL, &sz, NULL, 0)) return -1; kf = (struct kinfo_file*)zbx_malloc(kf, sz); if (0 != sysctl(mib, ZBX_KINFO_MIBS_NUM, kf, &sz, NULL, 0)) { zbx_free(kf); return -1; } num = sz / sizeof(struct kinfo_file); zbx_free(kf); return num; } static int get_kinfo_proc(struct ZBX_STRUCT_KINFO_PROC **proc, struct passwd *usrinfo, int pid, int *count, char **error) { int mib[ZBX_KINFO_MIBS_NUM]; size_t sz = 0; mib[0] = CTL_KERN; #ifdef KERN_PROC2 mib[1] = KERN_PROC2; mib[4] = sizeof(struct kinfo_proc2); mib[5] = 0; #else mib[1] = KERN_PROC; #endif if (-1 != pid) { mib[2] = KERN_PROC_PID | KERN_PROC_SHOW_THREADS; mib[3] = pid; } else if (NULL != usrinfo) { mib[2] = KERN_PROC_UID; mib[3] = usrinfo->pw_uid; } else { mib[2] = KERN_PROC_ALL; mib[3] = 0; } if (0 != sysctl(mib, ZBX_KINFO_MIBS_NUM, NULL, &sz, NULL, 0)) { if (NULL != error) { *error = zbx_dsprintf(*error, "Cannot obtain necessary buffer size from system: %s", zbx_strerror(errno)); } return FAIL; } *proc = (struct ZBX_STRUCT_KINFO_PROC *)zbx_malloc(NULL, sz); #ifdef KERN_PROC2 mib[5] = (int)(sz / sizeof(struct kinfo_proc2)); #endif if (0 != sysctl(mib, ZBX_KINFO_MIBS_NUM, *proc, &sz, NULL, 0)) { if (NULL != error) *error = zbx_dsprintf(*error, "Cannot obtain process information: %s", zbx_strerror(errno)); zbx_free(proc); return FAIL; } *count = sz / sizeof(struct ZBX_STRUCT_KINFO_PROC); return SUCCEED; } static char *get_state(struct ZBX_STRUCT_KINFO_PROC *proc) { char *state; if (SRUN == proc->ZBX_P_STAT || SONPROC == proc->ZBX_P_STAT) state = zbx_strdup(NULL, "running"); else if (SSLEEP == proc->ZBX_P_STAT && 0 != (proc->ZBX_P_FLAG & P_SINTR)) state = zbx_strdup(NULL, "sleeping"); else if (SZOMB == proc->ZBX_P_STAT || SDEAD == proc->ZBX_P_STAT) state = zbx_strdup(NULL, "zombie"); else if (SSLEEP == proc->ZBX_P_STAT && 0 == (proc->ZBX_P_FLAG & P_SINTR)) state = zbx_strdup(NULL, "disk sleep"); else if (SSTOP == proc->ZBX_P_STAT) state = zbx_strdup(NULL, "tracing stop"); else state = zbx_strdup(NULL, "other"); return state; } int proc_get(AGENT_REQUEST *request, AGENT_RESULT *result) { #define SUM_PROC_VALUE(param) \ do \ { \ if (0 <= pdata->param && 0 <= pdata_cmp->param) \ pdata->param += pdata_cmp->param; \ else if (0 <= pdata->param) \ pdata->param = -1; \ } while(0) char *procname, *proccomm, *param, *args = NULL, **argv = NULL, *error = NULL; int invalid_user = 0, count, i, k, zbx_proc_mode, argc, pagesize; size_t argv_alloc = 0, args_alloc = 0; struct passwd *usrinfo; zbx_vector_proc_data_ptr_t proc_data_ctx; struct zbx_json j; struct ZBX_STRUCT_KINFO_PROC *proc = NULL; if (4 < request->nparam) { SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters.")); return SYSINFO_RET_FAIL; } procname = get_rparam(request, 0); param = get_rparam(request, 1); if (NULL != param && '\0' != *param) { errno = 0; if (NULL == (usrinfo = getpwnam(param))) { if (0 != errno) { SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain user information: %s", zbx_strerror(errno))); return SYSINFO_RET_FAIL; } invalid_user = 1; } } else usrinfo = NULL; proccomm = get_rparam(request, 2); param = get_rparam(request, 3); if (NULL == param || '\0' == *param || 0 == strcmp(param, "process")) { zbx_proc_mode = ZBX_PROC_MODE_PROCESS; } else if (0 == strcmp(param, "thread")) { zbx_proc_mode = ZBX_PROC_MODE_THREAD; } else if (0 == strcmp(param, "summary") && (NULL == proccomm || '\0' == *proccomm)) { zbx_proc_mode = ZBX_PROC_MODE_SUMMARY; } else { SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid fourth parameter.")); return SYSINFO_RET_FAIL; } if (1 == invalid_user) { zbx_json_initarray(&j, ZBX_JSON_STAT_BUF_LEN); goto out; } pagesize = getpagesize(); if (SUCCEED != get_kinfo_proc(&proc, usrinfo, -1, &count, &error)) { SET_MSG_RESULT(result, error); return SYSINFO_RET_FAIL; } zbx_vector_proc_data_ptr_create(&proc_data_ctx); for (i = 0; i < count; i++) { proc_data_t *proc_data; int count_thread; struct ZBX_STRUCT_KINFO_PROC *proc_thread; struct passwd *pw; struct group *gr; if (NULL != procname && '\0' != *procname && 0 != strcmp(procname, proc[i].ZBX_P_COMM)) continue; if (SUCCEED == proc_argv(proc[i].ZBX_P_PID, &argv, &argv_alloc, &argc)) collect_args(argv, argc, &args, &args_alloc); else continue; if (NULL != proccomm && '\0' != *proccomm && NULL == zbx_regexp_match(args, proccomm, NULL)) continue; pw = getpwuid(proc[i].ZBX_P_UID); gr = getgrgid(proc[i].ZBX_P_GID); if (ZBX_PROC_MODE_THREAD == zbx_proc_mode) { if (SUCCEED != get_kinfo_proc(&proc_thread, NULL, proc[i].ZBX_P_PID, &count_thread, NULL)) continue; for (k = 0; k < count_thread; k++) { if (-1 == proc_thread[k].ZBX_P_TID) continue; proc_data = (proc_data_t *)zbx_malloc(NULL, sizeof(proc_data_t)); proc_data->tid = proc_thread[k].ZBX_P_TID; proc_data->pid = proc_thread[k].ZBX_P_PID; proc_data->ppid = proc_thread[k].ZBX_P_PPID; proc_data->name = zbx_strdup(NULL, proc[i].ZBX_P_COMM); proc_data->tname = zbx_strdup(NULL, proc_thread[k].ZBX_P_COMM); proc_data->state = get_state(&proc_thread[k]); proc_data->uid = proc[i].ZBX_P_UID; proc_data->gid = proc[i].ZBX_P_GID; proc_data->user = NULL != pw ? zbx_strdup(NULL, pw->pw_name) : zbx_dsprintf(NULL, ZBX_FS_UI64, proc_data->uid); proc_data->group = NULL != gr ? zbx_strdup(NULL, gr->gr_name) : zbx_dsprintf(NULL, ZBX_FS_UI64, proc_data->gid); proc_data->cputime_user = proc_thread[k].ZBX_P_UTIME; proc_data->cputime_system = proc_thread[k].ZBX_P_STIME; proc_data->ctx_switches = proc_thread[k].ZBX_P_NVCSW + proc_thread[k].ZBX_P_NIVCSW; proc_data->io_read_op = proc_thread[k].ZBX_P_OUBLOCK; proc_data->io_write_op = proc_thread[k].ZBX_P_INBLOCK; proc_data->cmdline = NULL; zbx_vector_proc_data_ptr_append(&proc_data_ctx, proc_data); } zbx_free(proc_thread); } else { proc_data = (proc_data_t *)zbx_malloc(NULL, sizeof(proc_data_t)); proc_data->name = zbx_strdup(NULL, proc[i].ZBX_P_COMM); proc_data->size = (proc[i].ZBX_P_VM_TSIZE + proc[i].ZBX_P_VM_DSIZE + proc[i].ZBX_P_VM_SSIZE) * pagesize; proc_data->rss = proc[i].ZBX_P_VM_RSSIZE * pagesize; proc_data->vsize = proc[i].ZBX_P_VM_VSIZE; proc_data->tsize = proc[i].ZBX_P_VM_TSIZE * pagesize; proc_data->dsize = proc[i].ZBX_P_VM_DSIZE * pagesize; proc_data->ssize = proc[i].ZBX_P_VM_SSIZE * pagesize; proc_data->cputime_user = proc[i].ZBX_P_UTIME; proc_data->cputime_system = proc[i].ZBX_P_STIME; proc_data->ctx_switches = proc[i].ZBX_P_NVCSW + proc[i].ZBX_P_NIVCSW; proc_data->page_faults = proc[i].ZBX_P_MAJFLT; proc_data->fds = get_fds((int)proc[i].ZBX_P_PID); proc_data->io_read_op = proc[i].ZBX_P_OUBLOCK; proc_data->io_write_op = proc[i].ZBX_P_INBLOCK; proc_data->swap = proc[i].ZBX_P_SWAP; if (ZBX_PROC_MODE_PROCESS == zbx_proc_mode) { proc_data->pid = proc[i].ZBX_P_PID; proc_data->ppid = proc[i].ZBX_P_PPID; proc_data->cmdline = zbx_strdup(NULL, args); proc_data->state = get_state(&proc[i]); proc_data->uid = proc[i].ZBX_P_UID; proc_data->gid = proc[i].ZBX_P_GID; proc_data->user = NULL != pw ? zbx_strdup(NULL, pw->pw_name) : zbx_dsprintf(NULL, ZBX_FS_UI64, proc_data->uid); proc_data->group = NULL != gr ? zbx_strdup(NULL, gr->gr_name) : zbx_dsprintf(NULL, ZBX_FS_UI64, proc_data->gid); } else { proc_data->cmdline = NULL; proc_data->state = NULL; proc_data->user = NULL; proc_data->group = NULL; } proc_data->tname = NULL; if (SUCCEED == get_kinfo_proc(&proc_thread, NULL, proc[i].ZBX_P_PID, &count_thread, NULL) && 1 < count_thread) { proc_data->threads = count_thread - 1; zbx_free(proc_thread); } else proc_data->threads = -1; zbx_vector_proc_data_ptr_append(&proc_data_ctx, proc_data); } } zbx_free(proc); if (ZBX_PROC_MODE_SUMMARY == zbx_proc_mode) { for (i = 0; i < proc_data_ctx.values_num; i++) { proc_data_t *pdata = proc_data_ctx.values[i]; pdata->processes = 1; for (k = i + 1; k < proc_data_ctx.values_num; k++) { proc_data_t *pdata_cmp = proc_data_ctx.values[k]; if (0 == strcmp(pdata->name, pdata_cmp->name)) { pdata->processes++; pdata->rss += pdata_cmp->rss; pdata->vsize += pdata_cmp->vsize; pdata->tsize += pdata_cmp->tsize; pdata->dsize += pdata_cmp->dsize; pdata->ssize += pdata_cmp->ssize; pdata->size += pdata_cmp->size; pdata->swap += pdata_cmp->swap; pdata->cputime_user += pdata_cmp->cputime_user; pdata->cputime_system += pdata_cmp->cputime_system; pdata->ctx_switches += pdata_cmp->ctx_switches; pdata->page_faults += pdata_cmp->page_faults; pdata->io_read_op += pdata_cmp->io_read_op; pdata->io_write_op += pdata_cmp->io_write_op; SUM_PROC_VALUE(threads); SUM_PROC_VALUE(fds); proc_data_free(pdata_cmp); zbx_vector_proc_data_ptr_remove(&proc_data_ctx, k--); } } } } zbx_json_initarray(&j, ZBX_JSON_STAT_BUF_LEN); for (i = 0; i < proc_data_ctx.values_num; i++) { proc_data_t *pdata; pdata = proc_data_ctx.values[i]; zbx_json_addobject(&j, NULL); if (ZBX_PROC_MODE_PROCESS == zbx_proc_mode) { zbx_json_addint64(&j, "pid", pdata->pid); zbx_json_addint64(&j, "ppid", pdata->ppid); zbx_json_addstring(&j, "name", ZBX_NULL2EMPTY_STR(pdata->name), ZBX_JSON_TYPE_STRING); zbx_json_addstring(&j, "cmdline", ZBX_NULL2EMPTY_STR(pdata->cmdline), ZBX_JSON_TYPE_STRING); zbx_json_addstring(&j, "user", ZBX_NULL2EMPTY_STR(pdata->user), ZBX_JSON_TYPE_STRING); zbx_json_addstring(&j, "group", ZBX_NULL2EMPTY_STR(pdata->group), ZBX_JSON_TYPE_STRING); zbx_json_adduint64(&j, "uid", pdata->uid); zbx_json_adduint64(&j, "gid", pdata->gid); zbx_json_adduint64(&j, "vsize", pdata->vsize); zbx_json_adduint64(&j, "rss", pdata->rss); zbx_json_adduint64(&j, "size", pdata->size); zbx_json_adduint64(&j, "tsize", pdata->tsize); zbx_json_adduint64(&j, "dsize", pdata->dsize); zbx_json_adduint64(&j, "ssize", pdata->ssize); zbx_json_adduint64(&j, "cputime_user", pdata->cputime_user); zbx_json_adduint64(&j, "cputime_system", pdata->cputime_system); zbx_json_addstring(&j, "state", ZBX_NULL2EMPTY_STR(pdata->state), ZBX_JSON_TYPE_STRING); zbx_json_adduint64(&j, "ctx_switches", pdata->ctx_switches); zbx_json_addint64(&j, "threads", pdata->threads); zbx_json_adduint64(&j, "page_faults", pdata->page_faults); zbx_json_addint64(&j, "fds", pdata->fds); zbx_json_adduint64(&j, "swap", pdata->swap); zbx_json_adduint64(&j, "io_read_op", pdata->io_read_op); zbx_json_adduint64(&j, "io_write_op", pdata->io_write_op); } else if (ZBX_PROC_MODE_THREAD == zbx_proc_mode) { zbx_json_addint64(&j, "pid", pdata->pid); zbx_json_addint64(&j, "ppid", pdata->ppid); zbx_json_addstring(&j, "name", ZBX_NULL2EMPTY_STR(pdata->name), ZBX_JSON_TYPE_STRING); zbx_json_addstring(&j, "user", ZBX_NULL2EMPTY_STR(pdata->user), ZBX_JSON_TYPE_STRING); zbx_json_addstring(&j, "group", ZBX_NULL2EMPTY_STR(pdata->group), ZBX_JSON_TYPE_STRING); zbx_json_adduint64(&j, "uid", pdata->uid); zbx_json_adduint64(&j, "gid", pdata->gid); zbx_json_addstring(&j, "tname", ZBX_NULL2EMPTY_STR(pdata->tname), ZBX_JSON_TYPE_STRING); zbx_json_addint64(&j, "tid", pdata->tid); zbx_json_adduint64(&j, "cputime_user", pdata->cputime_user); zbx_json_adduint64(&j, "cputime_system", pdata->cputime_system); zbx_json_addstring(&j, "state", ZBX_NULL2EMPTY_STR(pdata->state), ZBX_JSON_TYPE_STRING); zbx_json_adduint64(&j, "ctx_switches", pdata->ctx_switches); zbx_json_adduint64(&j, "io_read_op", pdata->io_read_op); zbx_json_adduint64(&j, "io_write_op", pdata->io_write_op); } else { zbx_json_addstring(&j, "name", ZBX_NULL2EMPTY_STR(pdata->name), ZBX_JSON_TYPE_STRING); zbx_json_adduint64(&j, "processes", pdata->processes); zbx_json_adduint64(&j, "vsize", pdata->vsize); zbx_json_adduint64(&j, "rss", pdata->rss); zbx_json_adduint64(&j, "size", pdata->size); zbx_json_adduint64(&j, "tsize", pdata->tsize); zbx_json_adduint64(&j, "dsize", pdata->dsize); zbx_json_adduint64(&j, "ssize", pdata->ssize); zbx_json_adduint64(&j, "cputime_user", pdata->cputime_user); zbx_json_adduint64(&j, "cputime_system", pdata->cputime_system); zbx_json_adduint64(&j, "ctx_switches", pdata->ctx_switches); zbx_json_addint64(&j, "threads", pdata->threads); zbx_json_adduint64(&j, "page_faults", pdata->page_faults); zbx_json_addint64(&j, "fds", pdata->fds); zbx_json_adduint64(&j, "swap", pdata->swap); zbx_json_adduint64(&j, "io_read_op", pdata->io_read_op); zbx_json_adduint64(&j, "io_write_op", pdata->io_write_op); } zbx_json_close(&j); } zbx_vector_proc_data_ptr_clear_ext(&proc_data_ctx, proc_data_free); zbx_vector_proc_data_ptr_destroy(&proc_data_ctx); out: zbx_json_close(&j); SET_STR_RESULT(result, zbx_strdup(NULL, j.buffer)); zbx_json_free(&j); return SYSINFO_RET_OK; #undef SUM_PROC_VALUE }