static int dns_query(const char *cmd, const char *param, unsigned flags, AGENT_RESULT *result, int short_answer) { #if defined(HAVE_RES_QUERY) || defined(_WINDOWS) size_t offset = 0; int res, type, retrans, retry, i, ret = SYSINFO_RET_FAIL; char ip[MAX_STRING_LEN], zone[MAX_STRING_LEN], tmp[MAX_STRING_LEN], buffer[MAX_STRING_LEN]; struct in_addr inaddr; #ifndef _WINDOWS int saved_nscount, saved_retrans, saved_retry; struct sockaddr_in saved_ns; #endif typedef struct { char *name; int type; } resolv_querytype_t; static const resolv_querytype_t qt[] = { {"ANY", T_ANY}, {"A", T_A}, {"NS", T_NS}, {"MD", T_MD}, {"MF", T_MF}, {"CNAME", T_CNAME}, {"SOA", T_SOA}, {"MB", T_MB}, {"MG", T_MG}, {"MR", T_MR}, {"NULL", T_NULL}, #ifndef _WINDOWS {"WKS", T_WKS}, #endif {"PTR", T_PTR}, {"HINFO", T_HINFO}, {"MINFO", T_MINFO}, {"MX", T_MX}, {"TXT", T_TXT}, {"SRV", T_SRV}, {NULL} }; #ifdef _WINDOWS PDNS_RECORD pQueryResults, pDnsRecord; LPTSTR wzone; char tmp2[MAX_STRING_LEN]; #else char *name; unsigned char *msg_end, *msg_ptr, *p; int num_answers, num_query, q_type, q_class, q_len, value, c, n; struct servent *s; HEADER *hp; struct protoent *pr; #if PACKETSZ > 1024 unsigned char buf[PACKETSZ]; #else unsigned char buf[1024]; #endif typedef union { HEADER h; #if defined(NS_PACKETSZ) unsigned char buffer[NS_PACKETSZ]; #elif defined(PACKETSZ) unsigned char buffer[PACKETSZ]; #else unsigned char buffer[512]; #endif } answer_t; answer_t answer; #endif /* _WINDOWS */ *buffer = '\0'; if (5 < num_param(param)) return SYSINFO_RET_FAIL; if (0 != get_param(param, 1, ip, sizeof(ip))) *ip = '\0'; if (0 != get_param(param, 2, zone, sizeof(zone)) || '\0' == *zone) strscpy(zone, "zabbix.com"); if (0 != get_param(param, 3, tmp, sizeof(tmp)) || '\0' == *tmp) type = T_SOA; else { for (i = 0; NULL != qt[i].name; i++) { #ifdef _WINDOWS if (0 == lstrcmpiA(qt[i].name, tmp)) #else if (0 == strcasecmp(qt[i].name, tmp)) #endif { type = qt[i].type; break; } } if (NULL == qt[i].name) return SYSINFO_RET_FAIL; } if (0 != get_param(param, 4, tmp, sizeof(tmp)) || '\0' == *tmp) retrans = 1; else retrans = atoi(tmp); if (0 != get_param(param, 5, tmp, sizeof(tmp)) || '\0' == *tmp) retry = 2; else retry = atoi(tmp); #ifdef _WINDOWS wzone = zbx_utf8_to_unicode(zone); res = DnsQuery(wzone, type, DNS_QUERY_STANDARD, NULL, &pQueryResults, NULL); zbx_free(wzone); if (1 == short_answer) { SET_UI64_RESULT(result, DNS_RCODE_NOERROR != res ? 0 : 1); ret = SYSINFO_RET_OK; goto clean; } if (DNS_RCODE_NOERROR != res) return SYSINFO_RET_FAIL; pDnsRecord = pQueryResults; while (NULL != pDnsRecord) { if (DnsSectionAnswer != pDnsRecord->Flags.S.Section) { pDnsRecord = pDnsRecord->pNext; continue; } if (NULL == pDnsRecord->pName) goto clean; offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, "%-20s", zbx_unicode_to_utf8_static(pDnsRecord->pName, tmp, sizeof(tmp))); offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %-8s", decode_type(pDnsRecord->wType)); switch (pDnsRecord->wType) { case T_A: inaddr.s_addr = pDnsRecord->Data.A.IpAddress; offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", inet_ntoa(inaddr)); break; case T_NS: offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", zbx_unicode_to_utf8_static(pDnsRecord->Data.NS.pNameHost, tmp, sizeof(tmp))); break; case T_MD: offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", zbx_unicode_to_utf8_static(pDnsRecord->Data.MD.pNameHost, tmp, sizeof(tmp))); break; case T_MF: offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", zbx_unicode_to_utf8_static(pDnsRecord->Data.MF.pNameHost, tmp, sizeof(tmp))); break; case T_CNAME: offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", zbx_unicode_to_utf8_static(pDnsRecord->Data.CNAME.pNameHost, tmp, sizeof(tmp))); break; case T_SOA: offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s %s %lu %lu %lu %lu %lu", zbx_unicode_to_utf8_static(pDnsRecord->Data.SOA.pNamePrimaryServer, tmp, sizeof(tmp)), zbx_unicode_to_utf8_static(pDnsRecord->Data.SOA.pNameAdministrator, tmp2, sizeof(tmp2)), pDnsRecord->Data.SOA.dwSerialNo, pDnsRecord->Data.SOA.dwRefresh, pDnsRecord->Data.SOA.dwRetry, pDnsRecord->Data.SOA.dwExpire, pDnsRecord->Data.SOA.dwDefaultTtl); break; case T_MB: offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", zbx_unicode_to_utf8_static(pDnsRecord->Data.MB.pNameHost, tmp, sizeof(tmp))); break; case T_MG: offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", zbx_unicode_to_utf8_static(pDnsRecord->Data.MG.pNameHost, tmp, sizeof(tmp))); break; case T_MR: offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", zbx_unicode_to_utf8_static(pDnsRecord->Data.MR.pNameHost, tmp, sizeof(tmp))); break; case T_NULL: offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " len:%lu", pDnsRecord->Data.Null.dwByteCount); break; case T_PTR: offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", zbx_unicode_to_utf8_static(pDnsRecord->Data.PTR.pNameHost, tmp, sizeof(tmp))); break; case T_HINFO: for (i = 0; i < (int)(pDnsRecord->Data.HINFO.dwStringCount); i++) offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " \"%s\"", zbx_unicode_to_utf8_static(pDnsRecord->Data.HINFO.pStringArray[i], tmp, sizeof(tmp))); break; case T_MINFO: offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s %s", zbx_unicode_to_utf8_static(pDnsRecord->Data.MINFO.pNameMailbox, tmp, sizeof(tmp)), zbx_unicode_to_utf8_static(pDnsRecord->Data.MINFO.pNameErrorsMailbox, tmp2, sizeof(tmp2))); break; case T_MX: offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %hu %s", pDnsRecord->Data.MX.wPreference, zbx_unicode_to_utf8_static(pDnsRecord->Data.MX.pNameExchange, tmp, sizeof(tmp))); break; case T_TXT: offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " \""); for (i = 0; i < (int)(pDnsRecord->Data.TXT.dwStringCount); i++) offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, "%s ", zbx_unicode_to_utf8_static(pDnsRecord->Data.TXT.pStringArray[i], tmp, sizeof(tmp))); if (0 < i) offset -= 1; /* remove the trailing space */ offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, "\""); break; case T_SRV: offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %hu %hu %hu %s", pDnsRecord->Data.SRV.wPriority, pDnsRecord->Data.SRV.wWeight, pDnsRecord->Data.SRV.wPort, zbx_unicode_to_utf8_static(pDnsRecord->Data.SRV.pNameTarget, tmp, sizeof(tmp))); break; default: break; } offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, "\n"); pDnsRecord = pDnsRecord->pNext; } #else /* not _WINDOWS */ if (-1 == res_init()) /* initialize always, settings might have changed */ return SYSINFO_RET_FAIL; if (-1 == (res = res_mkquery(QUERY, zone, C_IN, type, NULL, 0, NULL, buf, sizeof(buf)))) return SYSINFO_RET_FAIL; if ('\0' != *ip) { if (0 == inet_aton(ip, &inaddr)) return SYSINFO_RET_FAIL; memcpy(&saved_ns, &(_res.nsaddr_list[0]), sizeof(struct sockaddr_in)); saved_nscount = _res.nscount; _res.nsaddr_list[0].sin_addr = inaddr; _res.nsaddr_list[0].sin_family = AF_INET; _res.nsaddr_list[0].sin_port = htons(ZBX_DEFAULT_DNS_PORT); _res.nscount = 1; } saved_retrans = _res.retrans; saved_retry = _res.retry; _res.retrans = retrans; _res.retry = retry; res = res_send(buf, res, answer.buffer, sizeof(answer.buffer)); _res.retrans = saved_retrans; _res.retry = saved_retry; if ('\0' != *ip) { memcpy(&(_res.nsaddr_list[0]), &saved_ns, sizeof(struct sockaddr_in)); _res.nscount = saved_nscount; } hp = (HEADER *)answer.buffer; if (1 == short_answer) { SET_UI64_RESULT(result, NOERROR != hp->rcode || 0 == ntohs(hp->ancount) || -1 == res ? 0 : 1); return SYSINFO_RET_OK; } if (NOERROR != hp->rcode || 0 == ntohs(hp->ancount) || -1 == res) return SYSINFO_RET_FAIL; msg_end = answer.buffer + res; num_answers = ntohs(answer.h.ancount); num_query = ntohs(answer.h.qdcount); msg_ptr = answer.buffer + HFIXEDSZ; /* skipping query records */ for (; 0 < num_query && msg_ptr < msg_end; num_query--) msg_ptr += dn_skipname(msg_ptr, msg_end) + QFIXEDSZ; for (; 0 < num_answers && msg_ptr < msg_end; num_answers--) { if (NULL == (name = get_name(answer.buffer, msg_end, &msg_ptr))) return SYSINFO_RET_FAIL; offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, "%-20s", name); GETSHORT(q_type, msg_ptr); GETSHORT(q_class, msg_ptr); msg_ptr += INT32SZ; /* skipping TTL */ GETSHORT(q_len, msg_ptr); offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %-8s", decode_type(q_type)); switch (q_type) { case T_A: switch (q_class) { case C_IN: case C_HS: memcpy(&inaddr, msg_ptr, INADDRSZ); offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", inet_ntoa(inaddr)); break; default: ; } msg_ptr += q_len; break; case T_NS: case T_CNAME: case T_MB: case T_MD: case T_MF: case T_MG: case T_MR: case T_PTR: if (NULL == (name = get_name(answer.buffer, msg_end, &msg_ptr))) return SYSINFO_RET_FAIL; offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", name); break; case T_MX: GETSHORT(value, msg_ptr); /* preference */ offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %d", value); if (NULL == (name = get_name(answer.buffer, msg_end, &msg_ptr))) /* exchange */ return SYSINFO_RET_FAIL; offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", name); break; case T_SOA: if (NULL == (name = get_name(answer.buffer, msg_end, &msg_ptr))) /* source host */ return SYSINFO_RET_FAIL; offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", name); if (NULL == (name = get_name(answer.buffer, msg_end, &msg_ptr))) /* administrator */ return SYSINFO_RET_FAIL; offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", name); GETLONG(value, msg_ptr); /* serial number */ offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %d", value); GETLONG(value, msg_ptr); /* refresh time */ offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %d", value); GETLONG(value, msg_ptr); /* retry time */ offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %d", value); GETLONG(value, msg_ptr); /* expire time */ offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %d", value); GETLONG(value, msg_ptr); /* minimum TTL */ offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %d", value); break; case T_NULL: offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " len:%d", q_len); msg_ptr += q_len; break; case T_WKS: if (INT32SZ + 1 > q_len) return SYSINFO_RET_FAIL; p = msg_ptr + q_len; memcpy(&inaddr, msg_ptr, INADDRSZ); msg_ptr += INT32SZ; offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", inet_ntoa(inaddr)); if (NULL != (pr = getprotobynumber(*msg_ptr))) offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", pr->p_name); else offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %d", (int)*msg_ptr); msg_ptr++; n = 0; while (msg_ptr < p) { c = *msg_ptr++; do { if (0 != (c & 0200)) { s = getservbyport((int)htons(n), pr ? pr->p_name : NULL); if (NULL != s) offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", s->s_name); else offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " #%d", n); } c <<= 1; } while (0 != (++n & 07)); } break; case T_HINFO: p = msg_ptr + q_len; c = *msg_ptr++; if (0 != c) { offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " \"%.*s\"", c, msg_ptr); msg_ptr += c; } if (msg_ptr < p) { c = *msg_ptr++; if (0 != c) { offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " \"%.*s\"", c, msg_ptr); msg_ptr += c; } } break; case T_MINFO: if (NULL == (name = get_name(answer.buffer, msg_end, &msg_ptr))) /* mailbox responsible for mailing lists */ return SYSINFO_RET_FAIL; offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", name); if (NULL == (name = get_name(answer.buffer, msg_end, &msg_ptr))) /* mailbox for error messages */ return SYSINFO_RET_FAIL; offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", name); break; case T_TXT: offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " \""); p = msg_ptr + q_len; while (msg_ptr < p) { for (c = *msg_ptr++; 0 < c && msg_ptr < p; c--) offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, "%c", *msg_ptr++); } offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, "\""); break; case T_SRV: GETSHORT(value, msg_ptr); /* priority */ offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %d", value); GETSHORT(value, msg_ptr); /* weight */ offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %d", value); GETSHORT(value, msg_ptr); /* port */ offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %d", value); if (NULL == (name = get_name(answer.buffer, msg_end, &msg_ptr))) /* target */ return SYSINFO_RET_FAIL; offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, " %s", name); break; default: msg_ptr += q_len; break; } offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, "\n"); } #endif /* _WINDOWS */ if (0 != offset) buffer[--offset] = '\0'; SET_TEXT_RESULT(result, zbx_strdup(NULL, buffer)); ret = SYSINFO_RET_OK; #ifdef _WINDOWS clean: if (DNS_RCODE_NOERROR == res) DnsRecordListFree(pQueryResults, DnsFreeRecordList); #endif return ret; #else /* both HAVE_RES_QUERY and _WINDOWS not defined */ return SYSINFO_RET_FAIL; #endif /* defined(HAVE_RES_QUERY) || defined(_WINDOWS) */ }
/****************************************************************************** * * * Function: zbx_waitpid * * * * Purpose: this function waits for process to change state * * * * Parameters: pid - [IN] child process PID * * * * Return value: on success, PID is returned. On error, * * -1 is returned, and errno is set appropriately * * * * Author: Alexander Vladishev * * * * Comments: * * * ******************************************************************************/ static int zbx_waitpid(pid_t pid) { const char *__function_name = "zbx_waitpid"; int rc, status; zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name); do { #ifdef WCONTINUED static int wcontinued = WCONTINUED; retry: if (-1 == (rc = waitpid(pid, &status, WUNTRACED | wcontinued))) { if (EINVAL == errno && 0 != wcontinued) { wcontinued = 0; goto retry; } #else if (-1 == (rc = waitpid(pid, &status, WUNTRACED))) { #endif zabbix_log(LOG_LEVEL_DEBUG, "%s() waitpid failure: %s", __function_name, strerror(errno)); goto exit; } if (WIFEXITED(status)) zabbix_log(LOG_LEVEL_DEBUG, "%s() exited, status:%d", __function_name, WEXITSTATUS(status)); else if (WIFSIGNALED(status)) zabbix_log(LOG_LEVEL_DEBUG, "%s() killed by signal %d", __function_name, WTERMSIG(status)); else if (WIFSTOPPED(status)) zabbix_log(LOG_LEVEL_DEBUG, "%s() stopped by signal %d", __function_name, WSTOPSIG(status)); #ifdef WIFCONTINUED else if (WIFCONTINUED(status)) zabbix_log(LOG_LEVEL_DEBUG, "%s() continued", __function_name); #endif } while (!WIFEXITED(status) && !WIFSIGNALED(status)); exit: zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%d", __function_name, rc); return rc; } #endif /* _WINDOWS */ /****************************************************************************** * * * Function: zbx_execute * * * * Purpose: this function executes a script and returns result from stdout * * * * Parameters: command - [IN] command for execution * * buffer - [OUT] buffer for output, if NULL - ignored * * error - [OUT] error string if function fails * * max_error_len - [IN] length of error buffer * * * * Return value: SUCCEED if processed successfully, FAIL - otherwise * * * * Author: Alexander Vladishev * * * * Comments: * * * ******************************************************************************/ int zbx_execute(const char *command, char **buffer, char *error, size_t max_error_len, int timeout) { #ifdef _WINDOWS STARTUPINFO si = {0}; PROCESS_INFORMATION pi = {0}; SECURITY_ATTRIBUTES sa; HANDLE hWrite = NULL, hRead = NULL; char *cmd = NULL; LPTSTR wcmd = NULL; struct _timeb start_time, current_time; #else /* not _WINDOWS */ pid_t pid; int fd; #endif /* _WINDOWS */ char *p = NULL; size_t buf_size = MAX_BUFFER_LEN; int ret = SUCCEED; assert(timeout); if (NULL != buffer) { *buffer = p = zbx_realloc(*buffer, buf_size); buf_size--; /* '\0' */ } #ifdef _WINDOWS /* set the bInheritHandle flag so pipe handles are inherited */ sa.nLength = sizeof(SECURITY_ATTRIBUTES); sa.bInheritHandle = TRUE; sa.lpSecurityDescriptor = NULL; /* create a pipe for the child process's STDOUT */ if (0 == CreatePipe(&hRead, &hWrite, &sa, 0)) { zbx_snprintf(error, max_error_len, "Unable to create pipe [%s]", strerror_from_system(GetLastError())); ret = FAIL; goto lbl_exit; } /* fill in process startup info structure */ memset(&si, 0, sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO); si.dwFlags = STARTF_USESTDHANDLES; si.hStdInput = GetStdHandle(STD_INPUT_HANDLE); si.hStdOutput = hWrite; si.hStdError = hWrite; cmd = zbx_dsprintf(cmd, "cmd /C \"%s\"", command); wcmd = zbx_utf8_to_unicode(cmd); /* create new process */ if (0 == CreateProcess(NULL, wcmd, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) { zbx_snprintf(error, max_error_len, "Unable to create process: '%s' [%s]", cmd, strerror_from_system(GetLastError())); ret = FAIL; goto lbl_exit; } CloseHandle(hWrite); hWrite = NULL; _ftime(&start_time); timeout *= 1000; if (NULL != buffer) { if (SUCCEED == (ret = zbx_read_from_pipe(hRead, &p, buf_size, timeout))) *p = '\0'; } if (TIMEOUT_ERROR != ret) { _ftime(¤t_time); if (0 < (timeout -= zbx_get_timediff_ms(&start_time, ¤t_time))) { if (WAIT_TIMEOUT == WaitForSingleObject(pi.hProcess, timeout)) ret = TIMEOUT_ERROR; } } /* wait for child process to exit */ if (TIMEOUT_ERROR == ret) { zbx_strlcpy(error, "Timeout while executing a shell script", max_error_len); ret = FAIL; } /* terminate child process */ TerminateProcess(pi.hProcess, 0); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); CloseHandle(hRead); hRead = NULL; lbl_exit: if (NULL != hWrite) { CloseHandle(hWrite); hWrite = NULL; } if (NULL != hRead) { CloseHandle(hRead); hRead = NULL; } zbx_free(cmd); zbx_free(wcmd); #else /* not _WINDOWS */ alarm(timeout); if (-1 != (fd = zbx_popen(&pid, command))) { int rc = 0; if (NULL != buffer) { while (0 < (rc = read(fd, p, buf_size))) { p += rc; if (0 == (buf_size -= rc)) break; } *p = '\0'; } close(fd); if (-1 == rc) { if (EINTR == errno) zbx_strlcpy(error, "Timeout while executing a shell script", max_error_len); else zbx_strlcpy(error, strerror(errno), max_error_len); kill(pid, SIGTERM); zbx_waitpid(pid); ret = FAIL; } else { if (-1 == zbx_waitpid(pid)) { if (EINTR == errno) zbx_strlcpy(error, "Timeout while executing a shell script", max_error_len); else zbx_strlcpy(error, strerror(errno), max_error_len); kill(pid, SIGTERM); zbx_waitpid(pid); ret = FAIL; } } } else { zbx_strlcpy(error, strerror(errno), max_error_len); ret = FAIL; } alarm(0); #endif /* _WINDOWS */ if (FAIL == ret && NULL != buffer) zbx_free(*buffer); return ret; }
/****************************************************************************** * * * Function: calculate_checksums * * * * Purpose: calculate checksums of configuration data * * * * Parameters: * * * * Return value: SUCCESS - calculated successfully * * FAIL - an error occurred * * * * Author: Alexei Vladishev * * * * Comments: * * * ******************************************************************************/ int calculate_checksums(int nodeid, const char *tablename, const zbx_uint64_t recordid) { const char *__function_name = "calculate_checksums"; char *sql = NULL; size_t sql_alloc = 2 * ZBX_KIBIBYTE, sql_offset = 0; int t, f, res = SUCCEED; zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name); sql = zbx_malloc(sql, sql_alloc); zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "delete from node_cksum" " where nodeid=%d" " and cksumtype=%d", nodeid, NODE_CKSUM_TYPE_NEW); if (NULL != tablename) zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, " and tablename='%s'", tablename); if (0 != recordid) zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, " and recordid=" ZBX_FS_UI64, recordid); if (ZBX_DB_OK > DBexecute("%s", sql)) res = FAIL; for (t = 0; NULL != tables[t].table; t++) { if (0 == (tables[t].flags & ZBX_SYNC)) continue; if (NULL != tablename && 0 != strcmp(tablename, tables[t].table)) continue; sql_offset = 0; zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "insert into node_cksum (nodeid,tablename,recordid,cksumtype,cksum)" " select %d,'%s',%s,%d,", nodeid, tables[t].table, tables[t].recid, NODE_CKSUM_TYPE_NEW); #ifdef HAVE_MYSQL zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "concat_ws(',',"); #endif for (f = 0; NULL != tables[t].fields[f].name; f++) { const ZBX_FIELD *field = &tables[t].fields[f]; if (0 == (field->flags & ZBX_SYNC)) continue; if (field->flags & ZBX_NOTNULL) { switch (field->type) { case ZBX_TYPE_ID: case ZBX_TYPE_INT: case ZBX_TYPE_UINT: zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, field->name); break; case ZBX_TYPE_FLOAT: zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "md5(cast(%s as char))", field->name); break; default: zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "md5(%s)", field->name); break; } } else { zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "case when %s is null then 'NULL'", field->name); switch (field->type) { case ZBX_TYPE_ID: case ZBX_TYPE_INT: case ZBX_TYPE_UINT: zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, " else cast(%s as char) end", field->name); break; case ZBX_TYPE_FLOAT: zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, " else md5(cast(%s as char)) end", field->name); break; default: zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, " else md5(%s) end", field->name); break; } } #ifdef HAVE_MYSQL zbx_chrcpy_alloc(&sql, &sql_alloc, &sql_offset, ','); #else zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "||','||"); #endif } /* remove last delimiter */ if (f > 0) { #ifdef HAVE_MYSQL sql_offset--; zbx_chrcpy_alloc(&sql, &sql_alloc, &sql_offset, ')'); #else sql_offset -= 7; #endif } zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, " from %s", tables[t].table); if (0 != recordid) { zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, " where %s=" ZBX_FS_UI64, tables[t].recid, recordid); } else { zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, " where 1=1" DB_NODE, DBnode(tables[t].recid, nodeid)); } if (ZBX_DB_OK > DBexecute("%s", sql)) { res = FAIL; break; } } zbx_free(sql); zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(res)); return res; }
static int get_dmi_info(char *buf, int bufsize, int flags) { int ret = SYSINFO_RET_FAIL, fd, offset = 0; unsigned char membuf[SMBIOS_ENTRY_POINT_SIZE], *smbuf = NULL, *data; size_t len, fp; void *mmp = NULL; static long pagesize = 0; static int smbios_status = SMBIOS_STATUS_UNKNOWN; static size_t smbios_len, smbios; /* length and address of SMBIOS table (if found) */ if (-1 == (fd = open(DEV_MEM, O_RDONLY))) return ret; if (SMBIOS_STATUS_UNKNOWN == smbios_status) /* look for SMBIOS table only once */ { pagesize = sysconf(_SC_PAGESIZE); /* find smbios entry point - located between 0xF0000 and 0xFFFFF (according to the specs) */ for (fp = 0xf0000; 0xfffff > fp; fp += 16) { memset(membuf, 0, sizeof(membuf)); len = fp % pagesize; /* mmp needs to be a multiple of pagesize for munmap */ if (MAP_FAILED == (mmp = mmap(0, len + SMBIOS_ENTRY_POINT_SIZE, PROT_READ, MAP_SHARED, fd, fp - len))) goto close; memcpy(membuf, mmp + len, sizeof(membuf)); munmap(mmp, len + SMBIOS_ENTRY_POINT_SIZE); if (0 == strncmp((char *)membuf, "_DMI_", 5)) /* entry point found */ { smbios_len = membuf[7] << 8 | membuf[6]; smbios = (size_t)membuf[11] << 24 | (size_t)membuf[10] << 16 | (size_t)membuf[9] << 8 | membuf[8]; smbios_status = SMBIOS_STATUS_OK; break; } } } if (SMBIOS_STATUS_OK != smbios_status) { smbios_status = SMBIOS_STATUS_ERROR; goto close; } smbuf = zbx_malloc(smbuf, smbios_len); len = smbios % pagesize; /* mmp needs to be a multiple of pagesize for munmap */ if (MAP_FAILED == (mmp = mmap(0, len + smbios_len, PROT_READ, MAP_SHARED, fd, smbios - len))) goto clean; memcpy(smbuf, mmp + len, smbios_len); munmap(mmp, len + smbios_len); data = smbuf; while (data + DMI_HEADER_SIZE <= smbuf + smbios_len) { if (1 == data[0]) /* system information */ { if (0 != (flags & DMI_GET_VENDOR)) { offset += get_dmi_string(buf + offset, bufsize - offset, data, data[4]); flags &= ~DMI_GET_VENDOR; } if (0 != (flags & DMI_GET_MODEL)) { offset += get_dmi_string(buf + offset, bufsize - offset, data, data[5]); flags &= ~DMI_GET_MODEL; } if (0 != (flags & DMI_GET_SERIAL)) { offset += get_dmi_string(buf + offset, bufsize - offset, data, data[7]); flags &= ~DMI_GET_SERIAL; } } else if (3 == data[0] && 0 != (flags & DMI_GET_TYPE)) /* chassis */ { offset += get_chassis_type(buf + offset, bufsize - offset, data[5]); flags &= ~DMI_GET_TYPE; } if (0 == flags) break; data += data[1]; /* skip the main data */ while (0 != data[0] || 0 != data[1]) /* string data ends with two nulls */ { data++; } data += 2; } if (0 < offset) ret = SYSINFO_RET_OK; clean: zbx_free(smbuf); close: close(fd); return ret; }
int PROC_NUM(AGENT_REQUEST *request, AGENT_RESULT *result) { char *procname, *proccomm, *param; int zbx_proc_stat, count, i, proc_ok, stat_ok, comm_ok; int proccount = 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_strdup(NULL, "Specified user does not exist.")); else SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain user information: %s", zbx_strerror(errno))); return SYSINFO_RET_FAIL; } } 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); 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; stat_ok = (zbx_proc_stat == ZBX_PROC_STAT_ALL || (zbx_proc_stat == ZBX_PROC_STAT_RUN && (proc[i].ZBX_P_STAT == SRUN || proc[i].ZBX_P_STAT == SONPROC)) || (zbx_proc_stat == ZBX_PROC_STAT_SLEEP && proc[i].ZBX_P_STAT == SSLEEP) || (zbx_proc_stat == ZBX_PROC_STAT_ZOMB && (proc[i].ZBX_P_STAT == SZOMB || proc[i].ZBX_P_STAT == SDEAD))); 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); SET_UI64_RESULT(result, proccount); return SYSINFO_RET_OK; }
static void process_escalations(int now) { const char *__function_name = "process_escalations"; DB_RESULT result; DB_ROW row; DB_ESCALATION escalation, last_escalation; zbx_vector_uint64_t escalationids; char *sql = NULL; size_t sql_alloc = ZBX_KIBIBYTE, sql_offset; zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name); zbx_vector_uint64_create(&escalationids); sql = zbx_malloc(sql, sql_alloc); result = DBselect( "select escalationid,actionid,triggerid,eventid,r_eventid,esc_step,status,nextcheck" " from escalations" " where 1=1" DB_NODE " order by actionid,triggerid,escalationid", DBnode_local("escalationid")); memset(&escalation, 0, sizeof(escalation)); do { memset(&last_escalation, 0, sizeof(last_escalation)); if (NULL != (row = DBfetch(result))) { ZBX_STR2UINT64(last_escalation.escalationid, row[0]); ZBX_STR2UINT64(last_escalation.actionid, row[1]); ZBX_DBROW2UINT64(last_escalation.triggerid, row[2]); ZBX_DBROW2UINT64(last_escalation.eventid, row[3]); ZBX_DBROW2UINT64(last_escalation.r_eventid, row[4]); last_escalation.esc_step = atoi(row[5]); last_escalation.status = atoi(row[6]); last_escalation.nextcheck = atoi(row[7]); /* just delete on the next cycle */ if (0 != last_escalation.r_eventid) last_escalation.status = ESCALATION_STATUS_COMPLETED; } if (0 != escalation.escalationid) { unsigned char esc_superseded = 0; if (ESCALATION_STATUS_COMPLETED == escalation.status) { /* delete a recovery record and skip all processing */ zbx_vector_uint64_append(&escalationids, escalation.escalationid); goto next; } if (0 != last_escalation.escalationid) { esc_superseded = (escalation.actionid == last_escalation.actionid && escalation.triggerid == last_escalation.triggerid); if (1 == esc_superseded) { if (0 != last_escalation.r_eventid) { /* recover this escalation */ escalation.r_eventid = last_escalation.r_eventid; escalation.status = ESCALATION_STATUS_ACTIVE; } else if (escalation.nextcheck > now || ESCALATION_STATUS_SLEEP == escalation.status) { zbx_vector_uint64_append(&escalationids, escalation.escalationid); goto next; } } } if (ESCALATION_STATUS_ACTIVE != escalation.status || (escalation.nextcheck > now && 0 == escalation.r_eventid)) { goto next; } DBbegin(); if (escalation.nextcheck <= now) execute_escalation(&escalation); /* execute recovery */ if (ESCALATION_STATUS_COMPLETED != escalation.status && 0 != escalation.r_eventid) { escalation.status = ESCALATION_STATUS_RECOVERY; execute_escalation(&escalation); } else if (1 == esc_superseded) escalation.status = ESCALATION_STATUS_COMPLETED; sql_offset = 0; if (ESCALATION_STATUS_COMPLETED != escalation.status) { zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "update escalations set status=%d", escalation.status); if (ESCALATION_STATUS_ACTIVE == escalation.status) { zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, ",esc_step=%d,nextcheck=%d", escalation.esc_step, escalation.nextcheck); } zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, " where escalationid=" ZBX_FS_UI64, escalation.escalationid); } else { zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "delete from escalations where escalationid=" ZBX_FS_UI64, escalation.escalationid); } DBexecute("%s", sql); DBcommit(); } next: if (NULL != row) memcpy(&escalation, &last_escalation, sizeof(escalation)); } while (NULL != row); DBfree_result(result); zbx_free(sql); /* delete completed escalations */ if (0 != escalationids.values_num) { zbx_vector_uint64_sort(&escalationids, ZBX_DEFAULT_UINT64_COMPARE_FUNC); DBbegin(); DBexecute_multiple_query("delete from escalations where", "escalationid", &escalationids); DBcommit(); } zbx_vector_uint64_destroy(&escalationids); zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name); }
static void execute_operations(DB_ESCALATION *escalation, DB_EVENT *event, DB_ACTION *action) { const char *__function_name = "execute_operations"; DB_RESULT result; DB_ROW row; DB_OPERATION operation; int esc_period = 0, operations = 0; ZBX_USER_MSG *user_msg = NULL, *p; zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name); if (0 == action->esc_period) { result = DBselect( "select o.operationid,o.operationtype,o.esc_period,o.evaltype," "m.operationid,m.default_msg,subject,message,mediatypeid" " from operations o" " left join opmessage m" " on m.operationid=o.operationid" " where o.actionid=" ZBX_FS_UI64 " and o.operationtype in (%d,%d)", action->actionid, OPERATION_TYPE_MESSAGE, OPERATION_TYPE_COMMAND); } else { escalation->esc_step++; result = DBselect( "select o.operationid,o.operationtype,o.esc_period,o.evaltype," "m.operationid,m.default_msg,subject,message,mediatypeid" " from operations o" " left join opmessage m" " on m.operationid=o.operationid" " where o.actionid=" ZBX_FS_UI64 " and o.operationtype in (%d,%d)" " and o.esc_step_from<=%d" " and (o.esc_step_to=0 or o.esc_step_to>=%d)", action->actionid, OPERATION_TYPE_MESSAGE, OPERATION_TYPE_COMMAND, escalation->esc_step, escalation->esc_step); } while (NULL != (row = DBfetch(result))) { memset(&operation, 0, sizeof(operation)); ZBX_STR2UINT64(operation.operationid, row[0]); operation.actionid = action->actionid; operation.operationtype = atoi(row[1]); operation.esc_period = atoi(row[2]); operation.evaltype = (unsigned char)atoi(row[3]); if (SUCCEED == check_operation_conditions(event, operation.operationid, operation.evaltype)) { unsigned char default_msg; char *subject, *message; zbx_uint64_t mediatypeid; zabbix_log(LOG_LEVEL_DEBUG, "Conditions match our event. Execute operation."); if (0 == esc_period || esc_period > operation.esc_period) esc_period = operation.esc_period; switch (operation.operationtype) { case OPERATION_TYPE_MESSAGE: if (SUCCEED == DBis_null(row[4])) break; default_msg = (unsigned char)atoi(row[5]); ZBX_DBROW2UINT64(mediatypeid, row[8]); if (0 == default_msg) { subject = row[6]; message = row[7]; } else { subject = action->shortdata; message = action->longdata; } add_object_msg(operation.operationid, mediatypeid, &user_msg, subject, message, event->source, event->objectid); break; case OPERATION_TYPE_COMMAND: execute_commands(event, action->actionid, operation.operationid, escalation->esc_step); break; } } else zabbix_log(LOG_LEVEL_DEBUG, "Conditions do not match our event. Do not execute operation."); operations = 1; } DBfree_result(result); while (NULL != user_msg) { p = user_msg; user_msg = user_msg->next; add_message_alert(escalation, event, action, p->userid, p->mediatypeid, p->subject, p->message); zbx_free(p->subject); zbx_free(p->message); zbx_free(p); } if (0 == action->esc_period) { escalation->status = (action->recovery_msg == 1) ? ESCALATION_STATUS_SLEEP : ESCALATION_STATUS_COMPLETED; } else { if (0 == operations) { result = DBselect("select operationid from operations where actionid=" ZBX_FS_UI64 " and esc_step_from>%d", action->actionid, escalation->esc_step); if (NULL != (row = DBfetch(result)) && SUCCEED != DBis_null(row[0])) operations = 1; DBfree_result(result); } if (1 == operations) { esc_period = (0 != esc_period) ? esc_period : action->esc_period; escalation->nextcheck = time(NULL) + esc_period; } else escalation->status = (action->recovery_msg == 1) ? ESCALATION_STATUS_SLEEP : ESCALATION_STATUS_COMPLETED; } zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name); }
/****************************************************************************** * * * Function: update_checksums * * * * Purpose: overwrite old checksums with new ones * * * * Parameters: * * * * Return value: SUCCESS - calculated successfully * * FAIL - an error occurred * * * * Author: Alexei Vladishev * * * * Comments: * * * ******************************************************************************/ int update_checksums(int nodeid, int synked_nodetype, int synked, const char *tablename, const zbx_uint64_t id, char *fields) { const char *__function_name = "update_checksums"; char *r[2], *d[2], sync[129], *s; char c[2], sql[2][256]; char cksum[32*64+32], *ck; char *exsql = NULL; int exsql_alloc = 65536, exsql_offset = 0, cksumtype; DB_RESULT result; DB_ROW row; int f; const ZBX_TABLE *table; zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name); exsql = zbx_malloc(exsql, exsql_alloc); DBbegin(); #ifdef HAVE_ORACLE zbx_snprintf_alloc(&exsql, &exsql_alloc, &exsql_offset, 8, "begin\n"); #endif c[0] = synked == SUCCEED ? '1' : ' '; /* for new and updated records */ c[1] = synked == SUCCEED ? '2' : ' '; /* for deleted records */ if (NULL != tablename) { zbx_snprintf(sql[0], sizeof(sql[0]), " and curr.tablename='%s' and curr.recordid=" ZBX_FS_UI64, tablename, id); zbx_snprintf(sql[1], sizeof(sql[1]), " and prev.tablename='%s' and prev.recordid=" ZBX_FS_UI64, tablename, id); } else { *sql[0] = '\0'; *sql[1] = '\0'; } /* Find updated records */ result = DBselect("select curr.tablename,curr.recordid,prev.cksum,curr.cksum,prev.sync " "from node_cksum curr, node_cksum prev " "where curr.nodeid=%d and prev.nodeid=curr.nodeid and " "curr.tablename=prev.tablename and curr.recordid=prev.recordid and " "curr.cksumtype=%d and prev.cksumtype=%d%s " "union all " /* Find new records */ "select curr.tablename,curr.recordid,prev.cksum,curr.cksum,NULL " "from node_cksum curr left join node_cksum prev " "on prev.nodeid=curr.nodeid and prev.tablename=curr.tablename and " "prev.recordid=curr.recordid and prev.cksumtype=%d " "where curr.nodeid=%d and curr.cksumtype=%d and prev.tablename is null%s " "union all " /* Find deleted records */ "select prev.tablename,prev.recordid,prev.cksum,curr.cksum,prev.sync " "from node_cksum prev left join node_cksum curr " "on curr.nodeid=prev.nodeid and curr.tablename=prev.tablename and " "curr.recordid=prev.recordid and curr.cksumtype=%d " "where prev.nodeid=%d and prev.cksumtype=%d and curr.tablename is null%s", nodeid, NODE_CKSUM_TYPE_NEW, NODE_CKSUM_TYPE_OLD, sql[0], NODE_CKSUM_TYPE_OLD, nodeid, NODE_CKSUM_TYPE_NEW, sql[0], NODE_CKSUM_TYPE_NEW, nodeid, NODE_CKSUM_TYPE_OLD, sql[1]); while (NULL != (row = DBfetch(result))) { /* Found table */ if (NULL == (table = DBget_table(row[0]))) { zabbix_log(LOG_LEVEL_WARNING, "Cannot find table [%s]", row[0]); continue; } if (FAIL == DBis_null(row[4])) zbx_strlcpy(sync, row[4], sizeof(sync)); else memset(sync, ' ', sizeof(sync)); s = sync; ck = cksum; *ck = '\0'; /* Special (simpler) processing for operation DELETE */ if (SUCCEED == DBis_null(row[3])) { if (synked == SUCCEED) { if (synked_nodetype == ZBX_NODE_SLAVE) s[0] = c[1]; else if (synked_nodetype == ZBX_NODE_MASTER) s[1] = c[1]; } if ((0 == CONFIG_MASTER_NODEID || s[1] == c[1]) && (CONFIG_NODEID == nodeid || s[0] == c[1])) { zbx_snprintf_alloc(&exsql, &exsql_alloc, &exsql_offset, 256, "delete from node_cksum" " where nodeid=%d" " and cksumtype=%d" " and tablename='%s'" " and recordid=%s;\n", nodeid, NODE_CKSUM_TYPE_OLD, row[0], row[1]); DBexecute_overflowed_sql(&exsql, &exsql_alloc, &exsql_offset); continue; } s += 2; } else { r[0] = DBis_null(row[2]) == SUCCEED ? NULL : row[2]; r[1] = row[3]; f = 0; do { while ((table->fields[f].flags & ZBX_SYNC) == 0) f++; d[0] = NULL; d[1] = NULL; if (NULL != r[0] && NULL != (d[0] = strchr(r[0], ','))) *d[0] = '\0'; if (NULL != r[1] && NULL != (d[1] = strchr(r[1], ','))) *d[1] = '\0'; if (NULL == tablename || SUCCEED == str_in_list(fields, table->fields[f].name, ',')) { ck += zbx_snprintf(ck, 64, "%s,", NULL != r[1] ? r[1] : r[0]); if (r[0] == NULL || r[1] == NULL || strcmp(r[0], r[1]) != 0) { if (synked_nodetype == ZBX_NODE_SLAVE) { s[0] = c[0]; s[1] = ' '; } else if (synked_nodetype == ZBX_NODE_MASTER) { s[0] = ' '; s[1] = c[0]; } } else { if (synked == SUCCEED) { if (synked_nodetype == ZBX_NODE_SLAVE) s[0] = c[0]; else if (synked_nodetype == ZBX_NODE_MASTER) s[1] = c[0]; } } } else ck += zbx_snprintf(ck, 64, "%s,", NULL != r[0] ? r[0] : ""); s += 2; f++; if (d[0] != NULL) { *d[0] = ','; r[0] = d[0] + 1; } else r[0] = NULL; if (d[1] != NULL) { *d[1] = ','; r[1] = d[1] + 1; } else r[1] = NULL; } while (d[0] != NULL || d[1] != NULL); *--ck = '\0'; } *s = '\0'; if (SUCCEED == DBis_null(row[2]) || SUCCEED == DBis_null(row[3]) || 0 != strcmp(row[4], sync) || 0 != strcmp(row[2], row[3])) { cksumtype = (DBis_null(row[2]) == SUCCEED) ? NODE_CKSUM_TYPE_NEW : NODE_CKSUM_TYPE_OLD; zbx_snprintf_alloc(&exsql, &exsql_alloc, &exsql_offset, 2560, "update node_cksum" " set cksumtype=%d," "cksum='%s'," "sync='%s'" " where nodeid=%d" " and cksumtype=%d" " and tablename='%s'" " and recordid=%s;\n", NODE_CKSUM_TYPE_OLD, cksum, sync, nodeid, cksumtype, row[0], row[1]); DBexecute_overflowed_sql(&exsql, &exsql_alloc, &exsql_offset); } } DBfree_result(result); #ifdef HAVE_ORACLE zbx_snprintf_alloc(&exsql, &exsql_alloc, &exsql_offset, 8, "end;\n"); #endif if (exsql_offset > 16) /* In ORACLE always present begin..end; */ DBexecute("%s", exsql); zbx_free(exsql); DBcommit(); zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name); return SUCCEED; }
int zbx_tcp_listen(zbx_sock_t *s, const char *listen_ip, unsigned short listen_port) { struct addrinfo hints, *ai = NULL, *current_ai; char port[8], *ip, *ips, *delim; int i, err, on, ret = FAIL; ZBX_TCP_START(); zbx_tcp_clean(s); memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_flags = AI_NUMERICHOST | AI_PASSIVE; hints.ai_socktype = SOCK_STREAM; zbx_snprintf(port, sizeof(port), "%hu", listen_port); ip = ips = (NULL == listen_ip ? NULL : strdup(listen_ip)); while (1) { delim = (NULL == ip ? NULL : strchr(ip, ',')); if (NULL != delim) *delim = '\0'; if (0 != (err = getaddrinfo(ip, port, &hints, &ai))) { zbx_set_tcp_strerror("cannot resolve address [[%s]:%s]: [%d] %s", ip ? ip : "-", port, err, gai_strerror(err)); goto out; } for (current_ai = ai; NULL != current_ai; current_ai = current_ai->ai_next) { if (ZBX_SOCKET_COUNT == s->num_socks) { zbx_set_tcp_strerror("not enough space for socket [[%s]:%s]", ip ? ip : "-", port); goto out; } if (PF_INET != current_ai->ai_family && PF_INET6 != current_ai->ai_family) continue; if (ZBX_SOCK_ERROR == (s->sockets[s->num_socks] = socket(current_ai->ai_family, current_ai->ai_socktype | SOCK_CLOEXEC, current_ai->ai_protocol))) { zbx_set_tcp_strerror("socket() for [[%s]:%s] failed: %s", ip ? ip : "-", port, strerror_from_system(zbx_sock_last_error())); #ifdef _WINDOWS if (WSAEAFNOSUPPORT == zbx_sock_last_error()) #else if (EAFNOSUPPORT == zbx_sock_last_error()) #endif continue; else goto out; } #if !defined(_WINDOWS) && !SOCK_CLOEXEC fcntl(s->sockets[s->num_socks], F_SETFD, FD_CLOEXEC); #endif /* enable address reuse */ /* this is to immediately use the address even if it is in TIME_WAIT state */ /* http://www-128.ibm.com/developerworks/linux/library/l-sockpit/index.html */ on = 1; if (ZBX_TCP_ERROR == setsockopt(s->sockets[s->num_socks], SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on))) { zbx_set_tcp_strerror("setsockopt() with SO_REUSEADDR for [[%s]:%s] failed: %s", ip ? ip : "-", port, strerror_from_system(zbx_sock_last_error())); } #if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY) if (PF_INET6 == current_ai->ai_family && ZBX_TCP_ERROR == setsockopt(s->sockets[s->num_socks], IPPROTO_IPV6, IPV6_V6ONLY, (void *)&on, sizeof(on))) { zbx_set_tcp_strerror("setsockopt() with IPV6_V6ONLY for [[%s]:%s] failed: %s", ip ? ip : "-", port, strerror_from_system(zbx_sock_last_error())); } #endif if (ZBX_TCP_ERROR == bind(s->sockets[s->num_socks], current_ai->ai_addr, current_ai->ai_addrlen)) { zbx_set_tcp_strerror("bind() for [[%s]:%s] failed: %s", ip ? ip : "-", port, strerror_from_system(zbx_sock_last_error())); zbx_sock_close(s->sockets[s->num_socks]); #ifdef _WINDOWS if (WSAEADDRINUSE == zbx_sock_last_error()) #else if (EADDRINUSE == zbx_sock_last_error()) #endif continue; else goto out; } if (ZBX_TCP_ERROR == listen(s->sockets[s->num_socks], SOMAXCONN)) { zbx_set_tcp_strerror("listen() for [[%s]:%s] failed: %s", ip ? ip : "-", port, strerror_from_system(zbx_sock_last_error())); zbx_sock_close(s->sockets[s->num_socks]); goto out; } s->num_socks++; } if (NULL != ai) { freeaddrinfo(ai); ai = NULL; } if (NULL == ip || NULL == delim) break; *delim = ','; ip = delim + 1; } if (0 == s->num_socks) { zbx_set_tcp_strerror("zbx_tcp_listen() fatal error: unable to serve on any address [[%s]:%hu]", listen_ip ? listen_ip : "-", listen_port); goto out; } ret = SUCCEED; out: if (NULL != ips) zbx_free(ips); if (NULL != ai) freeaddrinfo(ai); if (SUCCEED != ret) { for (i = 0; i < s->num_socks; i++) zbx_sock_close(s->sockets[i]); } return ret; }
ZBX_THREAD_ENTRY(active_checks_thread, args) { ZBX_THREAD_ACTIVECHK_ARGS activechk_args; #if defined(ZABBIX_DAEMON) struct sigaction phan; #endif /* ZABBIX_DAEMON */ int nextcheck = 0, nextrefresh = 0, nextsend = 0; char *p = NULL; #if defined(ZABBIX_DAEMON) phan.sa_handler = child_signal_handler; sigemptyset(&phan.sa_mask); phan.sa_flags = 0; sigaction(SIGALRM, &phan, NULL); #endif /* ZABBIX_DAEMON */ activechk_args.host = strdup(((ZBX_THREAD_ACTIVECHK_ARGS *)args)->host); activechk_args.port = ((ZBX_THREAD_ACTIVECHK_ARGS *)args)->port; assert(activechk_args.host); p = strchr(activechk_args.host,','); if(p) *p = '\0'; zabbix_log( LOG_LEVEL_INFORMATION, "zabbix_agentd active check started [%s:%u]", activechk_args.host, activechk_args.port); init_active_metrics(); while(ZBX_IS_RUNNING) { if(time(NULL) >= nextsend) { send_buffer(activechk_args.host, activechk_args.port); nextsend = (int)time(NULL) + 1; } if(time(NULL) >= nextrefresh) { zbx_setproctitle("poller [getting list of active checks]"); if(FAIL == refresh_active_checks(activechk_args.host, activechk_args.port)) { nextrefresh = (int)time(NULL) + 60; } else { nextrefresh = (int)time(NULL) + CONFIG_REFRESH_ACTIVE_CHECKS; } } if(time(NULL) >= nextcheck) { zbx_setproctitle("poller [processing active checks]"); process_active_checks(activechk_args.host, activechk_args.port); nextcheck = get_min_nextcheck(); if(FAIL == nextcheck) nextcheck = (int)time(NULL) + 60; } else { zabbix_log(LOG_LEVEL_DEBUG, "Sleeping for %d seconds", 1 ); zbx_setproctitle("poller [sleeping for %d seconds]", 1); zbx_sleep(1); } } zbx_free(activechk_args.host); free_active_metrics(); zabbix_log( LOG_LEVEL_INFORMATION, "zabbix_agentd active check stopped"); ZBX_DO_EXIT(); zbx_tread_exit(0); }
/****************************************************************************** * * * Function: get_config_data * * * * Purpose: obtain configuration changes to required node * * * * Parameters: * * * * Return value: SUCCESS - processed successfully * * FAIL - an error occurred * * * * Author: Alexei Vladishev * * * * Comments: * * * ******************************************************************************/ char *get_config_data(int nodeid, int dest_nodetype) { const char *__function_name = "get_config_data"; DB_RESULT result; DB_RESULT result2; DB_ROW row; DB_ROW row2; const ZBX_TABLE *table; char *data = NULL, *hex = NULL, *sql = NULL, c[2], sync[129], *s, *r[2], *d[2]; int data_offset = 0, sql_offset = 0; int data_allocated = 1024, hex_allocated = 1024, sql_allocated = 8192; int f, j, rowlen; zabbix_log(LOG_LEVEL_DEBUG, "In %s() node:%d dest_nodetype:%s", __function_name, nodeid, (dest_nodetype == ZBX_NODE_MASTER) ? "MASTER" : "SLAVE"); data = zbx_malloc(data, data_allocated); hex = zbx_malloc(hex, hex_allocated); sql = zbx_malloc(sql, sql_allocated); c[0] = '1'; /* for new and updated records */ c[1] = '2'; /* for deleted records */ zbx_snprintf_alloc(&data, &data_allocated, &data_offset, 16, "Data%c%d%c%d", ZBX_DM_DELIMITER, CONFIG_NODEID, ZBX_DM_DELIMITER, nodeid); /* Find updated records */ result = DBselect("select curr.tablename,curr.recordid,prev.cksum,curr.cksum,prev.sync " "from node_cksum curr, node_cksum prev " "where curr.nodeid=%d and prev.nodeid=curr.nodeid and " "curr.tablename=prev.tablename and curr.recordid=prev.recordid and " "curr.cksumtype=%d and prev.cksumtype=%d " "union all " /* Find new records */ "select curr.tablename,curr.recordid,prev.cksum,curr.cksum,curr.sync " "from node_cksum curr left join node_cksum prev " "on prev.nodeid=curr.nodeid and prev.tablename=curr.tablename and " "prev.recordid=curr.recordid and prev.cksumtype=%d " "where curr.nodeid=%d and curr.cksumtype=%d and prev.tablename is null " "union all " /* Find deleted records */ "select prev.tablename,prev.recordid,prev.cksum,curr.cksum,prev.sync " "from node_cksum prev left join node_cksum curr " "on curr.nodeid=prev.nodeid and curr.tablename=prev.tablename and " "curr.recordid=prev.recordid and curr.cksumtype=%d " "where prev.nodeid=%d and prev.cksumtype=%d and curr.tablename is null", nodeid, NODE_CKSUM_TYPE_NEW, NODE_CKSUM_TYPE_OLD, NODE_CKSUM_TYPE_OLD, nodeid, NODE_CKSUM_TYPE_NEW, NODE_CKSUM_TYPE_NEW, nodeid, NODE_CKSUM_TYPE_OLD); while (NULL != (row = DBfetch(result))) { /* Found table */ if (NULL == (table = DBget_table(row[0]))) { zabbix_log(LOG_LEVEL_WARNING, "Cannot find table [%s]", row[0]); continue; } if (FAIL == DBis_null(row[4])) zbx_strlcpy(sync, row[4], sizeof(sync)); else memset(sync, ' ', sizeof(sync)); s = sync; /* Special (simpler) processing for operation DELETE */ if (SUCCEED == DBis_null(row[3])) { if ((dest_nodetype == ZBX_NODE_SLAVE && s[0] != c[1]) || (dest_nodetype == ZBX_NODE_MASTER && s[1] != c[1])) { zbx_snprintf_alloc(&data, &data_allocated, &data_offset, 128, "\n%s%c%s%c%d", row[0], ZBX_DM_DELIMITER, row[1], ZBX_DM_DELIMITER, NODE_CONFIGLOG_OP_DELETE); } continue; } r[0] = (SUCCEED == DBis_null(row[2]) ? NULL : row[2]); r[1] = row[3]; f = 0; sql_offset = 0; zbx_snprintf_alloc(&sql, &sql_allocated, &sql_offset, 128, "select "); do { while (0 == (table->fields[f].flags & ZBX_SYNC)) f++; d[0] = NULL; d[1] = NULL; if (NULL != r[0] && NULL != (d[0] = strchr(r[0], ','))) *d[0] = '\0'; if (NULL != r[1] && NULL != (d[1] = strchr(r[1], ','))) *d[1] = '\0'; if (NULL == r[0] || NULL == r[1] || (ZBX_NODE_SLAVE == dest_nodetype && s[0] != c[0]) || (ZBX_NODE_MASTER == dest_nodetype && s[1] != c[0]) || 0 != strcmp(r[0], r[1])) { zbx_snprintf_alloc(&sql, &sql_allocated, &sql_offset, 128, "%s,", table->fields[f].name); if (table->fields[f].type == ZBX_TYPE_BLOB) { zbx_snprintf_alloc(&sql, &sql_allocated, &sql_offset, 128, "length(%s),", table->fields[f].name); } } s += 2; f++; if (d[0] != NULL) { *d[0] = ','; r[0] = d[0] + 1; } else r[0] = NULL; if (d[1] != NULL) { *d[1] = ','; r[1] = d[1] + 1; } else r[1] = NULL; } while (NULL != d[0] || NULL != d[1]); if (sql[sql_offset-1] != ',') continue; sql_offset--; zbx_snprintf_alloc(&sql, &sql_allocated, &sql_offset, 128, " from %s where %s=%s", row[0], table->recid, row[1]); result2 = DBselect("%s", sql); if (NULL == (row2 = DBfetch(result2))) goto out; zbx_snprintf_alloc(&data, &data_allocated, &data_offset, 128, "\n%s%c%s%c%d", row[0], ZBX_DM_DELIMITER, row[1], ZBX_DM_DELIMITER, NODE_CONFIGLOG_OP_UPDATE); r[0] = DBis_null(row[2]) == SUCCEED ? NULL : row[2]; r[1] = row[3]; s = sync; f = 0; j = 0; do { while ((table->fields[f].flags & ZBX_SYNC) == 0) f++; d[0] = NULL; d[1] = NULL; if (NULL != r[0] && NULL != (d[0] = strchr(r[0], ','))) *d[0] = '\0'; if (NULL != r[1] && NULL != (d[1] = strchr(r[1], ','))) *d[1] = '\0'; if (r[0] == NULL || r[1] == NULL || (dest_nodetype == ZBX_NODE_SLAVE && *s != c[0]) || (dest_nodetype == ZBX_NODE_MASTER && *(s+1) != c[0]) || strcmp(r[0], r[1]) != 0) { zbx_snprintf_alloc(&data, &data_allocated, &data_offset, 128, "%c%s%c%d%c", ZBX_DM_DELIMITER, table->fields[f].name, ZBX_DM_DELIMITER, table->fields[f].type, ZBX_DM_DELIMITER); /* Fieldname, type, value */ if (SUCCEED == DBis_null(row2[j])) { zbx_snprintf_alloc(&data, &data_allocated, &data_offset, 5, "NULL"); } else if (table->fields[f].type == ZBX_TYPE_INT || table->fields[f].type == ZBX_TYPE_UINT || table->fields[f].type == ZBX_TYPE_ID || table->fields[f].type == ZBX_TYPE_FLOAT) { zbx_snprintf_alloc(&data, &data_allocated, &data_offset, 128, "%s", row2[j]); } else { if (ZBX_TYPE_BLOB == table->fields[f].type) rowlen = atoi(row2[j + 1]); else rowlen = strlen(row2[j]); zbx_binary2hex((u_char *)row2[j], rowlen, &hex, &hex_allocated); zbx_snprintf_alloc(&data, &data_allocated, &data_offset, strlen(hex) + 128, "%s", hex); } if (ZBX_TYPE_BLOB == table->fields[f].type) j += 2; else j++; } s += 2; f++; if (NULL != d[0]) { *d[0] = ','; r[0] = d[0] + 1; } else r[0] = NULL; if (NULL != d[1]) { *d[1] = ','; r[1] = d[1] + 1; } else r[1] = NULL; } while (NULL != d[0] || NULL != d[1]); out: DBfree_result(result2); } DBfree_result(result); zbx_free(hex); zbx_free(sql); zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name); return data; }
static void process_active_checks(char *server, unsigned short port) { register int i, s_count, p_count; char **pvalue; int now, send_err = SUCCEED, ret; unsigned long timestamp; char *source = NULL; char *value = NULL; unsigned short severity; long lastlogsize; char params[MAX_STRING_LEN]; char filename[MAX_STRING_LEN]; char pattern[MAX_STRING_LEN]; AGENT_RESULT result; zabbix_log( LOG_LEVEL_DEBUG, "In process_active_checks('%s',%u)",server, port); init_result(&result); now = (int)time(NULL); for(i=0; NULL != active_metrics[i].key && SUCCEED == send_err; i++) { if(active_metrics[i].nextcheck > now) continue; if(active_metrics[i].status != ITEM_STATUS_ACTIVE) continue; /* Special processing for log files */ if(strncmp(active_metrics[i].key,"log[",4) == 0) { do{ /* simple try realization */ if (parse_command(active_metrics[i].key, NULL, 0, params, MAX_STRING_LEN) != 2) break; if (num_param(params) > 2) break; if (get_param(params, 1, filename, sizeof(filename)) != 0) break; if (get_param(params, 2, pattern, sizeof(pattern)) != 0) *pattern = '\0'; s_count = 0; p_count = 0; lastlogsize = active_metrics[i].lastlogsize; while (SUCCEED == (ret = process_log(filename, &lastlogsize, &value))) { if (!value) /* EOF */ break; if (SUCCEED == regexp_match_ex(regexps, regexps_num, value, pattern, ZBX_CASE_SENSITIVE)) { send_err = process_value( server, port, CONFIG_HOSTNAME, active_metrics[i].key_orig, value, &lastlogsize, NULL, NULL, NULL ); s_count++; } p_count++; zbx_free(value); if (SUCCEED == send_err) active_metrics[i].lastlogsize = lastlogsize; else lastlogsize = active_metrics[i].lastlogsize; /* Do not flood ZABBIX server if file grows too fast */ if(s_count >= (MAX_LINES_PER_SECOND * active_metrics[i].refresh)) break; /* Do not flood local system if file grows too fast */ if(p_count >= (4 * MAX_LINES_PER_SECOND * active_metrics[i].refresh)) break; } if( FAIL == ret ) { active_metrics[i].status = ITEM_STATUS_NOTSUPPORTED; zabbix_log( LOG_LEVEL_WARNING, "Active check [%s] is not supported. Disabled.", active_metrics[i].key); send_err = process_value( server, port, CONFIG_HOSTNAME, active_metrics[i].key_orig, "ZBX_NOTSUPPORTED", &active_metrics[i].lastlogsize, NULL, NULL, NULL ); } }while(0); /* simple try realization */ } /* Special processing for eventlog */ else if(strncmp(active_metrics[i].key,"eventlog[",9) == 0) { do{ /* simple try realization */ if (parse_command(active_metrics[i].key, NULL, 0, params, MAX_STRING_LEN) != 2) break; if (num_param(params) > 2) break; if (get_param(params, 1, filename, sizeof(filename)) != 0) break; if (get_param(params, 2, pattern, sizeof(pattern)) != 0) *pattern = '\0'; s_count = 0; p_count = 0; lastlogsize = active_metrics[i].lastlogsize; while (SUCCEED == (ret = process_eventlog(filename, &lastlogsize, ×tamp, &source, &severity, &value))) { if (!value) /* EOF */ break; if (SUCCEED == regexp_match_ex(regexps, regexps_num, value, pattern, ZBX_CASE_SENSITIVE)) { send_err = process_value( server, port, CONFIG_HOSTNAME, active_metrics[i].key_orig, value, &lastlogsize, ×tamp, source, &severity ); s_count++; } p_count++; zbx_free(source); zbx_free(value); if (SUCCEED == send_err) active_metrics[i].lastlogsize = lastlogsize; else lastlogsize = active_metrics[i].lastlogsize; /* Do not flood ZABBIX server if file grows too fast */ if(s_count >= (MAX_LINES_PER_SECOND * active_metrics[i].refresh)) break; /* Do not flood local system if file grows too fast */ if(p_count >= (4 * MAX_LINES_PER_SECOND * active_metrics[i].refresh)) break; } if( FAIL == ret ) { active_metrics[i].status = ITEM_STATUS_NOTSUPPORTED; zabbix_log( LOG_LEVEL_WARNING, "Active check [%s] is not supported. Disabled.", active_metrics[i].key); send_err = process_value( server, port, CONFIG_HOSTNAME, active_metrics[i].key_orig, "ZBX_NOTSUPPORTED", &active_metrics[i].lastlogsize, NULL, NULL, NULL ); } }while(0); /* simple try realization NOTE: never loop */ } else { process(active_metrics[i].key, 0, &result); if( NULL == (pvalue = GET_TEXT_RESULT(&result)) ) pvalue = GET_MSG_RESULT(&result); if(pvalue) { zabbix_log( LOG_LEVEL_DEBUG, "For key [%s] received value [%s]", active_metrics[i].key, *pvalue); send_err = process_value( server, port, CONFIG_HOSTNAME, active_metrics[i].key_orig, *pvalue, NULL, NULL, NULL, NULL ); if( 0 == strcmp(*pvalue,"ZBX_NOTSUPPORTED") ) { active_metrics[i].status = ITEM_STATUS_NOTSUPPORTED; zabbix_log( LOG_LEVEL_WARNING, "Active check [%s] is not supported. Disabled.", active_metrics[i].key); } } free_result(&result); } active_metrics[i].nextcheck = (int)time(NULL)+active_metrics[i].refresh; } }
/****************************************************************************** * * * Function: process_value * * * * Purpose: Buffer new value or send the whole buffer to the server * * * * Parameters: host - IP or Hostname of ZABBIX server * * port - port of ZABBIX server * * hostname - name of host in ZABBIX database * * key - name of metric * * value - string version os key value * * lastlogsize - size of readed logfile * * timestamp - timestamp of readed value * * source - name of logged data source * * severity - severity of logged data sources * * * * Return value: returns SUCCEED on succesfull parsing, * * FAIL on other cases * * * * Author: Alexei Vladishev * * * * Comments: * * * ******************************************************************************/ static int process_value( const char *server, unsigned short port, const char *host, const char *key, const char *value, long *lastlogsize, unsigned long *timestamp, const char *source, unsigned short *severity ) { ZBX_ACTIVE_BUFFER_ELEMENT *el; int ret = SUCCEED; zabbix_log( LOG_LEVEL_DEBUG, "In process_value('%s','%s','%s')", host, key, value); send_buffer(server,port); /* Called first time, allocate memory */ if(NULL == buffer.data) { zabbix_log( LOG_LEVEL_DEBUG, "Buffer: first allocation for %d elements", CONFIG_BUFFER_SIZE); buffer.data = zbx_malloc(buffer.data, CONFIG_BUFFER_SIZE*sizeof(ZBX_ACTIVE_BUFFER_ELEMENT)); memset(buffer.data, 0, CONFIG_BUFFER_SIZE*sizeof(ZBX_ACTIVE_BUFFER_ELEMENT)); buffer.count = 0; } if(buffer.count < CONFIG_BUFFER_SIZE) { zabbix_log( LOG_LEVEL_DEBUG, "Buffer: new element %d", buffer.count); el = &buffer.data[buffer.count]; buffer.count++; } else { zabbix_log( LOG_LEVEL_DEBUG, "Buffer full: new element %d", buffer.count); if(buffer.data[0].host != NULL) zbx_free(buffer.data[0].host); if(buffer.data[0].key != NULL) zbx_free(buffer.data[0].key); if(buffer.data[0].value != NULL) zbx_free(buffer.data[0].value); if(buffer.data[0].source != NULL) zbx_free(buffer.data[0].source); memmove(&buffer.data[0],&buffer.data[1], (CONFIG_BUFFER_SIZE-1)*sizeof(ZBX_ACTIVE_BUFFER_ELEMENT)); el = &buffer.data[CONFIG_BUFFER_SIZE-1]; } memset(el, 0, sizeof(ZBX_ACTIVE_BUFFER_ELEMENT)); el->host = strdup(host); el->key = strdup(key); el->value = strdup(value); if (source) el->source = strdup(source); if (severity) el->severity = *severity; if (lastlogsize) el->lastlogsize = *lastlogsize; if (timestamp) el->timestamp = *timestamp; el->clock = (int)time(NULL); /* zabbix_log(LOG_LEVEL_DEBUG, "BUFFER"); for(i=0;i<buffer.count;i++) { zabbix_log(LOG_LEVEL_DEBUG, " Host %s Key %s Values %s", buffer.data[i].host, buffer.data[i].key, buffer.data[i].value); }*/ return ret; }
/****************************************************************************** * * * Function: send_buffer * * * * Purpose: Send value stgored in the buffer to ZABBIX server * * * * Parameters: host - IP or Hostname of ZABBIX server * * port - port number * * * * Return value: returns SUCCEED on succesfull parsing, * * FAIL on other cases * * * * Author: Alexei Vladishev * * * * Comments: * * * ******************************************************************************/ static int send_buffer( const char *host, unsigned short port ) { zbx_sock_t s; char *buf = NULL; int ret = SUCCEED; struct zbx_json json; int i; static int lastsent = 0; int now; zabbix_log( LOG_LEVEL_DEBUG, "In send_buffer('%s','%d')", host, port); zabbix_log( LOG_LEVEL_DEBUG, "Values in the buffer %d Max %d", buffer.count, CONFIG_BUFFER_SIZE); now = (int)time(NULL); if(buffer.count < CONFIG_BUFFER_SIZE && now-lastsent < CONFIG_BUFFER_SEND) { zabbix_log( LOG_LEVEL_DEBUG, "Will not send now. Now %d lastsent %d < %d", now, lastsent, CONFIG_BUFFER_SEND); return ret; } if(buffer.count < 1) { return ret; } zbx_json_init(&json, ZBX_JSON_STAT_BUF_LEN); zbx_json_addstring(&json, ZBX_PROTO_TAG_REQUEST, ZBX_PROTO_VALUE_AGENT_DATA, ZBX_JSON_TYPE_STRING); zbx_json_addarray(&json, ZBX_PROTO_TAG_DATA); for(i=0;i<buffer.count;i++) { zbx_json_addobject(&json, NULL); zbx_json_addstring(&json, ZBX_PROTO_TAG_HOST, buffer.data[i].host, ZBX_JSON_TYPE_STRING); zbx_json_addstring(&json, ZBX_PROTO_TAG_KEY, buffer.data[i].key, ZBX_JSON_TYPE_STRING); zbx_json_addstring(&json, ZBX_PROTO_TAG_VALUE, buffer.data[i].value, ZBX_JSON_TYPE_STRING); if (buffer.data[i].lastlogsize) zbx_json_adduint64(&json, ZBX_PROTO_TAG_LOGLASTSIZE, buffer.data[i].lastlogsize); if (buffer.data[i].timestamp) zbx_json_adduint64(&json, ZBX_PROTO_TAG_LOGTIMESTAMP, buffer.data[i].timestamp); if (buffer.data[i].source) zbx_json_addstring(&json, ZBX_PROTO_TAG_LOGSOURCE, buffer.data[i].source, ZBX_JSON_TYPE_STRING); if (buffer.data[i].severity) zbx_json_adduint64(&json, ZBX_PROTO_TAG_LOGSEVERITY, buffer.data[i].severity); zbx_json_adduint64(&json, ZBX_PROTO_TAG_CLOCK, buffer.data[i].clock); zbx_json_close(&json); } zbx_json_close(&json); zbx_json_adduint64(&json, ZBX_PROTO_TAG_CLOCK, (int)time(NULL)); if (SUCCEED == (ret = zbx_tcp_connect(&s, CONFIG_SOURCE_IP, host, port, MIN(buffer.count*CONFIG_TIMEOUT, 60)))) { zabbix_log(LOG_LEVEL_DEBUG, "JSON before sending [%s]", json.buffer); ret = zbx_tcp_send(&s, json.buffer); if( SUCCEED == ret ) { if( SUCCEED == (ret = zbx_tcp_recv(&s, &buf)) ) { zabbix_log(LOG_LEVEL_DEBUG, "JSON back [%s]", buf); if( !buf || check_response(buf) != SUCCEED ) { zabbix_log(LOG_LEVEL_DEBUG, "NOT OK"); } else { zabbix_log(LOG_LEVEL_DEBUG, "OK"); } } else zabbix_log(LOG_LEVEL_DEBUG, "Send value error: [recv] %s", zbx_tcp_strerror()); } else zabbix_log(LOG_LEVEL_DEBUG, "Send value error: [send] %s", zbx_tcp_strerror()); zbx_tcp_close(&s); } else zabbix_log(LOG_LEVEL_DEBUG, "Send value error: [connect] %s", zbx_tcp_strerror()); zbx_json_free(&json); if(SUCCEED == ret) { /* free buffer */ for(i=0;i<buffer.count;i++) { if(buffer.data[i].host != NULL) zbx_free(buffer.data[i].host); if(buffer.data[i].key != NULL) zbx_free(buffer.data[i].key); if(buffer.data[i].value != NULL) zbx_free(buffer.data[i].value); if(buffer.data[i].source != NULL) zbx_free(buffer.data[i].source); } buffer.count = 0; } if(SUCCEED == ret) lastsent = now; return ret; }
/****************************************************************************** * * * Function: free_event_info * * * * Purpose: clean allocated memory by function 'get_event_info' * * * * Parameters: event - [IN] event data * * * * Return value: * * * * Author: Alexander Vladishev * * * * Comments: * * * ******************************************************************************/ static void free_event_info(DB_EVENT *event) { zbx_free(event->trigger.comments); zbx_free(event->trigger.url); }
int zbx_tcp_listen(zbx_sock_t *s, const char *listen_ip, unsigned short listen_port) { ZBX_SOCKADDR serv_addr; char *ip, *ips, *delim; int i, on, ret = FAIL; ZBX_TCP_START(); zbx_tcp_clean(s); ip = ips = (NULL == listen_ip ? NULL : strdup(listen_ip)); while (1) { delim = (NULL == ip ? NULL : strchr(ip, ',')); if (NULL != delim) *delim = '\0'; if (NULL != ip && FAIL == is_ip4(ip)) { zbx_set_tcp_strerror("incorrect IPv4 address [%s]", ip); goto out; } if (ZBX_SOCKET_COUNT == s->num_socks) { zbx_set_tcp_strerror("not enough space for socket [[%s]:%hu]", ip ? ip : "-", listen_port); goto out; } if (ZBX_SOCK_ERROR == (s->sockets[s->num_socks] = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0))) { zbx_set_tcp_strerror("socket() for [[%s]:%hu] failed: %s", ip ? ip : "-", listen_port, strerror_from_system(zbx_sock_last_error())); goto out; } #if !defined(_WINDOWS) && !SOCK_CLOEXEC fcntl(s->sockets[s->num_socks], F_SETFD, FD_CLOEXEC); #endif /* Enable address reuse */ /* This is to immediately use the address even if it is in TIME_WAIT state */ /* http://www-128.ibm.com/developerworks/linux/library/l-sockpit/index.html */ on = 1; if (ZBX_TCP_ERROR == setsockopt(s->sockets[s->num_socks], SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on))) { zbx_set_tcp_strerror("setsockopt() for [[%s]:%hu] failed: %s", ip ? ip : "-", listen_port, strerror_from_system(zbx_sock_last_error())); } memset(&serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = NULL != ip ? inet_addr(ip) : htonl(INADDR_ANY); serv_addr.sin_port = htons((unsigned short)listen_port); if (ZBX_TCP_ERROR == bind(s->sockets[s->num_socks], (struct sockaddr *)&serv_addr, sizeof(serv_addr))) { zbx_set_tcp_strerror("bind() for [[%s]:%hu] failed: %s", ip ? ip : "-", listen_port, strerror_from_system(zbx_sock_last_error())); zbx_sock_close(s->sockets[s->num_socks]); goto out; } if (ZBX_TCP_ERROR == listen(s->sockets[s->num_socks], SOMAXCONN)) { zbx_set_tcp_strerror("listen() for [[%s]:%hu] failed: %s", ip ? ip : "-", listen_port, strerror_from_system(zbx_sock_last_error())); zbx_sock_close(s->sockets[s->num_socks]); goto out; } s->num_socks++; if (NULL == ip || NULL == delim) break; *delim = ','; ip = delim + 1; } if (0 == s->num_socks) { zbx_set_tcp_strerror("zbx_tcp_listen() fatal error: unable to serve on any address [[%s]:%hu]", listen_ip ? listen_ip : "-", listen_port); goto out; } ret = SUCCEED; out: if (NULL != ips) zbx_free(ips); if (SUCCEED != ret) { for (i = 0; i < s->num_socks; i++) zbx_sock_close(s->sockets[i]); } return ret; }
static void execute_escalation(DB_ESCALATION *escalation) { const char *__function_name = "execute_escalation"; DB_RESULT result; DB_ROW row; DB_ACTION action; DB_EVENT event; char *error = NULL; int source = (-1); zabbix_log(LOG_LEVEL_DEBUG, "In %s() escalationid:" ZBX_FS_UI64 " status:%s", __function_name, escalation->escalationid, zbx_escalation_status_string(escalation->status)); result = DBselect("select source from events where eventid=" ZBX_FS_UI64, escalation->eventid); if (NULL == (row = DBfetch(result))) error = zbx_dsprintf(error, "event [" ZBX_FS_UI64 "] deleted.", escalation->eventid); else source = atoi(row[0]); DBfree_result(result); if (NULL == error && EVENT_SOURCE_TRIGGERS == source) { /* trigger disabled? */ result = DBselect("select description,status from triggers where triggerid=" ZBX_FS_UI64, escalation->triggerid); if (NULL == (row = DBfetch(result))) error = zbx_dsprintf(error, "trigger [" ZBX_FS_UI64 "] deleted.", escalation->triggerid); else if (TRIGGER_STATUS_DISABLED == atoi(row[1])) error = zbx_dsprintf(error, "trigger '%s' disabled.", row[0]); DBfree_result(result); } if (NULL == error && EVENT_SOURCE_TRIGGERS == source) { /* item disabled? */ result = DBselect( "select i.name" " from items i,functions f,triggers t" " where i.itemid=f.itemid" " and f.triggerid=t.triggerid" " and t.triggerid=" ZBX_FS_UI64 " and i.status=%d", escalation->triggerid, ITEM_STATUS_DISABLED); if (NULL != (row = DBfetch(result))) error = zbx_dsprintf(error, "item '%s' disabled.", row[0]); DBfree_result(result); } if (NULL == error && EVENT_SOURCE_TRIGGERS == source) { /* host disabled? */ result = DBselect( "select h.host" " from hosts h,items i,functions f,triggers t" " where h.hostid=i.hostid" " and i.itemid=f.itemid" " and f.triggerid=t.triggerid" " and t.triggerid=" ZBX_FS_UI64 " and h.status=%d", escalation->triggerid, HOST_STATUS_NOT_MONITORED); if (NULL != (row = DBfetch(result))) error = zbx_dsprintf(error, "host '%s' disabled.", row[0]); DBfree_result(result); } switch (escalation->status) { case ESCALATION_STATUS_ACTIVE: result = DBselect( "select actionid,eventsource,esc_period,def_shortdata,def_longdata," "recovery_msg,status,name" " from actions" " where actionid=" ZBX_FS_UI64, escalation->actionid); break; case ESCALATION_STATUS_RECOVERY: result = DBselect( "select actionid,eventsource,esc_period,r_shortdata,r_longdata,recovery_msg," "status,name" " from actions" " where actionid=" ZBX_FS_UI64, escalation->actionid); break; default: THIS_SHOULD_NEVER_HAPPEN; return; } if (NULL != (row = DBfetch(result))) { memset(&action, 0, sizeof(action)); ZBX_STR2UINT64(action.actionid, row[0]); action.eventsource = atoi(row[1]); action.esc_period = atoi(row[2]); action.shortdata = row[3]; action.recovery_msg = atoi(row[5]); if (ACTION_STATUS_ACTIVE != atoi(row[6])) error = zbx_dsprintf(error, "action '%s' disabled.", row[7]); if (NULL != error) { action.longdata = zbx_dsprintf(action.longdata, "NOTE: Escalation cancelled: %s\n%s", error, row[4]); } else action.longdata = row[4]; switch (escalation->status) { case ESCALATION_STATUS_ACTIVE: if (SUCCEED == get_event_info(escalation->eventid, &event)) execute_operations(escalation, &event, &action); free_event_info(&event); break; case ESCALATION_STATUS_RECOVERY: if (SUCCEED == get_event_info(escalation->r_eventid, &event)) process_recovery_msg(escalation, &event, &action); free_event_info(&event); break; default: break; } if (NULL != error) zbx_free(action.longdata); } else error = zbx_dsprintf(error, "action [" ZBX_FS_UI64 "] deleted", escalation->actionid); DBfree_result(result); if (NULL != error) { escalation->status = ESCALATION_STATUS_COMPLETED; zabbix_log(LOG_LEVEL_WARNING, "escalation cancelled: %s", error); zbx_free(error); } zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name); }
/****************************************************************************** * * * Function: zbx_tcp_free * * * * Purpose: close open socket * * * * Author: Alexei Vladishev * * * ******************************************************************************/ void zbx_tcp_free(zbx_sock_t *s) { zbx_free(s->buf_dyn); }
static void add_message_alert(DB_ESCALATION *escalation, DB_EVENT *event, DB_ACTION *action, zbx_uint64_t userid, zbx_uint64_t mediatypeid, const char *subject, const char *message) { const char *__function_name = "add_message_alert"; DB_RESULT result; DB_ROW row; zbx_uint64_t alertid; int now, severity, medias = 0; char *subject_dyn, *message_dyn, *sendto_esc, *subject_esc, *message_esc, *error_esc; char error[MAX_STRING_LEN]; zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name); subject_dyn = zbx_strdup(NULL, subject); message_dyn = zbx_strdup(NULL, message); substitute_simple_macros(event, &userid, NULL, NULL, NULL, NULL, &subject_dyn, MACRO_TYPE_MESSAGE, NULL, 0); substitute_simple_macros(event, &userid, NULL, NULL, NULL, NULL, &message_dyn, MACRO_TYPE_MESSAGE, NULL, 0); now = time(NULL); subject_esc = DBdyn_escape_string_len(subject_dyn, ALERT_SUBJECT_LEN); message_esc = DBdyn_escape_string_len(message_dyn, ALERT_MESSAGE_LEN); zbx_free(subject_dyn); zbx_free(message_dyn); if (0 == mediatypeid) { result = DBselect( "select m.mediatypeid,m.sendto,m.severity,m.period,mt.status" " from media m,media_type mt" " where m.mediatypeid=mt.mediatypeid" " and m.active=%d" " and m.userid=" ZBX_FS_UI64, MEDIA_STATUS_ACTIVE, userid); } else { result = DBselect( "select m.mediatypeid,m.sendto,m.severity,m.period,mt.status" " from media m,media_type mt" " where m.mediatypeid=mt.mediatypeid" " and m.active=%d" " and m.userid=" ZBX_FS_UI64 " and m.mediatypeid=" ZBX_FS_UI64, MEDIA_STATUS_ACTIVE, userid, mediatypeid); } while (NULL != (row = DBfetch(result))) { medias = 1; ZBX_STR2UINT64(mediatypeid, row[0]); severity = atoi(row[2]); zabbix_log(LOG_LEVEL_DEBUG, "Trigger severity [%d] Media severity [%d] Period [%s]", (int)event->trigger.priority, severity, row[3]); if (((1 << event->trigger.priority) & severity) == 0) { zabbix_log(LOG_LEVEL_DEBUG, "Won't send message (severity)"); continue; } if (FAIL == check_time_period(row[3], (time_t)NULL)) { zabbix_log(LOG_LEVEL_DEBUG, "Won't send message (period)"); continue; } alertid = DBget_maxid("alerts"); sendto_esc = DBdyn_escape_string_len(row[1], ALERT_SENDTO_LEN); if (MEDIA_TYPE_STATUS_ACTIVE == atoi(row[4])) { DBexecute("insert into alerts (alertid,actionid,eventid,userid,clock" ",mediatypeid,sendto,subject,message,status,alerttype,esc_step)" " values (" ZBX_FS_UI64 "," ZBX_FS_UI64 "," ZBX_FS_UI64 "," ZBX_FS_UI64 ",%d" "," ZBX_FS_UI64 ",'%s','%s','%s',%d,%d,%d)", alertid, action->actionid, event->eventid, userid, now, mediatypeid, sendto_esc, subject_esc, message_esc, ALERT_STATUS_NOT_SENT, ALERT_TYPE_MESSAGE, escalation->esc_step); } else { error_esc = DBdyn_escape_string("Media type disabled"); DBexecute("insert into alerts (alertid,actionid,eventid,userid,clock" ",mediatypeid,sendto,subject,message,status,alerttype,esc_step,error)" " values (" ZBX_FS_UI64 "," ZBX_FS_UI64 "," ZBX_FS_UI64 "," ZBX_FS_UI64 ",%d" "," ZBX_FS_UI64 ",'%s','%s','%s',%d,%d,%d,'%s')", alertid, action->actionid, event->eventid, userid, now, mediatypeid, sendto_esc, subject_esc, message_esc, ALERT_STATUS_FAILED, ALERT_TYPE_MESSAGE, escalation->esc_step, error_esc); zbx_free(error_esc); } zbx_free(sendto_esc); } DBfree_result(result); if (0 == medias) { zbx_snprintf(error, sizeof(error), "No media defined for user \"%s\"", zbx_user_string(userid)); alertid = DBget_maxid("alerts"); error_esc = DBdyn_escape_string(error); DBexecute("insert into alerts (alertid,actionid,eventid,userid,retries,clock" ",subject,message,status,alerttype,error,esc_step)" " values (" ZBX_FS_UI64 "," ZBX_FS_UI64 "," ZBX_FS_UI64 "," ZBX_FS_UI64 ",%d,%d" ",'%s','%s',%d,%d,'%s',%d)", alertid, action->actionid, event->eventid, userid, ALERT_MAX_RETRIES, now, subject_esc, message_esc, ALERT_STATUS_FAILED, ALERT_TYPE_MESSAGE, error_esc, escalation->esc_step); zbx_free(error_esc); } zbx_free(subject_esc); zbx_free(message_esc); zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name); }
/****************************************************************************** * * * Function: zbx_tcp_recv_ext * * * * Purpose: receive data * * * * Return value: number of bytes received - success, * * FAIL - an error occurred * * * * Author: Eugene Grigorjev * * * ******************************************************************************/ ssize_t zbx_tcp_recv_ext(zbx_sock_t *s, char **data, unsigned char flags, int timeout) { #define ZBX_BUF_LEN (ZBX_STAT_BUF_LEN * 8) ssize_t nbytes, left, total_bytes; size_t allocated, offset, read_bytes; zbx_uint64_t expected_len; ZBX_TCP_START(); if (0 != timeout) zbx_tcp_timeout_set(s, timeout); zbx_free(s->buf_dyn); total_bytes = 0; read_bytes = 0; s->buf_type = ZBX_BUF_TYPE_STAT; *data = s->buf_stat; left = ZBX_TCP_HEADER_LEN; if (ZBX_TCP_ERROR == (nbytes = ZBX_TCP_READ(s->socket, s->buf_stat, left))) goto out; if (ZBX_TCP_HEADER_LEN == nbytes && 0 == strncmp(s->buf_stat, ZBX_TCP_HEADER, ZBX_TCP_HEADER_LEN)) { total_bytes += nbytes; left = sizeof(zbx_uint64_t); if (left != (nbytes = ZBX_TCP_READ(s->socket, (void *)&expected_len, left))) { total_bytes = FAIL; goto out; } expected_len = zbx_letoh_uint64(expected_len); if (ZBX_MAX_RECV_DATA_SIZE < expected_len) { zabbix_log(LOG_LEVEL_WARNING, "Message size " ZBX_FS_UI64 " from %s" " exceeds the maximum size " ZBX_FS_UI64 " bytes. Message ignored.", expected_len, get_ip_by_socket(s), (zbx_uint64_t)ZBX_MAX_RECV_DATA_SIZE); total_bytes = FAIL; goto cleanup; } flags |= ZBX_TCP_READ_UNTIL_CLOSE; } else { read_bytes = nbytes; expected_len = 16 * ZBX_MEBIBYTE; } s->buf_stat[read_bytes] = '\0'; if (0 != (flags & ZBX_TCP_READ_UNTIL_CLOSE)) { if (0 == nbytes) goto cleanup; } else { if (nbytes < left) goto cleanup; } left = sizeof(s->buf_stat) - read_bytes - 1; /* check for an empty socket if exactly ZBX_TCP_HEADER_LEN bytes (without a header) were sent */ if (0 == read_bytes || '\n' != s->buf_stat[read_bytes - 1]) /* requests to passive agents end with '\n' */ { /* fill static buffer */ while (read_bytes < expected_len && 0 < left && ZBX_TCP_ERROR != (nbytes = ZBX_TCP_READ(s->socket, s->buf_stat + read_bytes, left))) { read_bytes += nbytes; if (0 != (flags & ZBX_TCP_READ_UNTIL_CLOSE)) { if (0 == nbytes) break; } else { if (nbytes < left) /* should we stop reading? */ { /* XML protocol? */ if (0 == strncmp(s->buf_stat, "<req>", sizeof("<req>") - 1)) { /* closing tag received in the last 10 bytes? */ s->buf_stat[read_bytes] = '\0'; if (NULL != strstr(s->buf_stat + read_bytes - (10 > read_bytes ? read_bytes : 10), "</req>")) break; } else break; } } left -= nbytes; } } s->buf_stat[read_bytes] = '\0'; if (sizeof(s->buf_stat) - 1 == read_bytes) /* static buffer is full */ { allocated = ZBX_BUF_LEN; s->buf_type = ZBX_BUF_TYPE_DYN; s->buf_dyn = zbx_malloc(s->buf_dyn, allocated); memcpy(s->buf_dyn, s->buf_stat, sizeof(s->buf_stat)); offset = read_bytes; /* fill dynamic buffer */ while (read_bytes < expected_len && ZBX_TCP_ERROR != (nbytes = ZBX_TCP_READ(s->socket, s->buf_stat, sizeof(s->buf_stat)))) { zbx_strncpy_alloc(&s->buf_dyn, &allocated, &offset, s->buf_stat, nbytes); read_bytes += nbytes; if (0 != (flags & ZBX_TCP_READ_UNTIL_CLOSE)) { if (0 == nbytes) break; } else { if ((size_t)nbytes < sizeof(s->buf_stat) - 1) /* should we stop reading? */ { /* XML protocol? */ if (0 == strncmp(s->buf_dyn, "<req>", sizeof("<req>") - 1)) { /* closing tag received in the last 10 bytes? */ if (NULL != strstr(s->buf_dyn + read_bytes - 10, "</req>")) break; } else break; } } } *data = s->buf_dyn; } out: if (ZBX_TCP_ERROR == nbytes) { zbx_set_tcp_strerror("ZBX_TCP_READ() failed: %s", strerror_from_system(zbx_sock_last_error())); total_bytes = FAIL; } cleanup: if (0 != timeout) zbx_tcp_timeout_cleanup(s); if (FAIL != total_bytes) total_bytes += read_bytes; return total_bytes; }
int SYSTEM_HW_MACADDR(const char *cmd, const char *param, unsigned flags, AGENT_RESULT *result) { size_t offset; int ret = SYSINFO_RET_FAIL, s, i, show_names; char *p, regex[MAX_STRING_LEN], address[MAX_STRING_LEN], buffer[MAX_STRING_LEN]; struct ifreq *ifr; struct ifconf ifc; zbx_vector_str_t addresses; if (2 < num_param(param)) return ret; if (0 != get_param(param, 1, regex, sizeof(regex)) || 0 == strcmp(regex, "all")) *regex = '\0'; if (0 != get_param(param, 2, buffer, sizeof(buffer)) || '\0' == *buffer || 0 == strcmp(buffer, "full")) show_names = 1; /* show interface names */ else if (0 == strcmp(buffer, "short")) show_names = 0; else return ret; if (-1 == (s = socket(AF_INET, SOCK_DGRAM, 0))) return ret; /* get the interface list */ ifc.ifc_len = sizeof(buffer); ifc.ifc_buf = buffer; if (-1 == ioctl(s, SIOCGIFCONF, &ifc)) goto close; ifr = ifc.ifc_req; ret = SYSINFO_RET_OK; zbx_vector_str_create(&addresses); zbx_vector_str_reserve(&addresses, 8); /* go through the list */ for (i = ifc.ifc_len / sizeof(struct ifreq); 0 < i--; ifr++) { if ('\0' != *regex && NULL == zbx_regexp_match(ifr->ifr_name, regex, NULL)) continue; if (-1 != ioctl(s, SIOCGIFFLAGS, ifr) && /* get the interface */ 0 == (ifr->ifr_flags & IFF_LOOPBACK) && /* skip loopback interface */ -1 != ioctl(s, SIOCGIFHWADDR, ifr)) /* get the MAC address */ { offset = 0; if (1 == show_names) offset += zbx_snprintf(address + offset, sizeof(address) - offset, "[%s ", ifr->ifr_name); zbx_snprintf(address + offset, sizeof(address) - offset, "%.2hx:%.2hx:%.2hx:%.2hx:%.2hx:%.2hx", (unsigned short int)(unsigned char)ifr->ifr_hwaddr.sa_data[0], (unsigned short int)(unsigned char)ifr->ifr_hwaddr.sa_data[1], (unsigned short int)(unsigned char)ifr->ifr_hwaddr.sa_data[2], (unsigned short int)(unsigned char)ifr->ifr_hwaddr.sa_data[3], (unsigned short int)(unsigned char)ifr->ifr_hwaddr.sa_data[4], (unsigned short int)(unsigned char)ifr->ifr_hwaddr.sa_data[5]); if (0 == show_names && FAIL != zbx_vector_str_search(&addresses, address, ZBX_DEFAULT_STR_COMPARE_FUNC)) continue; zbx_vector_str_append(&addresses, zbx_strdup(NULL, address)); } } offset = 0; if (0 != addresses.values_num) { zbx_vector_str_sort(&addresses, ZBX_DEFAULT_STR_COMPARE_FUNC); for (i = 0; i < addresses.values_num; i++) { if (1 == show_names && NULL != (p = strchr(addresses.values[i], ' '))) *p = ']'; offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, "%s, ", addresses.values[i]); zbx_free(addresses.values[i]); } offset -= 2; } buffer[offset] = '\0'; if (SYSINFO_RET_OK == ret) SET_STR_RESULT(result, zbx_strdup(NULL, buffer)); zbx_vector_str_destroy(&addresses); close: close(s); return ret; }
int telnet_execute(ZBX_SOCKET socket_fd, const char *command, AGENT_RESULT *result, const char *encoding) { const char *__function_name = "telnet_execute"; char buf[MAX_BUFFER_LEN]; size_t sz, offset; int rc, ret = FAIL; char *command_lf = NULL, *command_crlf = NULL; size_t i, offset_lf, offset_crlf; zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name); /* `command' with multiple lines may contain CR+LF from the browser; */ /* it should be converted to plain LF to remove echo later on properly */ offset_lf = strlen(command); command_lf = zbx_malloc(command_lf, offset_lf + 1); zbx_strlcpy(command_lf, command, offset_lf + 1); convert_telnet_to_unix_eol(command_lf, &offset_lf); /* telnet protocol requires that end-of-line is transferred as CR+LF */ command_crlf = zbx_malloc(command_crlf, offset_lf * 2 + 1); convert_unix_to_telnet_eol(command_lf, offset_lf, command_crlf, &offset_crlf); telnet_socket_write(socket_fd, command_crlf, offset_crlf); telnet_socket_write(socket_fd, "\r\n", 2); sz = sizeof(buf); offset = 0; while (ZBX_TCP_ERROR != (rc = telnet_read(socket_fd, buf, &sz, &offset))) { if (prompt_char == telnet_lastchar(buf, offset)) break; } convert_telnet_to_unix_eol(buf, &offset); zabbix_log(LOG_LEVEL_DEBUG, "%s() command output:'%.*s'", __function_name, offset, buf); if (ZBX_TCP_ERROR == rc) { SET_MSG_RESULT(result, zbx_dsprintf(NULL, "No prompt: %s", zbx_tcp_strerror())); goto fail; } telnet_rm_echo(buf, &offset, command_lf, offset_lf); /* multi-line commands may have returned additional prompts; */ /* this is not a perfect solution, because in case of multiple */ /* multi-line shell statements these prompts might appear in */ /* the middle of the output, but we still try to be helpful by */ /* removing additional prompts at least from the beginning */ for (i = 0; i < offset_lf; i++) { if ('\n' == command_lf[i]) if (SUCCEED != telnet_rm_echo(buf, &offset, "$ ", 2) && SUCCEED != telnet_rm_echo(buf, &offset, "# ", 2) && SUCCEED != telnet_rm_echo(buf, &offset, "> ", 2) && SUCCEED != telnet_rm_echo(buf, &offset, "% ", 2)) { break; } } telnet_rm_echo(buf, &offset, "\n", 1); telnet_rm_prompt(buf, &offset); zabbix_log(LOG_LEVEL_DEBUG, "%s() stripped command output:'%.*s'", __function_name, offset, buf); if (MAX_BUFFER_LEN == offset) offset--; buf[offset] = '\0'; SET_STR_RESULT(result, convert_to_utf8(buf, offset, encoding)); ret = SUCCEED; fail: zbx_free(command_lf); zbx_free(command_crlf); zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret)); return ret; }
int PROC_MEM(AGENT_REQUEST *request, AGENT_RESULT *result) { char *procname, *proccomm, *param; int do_task, pagesize, count, i, proc_ok, comm_ok; double value = 0.0, memsize = 0; int proccount = 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_strdup(NULL, "Specified user does not exist.")); else SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot obtain user information: %s", zbx_strerror(errno))); return SYSINFO_RET_FAIL; } } 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); 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); if (ZBX_DO_AVG == do_task) SET_DBL_RESULT(result, proccount == 0 ? 0 : memsize/proccount); else SET_UI64_RESULT(result, memsize); return SYSINFO_RET_OK; }
static zbx_ipmi_host_t *init_ipmi_host(const char *ip, int port, int authtype, int privilege, const char *username, const char *password) { const char *__function_name = "init_ipmi_host"; zbx_ipmi_host_t *h; int ret; ipmi_open_option_t options[4]; struct timeval tv; char *addrs[1], *ports[1]; zabbix_log(LOG_LEVEL_DEBUG, "In %s() host:'[%s]:%d'", __function_name, ip, port); h = get_ipmi_host(ip, port, authtype, privilege, username, password); if (NULL != h) { if (1 == h->domain_up) { zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%p", __function_name, h); return h; } } else h = allocate_ipmi_host(ip, port, authtype, privilege, username, password); h->ret = SUCCEED; h->done = 0; addrs[0] = strdup(h->ip); ports[0] = zbx_dsprintf(NULL, "%d", h->port); if (0 != (ret = ipmi_ip_setup_con(addrs, ports, 1, h->authtype == -1 ? (unsigned int)IPMI_AUTHTYPE_DEFAULT : (unsigned int)h->authtype, (unsigned int)h->privilege, h->username, strlen(h->username), h->password, strlen(h->password), os_hnd, NULL, &h->con))) { h->err = zbx_dsprintf(h->err, "Cannot connect to IPMI host [%s]:%d." " ipmi_ip_setup_con() returned error 0x%x", h->ip, h->port, ret); h->ret = NETWORK_ERROR; goto out; } if (0 != (ret = h->con->start_con(h->con))) { h->err = zbx_dsprintf(h->err, "Cannot connect to IPMI host [%s]:%d." " start_con() returned error 0x%x", h->ip, h->port, ret); h->ret = NETWORK_ERROR; goto out; } options[0].option = IPMI_OPEN_OPTION_ALL; options[0].ival = 0; options[1].option = IPMI_OPEN_OPTION_SDRS; /* scan SDRs */ options[1].ival = 1; options[2].option = IPMI_OPEN_OPTION_IPMB_SCAN; /* scan IPMB bus to find out as much as possible */ options[2].ival = 1; options[3].option = IPMI_OPEN_OPTION_LOCAL_ONLY; /* scan only local resources */ options[3].ival = 1; if (0 != (ret = ipmi_open_domain("", &h->con, 1, setup_done, h, domain_up, h, options, ARRSIZE(options), NULL))) { h->err = zbx_dsprintf(h->err, "Cannot connect to IPMI host [%s]:%d. ipmi_open_domain() failed: %s", h->ip, h->port, zbx_strerror(ret)); h->ret = NETWORK_ERROR; goto out; } tv.tv_sec = 10; tv.tv_usec = 0; while (0 == h->done) os_hnd->perform_one_op(os_hnd, &tv); out: zbx_free(addrs[0]); zbx_free(ports[0]); zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%p", __function_name, h); return h; }
/****************************************************************************** * * * Function: housekeeping_cleanup * * * * Purpose: remove deleted items data * * * * Return value: number of rows deleted * * * * Author: Alexei Vladishev, Dmitry Borovikov * * * * Comments: sqlite3 does not use CONFIG_MAX_HOUSEKEEPER_DELETE, deletes all * * * ******************************************************************************/ static int housekeeping_cleanup() { const char *__function_name = "housekeeping_cleanup"; DB_HOUSEKEEPER housekeeper; DB_RESULT result; DB_ROW row; int d, deleted = 0; zbx_vector_uint64_t housekeeperids; char *sql = NULL, *table_name_esc; size_t sql_alloc = 0, sql_offset = 0; zbx_hk_cleanup_table_t *table; zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name); /* first handle the trivial case when history and trend housekeeping is disabled */ if (ZBX_HK_OPTION_DISABLED == hk_config.history_mode && ZBX_HK_OPTION_DISABLED == hk_config.trends_mode) goto out; zbx_vector_uint64_create(&housekeeperids); zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "select housekeeperid,tablename,field,value" " from housekeeper" " where tablename in ("); /* assemble list of tables excluded from housekeeping procedure */ for (table = hk_cleanup_tables; NULL != table->name; table++) { if (ZBX_HK_OPTION_ENABLED != *table->poption_mode) continue; table_name_esc = DBdyn_escape_string(table->name); zbx_chrcpy_alloc(&sql, &sql_alloc, &sql_offset, '\''); zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, table_name_esc); zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "',"); zbx_free(table_name_esc); } sql_offset--; /* order by tablename to effectively use DB cache */ zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ") order by tablename"); result = DBselect("%s", sql); while (NULL != (row = DBfetch(result))) { ZBX_STR2UINT64(housekeeper.housekeeperid, row[0]); housekeeper.tablename = row[1]; housekeeper.field = row[2]; ZBX_STR2UINT64(housekeeper.value, row[3]); if (0 == CONFIG_MAX_HOUSEKEEPER_DELETE) { d = DBexecute( "delete from %s" " where %s=" ZBX_FS_UI64, housekeeper.tablename, housekeeper.field, housekeeper.value); } else { #if defined(HAVE_IBM_DB2) || defined(HAVE_ORACLE) d = DBexecute( "delete from %s" " where %s=" ZBX_FS_UI64 " and rownum<=%d", housekeeper.tablename, housekeeper.field, housekeeper.value, CONFIG_MAX_HOUSEKEEPER_DELETE); #elif defined(HAVE_MYSQL) d = DBexecute( "delete from %s" " where %s=" ZBX_FS_UI64 " limit %d", housekeeper.tablename, housekeeper.field, housekeeper.value, CONFIG_MAX_HOUSEKEEPER_DELETE); #elif defined(HAVE_POSTGRESQL) d = DBexecute( "delete from %s" " where ctid = any(array(select ctid from %s" " where %s=" ZBX_FS_UI64 " limit %d))", housekeeper.tablename, housekeeper.tablename, housekeeper.field, housekeeper.value, CONFIG_MAX_HOUSEKEEPER_DELETE); #elif defined(HAVE_SQLITE3) d = 0; #endif } if (ZBX_DB_OK <= d) { if (0 == CONFIG_MAX_HOUSEKEEPER_DELETE || CONFIG_MAX_HOUSEKEEPER_DELETE > d) zbx_vector_uint64_append(&housekeeperids, housekeeper.housekeeperid); deleted += d; } } DBfree_result(result); if (0 != housekeeperids.values_num) { zbx_vector_uint64_sort(&housekeeperids, ZBX_DEFAULT_UINT64_COMPARE_FUNC); sql_offset = 0; zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "delete from housekeeper where"); DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "housekeeperid", housekeeperids.values, housekeeperids.values_num); DBexecute("%s", sql); } zbx_free(sql); zbx_vector_uint64_destroy(&housekeeperids); out: zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%d", __function_name, deleted); return deleted; }
/****************************************************************************** * * * Function: send_list_of_active_checks_json * * * * Purpose: send list of active checks to the host * * * * Parameters: sock - open socket of server-agent connection * * json - request buffer * * * * Return value: SUCCEED - list of active checks sent succesfully * * FAIL - an error occured * * * * Author: Aleksander Vladishev * * * * Comments: * * * ******************************************************************************/ int send_list_of_active_checks_json(zbx_sock_t *sock, struct zbx_json_parse *jp) { char host[HOST_HOST_LEN_MAX], *name_esc, params[MAX_STRING_LEN], pattern[MAX_STRING_LEN], tmp[32]; DB_RESULT result; DB_ROW row; DB_ITEM item; struct zbx_json json; int res = FAIL; zbx_uint64_t hostid; char error[MAX_STRING_LEN]; char **regexp = NULL; int regexp_alloc = 32; int regexp_num = 0, n; char *sql = NULL; int sql_alloc = 2048; int sql_offset; zabbix_log(LOG_LEVEL_DEBUG, "In send_list_of_active_checks_json()"); if (FAIL == zbx_json_value_by_name(jp, ZBX_PROTO_TAG_HOST, host, sizeof(host))) { zbx_snprintf(error, MAX_STRING_LEN, "%s", zbx_json_strerror()); goto out; } if (FAIL == get_hostid_by_host(host, &hostid, error)) goto out; regexp = zbx_malloc(regexp, regexp_alloc); sql = zbx_malloc(sql, sql_alloc); name_esc = DBdyn_escape_string(host); sql_offset = 0; zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, 1024, "select %s where i.hostid=h.hostid and h.status=%d and i.type=%d and h.hostid=" ZBX_FS_UI64 " and h.proxy_hostid=0", ZBX_SQL_ITEM_SELECT, HOST_STATUS_MONITORED, ITEM_TYPE_ZABBIX_ACTIVE, hostid); if (0 != CONFIG_REFRESH_UNSUPPORTED) zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, 256, " and (i.status=%d or (i.status=%d and i.nextcheck<=%d))", ITEM_STATUS_ACTIVE, ITEM_STATUS_NOTSUPPORTED, time(NULL)); else zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, 256, " and i.status=%d", ITEM_STATUS_ACTIVE); zbx_free(name_esc); zbx_json_init(&json, ZBX_JSON_STAT_BUF_LEN); zbx_json_addstring(&json, ZBX_PROTO_TAG_RESPONSE, ZBX_PROTO_VALUE_SUCCESS, ZBX_JSON_TYPE_STRING); zbx_json_addarray(&json, ZBX_PROTO_TAG_DATA); result = DBselect("%s", sql); while (NULL != (row = DBfetch(result))) { DBget_item_from_db(&item, row); zbx_json_addobject(&json, NULL); zbx_json_addstring(&json, ZBX_PROTO_TAG_KEY, item.key, ZBX_JSON_TYPE_STRING); if (0 != strcmp(item.key, item.key_orig)) zbx_json_addstring(&json, ZBX_PROTO_TAG_KEY_ORIG, item.key_orig, ZBX_JSON_TYPE_STRING); zbx_snprintf(tmp, sizeof(tmp), "%d", item.delay); zbx_json_addstring(&json, ZBX_PROTO_TAG_DELAY, tmp, ZBX_JSON_TYPE_STRING); zbx_snprintf(tmp, sizeof(tmp), "%d", item.lastlogsize); zbx_json_addstring(&json, ZBX_PROTO_TAG_LOGLASTSIZE, tmp, ZBX_JSON_TYPE_STRING); zbx_json_close(&json); /* Special processing for log[] and eventlog[] items */ do { /* simple try realization */ if (0 != strncmp(item.key, "log[", 4) && 0 != strncmp(item.key, "eventlog[", 9)) break; if (2 != parse_command(item.key, NULL, 0, params, MAX_STRING_LEN)) break;; if (0 != get_param(params, 2, pattern, sizeof(pattern))) break; if (*pattern != '@') break; for (n = 0; n < regexp_num; n++) if (0 == strcmp(regexp[n], pattern + 1)) break; if (n != regexp_num) break; if (regexp_num == regexp_alloc) { regexp_alloc += 32; regexp = zbx_realloc(regexp, regexp_alloc); } regexp[regexp_num++] = strdup(pattern + 1); } while (0); /* simple try realization */ } zbx_json_close(&json); DBfree_result(result); if (0 != regexp_num) { zbx_json_addarray(&json, ZBX_PROTO_TAG_REGEXP); sql_offset = 0; zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, 512, "select r.name,e.expression,e.expression_type,e.exp_delimiter,e.case_sensitive" " from regexps r,expressions e where r.regexpid=e.regexpid and r.name in ("); for (n = 0; n < regexp_num; n++) { name_esc = DBdyn_escape_string(regexp[n]); zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, 512, "%s'%s'", n == 0 ? "" : ",", name_esc); zbx_free(name_esc); zbx_free(regexp[n]); } zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, 8, ")"); result = DBselect("%s", sql); while (NULL != (row = DBfetch(result))) { zbx_json_addobject(&json, NULL); zbx_json_addstring(&json, "name", row[0], ZBX_JSON_TYPE_STRING); zbx_json_addstring(&json, "expression", row[1], ZBX_JSON_TYPE_STRING); zbx_json_addstring(&json, "expression_type", row[2], ZBX_JSON_TYPE_INT); zbx_json_addstring(&json, "exp_delimiter", row[3], ZBX_JSON_TYPE_STRING); zbx_json_addstring(&json, "case_sensitive", row[4], ZBX_JSON_TYPE_INT); zbx_json_close(&json); } DBfree_result(result); } zbx_free(regexp); zabbix_log(LOG_LEVEL_DEBUG, "Sending [%s]", json.buffer); if (SUCCEED != zbx_tcp_send_raw(sock, json.buffer)) zbx_snprintf(error, MAX_STRING_LEN, "%s", zbx_tcp_strerror()); else res = SUCCEED; zbx_json_free(&json); zbx_free(sql); out: if (FAIL == res) zabbix_log(LOG_LEVEL_WARNING, "Send list of active checks to [%s] failed: %s", get_ip_by_socket(sock), error); return res; }
/****************************************************************************** * * * Function: DMcolect_table_data * * * * Purpose: obtain configuration changes to required node * * * * Return value: SUCCESS - processed successfully * * FAIL - an error occurred * * * * Author: Alexander Vladishev * * * * Comments: the changes are collected into data parameter * * * ******************************************************************************/ static void DMcollect_table_data(int nodeid, unsigned char dest_nodetype, const ZBX_TABLE *table, char **data, size_t *data_alloc, size_t *data_offset) { #define ZBX_REC_UPDATED '1' #define ZBX_REC_DELETED '2' const char *__function_name = "DMcolect_table_data"; DB_RESULT result; DB_RESULT result2; DB_ROW row; DB_ROW row2; const char *s; char *hex = NULL, *sql = NULL, sync[128], *curr_cksum, *d_curr_cksum, *prev_cksum, *d_prev_cksum; size_t sql_alloc = 8 * ZBX_KIBIBYTE, sql_offset = 0, hex_alloc = ZBX_KIBIBYTE, rowlen; int f, j; zabbix_log(LOG_LEVEL_DEBUG, "In %s() table:'%s'", __function_name, table->table); hex = zbx_malloc(hex, hex_alloc); sql = zbx_malloc(sql, sql_alloc); result = DBselect( /* new records */ "select curr.recordid,prev.cksum,curr.cksum,curr.sync" " from node_cksum curr" " left join node_cksum prev" " on prev.nodeid=curr.nodeid" " and prev.tablename=curr.tablename" " and prev.recordid=curr.recordid" " and prev.cksumtype=%d" " where curr.nodeid=%d" " and curr.tablename='%s'" " and curr.cksumtype=%d" " and prev.tablename is null" " union all " /* updated records */ "select curr.recordid,prev.cksum,curr.cksum,prev.sync" " from node_cksum curr,node_cksum prev" " where curr.nodeid=prev.nodeid" " and curr.tablename=prev.tablename" " and curr.recordid=prev.recordid" " and curr.nodeid=%d" " and curr.tablename='%s'" " and curr.cksumtype=%d" " and prev.cksumtype=%d" " union all " /* deleted records */ "select prev.recordid,prev.cksum,curr.cksum,prev.sync" " from node_cksum prev" " left join node_cksum curr" " on curr.nodeid=prev.nodeid" " and curr.tablename=prev.tablename" " and curr.recordid=prev.recordid" " and curr.cksumtype=%d" " where prev.nodeid=%d" " and prev.tablename='%s'" " and prev.cksumtype=%d" " and curr.tablename is null", NODE_CKSUM_TYPE_OLD, nodeid, table->table, NODE_CKSUM_TYPE_NEW, nodeid, table->table, NODE_CKSUM_TYPE_NEW, NODE_CKSUM_TYPE_OLD, NODE_CKSUM_TYPE_NEW, nodeid, table->table, NODE_CKSUM_TYPE_OLD); while (NULL != (row = DBfetch(result))) { memset(sync, ' ', sizeof(sync)); memcpy(sync, row[3], strlen(row[3])); s = sync; /* special (simpler) processing for operation DELETE */ if (SUCCEED == DBis_null(row[2])) { if (ZBX_REC_DELETED != s[dest_nodetype]) { zbx_snprintf_alloc(data, data_alloc, data_offset, "\n%s%c%s%c%d", table->table, ZBX_DM_DELIMITER, row[0], ZBX_DM_DELIMITER, NODE_CONFIGLOG_OP_DELETE); } continue; } prev_cksum = (SUCCEED == DBis_null(row[1]) ? NULL : row[1]); curr_cksum = row[2]; f = 0; sql_offset = 0; zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "select "); do { while (0 == (table->fields[f].flags & ZBX_SYNC)) f++; d_prev_cksum = NULL; if (NULL != prev_cksum && NULL != (d_prev_cksum = strchr(prev_cksum, ','))) *d_prev_cksum = '\0'; d_curr_cksum = NULL; if (NULL != curr_cksum && NULL != (d_curr_cksum = strchr(curr_cksum, ','))) *d_curr_cksum = '\0'; if (NULL == prev_cksum || NULL == curr_cksum || ZBX_REC_UPDATED != s[dest_nodetype] || 0 != strcmp(prev_cksum, curr_cksum)) { zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%s,", table->fields[f].name); if (table->fields[f].type == ZBX_TYPE_BLOB) { zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "length(%s),", table->fields[f].name); } } /* "host_inventory" table has more than 64 fields */ /* remaining fields are processed as one */ if (126 > s - sync) s += 2; f++; if (d_prev_cksum != NULL) { *d_prev_cksum = ','; prev_cksum = d_prev_cksum + 1; } else prev_cksum = NULL; if (d_curr_cksum != NULL) { *d_curr_cksum = ','; curr_cksum = d_curr_cksum + 1; } else curr_cksum = NULL; } while (NULL != d_prev_cksum || NULL != d_curr_cksum); if (sql[sql_offset - 1] != ',') continue; sql_offset--; zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, " from %s where %s=%s", table->table, table->recid, row[0]); result2 = DBselect("%s", sql); if (NULL == (row2 = DBfetch(result2))) goto out; zbx_snprintf_alloc(data, data_alloc, data_offset, "\n%s%c%s%c%d", table->table, ZBX_DM_DELIMITER, row[0], ZBX_DM_DELIMITER, NODE_CONFIGLOG_OP_UPDATE); prev_cksum = DBis_null(row[1]) == SUCCEED ? NULL : row[1]; curr_cksum = row[2]; s = sync; f = 0; j = 0; do { while (0 == (table->fields[f].flags & ZBX_SYNC)) f++; d_prev_cksum = NULL; if (NULL != prev_cksum && NULL != (d_prev_cksum = strchr(prev_cksum, ','))) *d_prev_cksum = '\0'; d_curr_cksum = NULL; if (NULL != curr_cksum && NULL != (d_curr_cksum = strchr(curr_cksum, ','))) *d_curr_cksum = '\0'; if (NULL == prev_cksum || NULL == curr_cksum || ZBX_REC_UPDATED != s[dest_nodetype] || 0 != strcmp(prev_cksum, curr_cksum)) { /* fieldname, type */ zbx_snprintf_alloc(data, data_alloc, data_offset, "%c%s%c%d%c", ZBX_DM_DELIMITER, table->fields[f].name, ZBX_DM_DELIMITER, table->fields[f].type, ZBX_DM_DELIMITER); /* value */ if (SUCCEED == DBis_null(row2[j])) { zbx_strcpy_alloc(data, data_alloc, data_offset, "NULL"); } else if (ZBX_TYPE_INT == table->fields[f].type || ZBX_TYPE_UINT == table->fields[f].type || ZBX_TYPE_ID == table->fields[f].type || ZBX_TYPE_FLOAT == table->fields[f].type) { zbx_strcpy_alloc(data, data_alloc, data_offset, row2[j]); } else { if (table->fields[f].type == ZBX_TYPE_BLOB) rowlen = (size_t)atoi(row2[j + 1]); else rowlen = strlen(row2[j]); zbx_binary2hex((u_char *)row2[j], rowlen, &hex, &hex_alloc); zbx_strcpy_alloc(data, data_alloc, data_offset, hex); } if (table->fields[f].type == ZBX_TYPE_BLOB) j += 2; else j++; } /* "host_inventory" table has more than 64 fields */ /* remaining fields are processed as one */ if (126 > s - sync) s += 2; f++; if (d_prev_cksum != NULL) { *d_prev_cksum = ','; prev_cksum = d_prev_cksum + 1; } else prev_cksum = NULL; if (d_curr_cksum != NULL) { *d_curr_cksum = ','; curr_cksum = d_curr_cksum + 1; } else curr_cksum = NULL; } while (NULL != d_prev_cksum || NULL != d_curr_cksum); out: DBfree_result(result2); } DBfree_result(result); zbx_free(hex); zbx_free(sql); zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name); }
/****************************************************************************** * * * Function: send_list_of_active_checks * * * * Purpose: send list of active checks to the host * * * * Parameters: sock - open socket of server-agent connection * * request - request buffer * * * * Return value: SUCCEED - list of active checks sent succesfully * * FAIL - an error occured * * * * Author: Alexei Vladishev * * * * Comments: format of the request: ZBX_GET_ACTIVE_CHECKS\n<host name>\n * * format of the list: key:delay:last_log_size * * * ******************************************************************************/ int send_list_of_active_checks(zbx_sock_t *sock, char *request) { char *host = NULL, *p; DB_RESULT result; DB_ROW row; char *buffer = NULL; int buffer_alloc = 2048; int buffer_offset = 0; int res = FAIL; zbx_uint64_t hostid; char error[MAX_STRING_LEN]; zabbix_log(LOG_LEVEL_DEBUG, "In send_list_of_active_checks()"); if (NULL != (host = strchr(request, '\n'))) { host++; if (NULL != (p = strchr(host, '\n'))) *p = '\0'; } else { zbx_snprintf(error, MAX_STRING_LEN, "host is null"); goto out; } if (FAIL == get_hostid_by_host(host, &hostid, error)) goto out; buffer = zbx_malloc(buffer, buffer_alloc); buffer_offset = 0; zbx_snprintf_alloc(&buffer, &buffer_alloc, &buffer_offset, 1024, "select i.key_,i.delay,i.lastlogsize from items i,hosts h" " where i.hostid=h.hostid and h.status=%d and i.type=%d and h.hostid=" ZBX_FS_UI64 " and h.proxy_hostid=0", HOST_STATUS_MONITORED, ITEM_TYPE_ZABBIX_ACTIVE, hostid); if (0 != CONFIG_REFRESH_UNSUPPORTED) { zbx_snprintf_alloc(&buffer, &buffer_alloc, &buffer_offset, 256, " and (i.status=%d or (i.status=%d and i.nextcheck<=%d))", ITEM_STATUS_ACTIVE, ITEM_STATUS_NOTSUPPORTED, time(NULL)); } else { zbx_snprintf_alloc(&buffer, &buffer_alloc, &buffer_offset, 256, " and i.status=%d", ITEM_STATUS_ACTIVE); } result = DBselect("%s", buffer); buffer_offset = 0; while (NULL != (row = DBfetch(result))) { zbx_snprintf_alloc(&buffer, &buffer_alloc, &buffer_offset, 512, "%s:%s:%s\n", row[0], row[1], row[2]); } DBfree_result(result); zbx_snprintf_alloc(&buffer, &buffer_alloc, &buffer_offset, 512, "ZBX_EOF\n"); zabbix_log(LOG_LEVEL_DEBUG, "Sending [%s]", buffer); if (SUCCEED != zbx_tcp_send_raw(sock, buffer)) zbx_snprintf(error, MAX_STRING_LEN, "%s", zbx_tcp_strerror()); else res = SUCCEED; zbx_free(buffer); out: if (FAIL == res) zabbix_log(LOG_LEVEL_WARNING, "Send list of active checks to [%s] failed: %s", get_ip_by_socket(sock), error); return res; }
/****************************************************************************** * * * Function: update_checksums * * * * Purpose: overwrite old checksums with new ones * * * * Parameters: * * * * Return value: SUCCESS - calculated successfully * * FAIL - an error occurred * * * * Author: Alexei Vladishev * * * * Comments: * * * ******************************************************************************/ int update_checksums(int nodeid, int synked_nodetype, int synked, const char *tablename, const zbx_uint64_t id, const char *fields) { const char *__function_name = "update_checksums"; char *r[2], *d[2], sync[129], *s; char c[2], sql[2][256]; char cksum[32 * 72 + 72], *ck; char *exsql = NULL; size_t exsql_alloc = 64 * ZBX_KIBIBYTE, exsql_offset = 0; int cksumtype; DB_RESULT result; DB_ROW row; int f; const ZBX_TABLE *table; zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name); exsql = zbx_malloc(exsql, exsql_alloc); DBbegin(); DBbegin_multiple_update(&exsql, &exsql_alloc, &exsql_offset); c[0] = SUCCEED == synked ? '1' : ' '; /* for new and updated records */ c[1] = SUCCEED == synked ? '2' : ' '; /* for deleted records */ if (NULL != tablename) { zbx_snprintf(sql[0], sizeof(sql[0]), " and curr.tablename='%s' and curr.recordid=" ZBX_FS_UI64, tablename, id); zbx_snprintf(sql[1], sizeof(sql[1]), " and prev.tablename='%s' and prev.recordid=" ZBX_FS_UI64, tablename, id); } else { *sql[0] = '\0'; *sql[1] = '\0'; } result = DBselect( /* new records */ "select curr.tablename,curr.recordid,prev.cksum,curr.cksum,NULL" " from node_cksum curr" " left join node_cksum prev" " on prev.nodeid=curr.nodeid" " and prev.tablename=curr.tablename" " and prev.recordid=curr.recordid" " and prev.cksumtype=%d" " where curr.nodeid=%d" " and curr.cksumtype=%d" " and prev.tablename is null%s" " union all " /* updated records */ "select curr.tablename,curr.recordid,prev.cksum,curr.cksum,prev.sync" " from node_cksum curr, node_cksum prev" " where curr.nodeid=%d" " and prev.nodeid=curr.nodeid" " and curr.tablename=prev.tablename" " and curr.recordid=prev.recordid" " and curr.cksumtype=%d" " and prev.cksumtype=%d%s" " union all " /* deleted records */ "select prev.tablename,prev.recordid,prev.cksum,curr.cksum,prev.sync" " from node_cksum prev" " left join node_cksum curr" " on curr.nodeid=prev.nodeid" " and curr.tablename=prev.tablename" " and curr.recordid=prev.recordid" " and curr.cksumtype=%d" " where prev.nodeid=%d" " and prev.cksumtype=%d" " and curr.tablename is null%s", NODE_CKSUM_TYPE_OLD, nodeid, NODE_CKSUM_TYPE_NEW, sql[0], nodeid, NODE_CKSUM_TYPE_NEW, NODE_CKSUM_TYPE_OLD, sql[0], NODE_CKSUM_TYPE_NEW, nodeid, NODE_CKSUM_TYPE_OLD, sql[1]); while (NULL != (row = DBfetch(result))) { if (NULL == (table = DBget_table(row[0]))) { zabbix_log(LOG_LEVEL_WARNING, "cannot find table [%s]", row[0]); continue; } memset(sync, ' ', sizeof(sync)); if (FAIL == DBis_null(row[4])) memcpy(sync, row[4], strlen(row[4])); s = sync; ck = cksum; *ck = '\0'; /* special (simpler) processing for operation DELETE */ if (SUCCEED == DBis_null(row[3])) { if (SUCCEED == synked) s[synked_nodetype] = c[1]; if ((0 == CONFIG_MASTER_NODEID || s[1] == c[1]) && (CONFIG_NODEID == nodeid || s[0] == c[1])) { zbx_snprintf_alloc(&exsql, &exsql_alloc, &exsql_offset, "delete from node_cksum" " where nodeid=%d" " and cksumtype=%d" " and tablename='%s'" " and recordid=%s;\n", nodeid, NODE_CKSUM_TYPE_OLD, row[0], row[1]); DBexecute_overflowed_sql(&exsql, &exsql_alloc, &exsql_offset); continue; } s += 2; } else { r[0] = SUCCEED == DBis_null(row[2]) ? NULL : row[2]; r[1] = row[3]; f = 0; do { while ((table->fields[f].flags & ZBX_SYNC) == 0) f++; /* "host_inventory" table has more than 64 fields */ /* remaining fields are processed as one */ if (128 == s - sync) s -= 2; d[0] = NULL; d[1] = NULL; if (NULL != r[0] && NULL != (d[0] = strchr(r[0], ','))) *d[0] = '\0'; if (NULL != r[1] && NULL != (d[1] = strchr(r[1], ','))) *d[1] = '\0'; if (NULL == tablename || SUCCEED == str_in_list(fields, table->fields[f].name, ',')) { ck += zbx_snprintf(ck, 64, "%s,", NULL != r[1] ? r[1] : r[0]); if (NULL == r[0] || NULL == r[1] || 0 != strcmp(r[0], r[1])) { s[0] = s[1] = ' '; s[synked_nodetype] = c[0]; } else { if (SUCCEED == synked) s[synked_nodetype] = c[0]; } } else ck += zbx_snprintf(ck, 64, "%s,", NULL != r[0] ? r[0] : ""); s += 2; f++; if (d[0] != NULL) { *d[0] = ','; r[0] = d[0] + 1; } else r[0] = NULL; if (d[1] != NULL) { *d[1] = ','; r[1] = d[1] + 1; } else r[1] = NULL; } while (d[0] != NULL || d[1] != NULL); *--ck = '\0'; } *s = '\0'; if (SUCCEED == DBis_null(row[2]) || SUCCEED == DBis_null(row[3]) || 0 != strcmp(row[4], sync) || 0 != strcmp(row[2], row[3])) { cksumtype = (DBis_null(row[2]) == SUCCEED) ? NODE_CKSUM_TYPE_NEW : NODE_CKSUM_TYPE_OLD; zbx_snprintf_alloc(&exsql, &exsql_alloc, &exsql_offset, "update node_cksum" " set cksumtype=%d," "cksum='%s'," "sync='%s'" " where nodeid=%d" " and cksumtype=%d" " and tablename='%s'" " and recordid=%s;\n", NODE_CKSUM_TYPE_OLD, cksum, sync, nodeid, cksumtype, row[0], row[1]); DBexecute_overflowed_sql(&exsql, &exsql_alloc, &exsql_offset); } } DBfree_result(result); DBend_multiple_update(&exsql, &exsql_alloc, &exsql_offset); if (exsql_offset > 16) /* In ORACLE always present begin..end; */ DBexecute("%s", exsql); zbx_free(exsql); DBcommit(); zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name); return SUCCEED; }
/****************************************************************************** * * * Function: zbx_db_connect * * * * Purpose: connect to the database * * * * Return value: ZBX_DB_OK - succefully connected * * ZBX_DB_DOWN - database is down * * ZBX_DB_FAIL - failed to connect * * * ******************************************************************************/ int zbx_db_connect(char *host, char *user, char *password, char *dbname, char *dbschema, char *dbsocket, int port) { int ret = ZBX_DB_OK; #if defined(HAVE_IBM_DB2) char *connect = NULL; #elif defined(HAVE_ORACLE) char *connect = NULL; sword err = OCI_SUCCESS; #elif defined(HAVE_POSTGRESQL) char *cport = NULL; DB_RESULT result; DB_ROW row; #endif txn_init = 1; assert(NULL != host); #if defined(HAVE_IBM_DB2) connect = zbx_strdup(connect, "PROTOCOL=TCPIP;"); if ('\0' != *host) connect = zbx_strdcatf(connect, "HOSTNAME=%s;", host); if (NULL != dbname && '\0' != *dbname) connect = zbx_strdcatf(connect, "DATABASE=%s;", dbname); if (0 != port) connect = zbx_strdcatf(connect, "PORT=%d;", port); if (NULL != user && '\0' != *user) connect = zbx_strdcatf(connect, "UID=%s;", user); if (NULL != password && '\0' != *password) connect = zbx_strdcatf(connect, "PWD=%s;", password); memset(&ibm_db2, 0, sizeof(ibm_db2)); /* allocate an environment handle */ if (SUCCEED != zbx_ibm_db2_success(SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &ibm_db2.henv))) ret = ZBX_DB_FAIL; /* set attribute to enable application to run as ODBC 3.0 application; */ /* recommended for pure IBM DB2 CLI, but not required */ if (ZBX_DB_OK == ret && SUCCEED != zbx_ibm_db2_success(SQLSetEnvAttr(ibm_db2.henv, SQL_ATTR_ODBC_VERSION, (void *)SQL_OV_ODBC3, 0))) ret = ZBX_DB_FAIL; /* allocate a database connection handle */ if (ZBX_DB_OK == ret && SUCCEED != zbx_ibm_db2_success(SQLAllocHandle(SQL_HANDLE_DBC, ibm_db2.henv, &ibm_db2.hdbc))) ret = ZBX_DB_FAIL; /* connect to the database */ if (ZBX_DB_OK == ret && SUCCEED != zbx_ibm_db2_success(SQLDriverConnect(ibm_db2.hdbc, NULL, (SQLCHAR *)connect, SQL_NTS, NULL, 0, NULL, SQL_DRIVER_NOPROMPT))) ret = ZBX_DB_FAIL; /* set autocommit on */ if (ZBX_DB_OK == ret && SUCCEED != zbx_ibm_db2_success(SQLSetConnectAttr(ibm_db2.hdbc, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)SQL_AUTOCOMMIT_ON, SQL_NTS))) ret = ZBX_DB_DOWN; /* we do not generate vendor escape clause sequences */ if (ZBX_DB_OK == ret && SUCCEED != zbx_ibm_db2_success(SQLSetConnectAttr(ibm_db2.hdbc, SQL_ATTR_NOSCAN, (SQLPOINTER)SQL_NOSCAN_ON, SQL_NTS))) ret = ZBX_DB_DOWN; /* set current schema */ if (NULL != dbschema && '\0' != *dbschema && ZBX_DB_OK == ret) { char *dbschema_esc; dbschema_esc = DBdyn_escape_string(dbschema); DBexecute("set current schema='%s'", dbschema_esc); zbx_free(dbschema_esc); } /* output error information */ if (ZBX_DB_OK != ret) { zbx_ibm_db2_log_errors(SQL_HANDLE_ENV, ibm_db2.henv); zbx_ibm_db2_log_errors(SQL_HANDLE_DBC, ibm_db2.hdbc); zbx_db_close(); } zbx_free(connect); #elif defined(HAVE_MYSQL) conn = mysql_init(NULL); if (!mysql_real_connect(conn, host, user, password, dbname, port, dbsocket, CLIENT_MULTI_STATEMENTS)) { zabbix_errlog(ERR_Z3001, dbname, mysql_errno(conn), mysql_error(conn)); ret = ZBX_DB_FAIL; } if (ZBX_DB_OK == ret) { if (0 != mysql_select_db(conn, dbname)) { zabbix_errlog(ERR_Z3001, dbname, mysql_errno(conn), mysql_error(conn)); ret = ZBX_DB_FAIL; } } if (ZBX_DB_OK == ret) { DBexecute("set names utf8"); } if (ZBX_DB_FAIL == ret) { switch (mysql_errno(conn)) { case CR_CONN_HOST_ERROR: case CR_SERVER_GONE_ERROR: case CR_CONNECTION_ERROR: case CR_SERVER_LOST: case CR_UNKNOWN_HOST: case ER_SERVER_SHUTDOWN: case ER_ACCESS_DENIED_ERROR: /* wrong user or password */ case ER_ILLEGAL_GRANT_FOR_TABLE: /* user without any privileges */ case ER_TABLEACCESS_DENIED_ERROR: /* user without some privilege */ case ER_UNKNOWN_ERROR: ret = ZBX_DB_DOWN; break; default: break; } } #elif defined(HAVE_ORACLE) #if defined(HAVE_GETENV) && defined(HAVE_PUTENV) if (NULL == getenv("NLS_LANG")) putenv("NLS_LANG=.UTF8"); #endif memset(&oracle, 0, sizeof(oracle)); /* connection string format: [//]host[:port][/service name] */ if ('\0' != *host) { connect = zbx_strdcatf(connect, "//%s", host); if (0 != port) connect = zbx_strdcatf(connect, ":%d", port); if (NULL != dbname && '\0' != *dbname) connect = zbx_strdcatf(connect, "/%s", dbname); } else ret = ZBX_DB_FAIL; if (ZBX_DB_OK == ret) { /* initialize environment */ err = OCIEnvCreate((OCIEnv **)&oracle.envhp, (ub4)OCI_DEFAULT, (dvoid *)0, (dvoid * (*)(dvoid *,size_t))0, (dvoid * (*)(dvoid *, dvoid *, size_t))0, (void (*)(dvoid *, dvoid *))0, (size_t)0, (dvoid **)0); if (OCI_SUCCESS != err) { zabbix_errlog(ERR_Z3001, connect, err, zbx_oci_error(err)); ret = ZBX_DB_FAIL; } } if (ZBX_DB_OK == ret) { /* allocate an error handle */ (void)OCIHandleAlloc((dvoid *)oracle.envhp, (dvoid **)&oracle.errhp, OCI_HTYPE_ERROR, (size_t)0, (dvoid **)0); /* get the session */ err = OCILogon2(oracle.envhp, oracle.errhp, &oracle.svchp, (text *)user, (ub4)(NULL != user ? strlen(user) : 0), (text *)password, (ub4)(NULL != password ? strlen(password) : 0), (text *)connect, (ub4)strlen(connect), OCI_DEFAULT); if (OCI_SUCCESS != err) { zabbix_errlog(ERR_Z3001, connect, err, zbx_oci_error(err)); ret = ZBX_DB_DOWN; } else { err = OCIAttrGet((void *)oracle.svchp, OCI_HTYPE_SVCCTX, (void *)&oracle.srvhp, (ub4 *)0, OCI_ATTR_SERVER, oracle.errhp); if (OCI_SUCCESS != err) { zabbix_errlog(ERR_Z3001, connect, err, zbx_oci_error(err)); ret = ZBX_DB_DOWN; } } } zbx_free(connect); if (ZBX_DB_OK != ret) zbx_db_close(); #elif defined(HAVE_POSTGRESQL) if (0 != port) cport = zbx_dsprintf(cport, "%d", port); conn = PQsetdbLogin(host, cport, NULL, NULL, dbname, user, password); zbx_free(cport); /* check to see that the backend connection was successfully made */ if (CONNECTION_OK != PQstatus(conn)) { zabbix_errlog(ERR_Z3001, dbname, 0, PQerrorMessage(conn)); ret = ZBX_DB_DOWN; } else { result = DBselect("select oid from pg_type where typname='bytea'"); if (NULL != (row = DBfetch(result))) ZBX_PG_BYTEAOID = atoi(row[0]); DBfree_result(result); } #ifdef HAVE_FUNCTION_PQSERVERVERSION ZBX_PG_SVERSION = PQserverVersion(conn); zabbix_log(LOG_LEVEL_DEBUG, "PostgreSQL Server version: %d", ZBX_PG_SVERSION); #endif if (80100 <= ZBX_PG_SVERSION) { /* disable "nonstandard use of \' in a string literal" warning */ DBexecute("set escape_string_warning to off"); result = DBselect("show standard_conforming_strings"); if (NULL != (row = DBfetch(result))) ZBX_PG_ESCAPE_BACKSLASH = (0 == strcmp(row[0], "off")); DBfree_result(result); } if (90000 <= ZBX_PG_SVERSION) { /* change the output format for values of type bytea from hex (the default) to escape */ DBexecute("set bytea_output=escape"); } #elif defined(HAVE_SQLITE3) #ifdef HAVE_FUNCTION_SQLITE3_OPEN_V2 if (SQLITE_OK != sqlite3_open_v2(dbname, &conn, SQLITE_OPEN_READWRITE, NULL)) #else if (SQLITE_OK != sqlite3_open(dbname, &conn)) #endif { zabbix_errlog(ERR_Z3001, dbname, 0, sqlite3_errmsg(conn)); sqlite3_close(conn); ret = ZBX_DB_DOWN; } else { char *p, *path; /* do not return SQLITE_BUSY immediately, wait for N ms */ sqlite3_busy_timeout(conn, SEC_PER_MIN * 1000); path = strdup(dbname); if (NULL != (p = strrchr(path, '/'))) *++p = '\0'; else *path = '\0'; DBexecute("PRAGMA synchronous = 0"); /* OFF */ DBexecute("PRAGMA temp_store = 2"); /* MEMORY */ DBexecute("PRAGMA temp_store_directory = '%s'", path); zbx_free(path); } #endif /* HAVE_SQLITE3 */ txn_init = 0; return ret; }