diff options
-rw-r--r-- | include/sysinfo.h | 7 | ||||
-rw-r--r-- | src/libs/zbxsysinfo/linux/proc.c | 381 | ||||
-rw-r--r-- | src/libs/zbxsysinfo/solaris/proc.c | 273 | ||||
-rw-r--r-- | src/zabbix_agent/procstat.c | 241 |
4 files changed, 660 insertions, 242 deletions
diff --git a/include/sysinfo.h b/include/sysinfo.h index 0d805422aac..7175d8a580d 100644 --- a/include/sysinfo.h +++ b/include/sysinfo.h @@ -276,4 +276,11 @@ typedef struct } MODE_FUNCTION; +/* the fields used by proc queries */ +#define ZBX_SYSINFO_PROC_NONE 0x0000 +#define ZBX_SYSINFO_PROC_PID 0x0001 +#define ZBX_SYSINFO_PROC_NAME 0x0002 +#define ZBX_SYSINFO_PROC_CMDLINE 0x0004 +#define ZBX_SYSINFO_PROC_USER 0x0008 + #endif diff --git a/src/libs/zbxsysinfo/linux/proc.c b/src/libs/zbxsysinfo/linux/proc.c index 9aced0905ac..82a16c78c23 100644 --- a/src/libs/zbxsysinfo/linux/proc.c +++ b/src/libs/zbxsysinfo/linux/proc.c @@ -24,6 +24,40 @@ #include "stats.h" #include "db.h" + +typedef struct +{ + pid_t pid; + uid_t uid; + + char *name; + + /* the process name taken from the 0th argument */ + char *name_arg0; + + /* process command line in format <arg0> <arg1> ... <argN>\0 */ + char *cmdline; +} +zbx_sysinfo_proc_t; + + +/****************************************************************************** + * * + * Function: zbx_sysinfo_proc_free * + * * + * Purpose: frees process data structure * + * * + ******************************************************************************/ +void zbx_sysinfo_proc_free(zbx_sysinfo_proc_t *proc) +{ + zbx_free(proc->name); + zbx_free(proc->name_arg0); + zbx_free(proc->cmdline); + + zbx_free(proc); +} + + static int get_cmdline(FILE *f_cmd, char **line, size_t *line_offset) { size_t line_alloc = ZBX_KIBIBYTE, n; @@ -786,7 +820,128 @@ out: /****************************************************************************** * * - * Function: procstat_read_value * + * Function: proc_get_process_name * + * * + * Purpose: returns process name * + * * + * Parameters: pid - [IN] the process identifier * + * * + * Return value: The process name. * + * * + * Comments: The returned name must be freed by the caller. * + * * + ******************************************************************************/ +static char *proc_get_process_name(pid_t pid) +{ + char tmp[MAX_STRING_LEN], *ptr, *name = NULL, *pend; + int fd, offset = 0, n; + + zbx_snprintf(tmp, sizeof(tmp), "/proc/%d/status", (int)pid); + + if (-1 == (fd = open(tmp, O_RDONLY))) + return NULL; + + while (0 < (n = read(fd, tmp + offset, sizeof(tmp) - offset - 1))) + { + n += offset; + tmp[n] = '\0'; + + for (ptr = tmp; NULL != ptr; ptr = pend + 1) + { + if (NULL == (pend = strchr(ptr, '\n'))) + break; + + if (0 == strncmp(ptr, "Name:\t", 6)) + { + *pend = '\0'; + name = zbx_strdup(NULL, ptr + 6); + goto out; + } + } + + offset = n - (ptr - tmp); + memmove(tmp, ptr, offset); + } +out: + close(fd); + + return name; +} + +/****************************************************************************** + * * + * Function: proc_get_process_cmdline * + * * + * Purpose: returns process command line * + * * + * Parameters: pid - [IN] the process identifier * + * * + * Return value: The process command line * + * * + * Comments: The returned command line must be freed by the caller. * + * * + ******************************************************************************/ +static char *proc_get_process_cmdline(pid_t pid) +{ + char tmp[MAX_STRING_LEN], *cmdline, *arg; + int fd, n; + size_t cmdline_alloc = ZBX_KIBIBYTE, cmdline_offset = 0; + + zbx_snprintf(tmp, sizeof(tmp), "/proc/%d/cmdline", (int)pid); + + if (-1 == (fd = open(tmp, O_RDONLY))) + return NULL; + + cmdline = zbx_malloc(NULL, cmdline_alloc); + + while (0 < (n = read(fd, cmdline + cmdline_offset, cmdline_alloc - cmdline_offset))) + { + cmdline_offset += n; + + if (cmdline_offset == cmdline_alloc) + { + cmdline_alloc *= 2; + cmdline = realloc(cmdline, cmdline_alloc); + } + } + + close(fd); + + cmdline[cmdline_offset] = '\0'; + + for (arg = cmdline; '\0' != *arg; arg = arg + strlen(arg)) + *arg++ = ' '; + + return cmdline; +} + +/****************************************************************************** + * * + * Function: proc_get_process_uid * + * * + * Purpose: returns process user identifer * + * * + * Parameters: pid - [IN] the process identifier * + * * + * Return value: The process user identifier * + * * + ******************************************************************************/ +static uid_t proc_get_process_uid(pid_t pid) +{ + char tmp[MAX_STRING_LEN]; + zbx_stat_t st; + + zbx_snprintf(tmp, sizeof(tmp), "/proc/%d", (int)pid); + + if (0 != zbx_stat(tmp, &st)) + return 0; + + return st.st_uid; +} + +/****************************************************************************** + * * + * Function: proc_read_value * * * * Purpose: read 64 bit unsigned space or zero character terminated integer * * from a text string * @@ -797,7 +952,7 @@ out: * Return value: The length of the parsed text or FAIL if parsing failed. * * * ******************************************************************************/ -static int procstat_read_value(const char *ptr, zbx_uint64_t *value) +static int proc_read_value(const char *ptr, zbx_uint64_t *value) { const char *start = ptr; int len; @@ -861,7 +1016,7 @@ static int proc_read_cpu_util(zbx_procstat_util_t *procutil) switch (++n) { case 12: - if (FAIL == (offset = procstat_read_value(ptr, &procutil->utime))) + if (FAIL == (offset = proc_read_value(ptr, &procutil->utime))) { ret = -EINVAL; goto out; @@ -870,7 +1025,7 @@ static int proc_read_cpu_util(zbx_procstat_util_t *procutil) break; case 13: - if (FAIL == (offset = procstat_read_value(ptr, &procutil->stime))) + if (FAIL == (offset = proc_read_value(ptr, &procutil->stime))) { ret = -EINVAL; goto out; @@ -879,7 +1034,7 @@ static int proc_read_cpu_util(zbx_procstat_util_t *procutil) break; case 20: - if (FAIL == (offset = procstat_read_value(ptr, &procutil->starttime))) + if (FAIL == (offset = proc_read_value(ptr, &procutil->starttime))) { ret = -EINVAL; goto out; @@ -896,9 +1051,68 @@ out: return ret; } + +/****************************************************************************** + * * + * Function: proc_match_name * + * * + * Purpose: checks if the process name matches filter * + * * + ******************************************************************************/ +static int proc_match_name(const zbx_sysinfo_proc_t *proc, const char *procname) +{ + if (NULL == procname) + return SUCCEED; + + if (NULL != proc->name && 0 == strcmp(procname, proc->name)) + return SUCCEED; + + if (NULL != proc->name_arg0 && 0 == strcmp(procname, proc->name_arg0)) + return SUCCEED; + + return FAIL; +} + +/****************************************************************************** + * * + * Function: proc_match_user * + * * + * Purpose: checks if the process user matches filter * + * * + ******************************************************************************/ + +static int proc_match_user(const zbx_sysinfo_proc_t *proc, const struct passwd *usrinfo) +{ + if (NULL == usrinfo) + return SUCCEED; + + if (proc->uid == usrinfo->pw_uid) + return SUCCEED; + + return FAIL; +} + +/****************************************************************************** + * * + * Function: proc_match_cmdline * + * * + * Purpose: checks if the process command line matches filter * + * * + ******************************************************************************/ +static int proc_match_cmdline(const zbx_sysinfo_proc_t *proc, const char *cmdline) +{ + if (NULL == cmdline) + return SUCCEED; + + if (NULL != zbx_regexp_match(proc->cmdline, cmdline, NULL)) + return SUCCEED; + + return FAIL; +} + /****************************************************************************** * * - * Function: zbx_proc_get_stats * + * Function: zbx_proc_get_process_stats * * * * Purpose: get process cpu utilization data * * * @@ -906,9 +1120,9 @@ out: * procs_num - [IN] the number of items in procs array * * * ******************************************************************************/ -void zbx_proc_get_stats(zbx_procstat_util_t *procs, int procs_num) +void zbx_proc_get_process_stats(zbx_procstat_util_t *procs, int procs_num) { - const char *__function_name = "zbx_proc_get_pids"; + const char *__function_name = "zbx_proc_get_process_stats"; int i; zabbix_log(LOG_LEVEL_TRACE, "In %s() procs_num:%d", __function_name, procs_num); @@ -921,12 +1135,97 @@ void zbx_proc_get_stats(zbx_procstat_util_t *procs, int procs_num) /****************************************************************************** * * - * Function: zbx_proc_get_pids * + * Function: zbx_proc_get_processes * + * * + * Purpose: get system processes * + * * + * Parameters: processes - [OUT] the system processes * + * flags - [IN] the flags specifying the process properties * + * that must be returned * + * * + ******************************************************************************/ +int zbx_proc_get_processes(zbx_vector_ptr_t *processes, unsigned int flags) +{ + const char *__function_name = "zbx_proc_get_processes"; + + DIR *dir; + struct dirent *entries; + int ret = FAIL, pid; + char *arg0; + zbx_sysinfo_proc_t *proc; + + + zabbix_log(LOG_LEVEL_TRACE, "In %s()", __function_name); + + if (NULL == (dir = opendir("/proc"))) + { + ret = -errno; + goto out; + } + + while (NULL != (entries = readdir(dir))) + { + /* skip entries not containing pids */ + if (FAIL == is_uint32(entries->d_name, &pid)) + continue; + + proc = (zbx_sysinfo_proc_t *)zbx_malloc(NULL, sizeof(zbx_sysinfo_proc_t)); + memset(proc, 0, sizeof(zbx_sysinfo_proc_t)); + + proc->pid = pid; + + if (0 != (flags & ZBX_SYSINFO_PROC_USER)) + proc->uid = proc_get_process_uid(pid); + + if (0 != (flags & (ZBX_SYSINFO_PROC_CMDLINE | ZBX_SYSINFO_PROC_NAME))) + proc->cmdline = proc_get_process_cmdline(pid); + + if (0 != (flags & ZBX_SYSINFO_PROC_NAME) && NULL != proc->cmdline) + { + proc->name = proc_get_process_name(pid); + + if (NULL == (arg0 = strrchr(proc->cmdline, '/'))) + proc->name_arg0 = zbx_strdup(NULL, proc->cmdline); + else + proc->name_arg0 = zbx_strdup(NULL, arg0 + 1); + } + + zbx_vector_ptr_append(processes, proc); + } + + closedir(dir); + + ret = SUCCEED; +out: + zabbix_log(LOG_LEVEL_TRACE, "End of %s(): %s, processes:%d", __function_name, zbx_result_string(ret), + processes->values_num); + + return ret; +} + +/****************************************************************************** + * * + * Function: zbx_proc_free_processes * + * * + * Purpose: frees process vector read by zbx_proc_get_processes function * + * * + * Parameters: processes - [IN/OUT] the process vector to free * + * * + ******************************************************************************/ +void zbx_proc_free_processes(zbx_vector_ptr_t *processes) +{ + zbx_vector_ptr_clear_ext(processes, (zbx_mem_free_func_t)zbx_sysinfo_proc_free); +} + +/****************************************************************************** + * * + * Function: zbx_proc_get_matching_pids * * * * Purpose: get pids matching the specified process name, user name and * * command line * * * - * Parameters: procname - [IN] the process name, NULL - all * + * Parameters: processes - [IN] the list of system processes * + * procname - [IN] the process name, NULL - all * * username - [IN] the user name, NULL - all * * cmdline - [IN] the command line, NULL - all * * pids - [OUT] the vector of matching pids * @@ -935,16 +1234,13 @@ void zbx_proc_get_stats(zbx_procstat_util_t *procs, int procs_num) * -errno - failed to read pids * * * ******************************************************************************/ -int zbx_proc_get_pids(const char *procname, const char *username, const char *cmdline, zbx_uint64_t flags, - zbx_vector_uint64_t *pids) +void zbx_proc_get_matching_pids(const zbx_vector_ptr_t *processes, const char *procname, const char *username, + const char *cmdline, zbx_uint64_t flags, zbx_vector_uint64_t *pids) { - const char *__function_name = "zbx_proc_get_pids"; - DIR *dir; - struct dirent *entries; - struct passwd *usrinfo; - char tmp[MAX_STRING_LEN]; - FILE *f_cmd = NULL, *f_stat = NULL; - int pid, ret = FAIL; + const char *__function_name = "zbx_proc_get_matching_pids"; + struct passwd *usrinfo; + int i; + zbx_sysinfo_proc_t *proc; zabbix_log(LOG_LEVEL_TRACE, "In %s() procname:%s username:%s cmdline:%s", __function_name, ZBX_NULL2EMPTY_STR(procname), ZBX_NULL2EMPTY_STR(username), ZBX_NULL2EMPTY_STR(cmdline)); @@ -953,61 +1249,28 @@ int zbx_proc_get_pids(const char *procname, const char *username, const char *cm { /* in the case of invalid user there are no matching processes, set empty result */ if (NULL == (usrinfo = getpwnam(username))) - { - ret = SUCCEED; goto out; - } } else usrinfo = NULL; - if (NULL == (dir = opendir("/proc"))) - { - ret = -errno; - goto out; - } - - while (NULL != (entries = readdir(dir))) + for (i = 0; i < processes->values_num; i++) { - /* skip entries not containing pids */ - if (FAIL == is_uint32(entries->d_name, &pid)) - continue; - - zbx_fclose(f_cmd); - zbx_fclose(f_stat); - - 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; + proc = (zbx_sysinfo_proc_t *)processes->values[i]; - if (FAIL == check_procname(f_cmd, f_stat, procname)) + if (SUCCEED != proc_match_user(proc, usrinfo)) continue; - if (FAIL == check_proccomm(f_cmd, cmdline)) + if (SUCCEED != proc_match_name(proc, procname)) continue; - if (FAIL == check_user(f_stat, usrinfo)) + if (SUCCEED != proc_match_cmdline(proc, cmdline)) continue; - zbx_vector_uint64_append(pids, (zbx_uint64_t)pid); + zbx_vector_uint64_append(pids, (zbx_uint64_t)proc->pid); } - - zbx_fclose(f_cmd); - zbx_fclose(f_stat); - - closedir(dir); - - ret = SUCCEED; out: - zabbix_log(LOG_LEVEL_TRACE, "End of %s(): %s", __function_name, zbx_result_string(ret)); - - return ret; + zabbix_log(LOG_LEVEL_TRACE, "End of %s()", __function_name); } int PROC_CPU_UTIL(AGENT_REQUEST *request, AGENT_RESULT *result) diff --git a/src/libs/zbxsysinfo/solaris/proc.c b/src/libs/zbxsysinfo/solaris/proc.c index 8e1f6fdba33..ec36403922e 100644 --- a/src/libs/zbxsysinfo/solaris/proc.c +++ b/src/libs/zbxsysinfo/solaris/proc.c @@ -24,6 +24,39 @@ #include "log.h" #include "stats.h" +typedef struct +{ + pid_t pid; + uid_t uid; + + char *name; + + /* process command line in format <arg0> <arg1> ... <argN>\0 */ + char *cmdline; + +#ifdef HAVE_ZONE_H + zoneid_t zoneid; +#endif +} +zbx_sysinfo_proc_t; + + +/****************************************************************************** + * * + * Function: zbx_sysinfo_proc_free * + * * + * Purpose: frees process data structure * + * * + ******************************************************************************/ +void zbx_sysinfo_proc_free(zbx_sysinfo_proc_t *proc) +{ + zbx_free(proc->name); + zbx_free(proc->cmdline); + + zbx_free(proc); +} + + static int check_procstate(psinfo_t *psinfo, int zbx_proc_stat) { if (zbx_proc_stat == ZBX_PROC_STAT_ALL) @@ -322,6 +355,82 @@ out: /****************************************************************************** * * + * Function: proc_match_name * + * * + * Purpose: checks if the process name matches filter * + * * + ******************************************************************************/ +static int proc_match_name(const zbx_sysinfo_proc_t *proc, const char *procname) +{ + if (NULL == procname) + return SUCCEED; + + if (NULL != proc->name && 0 == strcmp(procname, proc->name)) + return SUCCEED; + + return FAIL; +} + +/****************************************************************************** + * * + * Function: proc_match_user * + * * + * Purpose: checks if the process user matches filter * + * * + ******************************************************************************/ + +static int proc_match_user(const zbx_sysinfo_proc_t *proc, const struct passwd *usrinfo) +{ + if (NULL == usrinfo) + return SUCCEED; + + if (proc->uid == usrinfo->pw_uid) + return SUCCEED; + + return FAIL; +} + +/****************************************************************************** + * * + * Function: proc_match_cmdline * + * * + * Purpose: checks if the process command line matches filter * + * * + ******************************************************************************/ +static int proc_match_cmdline(const zbx_sysinfo_proc_t *proc, const char *cmdline) +{ + if (NULL == cmdline) + return SUCCEED; + + if (NULL != zbx_regexp_match(proc->cmdline, cmdline, NULL)) + return SUCCEED; + + return FAIL; +} + + +#ifdef HAVE_ZONE_H +/****************************************************************************** + * * + * Function: proc_match_user * + * * + * Purpose: checks if the process user matches filter * + * * + ******************************************************************************/ +static int proc_match_zone(const zbx_sysinfo_proc_t *proc, zbx_uint64_t flags, zoneid_t zoneid) +{ + if (0 != (ZBX_PROCSTAT_FLAGS_ZONE_ALL & flags)) + return SUCCEED; + + if (proc->zoneid == zoneid) + return SUCCEED; + + return FAIL; +} +#endif + +/****************************************************************************** + * * * Function: proc_read_cpu_util * * * * Purpose: reads process cpu utilization values from /proc/[pid]/stat file * @@ -376,7 +485,7 @@ static int proc_read_cpu_util(zbx_procstat_util_t *procutil) /****************************************************************************** * * - * Function: zbx_proc_get_stats * + * Function: zbx_proc_get_process_stats * * * * Purpose: get process cpu utilization data * * * @@ -384,7 +493,7 @@ static int proc_read_cpu_util(zbx_procstat_util_t *procutil) * procs_num - [IN] the number of items in procs array * * * ******************************************************************************/ -void zbx_proc_get_stats(zbx_procstat_util_t *procs, int procs_num) +void zbx_proc_get_process_stats(zbx_procstat_util_t *procs, int procs_num) { const char *__function_name = "zbx_proc_get_stats"; int i; @@ -399,6 +508,98 @@ void zbx_proc_get_stats(zbx_procstat_util_t *procs, int procs_num) /****************************************************************************** * * + * Function: zbx_proc_get_processes * + * * + * Purpose: get system processes * + * * + * Parameters: processes - [OUT] the system processes * + * flags - [IN] the flags specifying the process properties * + * that must be returned * + * * + ******************************************************************************/ +int zbx_proc_get_processes(zbx_vector_ptr_t *processes, unsigned int flags) +{ + const char *__function_name = "zbx_proc_get_processes"; + + DIR *dir; + struct dirent *entries; + struct passwd *usrinfo; + char tmp[MAX_STRING_LEN]; + int pid, ret = FAIL, fd = -1, n; + psinfo_t psinfo; /* In the correct procfs.h, the structure name is psinfo_t */ + zbx_sysinfo_proc_t *proc; + + zabbix_log(LOG_LEVEL_TRACE, "In %s()", __function_name); + + if (NULL == (dir = opendir("/proc"))) + { + ret = -errno; + goto out; + } + + while (NULL != (entries = readdir(dir))) + { + /* skip entries not containing pids */ + if (FAIL == is_uint32(entries->d_name, &pid)) + continue; + + zbx_snprintf(tmp, sizeof(tmp), "/proc/%s/psinfo", entries->d_name); + + if (-1 == (fd = open(tmp, O_RDONLY))) + continue; + + n = read(fd, &psinfo, sizeof(psinfo)); + close(fd); + + if (-1 == n) + continue; + + proc = (zbx_sysinfo_proc_t *)zbx_malloc(NULL, sizeof(zbx_sysinfo_proc_t)); + memset(proc, 0, sizeof(zbx_sysinfo_proc_t)); + + proc->pid = pid; + + if (0 != (flags & ZBX_SYSINFO_PROC_NAME)) + proc->name = zbx_strdup(NULL, psinfo.pr_fname); + + if (0 != (flags & ZBX_SYSINFO_PROC_USER)) + proc->uid = psinfo.pr_uid; + + if (0 != (flags & ZBX_SYSINFO_PROC_CMDLINE)) + proc->cmdline = zbx_strdup(NULL, psinfo.pr_psargs); + +#ifdef HAVE_ZONE_H + proc->zoneid = psinfo.pr_zoneid; +#endif + + zbx_vector_ptr_append(processes, proc); + } + + closedir(dir); + + ret = SUCCEED; +out: + zabbix_log(LOG_LEVEL_TRACE, "End of %s(): %s", __function_name, zbx_result_string(ret)); + + return ret; +} + +/****************************************************************************** + * * + * Function: zbx_proc_free_processes * + * * + * Purpose: frees process vector read by zbx_proc_get_processes function * + * * + * Parameters: processes - [IN/OUT] the process vector to free * + * * + ******************************************************************************/ +void zbx_proc_free_processes(zbx_vector_ptr_t *processes) +{ + zbx_vector_ptr_clear_ext(processes, (zbx_mem_free_func_t)zbx_sysinfo_proc_free); +} + +/****************************************************************************** + * * * Function: zbx_proc_get_pids * * * * Purpose: get pids matching the specified process name, user name and * @@ -413,18 +614,19 @@ void zbx_proc_get_stats(zbx_procstat_util_t *procs, int procs_num) * -errno - failed to read pids * * * ******************************************************************************/ -int zbx_proc_get_pids(const char *procname, const char *username, const char *cmdline, zbx_uint64_t flags, - zbx_vector_uint64_t *pids) +int zbx_proc_get_matching_pids(const zbx_vector_ptr_t *processes, const char *procname, const char *username, + const char *cmdline, zbx_uint64_t flags, zbx_vector_uint64_t *pids) { - const char *__function_name = "zbx_proc_get_pids"; - DIR *dir; - struct dirent *entries; - struct passwd *usrinfo; - char tmp[MAX_STRING_LEN]; - int pid, ret = FAIL, fd = -1; - psinfo_t psinfo; /* In the correct procfs.h, the structure name is psinfo_t */ + const char *__function_name = "zbx_proc_get_matching_pids"; + DIR *dir; + struct dirent *entries; + struct passwd *usrinfo; + char tmp[MAX_STRING_LEN]; + int pid, ret = FAIL, fd = -1, i; + psinfo_t psinfo; /* In the correct procfs.h, the structure name is psinfo_t */ + zbx_sysinfo_proc_t *proc; #ifdef HAVE_ZONE_H - zoneid_t zoneid; + zoneid_t zoneid; #endif zabbix_log(LOG_LEVEL_TRACE, "In %s() procname:%s username:%s cmdline:%s zone:%d", __function_name, @@ -442,64 +644,35 @@ int zbx_proc_get_pids(const char *procname, const char *username, const char *cm else usrinfo = NULL; - if (NULL == (dir = opendir("/proc"))) - { - ret = -errno; - goto out; - } - #ifdef HAVE_ZONE_H zoneid = getzoneid(); #endif - while (NULL != (entries = readdir(dir))) + for (i = 0; i < processes->values_num; i++) { - /* skip entries not containing pids */ - if (FAIL == is_uint32(entries->d_name, &pid)) - continue; - - if (-1 != fd) - { - close(fd); - fd = -1; - } - - zbx_snprintf(tmp, sizeof(tmp), "/proc/%s/psinfo", entries->d_name); + proc = (zbx_sysinfo_proc_t *)processes->values[i]; - if (-1 == (fd = open(tmp, O_RDONLY))) + if (SUCCEED != proc_match_user(proc, usrinfo)) continue; - if (-1 == read(fd, &psinfo, sizeof(psinfo))) - continue; - - if (NULL != procname && '\0' != *procname && 0 != strcmp(procname, psinfo.pr_fname)) - continue; - - if (NULL != usrinfo && usrinfo->pw_uid != psinfo.pr_uid) + if (SUCCEED != proc_match_name(proc, procname)) continue; - if (NULL != cmdline && '\0' != *cmdline && NULL == zbx_regexp_match(psinfo.pr_psargs, cmdline, NULL)) + if (SUCCEED != proc_match_cmdline(proc, cmdline)) continue; #ifdef HAVE_ZONE_H - if (0 == (ZBX_PROCSTAT_FLAGS_ZONE_ALL & flags) && psinfo.pr_zoneid != zoneid) + if (SUCCEED != proc_match_zone(proc, flags, zoneid)) continue; #endif - zbx_vector_uint64_append(pids, (zbx_uint64_t)pid); + zbx_vector_uint64_append(pids, (zbx_uint64_t)proc->pid); } - - closedir(dir); - if (-1 != fd) - close(fd); - - ret = SUCCEED; out: - zabbix_log(LOG_LEVEL_TRACE, "End of %s(): %s", __function_name, zbx_result_string(ret)); - - return ret; + zabbix_log(LOG_LEVEL_TRACE, "End of %s()", __function_name); } + int PROC_CPU_UTIL(AGENT_REQUEST *request, AGENT_RESULT *result) { const char *procname, *username, *cmdline, *tmp, *flags; diff --git a/src/zabbix_agent/procstat.c b/src/zabbix_agent/procstat.c index 05626cc2169..b7cb3190f54 100644 --- a/src/zabbix_agent/procstat.c +++ b/src/zabbix_agent/procstat.c @@ -83,9 +83,6 @@ static zbx_dshm_ref_t procstat_ref; typedef struct { - /* the number of processes in process statistics snapshot */ - int pids_num; - /* a linked list of active queries (offset of the first active query) */ int queries; @@ -112,10 +109,6 @@ zbx_procstat_header_t; #define PROCSTAT_QUERY_NEXT(base, query) \ (zbx_procstat_query_t*)PROCSTAT_PTR_NULL(base, query->next) -#define PROCSTAT_SNAPSHOT(base) \ - ((zbx_procstat_util_t *)((char *)base + ((zbx_procstat_header_t *)base)->size - \ - ((zbx_procstat_header_t *)base)->pids_num * sizeof(zbx_procstat_util_t))) - #define PROCSTAT_OFFSET(base, ptr) ((char *)ptr - (char *)base) /* data sample collected every second for the process cpu utilization queries */ @@ -181,10 +174,19 @@ typedef struct } zbx_procstat_query_data_t; + +static zbx_procstat_util_t *procstat_snapshot; +static int procstat_snapshot_num; + /* external functions used by procstat collector */ -int zbx_proc_get_pids(const char *procname, const char *username, const char *cmdline, zbx_uint64_t flags, - zbx_vector_uint64_t *pids); -void zbx_proc_get_stats(zbx_procstat_util_t *procs, int procs_num); +int zbx_proc_get_processes(zbx_vector_ptr_t *processes, unsigned int flags); + +int zbx_proc_get_matching_pids(const zbx_vector_ptr_t *processes, const char *procname, const char *username, + const char *cmdline, zbx_uint64_t flags, zbx_vector_uint64_t *pids); + +void zbx_proc_get_process_stats(zbx_procstat_util_t *procs, int procs_num); + +void zbx_proc_free_processes(zbx_vector_ptr_t *processes); /****************************************************************************** * * @@ -204,7 +206,7 @@ static int procstat_dshm_has_enough_space(void *base, size_t size) { zbx_procstat_header_t *header = (zbx_procstat_header_t *)base; - if (header->size > size + header->size_allocated + header->pids_num * sizeof(zbx_procstat_util_t)) + if (header->size >= size + header->size_allocated) return SUCCEED; return FAIL; @@ -313,8 +315,7 @@ static void procstat_copy_data(void *dst, size_t size_dst, const void *src) { const char *__function_name = "procstat_copy_data"; - int offset, size_snapshot, *query_offset, now; - zbx_procstat_header_t *hsrc = (zbx_procstat_header_t *)src; + int offset, *query_offset; zbx_procstat_header_t *hdst = (zbx_procstat_header_t *)dst; zbx_procstat_query_t *qsrc, *qdst = NULL; @@ -324,8 +325,6 @@ static void procstat_copy_data(void *dst, size_t size_dst, const void *src) hdst->size_allocated = PROCSTAT_ALIGNED_HEADER_SIZE; hdst->queries = PROCSTAT_NULL_OFFSET; - now = time(NULL); - if (NULL != src) { query_offset = &hdst->queries; @@ -333,10 +332,6 @@ static void procstat_copy_data(void *dst, size_t size_dst, const void *src) /* copy queries */ for (qsrc = PROCSTAT_QUERY_FIRST(src); NULL != qsrc; qsrc = PROCSTAT_QUERY_NEXT(src, qsrc)) { - /* don't copy queries not used during the last day */ - if (SEC_PER_DAY < now - qsrc->last_accessed) - continue; - /* the new shared memory segment must have enough space */ offset = procstat_alloc(dst, sizeof(zbx_procstat_query_t)); @@ -351,15 +346,7 @@ static void procstat_copy_data(void *dst, size_t size_dst, const void *src) *query_offset = offset; query_offset = &qdst->next; } - - /* copy process cpu utilization snapshot */ - hdst->pids_num = hsrc->pids_num; - size_snapshot = hsrc->pids_num * sizeof(zbx_procstat_util_t); - memcpy((char *)dst + hdst->size - size_snapshot, (char *)src + hsrc->size - size_snapshot, - size_snapshot); } - else - hdst->pids_num = 0; zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name); } @@ -461,17 +448,13 @@ static void procstat_add(const char *procname, const char *username, const char if (NULL != cmdline) size += ZBX_SIZE_T_ALIGN8(strlen(cmdline) + 1); - /* reserve space for process cpu utilization snapshot */ - size += sizeof(zbx_procstat_util_t) * 32; - /* procstat_add() is called when the shared memory reference has already been validated - */ /* no need to call procstat_reattach() */ - header = (zbx_procstat_header_t *)procstat_ref.addr; /* reserve space for a new query only if there are no freed queries */ size += ZBX_SIZE_T_ALIGN8(sizeof(zbx_procstat_query_t)); - if (NULL == header || FAIL == procstat_dshm_has_enough_space(header, size)) + if (NULL == procstat_ref.addr || FAIL == procstat_dshm_has_enough_space(procstat_ref.addr, size)) { if (FAIL == zbx_dshm_reserve(&collector->procstat, size, &errmsg)) { @@ -484,9 +467,10 @@ static void procstat_add(const char *procname, const char *username, const char /* header initialised in procstat_copy_data() which is called back from zbx_dshm_reserve() */ procstat_reattach(); - header = (zbx_procstat_header_t *)procstat_ref.addr; } + header = (zbx_procstat_header_t *)procstat_ref.addr; + query_offset = procstat_alloc(procstat_ref.addr, sizeof(zbx_procstat_query_t)); /* initialize the created query */ @@ -530,9 +514,8 @@ static void procstat_free_query_data(zbx_procstat_query_data_t *data) * runid - [IN] marker for queries to be processed in the * * current collector iteration * * * - * Return value: SUCCEED - unused queries removed, the rest of the queries * - * copied from shared memory segment to local vector * - * FAIL - no active quueries * + * Return value: The flags defining the process properties to be retrieved. * + * See ZBX_SYSINFO_PROC_ defines. * * * * Comments: updates queries (runid) in shared memory segment * * * @@ -543,7 +526,7 @@ static int procstat_build_local_query_vector(zbx_vector_ptr_t *queries_ptr, int time_t now; zbx_procstat_query_t *query; zbx_procstat_query_data_t *qdata; - int ret = FAIL; + int flags = ZBX_SYSINFO_PROC_NONE, *pnext_query; zbx_dshm_lock(&collector->procstat); @@ -554,27 +537,39 @@ static int procstat_build_local_query_vector(zbx_vector_ptr_t *queries_ptr, int if (PROCSTAT_NULL_OFFSET == header->queries) goto out; + flags = ZBX_SYSINFO_PROC_PID; + now = time(NULL); - zbx_vector_ptr_create(queries_ptr); + pnext_query = &header->queries; for (query = PROCSTAT_QUERY_FIRST(procstat_ref.addr); NULL != query; query = PROCSTAT_QUERY_NEXT(procstat_ref.addr, query)) { - /* skip unused queries */ + /* remove unused queries, the data is still allocated until the next resize */ if (SEC_PER_DAY < now - query->last_accessed) + { + *pnext_query = query->next; continue; + } qdata = (zbx_procstat_query_data_t *)zbx_malloc(NULL, sizeof(zbx_procstat_query_data_t)); zbx_vector_uint64_create(&qdata->pids); /* store the reference to query attributes, which is guaranteed to be */ /* valid until we call process_reattach() */ - qdata->procname = PROCSTAT_PTR_NULL(procstat_ref.addr, query->procname); - qdata->username = PROCSTAT_PTR_NULL(procstat_ref.addr, query->username); - qdata->cmdline = PROCSTAT_PTR_NULL(procstat_ref.addr, query->cmdline); + if (NULL != (qdata->procname = PROCSTAT_PTR_NULL(procstat_ref.addr, query->procname))) + flags |= ZBX_SYSINFO_PROC_NAME; + + if (NULL != (qdata->username = PROCSTAT_PTR_NULL(procstat_ref.addr, query->username))) + flags |= ZBX_SYSINFO_PROC_USER; + + if (NULL != (qdata->cmdline = PROCSTAT_PTR_NULL(procstat_ref.addr, query->cmdline))) + flags |= ZBX_SYSINFO_PROC_CMDLINE; + qdata->flags = query->flags; qdata->utime = 0; qdata->stime = 0; + qdata->error = 0; zbx_vector_ptr_append(queries_ptr, qdata); @@ -585,18 +580,19 @@ static int procstat_build_local_query_vector(zbx_vector_ptr_t *queries_ptr, int /* is incremented at the end of every data gathering cycle. We can be sure that */ /* our local copy will match the queries in shared memory having the same runid. */ query->runid = runid; - } - ret = SUCCEED; + pnext_query = &query->next; + } out: zbx_dshm_unlock(&collector->procstat); - return ret; + + return flags; } /****************************************************************************** * * - * Function: procstat_get_pids_matching_query_attributes * + * Function: procstat_scan_query_pids * * * * Purpose: for every query gets the pids of processes matching query * * attributes * @@ -606,21 +602,20 @@ out: * Return value: total number of pids saved in all queries * * * ******************************************************************************/ -static int procstat_get_pids_matching_query_attributes(zbx_vector_ptr_t queries) +static int procstat_scan_query_pids(zbx_vector_ptr_t *queries, const zbx_vector_ptr_t *processes) { zbx_procstat_query_data_t *qdata; int i; int pids_num = 0; - for (i = 0; i < queries.values_num; i++) + for (i = 0; i < queries->values_num; i++) { - qdata = (zbx_procstat_query_data_t *)queries.values[i]; + qdata = (zbx_procstat_query_data_t *)queries->values[i]; - qdata->error = zbx_proc_get_pids(qdata->procname, qdata->username, qdata->cmdline, qdata->flags, + zbx_proc_get_matching_pids(processes, qdata->procname, qdata->username, qdata->cmdline, qdata->flags, &qdata->pids); - if (SUCCEED == qdata->error) - pids_num += qdata->pids.values_num; + pids_num += qdata->pids.values_num; } return pids_num; @@ -628,39 +623,34 @@ static int procstat_get_pids_matching_query_attributes(zbx_vector_ptr_t queries) /****************************************************************************** * * - * Function: procstat_build_unique_pids * + * Function: procstat_get_monitored_pids * * * * Purpose: creates a list of unique pids that are monitored by current data * * gathering cycle * * * - * Parameters: pids_ptr - [OUT] the list of unique pids * - * queries - [IN] local, working copy of queries * - * pids_num - [IN] total number of pids saved in all queries * + * Parameters: pids - [OUT] a sorted vector of unique pids * + * queries - [IN] local, working copy of queries * * * ******************************************************************************/ -static void procstat_build_unique_pids(zbx_vector_uint64_t *pids_ptr, - zbx_vector_ptr_t queries, int pids_num) +static void procstat_get_monitored_pids(zbx_vector_uint64_t *pids, const zbx_vector_ptr_t *queries) { zbx_procstat_query_data_t *qdata; int i; - zbx_vector_uint64_create(pids_ptr); - zbx_vector_uint64_reserve(pids_ptr, pids_num); - - for (i = 0; i < queries.values_num; i++) + for (i = 0; i < queries->values_num; i++) { - qdata = (zbx_procstat_query_data_t *)queries.values[i]; + qdata = (zbx_procstat_query_data_t *)queries->values[i]; if (SUCCEED != qdata->error) continue; - memcpy(pids_ptr->values + pids_ptr->values_num, qdata->pids.values, + memcpy(pids->values + pids->values_num, qdata->pids.values, sizeof(zbx_uint64_t) * qdata->pids.values_num); - pids_ptr->values_num += qdata->pids.values_num; + pids->values_num += qdata->pids.values_num; } - zbx_vector_uint64_sort(pids_ptr, ZBX_DEFAULT_UINT64_COMPARE_FUNC); - zbx_vector_uint64_uniq(pids_ptr, ZBX_DEFAULT_UINT64_COMPARE_FUNC); + zbx_vector_uint64_sort(pids, ZBX_DEFAULT_UINT64_COMPARE_FUNC); + zbx_vector_uint64_uniq(pids, ZBX_DEFAULT_UINT64_COMPARE_FUNC); } /****************************************************************************** @@ -669,27 +659,24 @@ static void procstat_build_unique_pids(zbx_vector_uint64_t *pids_ptr, * * * Purpose: gets cpu utilization data snapshot for the monitored processes * * * - * Parameters: stats_ptr - [OUT] current reading of the per-pid cpu usage * + * Parameters: stats - [OUT] current reading of the per-pid cpu usage * * statistics (array, items correspond to pids) * - * pids - [IN] pids (unique) for which to collect data in * - * this iteration * + * pids - [IN] pids (unique) for which to collect data in this * + * iteration * * * * Return value: timestamp of the snapshot * * * ******************************************************************************/ -static zbx_timespec_t procstat_get_cpu_util_snapshot_for_pids(zbx_procstat_util_t **stats_ptr, - zbx_vector_uint64_t pids) +static zbx_timespec_t procstat_get_cpu_util_snapshot_for_pids(zbx_procstat_util_t *stats, + zbx_vector_uint64_t *pids) { zbx_timespec_t snapshot_timestamp; int i; - *stats_ptr = (zbx_procstat_util_t *)zbx_malloc(NULL, sizeof(zbx_procstat_util_t) * pids.values_num); - memset(*stats_ptr, 0, sizeof(zbx_procstat_util_t) * pids.values_num); - - for (i = 0; i < pids.values_num; i++) - (*stats_ptr)[i].pid = pids.values[i]; + for (i = 0; i < pids->values_num; i++) + stats[i].pid = pids->values[i]; - zbx_proc_get_stats(*stats_ptr, pids.values_num); + zbx_proc_get_process_stats(stats, pids->values_num); zbx_timespec(&snapshot_timestamp); @@ -711,19 +698,16 @@ static zbx_timespec_t procstat_get_cpu_util_snapshot_for_pids(zbx_procstat_util_ * statistics (array, items correspond to pids) * * * ******************************************************************************/ -static void procstat_calculate_cpu_util_for_queries(zbx_vector_ptr_t queries, - zbx_vector_uint64_t pids, const zbx_procstat_util_t *stats) +static void procstat_calculate_cpu_util_for_queries(zbx_vector_ptr_t *queries, + zbx_vector_uint64_t *pids, const zbx_procstat_util_t *stats) { zbx_procstat_query_data_t *qdata; zbx_procstat_util_t *putil; int j, i; - for (j = 0; j < queries.values_num; j++) + for (j = 0; j < queries->values_num; j++) { - qdata = (zbx_procstat_query_data_t *)queries.values[j]; - - if (SUCCEED != qdata->error) - continue; + qdata = (zbx_procstat_query_data_t *)queries->values[j]; /* sum the cpu utilization for processes that are present in current */ /* and last process cpu utilization snapshot */ @@ -732,14 +716,11 @@ static void procstat_calculate_cpu_util_for_queries(zbx_vector_ptr_t queries, zbx_uint64_t starttime, utime, stime; /* find the process utilization data in current snapshot */ - putil = (zbx_procstat_util_t *)bsearch(&qdata->pids.values[i], stats, pids.values_num, + putil = (zbx_procstat_util_t *)bsearch(&qdata->pids.values[i], stats, pids->values_num, sizeof(zbx_procstat_util_t), ZBX_DEFAULT_INT_COMPARE_FUNC); - if (SUCCEED == qdata->error && SUCCEED != putil->error) - { - qdata->error = putil->error; - break; - } + if (SUCCEED != putil->error) + continue; utime = putil->utime; stime = putil->stime; @@ -748,7 +729,7 @@ static void procstat_calculate_cpu_util_for_queries(zbx_vector_ptr_t queries, /* find the process utilization data in last snapshot */ putil = (zbx_procstat_util_t *)bsearch(&qdata->pids.values[i], - PROCSTAT_SNAPSHOT(procstat_ref.addr), pids.values_num, + procstat_snapshot, procstat_snapshot_num, sizeof(zbx_procstat_util_t), ZBX_DEFAULT_INT_COMPARE_FUNC); if (NULL == putil || putil->starttime != starttime) @@ -769,10 +750,6 @@ static void procstat_calculate_cpu_util_for_queries(zbx_vector_ptr_t queries, * * * Parameters: queries - [IN] local, working copy of queries (utime, stime * * and error must be set) * - * pids - [IN] pids (unique) for which data is collected in * - * this iteration * - * stats - [IN] current reading of the per-pid cpu usage * - * statistics (array, items correspond to pids) * * runid - [IN] marker for queries to be processed in the * * current collector iteration * * snapshot_timestamp - [IN] timestamp of the current snapshot * @@ -782,37 +759,17 @@ static void procstat_calculate_cpu_util_for_queries(zbx_vector_ptr_t queries, * memory segment * * * ******************************************************************************/ -static void procstat_save_cpu_util_snapshot_in_queries(zbx_vector_ptr_t queries, - zbx_vector_uint64_t pids, zbx_procstat_util_t *stats, - int runid, zbx_timespec_t snapshot_timestamp) +static void procstat_save_cpu_util_snapshot_in_queries(zbx_vector_ptr_t *queries, int runid, + zbx_timespec_t snapshot_timestamp) { - zbx_procstat_header_t *header; zbx_procstat_query_t *query; zbx_procstat_query_data_t *qdata; int index; int i; - char *errmsg = NULL; zbx_dshm_lock(&collector->procstat); procstat_reattach(); - header = (zbx_procstat_header_t *)procstat_ref.addr; - - if (header->size - header->size_allocated < pids.values_num * sizeof(zbx_procstat_util_t)) - { - if (FAIL == zbx_dshm_reserve(&collector->procstat, pids.values_num * sizeof(zbx_procstat_util_t) * 1.5, - &errmsg)) - { - zabbix_log(LOG_LEVEL_CRIT, "cannot reserve memory in process data collector: %s", errmsg); - zbx_free(errmsg); - zbx_dshm_unlock(&collector->procstat); - - exit(EXIT_FAILURE); - } - - procstat_reattach(); - header = (zbx_procstat_header_t *)procstat_ref.addr; - } for (query = PROCSTAT_QUERY_FIRST(procstat_ref.addr), i = 0; NULL != query; query = PROCSTAT_QUERY_NEXT(procstat_ref.addr, query)) @@ -820,13 +777,13 @@ static void procstat_save_cpu_util_snapshot_in_queries(zbx_vector_ptr_t queries, if (runid != query->runid) continue; - if (i >= queries.values_num) + if (i >= queries->values_num) { THIS_SHOULD_NEVER_HAPPEN; break; } - qdata = (zbx_procstat_query_data_t *)queries.values[i++]; + qdata = (zbx_procstat_query_data_t *)queries->values[i++]; if (SUCCEED != (query->error = qdata->error)) continue; @@ -859,11 +816,6 @@ static void procstat_save_cpu_util_snapshot_in_queries(zbx_vector_ptr_t queries, query->h_data[index].timestamp = snapshot_timestamp; } - header->pids_num = pids.values_num; - - /* check for free space done at the beginning of the function */ - memcpy(PROCSTAT_SNAPSHOT(procstat_ref.addr), stats, sizeof(zbx_procstat_util_t) * pids.values_num); - zbx_dshm_unlock(&collector->procstat); } @@ -1036,9 +988,15 @@ void zbx_procstat_collect() /* number of (non-unique) pids that match queries */ int pids_num = 0; + /* flags specifying what process properties must be retrieved */ + int flags; + /* local, working copy of queries */ zbx_vector_ptr_t queries; + /* data about all processes on system */ + zbx_vector_ptr_t processes; + /* pids (unique) for which to collect data in this iteration */ zbx_vector_uint64_t pids; @@ -1051,21 +1009,38 @@ void zbx_procstat_collect() if (FAIL == zbx_procstat_collector_started() || FAIL == procstat_running()) goto out; - if (FAIL == procstat_build_local_query_vector(&queries, runid)) - goto out; + zbx_vector_ptr_create(&queries); + zbx_vector_ptr_create(&processes); + zbx_vector_uint64_create(&pids); + + if (ZBX_SYSINFO_PROC_NONE == (flags = procstat_build_local_query_vector(&queries, runid))) + goto clean; - pids_num = procstat_get_pids_matching_query_attributes(queries); + if (SUCCEED != zbx_proc_get_processes(&processes, flags)) + goto clean; - procstat_build_unique_pids(&pids, queries, pids_num); + pids_num = procstat_scan_query_pids(&queries, &processes); - snapshot_timestamp = procstat_get_cpu_util_snapshot_for_pids(&stats, pids); + zbx_vector_uint64_reserve(&pids, pids_num); + procstat_get_monitored_pids(&pids, &queries); - procstat_calculate_cpu_util_for_queries(queries, pids, stats); + stats = (zbx_procstat_util_t *)zbx_malloc(NULL, sizeof(zbx_procstat_util_t) * pids.values_num); + snapshot_timestamp = procstat_get_cpu_util_snapshot_for_pids(stats, &pids); - procstat_save_cpu_util_snapshot_in_queries(queries, pids, stats, runid, snapshot_timestamp); + procstat_calculate_cpu_util_for_queries(&queries, &pids, stats); - zbx_free(stats); + procstat_save_cpu_util_snapshot_in_queries(&queries, runid, snapshot_timestamp); + + /* replace the current snapshot with the new stats */ + zbx_free(procstat_snapshot); + procstat_snapshot = stats; + procstat_snapshot_num = pids.values_num; +clean: zbx_vector_uint64_destroy(&pids); + + zbx_proc_free_processes(&processes); + zbx_vector_ptr_destroy(&processes); + zbx_vector_ptr_clear_ext(&queries, (zbx_mem_free_func_t)procstat_free_query_data); zbx_vector_ptr_destroy(&queries); |