int PROC_NUM(const char *cmd, const char *param, unsigned flags, AGENT_RESULT *result) { char tmp[MAX_STRING_LEN], procname[MAX_STRING_LEN], proccomm[MAX_STRING_LEN]; DIR *dir; struct dirent *entries; struct passwd *usrinfo; FILE *f_cmd = NULL, *f_stat = NULL; int zbx_proc_stat; zbx_uint64_t proccount = 0; if (num_param(param) > 4) return SYSINFO_RET_FAIL; if (0 != get_param(param, 1, procname, sizeof(procname))) *procname = '\0'; if (0 != get_param(param, 2, tmp, sizeof(tmp))) *tmp = '\0'; if (*tmp != '\0') { usrinfo = getpwnam(tmp); if (usrinfo == NULL) /* incorrect user name */ return SYSINFO_RET_FAIL; } else usrinfo = NULL; if (0 != get_param(param, 3, tmp, sizeof(tmp))) *tmp = '\0'; if (*tmp != '\0') { if (0 == strcmp(tmp, "run")) zbx_proc_stat = ZBX_PROC_STAT_RUN; else if (0 == strcmp(tmp, "sleep")) zbx_proc_stat = ZBX_PROC_STAT_SLEEP; else if (0 == strcmp(tmp, "zomb")) zbx_proc_stat = ZBX_PROC_STAT_ZOMB; else if (0 == strcmp(tmp, "all")) zbx_proc_stat = ZBX_PROC_STAT_ALL; else return SYSINFO_RET_FAIL; } else zbx_proc_stat = ZBX_PROC_STAT_ALL; if (0 != get_param(param, 4, proccomm, sizeof(proccomm))) *proccomm = '\0'; if (NULL == (dir = opendir("/proc"))) return SYSINFO_RET_FAIL; while (NULL != (entries = readdir(dir))) { zbx_fclose(f_cmd); zbx_fclose(f_stat); /* Self is a symbolic link. It leads to incorrect results for proc_cnt[zabbix_agentd] */ /* Better approach: check if /proc/x/ is symbolic link */ if (0 == strncmp(entries->d_name, "self", MAX_STRING_LEN)) continue; zbx_snprintf(tmp, sizeof(tmp), "/proc/%s/cmdline", entries->d_name); if (NULL == (f_cmd = open_proc_file(tmp))) continue; zbx_snprintf(tmp, sizeof(tmp), "/proc/%s/status", entries->d_name); if (NULL == (f_stat = open_proc_file(tmp))) continue; if (FAIL == check_procname(f_cmd, f_stat, procname)) continue; if (FAIL == check_user(f_stat, usrinfo)) continue; if (FAIL == check_proccomm(f_cmd, proccomm)) continue; if (FAIL == check_procstate(f_stat, zbx_proc_stat)) continue; proccount++; } zbx_fclose(f_cmd); zbx_fclose(f_stat); closedir(dir); SET_UI64_RESULT(result, proccount); return SYSINFO_RET_OK; }
int PROC_NUM(AGENT_REQUEST *request, AGENT_RESULT *result) { char tmp[MAX_STRING_LEN], *procname, *proccomm, *param; DIR *dir; struct dirent *entries; struct passwd *usrinfo; FILE *f_cmd = NULL, *f_stat = NULL; int proccount = 0, invalid_user = 0, zbx_proc_stat; 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 { 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; if (NULL == (dir = opendir("/proc"))) { SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot open /proc: %s", zbx_strerror(errno))); return SYSINFO_RET_FAIL; } while (NULL != (entries = readdir(dir))) { zbx_fclose(f_cmd); zbx_fclose(f_stat); if (0 == strcmp(entries->d_name, "self")) continue; zbx_snprintf(tmp, sizeof(tmp), "/proc/%s/cmdline", entries->d_name); if (NULL == (f_cmd = fopen(tmp, "r"))) continue; zbx_snprintf(tmp, sizeof(tmp), "/proc/%s/status", entries->d_name); if (NULL == (f_stat = fopen(tmp, "r"))) continue; if (FAIL == check_procname(f_cmd, f_stat, procname)) continue; if (FAIL == check_user(f_stat, usrinfo)) continue; if (FAIL == check_proccomm(f_cmd, proccomm)) continue; if (FAIL == check_procstate(f_stat, zbx_proc_stat)) continue; proccount++; } zbx_fclose(f_cmd); zbx_fclose(f_stat); closedir(dir); out: SET_UI64_RESULT(result, proccount); return SYSINFO_RET_OK; }
int PROC_MEM(const char *cmd, const char *param, unsigned flags, AGENT_RESULT *result) { char tmp[MAX_STRING_LEN], *p, *p1, procname[MAX_STRING_LEN], proccomm[MAX_STRING_LEN]; DIR *dir; struct dirent *entries; struct passwd *usrinfo; FILE *f_cmd = NULL, *f_stat = NULL; zbx_uint64_t value = 0; int do_task, proccount = 0; double memsize = 0; if (4 < num_param(param)) return SYSINFO_RET_FAIL; if (0 != get_param(param, 1, procname, sizeof(procname))) *procname = '\0'; if (0 != get_param(param, 2, tmp, sizeof(tmp))) *tmp = '\0'; if ('\0' != *tmp) { usrinfo = getpwnam(tmp); if (NULL == usrinfo) /* incorrect user name */ return SYSINFO_RET_FAIL; } else usrinfo = NULL; if (0 != get_param(param, 3, tmp, sizeof(tmp))) *tmp = '\0'; if ('\0' != *tmp) { if (0 == strcmp(tmp, "avg")) do_task = DO_AVG; else if (0 == strcmp(tmp, "max")) do_task = DO_MAX; else if (0 == strcmp(tmp, "min")) do_task = DO_MIN; else if (0 == strcmp(tmp, "sum")) do_task = DO_SUM; else return SYSINFO_RET_FAIL; } else do_task = DO_SUM; if (0 != get_param(param, 4, proccomm, sizeof(proccomm))) *proccomm = '\0'; if (NULL == (dir = opendir("/proc"))) return SYSINFO_RET_FAIL; while (NULL != (entries = readdir(dir))) { zbx_fclose(f_cmd); zbx_fclose(f_stat); /* Self is a symbolic link. It leads to incorrect results for proc_cnt[zabbix_agentd]. */ /* Better approach: check if /proc/x/ is symbolic link. */ if (0 == strncmp(entries->d_name, "self", MAX_STRING_LEN)) continue; zbx_snprintf(tmp, sizeof(tmp), "/proc/%s/cmdline", entries->d_name); if (NULL == (f_cmd = open_proc_file(tmp))) continue; zbx_snprintf(tmp, sizeof(tmp), "/proc/%s/status", entries->d_name); if (NULL == (f_stat = open_proc_file(tmp))) continue; if (FAIL == check_procname(f_cmd, f_stat, procname)) continue; if (FAIL == check_user(f_stat, usrinfo)) continue; if (FAIL == check_proccomm(f_cmd, proccomm)) continue; rewind(f_stat); while (NULL != fgets(tmp, sizeof(tmp), f_stat)) { if (0 != strncmp(tmp, "VmSize:\t", 8)) continue; p = tmp + 8; if (NULL == (p1 = strrchr(p, ' '))) continue; *p1++ = '\0'; ZBX_STR2UINT64(value, p); zbx_rtrim(p1, "\n"); if (0 == strcasecmp(p1, "kB")) value <<= 10; else if(0 == strcasecmp(p1, "mB")) value <<= 20; else if(0 == strcasecmp(p1, "GB")) value <<= 30; else if(0 == strcasecmp(p1, "TB")) value <<= 40; if (0 == proccount++) memsize = value; else { if (DO_MAX == do_task) memsize = MAX(memsize, value); else if (DO_MIN == do_task) memsize = MIN(memsize, value); else memsize += value; } break; } } zbx_fclose(f_cmd); zbx_fclose(f_stat); closedir(dir); if (do_task == DO_AVG) { SET_DBL_RESULT(result, proccount == 0 ? 0 : memsize / proccount); } else SET_UI64_RESULT(result, memsize); return SYSINFO_RET_OK; }
int PROC_MEM(AGENT_REQUEST *request, AGENT_RESULT *result) { #define ZBX_SIZE 0 #define ZBX_RSS 1 #define ZBX_VSIZE 2 #define ZBX_PMEM 3 #define ZBX_VMPEAK 4 #define ZBX_VMSWAP 5 #define ZBX_VMLIB 6 #define ZBX_VMLCK 7 #define ZBX_VMPIN 8 #define ZBX_VMHWM 9 #define ZBX_VMDATA 10 #define ZBX_VMSTK 11 #define ZBX_VMEXE 12 #define ZBX_VMPTE 13 char tmp[MAX_STRING_LEN], *procname, *proccomm, *param; DIR *dir; struct dirent *entries; struct passwd *usrinfo; FILE *f_cmd = NULL, *f_stat = NULL; zbx_uint64_t mem_size = 0, byte_value = 0, total_memory; double pct_size = 0.0, pct_value = 0.0; int do_task, res, proccount = 0, invalid_user = 0, invalid_read = 0; int mem_type_tried = 0, mem_type_code; char *mem_type = NULL; const char *mem_type_search = NULL; if (5 < 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); mem_type = get_rparam(request, 4); /* Comments for process memory types were compiled from: */ /* man 5 proc */ /* https://www.kernel.org/doc/Documentation/filesystems/proc.txt */ /* Himanshu Arora, Linux Processes explained - Part II, http://mylinuxbook.com/linux-processes-part2/ */ if (NULL == mem_type || '\0' == *mem_type || 0 == strcmp(mem_type, "vsize")) { mem_type_code = ZBX_VSIZE; /* current virtual memory size (total program size) */ mem_type_search = "VmSize:\t"; } else if (0 == strcmp(mem_type, "rss")) { mem_type_code = ZBX_RSS; /* current resident set size (size of memory portions) */ mem_type_search = "VmRSS:\t"; } else if (0 == strcmp(mem_type, "pmem")) { mem_type_code = ZBX_PMEM; /* percentage of real memory used by process */ } else if (0 == strcmp(mem_type, "size")) { mem_type_code = ZBX_SIZE; /* size of process (code + data + stack) */ } else if (0 == strcmp(mem_type, "peak")) { mem_type_code = ZBX_VMPEAK; /* peak virtual memory size */ mem_type_search = "VmPeak:\t"; } else if (0 == strcmp(mem_type, "swap")) { mem_type_code = ZBX_VMSWAP; /* size of swap space used */ mem_type_search = "VmSwap:\t"; } else if (0 == strcmp(mem_type, "lib")) { mem_type_code = ZBX_VMLIB; /* size of shared libraries */ mem_type_search = "VmLib:\t"; } else if (0 == strcmp(mem_type, "lck")) { mem_type_code = ZBX_VMLCK; /* size of locked memory */ mem_type_search = "VmLck:\t"; } else if (0 == strcmp(mem_type, "pin")) { mem_type_code = ZBX_VMPIN; /* size of pinned pages, they are never swappable */ mem_type_search = "VmPin:\t"; } else if (0 == strcmp(mem_type, "hwm")) { mem_type_code = ZBX_VMHWM; /* peak resident set size ("high water mark") */ mem_type_search = "VmHWM:\t"; } else if (0 == strcmp(mem_type, "data")) { mem_type_code = ZBX_VMDATA; /* size of data segment */ mem_type_search = "VmData:\t"; } else if (0 == strcmp(mem_type, "stk")) { mem_type_code = ZBX_VMSTK; /* size of stack segment */ mem_type_search = "VmStk:\t"; } else if (0 == strcmp(mem_type, "exe")) { mem_type_code = ZBX_VMEXE; /* size of text (code) segment */ mem_type_search = "VmExe:\t"; } else if (0 == strcmp(mem_type, "pte")) { mem_type_code = ZBX_VMPTE; /* size of page table entries */ mem_type_search = "VmPTE:\t"; } else { SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid fifth parameter.")); return SYSINFO_RET_FAIL; } if (1 == invalid_user) /* handle 0 for non-existent user after all parameters have been parsed and validated */ goto out; if (ZBX_PMEM == mem_type_code) { if (SUCCEED != get_total_memory(&total_memory)) { SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain amount of total memory: %s", zbx_strerror(errno))); return SYSINFO_RET_FAIL; } if (0 == total_memory) /* this should never happen but anyway - avoid crash due to dividing by 0 */ { SET_MSG_RESULT(result, zbx_strdup(NULL, "Total memory reported is 0.")); return SYSINFO_RET_FAIL; } } if (NULL == (dir = opendir("/proc"))) { SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot open /proc: %s", zbx_strerror(errno))); return SYSINFO_RET_FAIL; } while (NULL != (entries = readdir(dir))) { zbx_fclose(f_cmd); zbx_fclose(f_stat); if (0 == strcmp(entries->d_name, "self")) continue; zbx_snprintf(tmp, sizeof(tmp), "/proc/%s/cmdline", entries->d_name); if (NULL == (f_cmd = fopen(tmp, "r"))) continue; zbx_snprintf(tmp, sizeof(tmp), "/proc/%s/status", entries->d_name); if (NULL == (f_stat = fopen(tmp, "r"))) continue; if (FAIL == check_procname(f_cmd, f_stat, procname)) continue; if (FAIL == check_user(f_stat, usrinfo)) continue; if (FAIL == check_proccomm(f_cmd, proccomm)) continue; rewind(f_stat); if (0 == mem_type_tried) mem_type_tried = 1; switch (mem_type_code) { case ZBX_VSIZE: case ZBX_RSS: case ZBX_VMPEAK: case ZBX_VMSWAP: case ZBX_VMLIB: case ZBX_VMLCK: case ZBX_VMPIN: case ZBX_VMHWM: case ZBX_VMDATA: case ZBX_VMSTK: case ZBX_VMEXE: case ZBX_VMPTE: res = byte_value_from_proc_file(f_stat, mem_type_search, NULL, &byte_value); if (NOTSUPPORTED == res) continue; if (FAIL == res) { invalid_read = 1; goto clean; } break; case ZBX_SIZE: { zbx_uint64_t m; /* VmData, VmStk and VmExe follow in /proc/PID/status file in that order. */ /* Therefore we do not rewind f_stat between calls. */ mem_type_search = "VmData:\t"; if (SUCCEED == (res = byte_value_from_proc_file(f_stat, mem_type_search, NULL, &byte_value))) { mem_type_search = "VmStk:\t"; if (SUCCEED == (res = byte_value_from_proc_file(f_stat, mem_type_search, NULL, &m))) { byte_value += m; mem_type_search = "VmExe:\t"; if (SUCCEED == (res = byte_value_from_proc_file(f_stat, mem_type_search, NULL, &m))) { byte_value += m; } } } if (SUCCEED != res) { if (NOTSUPPORTED == res) { /* NOTSUPPORTED - at least one of data strings not found in */ /* the /proc/PID/status file */ continue; } else /* FAIL */ { invalid_read = 1; goto clean; } } } break; case ZBX_PMEM: mem_type_search = "VmRSS:\t"; res = byte_value_from_proc_file(f_stat, mem_type_search, NULL, &byte_value); if (SUCCEED == res) { pct_value = ((double)byte_value / (double)total_memory) * 100.0; } else if (NOTSUPPORTED == res) { continue; } else /* FAIL */ { invalid_read = 1; goto clean; } break; } if (ZBX_PMEM != mem_type_code) { if (0 != proccount++) { if (ZBX_DO_MAX == do_task) mem_size = MAX(mem_size, byte_value); else if (ZBX_DO_MIN == do_task) mem_size = MIN(mem_size, byte_value); else mem_size += byte_value; } else mem_size = byte_value; } else { if (0 != proccount++) { if (ZBX_DO_MAX == do_task) pct_size = MAX(pct_size, pct_value); else if (ZBX_DO_MIN == do_task) pct_size = MIN(pct_size, pct_value); else pct_size += pct_value; } else pct_size = pct_value; } } clean: zbx_fclose(f_cmd); zbx_fclose(f_stat); closedir(dir); if ((0 == proccount && 0 != mem_type_tried) || 0 != invalid_read) { char *s; s = zbx_strdup(NULL, mem_type_search); zbx_rtrim(s, ":\t"); SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot get amount of \"%s\" memory.", s)); zbx_free(s); return SYSINFO_RET_FAIL; } out: if (ZBX_PMEM != mem_type_code) { if (ZBX_DO_AVG == do_task) SET_DBL_RESULT(result, 0 == proccount ? 0 : (double)mem_size / (double)proccount); else SET_UI64_RESULT(result, mem_size); } else { if (ZBX_DO_AVG == do_task) SET_DBL_RESULT(result, 0 == proccount ? 0 : pct_size / (double)proccount); else SET_DBL_RESULT(result, pct_size); } return SYSINFO_RET_OK; #undef ZBX_SIZE #undef ZBX_RSS #undef ZBX_VSIZE #undef ZBX_PMEM #undef ZBX_VMPEAK #undef ZBX_VMSWAP #undef ZBX_VMLIB #undef ZBX_VMLCK #undef ZBX_VMPIN #undef ZBX_VMHWM #undef ZBX_VMDATA #undef ZBX_VMSTK #undef ZBX_VMEXE #undef ZBX_VMPTE }