"Fossies" - the Fresh Open Source Software Archive

Member "monit-5.28.0/src/device/sysdep_FREEBSD.c" (28 Mar 2021, 14536 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_FREEBSD.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_STRING_H
   42 #include <string.h>
   43 #endif
   44 
   45 #ifdef HAVE_SYS_PARAM_H
   46 #include <sys/param.h>
   47 #endif
   48 
   49 #if defined HAVE_SYS_UCRED_H
   50 #include <sys/ucred.h>
   51 #endif
   52 
   53 #ifdef HAVE_SYS_MOUNT_H
   54 #include <sys/mount.h>
   55 #endif
   56 
   57 #ifdef HAVE_FCNTL_H
   58 #include <fcntl.h>
   59 #endif
   60 
   61 #ifdef HAVE_SYS_SYSCTL_H
   62 #include <sys/sysctl.h>
   63 #endif
   64 
   65 #ifdef HAVE_CTYPE_H
   66 #include <ctype.h>
   67 #endif
   68 
   69 #ifdef HAVE_KVM_H
   70 #include <kvm.h>
   71 #endif
   72 
   73 #ifdef HAVE_PATHS_H
   74 #include <paths.h>
   75 #endif
   76 
   77 #ifdef HAVE_DEVSTAT_H
   78 #include <devstat.h>
   79 #endif
   80 
   81 #include "monit.h"
   82 #include "device.h"
   83 
   84 // libmonit
   85 #include "system/Time.h"
   86 #include "io/File.h"
   87 
   88 
   89 /* ------------------------------------------------------------- Definitions */
   90 
   91 
   92 static struct {
   93         unsigned long long timestamp;
   94         struct statinfo disk;
   95 } _statistics = {};
   96 
   97 
   98 /* --------------------------------------- Static constructor and destructor */
   99 
  100 
  101 static void __attribute__ ((constructor)) _constructor() {
  102         _statistics.disk.dinfo = CALLOC(1, sizeof(struct devinfo));
  103 }
  104 
  105 
  106 static void __attribute__ ((destructor)) _destructor() {
  107         FREE(_statistics.disk.dinfo);
  108 }
  109 
  110 
  111 /* ----------------------------------------------------------------- Private */
  112 
  113 
  114 static unsigned long long _bintimeToMilli(struct bintime *time) {
  115         return time->sec * 1000 + (((unsigned long long)1000 * (uint32_t)(time->frac >> 32)) >> 32);
  116 }
  117 
  118 
  119 // Parse the device path like /dev/da0p2 or /dev/gpt/myfilesystemlabel into name:instance -> da:0
  120 static bool _parseDevice(const char *path, Device_T device) {
  121         if (strlen(path) > 5 && Str_startsWith(path, "/dev/")) {
  122                 // Get the disk map
  123                 size_t len = 0;
  124                 if (sysctlbyname("kern.geom.conftxt", NULL, &len, NULL, 0)) {
  125                         Log_error("system statistics error -- cannot get kern.geom.conftxt size");
  126                         return false;
  127                 }
  128                 char buf[len + 1];
  129                 if (sysctlbyname("kern.geom.conftxt", buf, &len, NULL, 0)) {
  130                         Log_error("system statistics error -- cannot get kern.geom.conftxt");
  131                         return false;
  132                 }
  133                 buf[len] = 0;
  134                 // Scan the table for matching label/partition
  135                 char disk[PATH_MAX] = {};
  136                 const char *pathname = path + 5; // cut "/dev/" from the path
  137                 for (const char *cursor = buf; cursor; cursor = strchr(cursor, '\n')) {
  138                         while (*cursor == '\n') {
  139                                 cursor++;
  140                         }
  141                         if (*cursor) {
  142                                 int index;
  143                                 char type[64] = {};
  144                                 char name[PATH_MAX] = {};
  145                                 if (sscanf(cursor, "%d %63s %1023s ", &index, type, name) == 3) {
  146                                         if (Str_isEqual(type, "DISK")) {
  147                                                 snprintf(disk, sizeof(disk), "%s", name);
  148                                         } else {
  149                                                 if (Str_isEqual(pathname, name)) {
  150                                                         // Matching label/partition found, parse the disk
  151                                                         for (size_t i = 0; disk[i]; i++) {
  152                                                                 if (isdigit(*(disk + i))) {
  153                                                                         strncpy(device->key, disk, i < sizeof(device->key) ? i : sizeof(device->key) - 1);
  154                                                                         device->instance = Str_parseInt(disk + i);
  155                                                                         return true;
  156                                                                 }
  157                                                         }
  158                                                 }
  159                                         }
  160                                 }
  161                         }
  162                 }
  163         }
  164         Log_error("filesystem statistics error -- cannot parse device '%s'\n", path);
  165         return false;
  166 }
  167 
  168 
  169 static bool _getStatistics(unsigned long long now) {
  170         // Refresh only if the statistics are older then 1 second (handle also backward time jumps)
  171         if (now > _statistics.timestamp + 1000 || now < _statistics.timestamp - 1000) {
  172                 if (devstat_getdevs(NULL, &(_statistics.disk)) == -1) {
  173                         Log_error("filesystem statistics error -- devstat_getdevs: %s\n", devstat_errbuf);
  174                         return false;
  175                 }
  176                 _statistics.timestamp = now;
  177         }
  178         return true;
  179 }
  180 
  181 
  182 static bool _getDummyDiskActivity(__attribute__ ((unused)) void *_inf) {
  183         return true;
  184 }
  185 
  186 
  187 static bool _getBlockDiskActivity(void *_inf) {
  188         Info_T inf = _inf;
  189         unsigned long long now = Time_milli();
  190         bool rv = _getStatistics(now);
  191         if (rv) {
  192                 for (int i = 0; i < _statistics.disk.dinfo->numdevs; i++) {
  193                         if (_statistics.disk.dinfo->devices[i].unit_number == inf->filesystem->object.instance && IS(_statistics.disk.dinfo->devices[i].device_name, inf->filesystem->object.key)) {
  194                                 unsigned long long now = _statistics.disk.snap_time * 1000;
  195                                 Statistics_update(&(inf->filesystem->time.read), now, _bintimeToMilli(&(_statistics.disk.dinfo->devices[i].duration[DEVSTAT_READ])));
  196                                 Statistics_update(&(inf->filesystem->read.bytes), now, _statistics.disk.dinfo->devices[i].bytes[DEVSTAT_READ]);
  197                                 Statistics_update(&(inf->filesystem->read.operations),  now, _statistics.disk.dinfo->devices[i].operations[DEVSTAT_READ]);
  198                                 Statistics_update(&(inf->filesystem->time.write), now, _bintimeToMilli(&(_statistics.disk.dinfo->devices[i].duration[DEVSTAT_WRITE])));
  199                                 Statistics_update(&(inf->filesystem->write.bytes), now, _statistics.disk.dinfo->devices[i].bytes[DEVSTAT_WRITE]);
  200                                 Statistics_update(&(inf->filesystem->write.operations), now, _statistics.disk.dinfo->devices[i].operations[DEVSTAT_WRITE]);
  201                                 break;
  202                         }
  203                 }
  204         }
  205         return rv;
  206 }
  207 
  208 
  209 static bool _getDiskUsage(void *_inf) {
  210         Info_T inf = _inf;
  211         struct statfs usage;
  212         if (statfs(inf->filesystem->object.mountpoint, &usage) != 0) {
  213                 Log_error("Error getting usage statistics for filesystem '%s' -- %s\n", inf->filesystem->object.mountpoint, STRERROR);
  214                 return false;
  215         }
  216         inf->filesystem->f_bsize = usage.f_bsize;
  217         inf->filesystem->f_blocks = usage.f_blocks;
  218         inf->filesystem->f_blocksfree = usage.f_bavail;
  219         inf->filesystem->f_blocksfreetotal = usage.f_bfree;
  220         inf->filesystem->f_files = usage.f_files;
  221         inf->filesystem->f_filesfree = usage.f_ffree;
  222         return true;
  223 }
  224 
  225 
  226 static bool _compareMountpoint(const char *mountpoint, struct statfs *mnt) {
  227         return IS(mountpoint, mnt->f_mntonname);
  228 }
  229 
  230 
  231 static bool _compareDevice(const char *device, struct statfs *mnt) {
  232         return IS(device, mnt->f_mntfromname);
  233 }
  234 
  235 
  236 static void _filesystemFlagsToString(Info_T inf, unsigned long long flags) {
  237         struct mystable {
  238                 unsigned long long flag;
  239                 char *description;
  240         } t[]= {
  241 #ifdef MNT_AUTOMOUNTED
  242                 {MNT_AUTOMOUNTED, "automounted"},
  243 #endif
  244 #ifdef MNT_NFS4ACLS
  245                 {MNT_NFS4ACLS, "nfs4acls"},
  246 #endif
  247 #ifdef MNT_SUJ
  248                 {MNT_SUJ, "journaled soft updates"},
  249 #endif
  250                 {MNT_RDONLY, "ro"},
  251                 {MNT_SYNCHRONOUS, "synchronous"},
  252                 {MNT_NOEXEC, "noexec"},
  253                 {MNT_NOSUID, "nosuid"},
  254                 {MNT_UNION, "union"},
  255                 {MNT_ASYNC, "async"},
  256                 {MNT_SUIDDIR, "suiddir"},
  257                 {MNT_SOFTDEP, "soft updates"},
  258                 {MNT_NOSYMFOLLOW, "nosymfollow"},
  259                 {MNT_GJOURNAL, "GEOM journal"},
  260                 {MNT_MULTILABEL, "multilabel"},
  261                 {MNT_ACLS, "acls"},
  262                 {MNT_NOATIME, "noatime"},
  263                 {MNT_NOCLUSTERR, "noclusterr"},
  264                 {MNT_NOCLUSTERW, "noclusterw"},
  265                 {MNT_EXRDONLY, "exported read only"},
  266                 {MNT_EXPORTED, "exported"},
  267                 {MNT_DEFEXPORTED, "exported to the world"},
  268                 {MNT_EXPORTANON, "anon uid mapping"},
  269                 {MNT_EXKERB, "exported with kerberos"},
  270                 {MNT_EXPUBLIC, "public export"},
  271                 {MNT_LOCAL, "local"},
  272                 {MNT_QUOTA, "quota"},
  273                 {MNT_ROOTFS, "rootfs"},
  274                 {MNT_USER, "user"},
  275                 {MNT_IGNORE, "ignore"}
  276         };
  277         for (size_t i = 0, count = 0; i < sizeof(t) / sizeof(t[0]); i++) {
  278                 if (flags & t[i].flag) {
  279                         snprintf(inf->filesystem->flags + strlen(inf->filesystem->flags), sizeof(inf->filesystem->flags) - strlen(inf->filesystem->flags) - 1, "%s%s", count++ ? ", " : "", t[i].description);
  280                 }
  281         }
  282 }
  283 
  284 
  285 static bool _setDevice(Info_T inf, const char *path, bool (*compare)(const char *path, struct statfs *mnt)) {
  286         int countfs = getfsstat(NULL, 0, MNT_NOWAIT);
  287         if (countfs != -1) {
  288                 struct statfs *mnt = CALLOC(countfs, sizeof(struct statfs));
  289                 if ((countfs = getfsstat(mnt, countfs * sizeof(struct statfs), MNT_NOWAIT)) != -1) {
  290                         for (int i = 0; i < countfs; i++) {
  291                                 struct statfs *mntItem = mnt + i;
  292                                 if (compare(path, mntItem)) {
  293                                         if (IS(mntItem->f_fstypename, "ufs")) {
  294                                                 if (_parseDevice(mntItem->f_mntfromname, &(inf->filesystem->object))) {
  295                                                         inf->filesystem->object.getDiskActivity = _getBlockDiskActivity;
  296                                                 } else {
  297                                                         inf->filesystem->object.getDiskActivity = _getDummyDiskActivity;
  298                                                         DEBUG("I/O monitoring for filesystem '%s' skipped - unable to parse the device %s\n", path, mntItem->f_mntfromname);
  299                                                 }
  300                                         } else {
  301                                                 //FIXME: can add ZFS support (see sysdep_SOLARIS.c), but libzfs headers are not installed on FreeBSD by default (part of "cddl" set)
  302                                                 inf->filesystem->object.getDiskActivity = _getDummyDiskActivity;
  303                                         }
  304                                         if ((mntItem->f_flags & MNT_VISFLAGMASK) != inf->filesystem->object.flags) {
  305                                                 if (inf->filesystem->object.flags) {
  306                                                         inf->filesystem->flagsChanged = true;
  307                                                 }
  308                                                 inf->filesystem->object.flags = mntItem->f_flags & MNT_VISFLAGMASK;
  309                                                 _filesystemFlagsToString(inf, inf->filesystem->object.flags);
  310                                         }
  311                                         strncpy(inf->filesystem->object.device, mntItem->f_mntfromname, sizeof(inf->filesystem->object.device) - 1);
  312                                         strncpy(inf->filesystem->object.mountpoint, mntItem->f_mntonname, sizeof(inf->filesystem->object.mountpoint) - 1);
  313                                         strncpy(inf->filesystem->object.type, mntItem->f_fstypename, sizeof(inf->filesystem->object.type) - 1);
  314                                         inf->filesystem->object.getDiskUsage = _getDiskUsage;
  315                                         inf->filesystem->object.mounted = true;
  316                                         FREE(mnt);
  317                                         return true;
  318                                 }
  319                         }
  320                 }
  321                 FREE(mnt);
  322         }
  323         Log_error("Lookup for '%s' filesystem failed\n", path);
  324 error:
  325         inf->filesystem->object.mounted = false;
  326         return false;
  327 }
  328 
  329 
  330 static bool _getDevice(Info_T inf, const char *path, bool (*compare)(const char *path, struct statfs *mnt)) {
  331         if (_setDevice(inf, path, compare)) {
  332                 return (inf->filesystem->object.getDiskUsage(inf) && inf->filesystem->object.getDiskActivity(inf));
  333         }
  334         return false;
  335 }
  336 
  337 
  338 /* ------------------------------------------------------------------ Public */
  339 
  340 
  341 bool Filesystem_getByMountpoint(Info_T inf, const char *path) {
  342         ASSERT(inf);
  343         ASSERT(path);
  344         return _getDevice(inf, path, _compareMountpoint);
  345 }
  346 
  347 
  348 bool Filesystem_getByDevice(Info_T inf, const char *path) {
  349         ASSERT(inf);
  350         ASSERT(path);
  351         return _getDevice(inf, path, _compareDevice);
  352 }
  353