"Fossies" - the Fresh Open Source Software Archive

Member "monit-5.28.0/src/device/sysdep_SOLARIS.c" (28 Mar 2021, 15460 Bytes) of package /linux/privat/monit-5.28.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "sysdep_SOLARIS.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 5.27.2_vs_5.28.0.

    1 /*
    2  * Copyright (C) Tildeslash Ltd. All rights reserved.
    3  *
    4  * This program is free software: you can redistribute it and/or modify
    5  * it under the terms of the GNU Affero General Public License version 3.
    6  *
    7  * This program is distributed in the hope that it will be useful,
    8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   10  * GNU General Public License for more details.
   11  *
   12  * You should have received a copy of the GNU Affero General Public License
   13  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
   14  *
   15  * In addition, as a special exception, the copyright holders give
   16  * permission to link the code of portions of this program with the
   17  * OpenSSL library under certain conditions as described in each
   18  * individual source file, and distribute linked combinations
   19  * including the two.
   20  *
   21  * You must obey the GNU Affero General Public License in all respects
   22  * for all of the code used other than OpenSSL.
   23  */
   24 
   25 /**
   26  *  System dependent filesystem methods.
   27  *
   28  *  @file
   29  */
   30 
   31 #include "config.h"
   32 
   33 #ifdef HAVE_STDIO_H
   34 #include <stdio.h>
   35 #endif
   36 
   37 #ifdef HAVE_ERRNO_H
   38 #include <errno.h>
   39 #endif
   40 
   41 #ifdef HAVE_STRINGS_H
   42 #include <strings.h>
   43 #endif
   44 
   45 #ifdef HAVE_KSTAT_H
   46 #include <kstat.h>
   47 #endif
   48 
   49 #ifdef HAVE_SYS_TYPES_H
   50 #include <sys/types.h>
   51 #endif
   52 
   53 #ifdef HAVE_SYS_STATVFS_H
   54 #include <sys/statvfs.h>
   55 #endif
   56 
   57 #ifdef HAVE_SYS_MNTENT_H
   58 #include <sys/mntent.h>
   59 #endif
   60 
   61 #ifdef HAVE_SYS_MNTTAB_H
   62 #include <sys/mnttab.h>
   63 #endif
   64 
   65 #ifdef HAVE_LIBZFS_H
   66 #include <libzfs.h>
   67 #endif
   68 
   69 #ifdef HAVE_NVPAIR_H
   70 #include <sys/nvpair.h>
   71 #endif
   72 
   73 #ifdef HAVE_FS_ZFS_H
   74 #include <sys/fs/zfs.h>
   75 #endif
   76 
   77 #include "monit.h"
   78 #include "device.h"
   79 
   80 // libmonit
   81 #include "system/Time.h"
   82 #include "io/File.h"
   83 
   84 
   85 /* ------------------------------------------------------------- Definitions */
   86 
   87 
   88 #define PATHTOINST "/etc/path_to_inst"
   89 
   90 
   91 static struct {
   92         int generation;     // Increment each time the mount table is changed
   93         unsigned long long timestamp; // /etc/mnttab timestamp [ms] (changed on mount/unmount)
   94 } _statistics = {};
   95 
   96 
   97 /* ----------------------------------------------------------------- Private */
   98 
   99 
  100 static bool _getDummyDiskActivity(__attribute__ ((unused)) void *_inf) {
  101         return true;
  102 }
  103 
  104 
  105 static bool _getZfsDiskActivity(void *_inf) {
  106         Info_T inf = _inf;
  107         bool rv = false;
  108         libzfs_handle_t *z = libzfs_init();
  109         libzfs_print_on_error(z, 1);
  110         zpool_handle_t *zp = zpool_open_canfail(z, inf->filesystem->object.key);
  111         if (zp) {
  112                 nvlist_t *zpoolConfig = zpool_get_config(zp, NULL);
  113                 nvlist_t *zpoolVdevTree = NULL;
  114                 if (nvlist_lookup_nvlist(zpoolConfig, ZPOOL_CONFIG_VDEV_TREE, &zpoolVdevTree) == 0) {
  115                         vdev_stat_t *zpoolStatistics = NULL;
  116                         uint_t zpoolStatisticsCount = 0;
  117                         if (nvlist_lookup_uint64_array(zpoolVdevTree, ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&zpoolStatistics, &zpoolStatisticsCount) == 0) {
  118                                 //FIXME: if the zpool state has error, trigger the fs event, can also report number of read/write/checksum errors (see vdev_stat_t in /usr/include/sys/fs/zfs.h)
  119                                 DEBUG("ZFS pool '%s' state: %s\n", inf->filesystem->object.key, zpool_state_to_name(zpoolStatistics->vs_state, zpoolStatistics->vs_aux));
  120                                 unsigned long long now = Time_milli();
  121                                 Statistics_update(&(inf->filesystem->read.bytes), now, zpoolStatistics->vs_bytes[ZIO_TYPE_READ]);
  122                                 Statistics_update(&(inf->filesystem->write.bytes), now, zpoolStatistics->vs_bytes[ZIO_TYPE_WRITE]);
  123                                 Statistics_update(&(inf->filesystem->read.operations),  now, zpoolStatistics->vs_ops[ZIO_TYPE_READ]);
  124                                 Statistics_update(&(inf->filesystem->write.operations), now, zpoolStatistics->vs_ops[ZIO_TYPE_WRITE]);
  125                                 rv = true;
  126                         }
  127                 }
  128                 zpool_close(zp);
  129         }
  130         libzfs_fini(z);
  131         return rv;
  132 }
  133 
  134 
  135 static bool _getKstatDiskActivity(void *_inf) {
  136         Info_T inf = _inf;
  137         bool rv = false;
  138         kstat_ctl_t *kctl = kstat_open();
  139         if (kctl) {
  140                 kstat_t *kstat;
  141                 for (kstat = kctl->kc_chain; kstat; kstat = kstat->ks_next) {
  142                         if (kstat->ks_type == KSTAT_TYPE_IO && kstat->ks_instance == inf->filesystem->object.instance && IS(kstat->ks_module, inf->filesystem->object.module) && IS(kstat->ks_name, inf->filesystem->object.key)) {
  143                                 static kstat_io_t kio;
  144                                 if (kstat_read(kctl, kstat, &kio) == -1) {
  145                                         Log_error("filesystem statistics error: kstat_read failed -- %s\n", STRERROR);
  146                                 } else {
  147                                         unsigned long long now = Time_milli();
  148                                         Statistics_update(&(inf->filesystem->read.bytes), now, kio.nread);
  149                                         Statistics_update(&(inf->filesystem->write.bytes), now, kio.nwritten);
  150                                         Statistics_update(&(inf->filesystem->read.operations),  now, kio.reads);
  151                                         Statistics_update(&(inf->filesystem->write.operations), now, kio.writes);
  152                                         Statistics_update(&(inf->filesystem->time.wait), now, kio.wtime / 1000000.);
  153                                         Statistics_update(&(inf->filesystem->time.run), now, kio.rtime / 1000000.);
  154                                         rv = true;
  155                                 }
  156                         }
  157                 }
  158                 kstat_close(kctl);
  159         }
  160         return rv;
  161 }
  162 
  163 
  164 static bool _getDiskUsage(void *_inf) {
  165         Info_T inf = _inf;
  166         struct statvfs usage;
  167         if (statvfs(inf->filesystem->object.mountpoint, &usage) != 0) {
  168                 Log_error("Error getting usage statistics for filesystem '%s' -- %s\n", inf->filesystem->object.mountpoint, STRERROR);
  169                 return false;
  170         }
  171         int size = usage.f_frsize ? (usage.f_bsize / usage.f_frsize) : 1;
  172         inf->filesystem->f_bsize = usage.f_bsize;
  173         inf->filesystem->f_blocks = usage.f_blocks / size;
  174         inf->filesystem->f_blocksfree = usage.f_bavail / size;
  175         inf->filesystem->f_blocksfreetotal = usage.f_bfree  / size;
  176         inf->filesystem->f_files = usage.f_files;
  177         inf->filesystem->f_filesfree = usage.f_ffree;
  178         return true;
  179 }
  180 
  181 
  182 static bool _compareMountpoint(const char *mountpoint, struct extmnttab *mnt) {
  183         return IS(mountpoint, mnt->mnt_mountp);
  184 }
  185 
  186 
  187 static bool _compareDevice(const char *device, struct extmnttab *mnt) {
  188         char target[PATH_MAX] = {};
  189         return (IS(device, mnt->mnt_special) || (realpath(mnt->mnt_special, target) && IS(device, target)));
  190 }
  191 
  192 
  193 static bool _setDevice(Info_T inf, const char *path, bool (*compare)(const char *path, struct extmnttab *mnt)) {
  194         FILE *f = fopen(MNTTAB, "r");
  195         if (! f) {
  196                 Log_error("Cannot open %s\n", MNTTAB);
  197                 return false;
  198         }
  199         resetmnttab(f);
  200         struct extmnttab mnt;
  201         bool rv = false;
  202         inf->filesystem->object.generation = _statistics.generation;
  203         while (getextmntent(f, &mnt, sizeof(struct extmnttab)) == 0) {
  204                 if (compare(path, &mnt)) {
  205                         strncpy(inf->filesystem->object.device, mnt.mnt_special, sizeof(inf->filesystem->object.device) - 1);
  206                         strncpy(inf->filesystem->object.mountpoint, mnt.mnt_mountp, sizeof(inf->filesystem->object.mountpoint) - 1);
  207                         strncpy(inf->filesystem->object.type, mnt.mnt_fstype, sizeof(inf->filesystem->object.type) - 1);
  208                         inf->filesystem->object.getDiskUsage = _getDiskUsage; // The disk usage method is common for all filesystem types
  209                         if (! IS(mnt.mnt_mntopts, inf->filesystem->flags)) {
  210                                 if (*(inf->filesystem->flags)) {
  211                                         inf->filesystem->flagsChanged = true;
  212                                 }
  213                                 snprintf(inf->filesystem->flags, sizeof(inf->filesystem->flags), "%s", mnt.mnt_mntopts);
  214                         }
  215                         if (Str_startsWith(mnt.mnt_fstype, MNTTYPE_NFS)) {
  216                                 strncpy(inf->filesystem->object.module, "nfs", sizeof(inf->filesystem->object.module) - 1);
  217                                 snprintf(inf->filesystem->object.key, sizeof(inf->filesystem->object.key), "nfs%d", mnt.mnt_minor);
  218                                 inf->filesystem->object.instance = mnt.mnt_minor;
  219                                 inf->filesystem->object.getDiskActivity = _getKstatDiskActivity;
  220                                 rv = true;
  221                         } else if (IS(mnt.mnt_fstype, MNTTYPE_ZFS)) {
  222                                 strncpy(inf->filesystem->object.module, "zfs", sizeof(inf->filesystem->object.module) - 1);
  223                                 char *slash = strchr(mnt.mnt_special, '/');
  224                                 strncpy(inf->filesystem->object.key, mnt.mnt_special, slash ? slash - mnt.mnt_special : sizeof(inf->filesystem->object.key) - 1);
  225                                 inf->filesystem->object.getDiskActivity = _getZfsDiskActivity;
  226                                 rv = true;
  227                         } else if (IS(mnt.mnt_fstype, MNTTYPE_UFS)) {
  228                                 char special[PATH_MAX];
  229                                 if (! realpath(mnt.mnt_special, special)) {
  230                                         // If the file doesn't exist it's a virtual filesystem -> ENOENT doesn't mean error
  231                                         if (errno != ENOENT && errno != ENOTDIR)
  232                                                 Log_error("Lookup for '%s' filesystem failed -- %s\n", path, STRERROR);
  233                                 } else if (! Str_startsWith(special, "/devices/")) {
  234                                         Log_error("Lookup for '%s' filesystem -- invalid device %s\n", path, special);
  235                                 } else {
  236                                         // Strip "/devices" prefix and :X partition postfix: /devices/pci@0,0/pci15ad,1976@10/sd@0,0:a -> /pci@0,0/pci15ad,1976@10/sd@0,0
  237                                         int speclen = strlen(special);
  238                                         int devlen = strlen("/devices");
  239                                         int len = speclen - devlen - 2;
  240                                         inf->filesystem->object.partition = *(special + speclen - 1);
  241                                         memmove(special, special + devlen, len);
  242                                         special[len] = 0;
  243                                         char line[PATH_MAX] = {};
  244                                         FILE *pti = fopen(PATHTOINST, "r");
  245                                         if (! pti) {
  246                                                 Log_error("Cannot open %s\n", PATHTOINST);
  247                                         } else {
  248                                                 while (fgets(line, sizeof(line), pti)) {
  249                                                         char path[1024] = {};
  250                                                         if (sscanf(line, "\"%1023[^\"]\" %d \"%255[^\"]\"", path, &(inf->filesystem->object.instance), inf->filesystem->object.module) == 3) {
  251                                                                 if (IS(path, special)) {
  252                                                                         if (IS(inf->filesystem->object.module, "cmdk")) {
  253                                                                                 // the "common disk driver" has no "partition" iostat class, only whole "disk" (at least on Solaris 10)
  254                                                                                 snprintf(inf->filesystem->object.key, sizeof(inf->filesystem->object.key), "%s%d", inf->filesystem->object.module, inf->filesystem->object.instance);
  255                                                                         } else {
  256                                                                                 // use partition for other drivers
  257                                                                                 snprintf(inf->filesystem->object.key, sizeof(inf->filesystem->object.key), "%s%d,%c", inf->filesystem->object.module, inf->filesystem->object.instance, inf->filesystem->object.partition);
  258                                                                         }
  259                                                                         inf->filesystem->object.getDiskActivity = _getKstatDiskActivity;
  260                                                                         rv = true;
  261                                                                         break;
  262                                                                 }
  263                                                         }
  264                                                 }
  265                                                 fclose(pti);
  266                                         }
  267                                 }
  268                         } else {
  269                                 inf->filesystem->object.getDiskActivity = _getDummyDiskActivity;
  270                                 rv = true;
  271                         }
  272                         fclose(f);
  273                         inf->filesystem->object.mounted = rv;
  274                         return rv;
  275                 }
  276         }
  277         Log_error("Lookup for '%s' filesystem failed  -- not found in %s\n", path, MNTTAB);
  278         fclose(f);
  279         inf->filesystem->object.mounted = false;
  280         return false;
  281 }
  282 
  283 
  284 static bool _getDevice(Info_T inf, const char *path, bool (*compare)(const char *path, struct extmnttab *mnt)) {
  285         struct stat sb;
  286         if (stat(MNTTAB, &sb) != 0 || _statistics.timestamp != (unsigned long long)((double)sb.st_mtim.tv_sec * 1000. + (double)sb.st_mtim.tv_nsec / 1000000.)) {
  287                 DEBUG("Mount notification: change detected\n");
  288                 _statistics.timestamp = (double)sb.st_mtim.tv_sec * 1000. + (double)sb.st_mtim.tv_nsec / 1000000.;
  289                 _statistics.generation++; // Increment, so all other filesystems can see the generation has changed
  290         }
  291         if (inf->filesystem->object.generation != _statistics.generation) {
  292                 _setDevice(inf, path, compare); // The mount table has changed => refresh
  293         }
  294         if (inf->filesystem->object.mounted) {
  295                 return (inf->filesystem->object.getDiskUsage(inf) && inf->filesystem->object.getDiskActivity(inf));
  296         }
  297         return false;
  298 }
  299 
  300 
  301 /* ------------------------------------------------------------------ Public */
  302 
  303 
  304 bool Filesystem_getByMountpoint(Info_T inf, const char *path) {
  305         ASSERT(inf);
  306         ASSERT(path);
  307         return _getDevice(inf, path, _compareMountpoint);
  308 }
  309 
  310 
  311 bool Filesystem_getByDevice(Info_T inf, const char *path) {
  312         ASSERT(inf);
  313         ASSERT(path);
  314         return _getDevice(inf, path, _compareDevice);
  315 }
  316