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 "zbxjson.h" 23 #include "log.h" 24 #include "zbxalgo.h" 25 #include "inodes.h" 26 27 static int get_fs_size_stat(const char *fs, zbx_uint64_t *total, zbx_uint64_t *free, 28 zbx_uint64_t *used, double *pfree, double *pused, char **error) 29 { 30 #ifdef HAVE_SYS_STATVFS_H 31 # define ZBX_STATFS statvfs 32 # define ZBX_BSIZE f_frsize 33 #else 34 # define ZBX_STATFS statfs 35 # define ZBX_BSIZE f_bsize 36 #endif 37 struct ZBX_STATFS s; 38 39 if (NULL == fs || '\0' == *fs) 40 { 41 *error = zbx_strdup(NULL, "Filesystem name cannot be empty."); 42 zabbix_log(LOG_LEVEL_DEBUG,"%s failed with error: %s",__func__, *error); 43 return SYSINFO_RET_FAIL; 44 } 45 46 if (0 != ZBX_STATFS(fs, &s)) 47 { 48 *error = zbx_dsprintf(NULL, "Cannot obtain filesystem information: %s", zbx_strerror(errno)); 49 zabbix_log(LOG_LEVEL_DEBUG,"%s failed with error: %s",__func__, *error); 50 return SYSINFO_RET_FAIL; 51 } 52 /* Available space could be negative (top bit set) if we hit disk space */ 53 /* reserved for non-privileged users. Treat it as 0. */ 54 if (0 != ZBX_IS_TOP_BIT_SET(s.f_bavail)) 55 s.f_bavail = 0; 56 57 if (NULL != total) 58 *total = (zbx_uint64_t)s.f_blocks * s.ZBX_BSIZE; 59 60 if (NULL != free) 61 *free = (zbx_uint64_t)s.f_bavail * s.ZBX_BSIZE; 62 63 if (NULL != used) 64 *used = (zbx_uint64_t)(s.f_blocks - s.f_bfree) * s.ZBX_BSIZE; 65 66 if (NULL != pfree) 67 { 68 if (0 != s.f_blocks - s.f_bfree + s.f_bavail) 69 *pfree = (double)(100.0 * s.f_bavail) / (s.f_blocks - s.f_bfree + s.f_bavail); 70 else 71 *pfree = 0; 72 } get_diskstat(const char * devname,zbx_uint64_t * dstat)73 74 if (NULL != pused) 75 { 76 if (0 != s.f_blocks - s.f_bfree + s.f_bavail) 77 *pused = 100.0 - (double)(100.0 * s.f_bavail) / (s.f_blocks - s.f_bfree + s.f_bavail); 78 else 79 *pused = 0; 80 } 81 82 return SYSINFO_RET_OK; 83 } 84 85 static int vfs_fs_size(AGENT_REQUEST *request, AGENT_RESULT *result) 86 { 87 char *fsname, *mode, *error; 88 zbx_uint64_t total, free, used; 89 double pfree, pused; 90 91 if (2 < request->nparam) 92 { 93 SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters.")); 94 return SYSINFO_RET_FAIL; 95 } 96 97 fsname = get_rparam(request, 0); 98 mode = get_rparam(request, 1); 99 100 if (SYSINFO_RET_OK != get_fs_size_stat(fsname, &total, &free, &used, &pfree, &pused, &error)) 101 { 102 SET_MSG_RESULT(result, error); 103 return SYSINFO_RET_FAIL; 104 } 105 106 if (NULL == mode || '\0' == *mode || 0 == strcmp(mode, "total")) /* default parameter */ 107 SET_UI64_RESULT(result, total); 108 else if (0 == strcmp(mode, "free")) 109 SET_UI64_RESULT(result, free); 110 else if (0 == strcmp(mode, "used")) 111 SET_UI64_RESULT(result, used); 112 else if (0 == strcmp(mode, "pfree")) 113 SET_DBL_RESULT(result, pfree); 114 else if (0 == strcmp(mode, "pused")) 115 SET_DBL_RESULT(result, pused); 116 else 117 { 118 SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid second parameter.")); 119 return SYSINFO_RET_FAIL; 120 } 121 122 return SYSINFO_RET_OK; 123 } 124 125 int VFS_FS_SIZE(AGENT_REQUEST *request, AGENT_RESULT *result) 126 { 127 return zbx_execute_threaded_metric(vfs_fs_size, request, result); 128 } 129 130 int VFS_FS_DISCOVERY(AGENT_REQUEST *request, AGENT_RESULT *result) 131 { 132 char line[MAX_STRING_LEN], *p, *mpoint, *mtype; 133 FILE *f; 134 struct zbx_json j; 135 136 ZBX_UNUSED(request); 137 138 if (NULL == (f = fopen("/proc/mounts", "r"))) get_kernel_devname(const char * devname,char * kernel_devname,size_t max_kernel_devname_len)139 { 140 SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot open /proc/mounts: %s", zbx_strerror(errno))); 141 return SYSINFO_RET_FAIL; 142 } 143 144 zbx_json_initarray(&j, ZBX_JSON_STAT_BUF_LEN); 145 146 while (NULL != fgets(line, sizeof(line), f)) 147 { 148 if (NULL == (p = strchr(line, ' '))) 149 continue; 150 151 mpoint = ++p; 152 153 if (NULL == (p = strchr(mpoint, ' '))) 154 continue; 155 156 *p = '\0'; 157 158 mtype = ++p; 159 160 if (NULL == (p = strchr(mtype, ' '))) 161 continue; 162 163 *p = '\0'; 164 165 zbx_json_addobject(&j, NULL); 166 zbx_json_addstring(&j, ZBX_LLD_MACRO_FSNAME, mpoint, ZBX_JSON_TYPE_STRING); 167 zbx_json_addstring(&j, ZBX_LLD_MACRO_FSTYPE, mtype, ZBX_JSON_TYPE_STRING); 168 zbx_json_close(&j); 169 } 170 171 zbx_fclose(f); 172 vfs_dev_rw(AGENT_REQUEST * request,AGENT_RESULT * result,int rw)173 zbx_json_close(&j); 174 175 SET_STR_RESULT(result, zbx_strdup(NULL, j.buffer)); 176 177 zbx_json_free(&j); 178 179 return SYSINFO_RET_OK; 180 } 181 182 static int vfs_fs_get(AGENT_REQUEST *request, AGENT_RESULT *result) 183 { 184 char line[MAX_STRING_LEN], *p, *mpoint, *mtype, *error; 185 FILE *f; 186 zbx_uint64_t total, not_used, used; 187 zbx_uint64_t itotal, inot_used, iused; 188 double pfree, pused; 189 double ipfree, ipused; 190 struct zbx_json j; 191 zbx_vector_ptr_t mntpoints; 192 zbx_mpoint_t *mntpoint; 193 int ret = SYSINFO_RET_FAIL; 194 195 ZBX_UNUSED(request); 196 197 if (NULL == (f = fopen("/proc/mounts", "r"))) 198 { 199 SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot open /proc/mounts: %s", zbx_strerror(errno))); 200 return SYSINFO_RET_FAIL; 201 } 202 203 zbx_vector_ptr_create(&mntpoints); 204 205 while (NULL != fgets(line, sizeof(line), f)) 206 { 207 if (NULL == (p = strchr(line, ' '))) 208 continue; 209 210 mpoint = ++p; 211 212 if (NULL == (p = strchr(mpoint, ' '))) 213 continue; 214 215 *p = '\0'; 216 217 mtype = ++p; 218 219 if (NULL == (p = strchr(mtype, ' '))) 220 continue; 221 222 *p = '\0'; 223 224 if (SYSINFO_RET_OK != get_fs_size_stat(mpoint, &total, ¬_used, &used, &pfree, &pused, &error)) 225 { 226 zbx_free(error); 227 continue; 228 } 229 if (SYSINFO_RET_OK != get_fs_inode_stat(mpoint, &itotal, &inot_used, &iused, &ipfree, &ipused, "pused", 230 &error)) 231 { 232 zbx_free(error); 233 continue; 234 } 235 236 mntpoint = (zbx_mpoint_t *)zbx_malloc(NULL, sizeof(zbx_mpoint_t)); 237 zbx_strlcpy(mntpoint->fsname, mpoint, MAX_STRING_LEN); 238 zbx_strlcpy(mntpoint->fstype, mtype, MAX_STRING_LEN); 239 mntpoint->bytes.total = total; 240 mntpoint->bytes.used = used; 241 mntpoint->bytes.not_used = not_used; 242 mntpoint->bytes.pfree = pfree; 243 mntpoint->bytes.pused = pused; 244 mntpoint->inodes.total = itotal; 245 mntpoint->inodes.used = iused; 246 mntpoint->inodes.not_used = inot_used; 247 mntpoint->inodes.pfree = ipfree; 248 mntpoint->inodes.pused = ipused; 249 250 zbx_vector_ptr_append(&mntpoints, mntpoint); 251 } 252 zbx_fclose(f); 253 254 if (NULL == (f = fopen("/proc/mounts", "r"))) 255 { 256 SET_MSG_RESULT(result, zbx_dsprintf(NULL, "Cannot open /proc/mounts: %s", zbx_strerror(errno))); 257 goto out; 258 } 259 zbx_json_initarray(&j, ZBX_JSON_STAT_BUF_LEN); 260 261 while (NULL != fgets(line, sizeof(line), f)) 262 { 263 int idx; 264 265 if (NULL == (p = strchr(line, ' '))) 266 continue; 267 268 mpoint = ++p; 269 270 if (NULL == (p = strchr(mpoint, ' '))) 271 continue; 272 273 *p = '\0'; 274 if (FAIL != (idx = zbx_vector_ptr_search(&mntpoints, mpoint, ZBX_DEFAULT_STR_COMPARE_FUNC))) 275 { 276 mntpoint = (zbx_mpoint_t *)mntpoints.values[idx]; 277 zbx_json_addobject(&j, NULL); 278 zbx_json_addstring(&j, ZBX_SYSINFO_TAG_FSNAME, mntpoint->fsname, ZBX_JSON_TYPE_STRING); 279 zbx_json_addstring(&j, ZBX_SYSINFO_TAG_FSTYPE, mntpoint->fstype, ZBX_JSON_TYPE_STRING); 280 zbx_json_addobject(&j, ZBX_SYSINFO_TAG_BYTES); 281 zbx_json_adduint64(&j, ZBX_SYSINFO_TAG_TOTAL, mntpoint->bytes.total); 282 zbx_json_adduint64(&j, ZBX_SYSINFO_TAG_FREE, mntpoint->bytes.not_used); 283 zbx_json_adduint64(&j, ZBX_SYSINFO_TAG_USED, mntpoint->bytes.used); 284 zbx_json_addfloat(&j, ZBX_SYSINFO_TAG_PFREE, mntpoint->bytes.pfree); 285 zbx_json_addfloat(&j, ZBX_SYSINFO_TAG_PUSED, mntpoint->bytes.pused); VFS_DEV_READ(AGENT_REQUEST * request,AGENT_RESULT * result)286 zbx_json_close(&j); 287 zbx_json_addobject(&j, ZBX_SYSINFO_TAG_INODES); 288 zbx_json_adduint64(&j, ZBX_SYSINFO_TAG_TOTAL, mntpoint->inodes.total); 289 zbx_json_adduint64(&j, ZBX_SYSINFO_TAG_FREE, mntpoint->inodes.not_used); 290 zbx_json_adduint64(&j, ZBX_SYSINFO_TAG_USED, mntpoint->inodes.used); VFS_DEV_WRITE(AGENT_REQUEST * request,AGENT_RESULT * result)291 zbx_json_addfloat(&j, ZBX_SYSINFO_TAG_PFREE, mntpoint->inodes.pfree); 292 zbx_json_addfloat(&j, ZBX_SYSINFO_TAG_PUSED, mntpoint->inodes.pused); 293 zbx_json_close(&j); 294 zbx_json_close(&j); 295 } 296 } 297 298 zbx_fclose(f); VFS_DEV_DISCOVERY(AGENT_REQUEST * request,AGENT_RESULT * result)299 300 zbx_json_close(&j); 301 302 SET_STR_RESULT(result, zbx_strdup(NULL, j.buffer)); 303 304 zbx_json_free(&j); 305 ret = SYSINFO_RET_OK; 306 307 out: 308 zbx_vector_ptr_clear_ext(&mntpoints, (zbx_clean_func_t)zbx_mpoints_free); 309 zbx_vector_ptr_destroy(&mntpoints); 310 311 return ret; 312 } 313 314 int VFS_FS_GET(AGENT_REQUEST *request, AGENT_RESULT *result) 315 { 316 return zbx_execute_threaded_metric(vfs_fs_get, request, result); 317 318 } 319