1 /*
2 ** Zabbix
3 ** Copyright (C) 2001-2021 Zabbix SIA
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 **/
19
20 #include "common.h"
21 #include "sysinfo.h"
22 #include "stats.h"
23 #include "diskdevices.h"
24
25 #define ZBX_DEV_PFX "/dev/"
26 #define ZBX_DEV_READ 0
27 #define ZBX_DEV_WRITE 1
28
29 static struct statinfo *si = NULL;
30
get_diskstat(const char * devname,zbx_uint64_t * dstat)31 int get_diskstat(const char *devname, zbx_uint64_t *dstat)
32 {
33 int i;
34 struct devstat *ds = NULL;
35 int ret = FAIL;
36 char dev[DEVSTAT_NAME_LEN + 10];
37 const char *pd; /* pointer to device name without '/dev/' prefix, e.g. 'da0' */
38
39 assert(devname);
40
41 for (i = 0; i < ZBX_DSTAT_MAX; i++)
42 dstat[i] = (zbx_uint64_t)__UINT64_C(0);
43
44 if (NULL == si)
45 {
46 si = (struct statinfo *)zbx_malloc(si, sizeof(struct statinfo));
47 si->dinfo = (struct devinfo *)zbx_malloc(NULL, sizeof(struct devinfo));
48 memset(si->dinfo, 0, sizeof(struct devinfo));
49 }
50
51 pd = devname;
52
53 /* skip prefix ZBX_DEV_PFX, if present */
54 if ('\0' != *devname && 0 == strncmp(pd, ZBX_DEV_PFX, ZBX_CONST_STRLEN(ZBX_DEV_PFX)))
55 pd += ZBX_CONST_STRLEN(ZBX_DEV_PFX);
56
57 #if DEVSTAT_USER_API_VER >= 5
58 if (-1 == devstat_getdevs(NULL, si))
59 #else
60 if (-1 == getdevs(si))
61 #endif
62 return FAIL;
63
64 for (i = 0; i < si->dinfo->numdevs; i++)
65 {
66 ds = &si->dinfo->devices[i];
67
68 /* empty '*devname' string means adding statistics for all disks together */
69 if ('\0' != *devname)
70 {
71 zbx_snprintf(dev, sizeof(dev), "%s%d", ds->device_name, ds->unit_number);
72 if (0 != strcmp(dev, pd))
73 continue;
74 }
75
76 #if DEVSTAT_USER_API_VER >= 5
77 dstat[ZBX_DSTAT_R_OPER] += (zbx_uint64_t)ds->operations[DEVSTAT_READ];
78 dstat[ZBX_DSTAT_W_OPER] += (zbx_uint64_t)ds->operations[DEVSTAT_WRITE];
79 dstat[ZBX_DSTAT_R_BYTE] += (zbx_uint64_t)ds->bytes[DEVSTAT_READ];
80 dstat[ZBX_DSTAT_W_BYTE] += (zbx_uint64_t)ds->bytes[DEVSTAT_WRITE];
81 #else
82 dstat[ZBX_DSTAT_R_OPER] += (zbx_uint64_t)ds->num_reads;
83 dstat[ZBX_DSTAT_W_OPER] += (zbx_uint64_t)ds->num_writes;
84 dstat[ZBX_DSTAT_R_BYTE] += (zbx_uint64_t)ds->bytes_read;
85 dstat[ZBX_DSTAT_W_BYTE] += (zbx_uint64_t)ds->bytes_written;
86 #endif
87 ret = SUCCEED;
88
89 if ('\0' != *devname)
90 break;
91 }
92
93 return ret;
94 }
95
vfs_dev_rw(AGENT_REQUEST * request,AGENT_RESULT * result,int rw)96 static int vfs_dev_rw(AGENT_REQUEST *request, AGENT_RESULT *result, int rw)
97 {
98 ZBX_SINGLE_DISKDEVICE_DATA *device;
99 char devname[32], *tmp;
100 int type, mode;
101 zbx_uint64_t dstats[ZBX_DSTAT_MAX];
102 char *pd; /* pointer to device name without '/dev/' prefix, e.g. 'da0' */
103
104 if (3 < request->nparam)
105 {
106 SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters."));
107 return SYSINFO_RET_FAIL;
108 }
109
110 tmp = get_rparam(request, 0);
111
112 if (NULL == tmp || 0 == strcmp(tmp, "all"))
113 *devname = '\0';
114 else
115 strscpy(devname, tmp);
116
117 pd = devname;
118
119 if ('\0' != *pd)
120 {
121 /* skip prefix ZBX_DEV_PFX, if present */
122 if (0 == strncmp(pd, ZBX_DEV_PFX, ZBX_CONST_STRLEN(ZBX_DEV_PFX)))
123 pd += ZBX_CONST_STRLEN(ZBX_DEV_PFX);
124 }
125
126 tmp = get_rparam(request, 1);
127
128 if (NULL == tmp || '\0' == *tmp || 0 == strcmp(tmp, "bps")) /* default parameter */
129 type = ZBX_DSTAT_TYPE_BPS;
130 else if (0 == strcmp(tmp, "ops"))
131 type = ZBX_DSTAT_TYPE_OPS;
132 else if (0 == strcmp(tmp, "bytes"))
133 type = ZBX_DSTAT_TYPE_BYTE;
134 else if (0 == strcmp(tmp, "operations"))
135 type = ZBX_DSTAT_TYPE_OPER;
136 else
137 {
138 SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid second parameter."));
139 return SYSINFO_RET_FAIL;
140 }
141
142 if (type == ZBX_DSTAT_TYPE_BYTE || type == ZBX_DSTAT_TYPE_OPER)
143 {
144 if (2 < request->nparam)
145 {
146 SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid number of parameters."));
147 return SYSINFO_RET_FAIL;
148 }
149
150 if (FAIL == get_diskstat(pd, dstats))
151 {
152 SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot obtain disk information."));
153 return SYSINFO_RET_FAIL;
154 }
155
156 if (ZBX_DSTAT_TYPE_BYTE == type)
157 SET_UI64_RESULT(result, dstats[(ZBX_DEV_READ == rw ? ZBX_DSTAT_R_BYTE : ZBX_DSTAT_W_BYTE)]);
158 else /* ZBX_DSTAT_TYPE_OPER */
159 SET_UI64_RESULT(result, dstats[(ZBX_DEV_READ == rw ? ZBX_DSTAT_R_OPER : ZBX_DSTAT_W_OPER)]);
160
161 return SYSINFO_RET_OK;
162 }
163
164 tmp = get_rparam(request, 2);
165
166 if (NULL == tmp || '\0' == *tmp || 0 == strcmp(tmp, "avg1")) /* default parameter */
167 mode = ZBX_AVG1;
168 else if (0 == strcmp(tmp, "avg5"))
169 mode = ZBX_AVG5;
170 else if (0 == strcmp(tmp, "avg15"))
171 mode = ZBX_AVG15;
172 else
173 {
174 SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid third parameter."));
175 return SYSINFO_RET_FAIL;
176 }
177
178 if (NULL == collector)
179 {
180 /* CPU statistics collector and (optionally) disk statistics collector is started only when Zabbix */
181 /* agentd is running as a daemon. When Zabbix agent or agentd is started with "-p" or "-t" parameter */
182 /* the collectors are not available and keys "vfs.dev.read", "vfs.dev.write" with some parameters */
183 /* (e.g. sps, ops) are not supported. */
184
185 SET_MSG_RESULT(result, zbx_strdup(NULL, "This item is available only in daemon mode when collectors are"
186 " started."));
187 return SYSINFO_RET_FAIL;
188 }
189
190 if (NULL == (device = collector_diskdevice_get(pd)))
191 {
192 if (FAIL == get_diskstat(pd, dstats)) /* validate device name */
193 {
194 SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot obtain disk information."));
195 return SYSINFO_RET_FAIL;
196 }
197
198 if (NULL == (device = collector_diskdevice_add(pd)))
199 {
200 SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot add disk device to agent collector."));
201 return SYSINFO_RET_FAIL;
202 }
203 }
204
205 if (ZBX_DSTAT_TYPE_BPS == type) /* default parameter */
206 SET_DBL_RESULT(result, (ZBX_DEV_READ == rw ? device->r_bps[mode] : device->w_bps[mode]));
207 else if (ZBX_DSTAT_TYPE_OPS == type)
208 SET_DBL_RESULT(result, (ZBX_DEV_READ == rw ? device->r_ops[mode] : device->w_ops[mode]));
209
210 return SYSINFO_RET_OK;
211 }
212
VFS_DEV_READ(AGENT_REQUEST * request,AGENT_RESULT * result)213 int VFS_DEV_READ(AGENT_REQUEST *request, AGENT_RESULT *result)
214 {
215 return vfs_dev_rw(request, result, ZBX_DEV_READ);
216 }
217
VFS_DEV_WRITE(AGENT_REQUEST * request,AGENT_RESULT * result)218 int VFS_DEV_WRITE(AGENT_REQUEST *request, AGENT_RESULT *result)
219 {
220 return vfs_dev_rw(request, result, ZBX_DEV_WRITE);
221 }
222