"Fossies" - the Fresh Open Source Software Archive

Member "monit-5.28.0/src/process/sysdep_SOLARIS.c" (28 Mar 2021, 15357 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 #include "config.h"
   27 
   28 #ifdef HAVE_STDIO_H
   29 #include <stdio.h>
   30 #endif
   31 
   32 #ifdef HAVE_ERRNO_H
   33 #include <errno.h>
   34 #endif
   35 
   36 #ifdef HAVE_SYS_TYPES_H
   37 #include <sys/types.h>
   38 #endif
   39 
   40 #ifdef HAVE_UNISTD_H
   41 #include <unistd.h>
   42 #endif
   43 
   44 #ifdef HAVE_SYS_STAT_H
   45 #include <sys/stat.h>
   46 #endif
   47 
   48 #ifdef HAVE_FCNTL_H
   49 #include <fcntl.h>
   50 #endif
   51 
   52 #ifdef HAVE_STDLIB_H
   53 #include <stdlib.h>
   54 #endif
   55 
   56 #ifdef HAVE_SYS_LOADAVG_H
   57 #include <sys/loadavg.h>
   58 #endif
   59 
   60 #ifdef HAVE_STRING_H
   61 #include <string.h>
   62 #endif
   63 
   64 #ifdef HAVE_PROCFS_H
   65 #include <procfs.h>
   66 #endif
   67 
   68 #ifdef HAVE_GLOB_H
   69 #include <glob.h>
   70 #endif
   71 
   72 #ifdef HAVE_KSTAT_H
   73 #include <kstat.h>
   74 #endif
   75 
   76 #ifdef HAVE_SYS_SWAP_H
   77 #define _SYS_VNODE_H
   78 #include <sys/swap.h>
   79 #endif
   80 
   81 #ifdef HAVE_SYS_SYSINFO_H
   82 #include <sys/sysinfo.h>
   83 #endif
   84 
   85 #ifdef HAVE_ZONE_H
   86 #include <zone.h>
   87 #endif
   88 
   89 #ifdef HAVE_SYS_VM_USAGE_H
   90 #include <sys/vm_usage.h>
   91 #endif
   92 
   93 #include "monit.h"
   94 #include "system/Time.h"
   95 #include "ProcessTree.h"
   96 #include "process_sysdep.h"
   97 
   98 /**
   99  *  System dependent resource data collecting code for Solaris.
  100  *
  101  *  @file
  102  */
  103 
  104 static int    page_size;
  105 static long   old_cpu_user = 0;
  106 static long   old_cpu_syst = 0;
  107 static long   old_cpu_iowait = 0;
  108 static long   old_total = 0;
  109 
  110 #define MAXSTRSIZE 80
  111 
  112 bool init_process_info_sysdep(void) {
  113         systeminfo.cpu.count = sysconf( _SC_NPROCESSORS_ONLN);
  114         page_size = getpagesize();
  115         systeminfo.memory.size = (unsigned long long)sysconf(_SC_PHYS_PAGES) * (unsigned long long)page_size;
  116         kstat_ctl_t *kctl = kstat_open();
  117         if (kctl) {
  118                 kstat_t *kstat = kstat_lookup(kctl, "unix", 0, "system_misc");
  119                 if (kstat) {
  120                         if (kstat_read(kctl, kstat, 0) != -1) {
  121                                 kstat_named_t *knamed = kstat_data_lookup(kstat, "boot_time");
  122                                 if (knamed)
  123                                         systeminfo.booted = (unsigned long long)knamed->value.ul;
  124                         }
  125                 }
  126                 kstat_close(kctl);
  127         }
  128         return true;
  129 }
  130 
  131 double timestruc_to_tseconds(timestruc_t t) {
  132         return  t.tv_sec * 10 + t.tv_nsec / 100000000.0;
  133 }
  134 
  135 
  136 /**
  137  * Read all processes of the proc files system to initialize the process tree
  138  * @param reference reference of ProcessTree
  139  * @param pflags Process engine flags
  140  * @return treesize > 0 if succeeded otherwise 0
  141  */
  142 int initprocesstree_sysdep(ProcessTree_T **reference, ProcessEngine_Flags pflags) {
  143         ASSERT(reference);
  144 
  145         /* Find all processes in the /proc directory */
  146         glob_t globbuf;
  147         int rv = glob("/proc/[0-9]*", 0, NULL, &globbuf);
  148         if (rv != 0) {
  149                 Log_error("system statistic error -- glob failed: %d (%s)\n", rv, STRERROR);
  150                 return 0;
  151         }
  152 
  153         int treesize = globbuf.gl_pathc;
  154 
  155         /* Allocate the tree */
  156         ProcessTree_T *pt = CALLOC(sizeof(ProcessTree_T), treesize);
  157 
  158         char buf[4096];
  159         for (int i = 0; i < treesize; i++) {
  160                 pt[i].pid = atoi(globbuf.gl_pathv[i] + strlen("/proc/"));
  161                 if (file_readProc(buf, sizeof(buf), "psinfo", pt[i].pid, NULL)) {
  162                         psinfo_t *psinfo = (psinfo_t *)&buf;
  163                         pt[i].ppid         = psinfo->pr_ppid;
  164                         pt[i].cred.uid     = psinfo->pr_uid;
  165                         pt[i].cred.euid    = psinfo->pr_euid;
  166                         pt[i].cred.gid     = psinfo->pr_gid;
  167                         pt[i].uptime       = systeminfo.time / 10. - psinfo->pr_start.tv_sec;
  168                         pt[i].zombie       = psinfo->pr_nlwp == 0 ? true : false; // If we don't have any light-weight processes (LWP) then we are definitely a zombie
  169                         pt[i].memory.usage = (unsigned long long)psinfo->pr_rssize * 1024;
  170                         if (pflags & ProcessEngine_CollectCommandLine) {
  171                                 pt[i].cmdline = Str_dup(psinfo->pr_psargs);
  172                                 if (STR_UNDEF(pt[i].cmdline)) {
  173                                         FREE(pt[i].cmdline);
  174                                         pt[i].cmdline = Str_dup(psinfo->pr_fname);
  175                                 }
  176                         }
  177                         if (file_readProc(buf, sizeof(buf), "status", pt[i].pid, NULL)) {
  178                                 pstatus_t *pstatus = (pstatus_t *)&buf;
  179                                 pt[i].cpu.time = timestruc_to_tseconds(pstatus->pr_utime) + timestruc_to_tseconds(pstatus->pr_stime);
  180                                 pt[i].threads.self = pstatus->pr_nlwp;
  181                         }
  182                         if (file_readProc(buf, sizeof(buf), "usage", pt[i].pid, NULL)) {
  183                                 struct prusage *usage = (struct prusage *)&buf;
  184                                 pt[i].read.bytes          = -1;
  185                                 pt[i].read.bytesPhysical  = -1;
  186                                 pt[i].read.operations     = usage->pr_inblk;
  187                                 pt[i].write.bytes         = -1;
  188                                 pt[i].write.bytesPhysical = -1;
  189                                 pt[i].write.operations    = usage->pr_oublk;
  190                                 pt[i].read.time = pt[i].write.time = Time_milli();
  191                         }
  192                 }
  193         }
  194 
  195         *reference = pt;
  196 
  197         /* Free globbing buffer */
  198         globfree(&globbuf);
  199 
  200         return treesize;
  201 }
  202 
  203 /**
  204  * This routine returns 'nelem' double precision floats containing
  205  * the load averages in 'loadv'; at most 3 values will be returned.
  206  * @param loadv destination of the load averages
  207  * @param nelem number of averages
  208  * @return: 0 if successful, -1 if failed (and all load averages are 0).
  209  */
  210 int getloadavg_sysdep (double *loadv, int nelem) {
  211         return getloadavg(loadv, nelem);
  212 }
  213 
  214 
  215 /**
  216  * This routine returns kbyte of real memory in use.
  217  * @return: true if successful, false if failed (or not available)
  218  */
  219 bool used_system_memory_sysdep(SystemInfo_T *si) {
  220         int                 n, num;
  221         kstat_ctl_t        *kctl;
  222         kstat_named_t      *knamed;
  223         kstat_t            *kstat;
  224         swaptbl_t          *s;
  225         char               *strtab;
  226         unsigned long long  total = 0ULL;
  227         unsigned long long  used  = 0ULL;
  228 
  229         /* Memory */
  230         kctl = kstat_open();
  231         zoneid_t zoneid = getzoneid();
  232         if (zoneid != GLOBAL_ZONEID) {
  233                 /* Zone */
  234                 if ((kstat = kstat_lookup(kctl, "memory_cap", -1, NULL))) {
  235                         /* Joyent SmartOS zone: reports wrong unix::system_pages:freemem in the zone - shows global zone freemem, switch to SmartOS specific memory_cap kstat, which is more effective then common getvmusage() */
  236                         if (kstat_read(kctl, kstat, NULL) == -1) {
  237                                 Log_error("system statistic error -- memory_cap usage data collection failed\n");
  238                                 kstat_close(kctl);
  239                                 return false;
  240                         }
  241                         kstat_named_t *rss = kstat_data_lookup(kstat, "rss");
  242                         if (rss)
  243                                 si->memory.usage.bytes = (unsigned long long)rss->value.i64;
  244                 } else {
  245                         /* Solaris Zone */
  246                         size_t nres;
  247                         vmusage_t result;
  248                         if (getvmusage(VMUSAGE_ZONE, Run.polltime, &result, &nres) != 0) {
  249                                 Log_error("system statistic error -- getvmusage failed\n");
  250                                 kstat_close(kctl);
  251                                 return false;
  252                         }
  253                         si->memory.usage.bytes = (unsigned long long)result.vmu_rss_all;
  254                 }
  255         } else {
  256                 kstat = kstat_lookup(kctl, "unix", 0, "system_pages");
  257                 if (kstat_read(kctl, kstat, 0) == -1) {
  258                         Log_error("system statistic error -- memory usage data collection failed\n");
  259                         kstat_close(kctl);
  260                         return false;
  261                 }
  262                 knamed = kstat_data_lookup(kstat, "freemem");
  263                 if (knamed) {
  264                         unsigned long long freemem = (unsigned long long)knamed->value.ul * (unsigned long long)page_size, arcsize = 0ULL;
  265                         kstat = kstat_lookup(kctl, "zfs", 0, "arcstats");
  266                         if (kstat_read(kctl, kstat, 0) != -1) {
  267                                 knamed = kstat_data_lookup(kstat, "size");
  268                                 arcsize = (unsigned long long)knamed->value.ul;
  269                         }
  270                         si->memory.usage.bytes = systeminfo.memory.size - freemem - arcsize;
  271                 }
  272         }
  273         kstat_close(kctl);
  274 
  275         /* Swap */
  276 again:
  277         if ((num = swapctl(SC_GETNSWP, 0)) == -1) {
  278                 Log_error("system statistic error -- swap usage data collection failed: %s\n", STRERROR);
  279                 return false;
  280         }
  281         if (num == 0) {
  282                 DEBUG("system statistic -- no swap configured\n");
  283                 si->swap.size = 0ULL;
  284                 return true;
  285         }
  286         s = (swaptbl_t *)ALLOC(num * sizeof(swapent_t) + sizeof(struct swaptable));
  287         strtab = (char *)ALLOC((num + 1) * MAXSTRSIZE);
  288         for (int i = 0; i < (num + 1); i++)
  289                 s->swt_ent[i].ste_path = strtab + (i * MAXSTRSIZE);
  290         s->swt_n = num + 1;
  291         if ((n = swapctl(SC_LIST, s)) < 0) {
  292                 Log_error("system statistic error -- swap usage data collection failed: %s\n", STRERROR);
  293                 si->swap.size = 0ULL;
  294                 FREE(s);
  295                 FREE(strtab);
  296                 return false;
  297         }
  298         if (n > num) {
  299                 DEBUG("system statistic -- new swap added: deferring swap usage statistics to next cycle\n");
  300                 FREE(s);
  301                 FREE(strtab);
  302                 goto again;
  303         }
  304         for (int i = 0; i < n; i++) {
  305                 if (! (s->swt_ent[i].ste_flags & ST_INDEL) && ! (s->swt_ent[i].ste_flags & ST_DOINGDEL)) {
  306                         total += s->swt_ent[i].ste_pages;
  307                         used  += s->swt_ent[i].ste_pages - s->swt_ent[i].ste_free;
  308                 }
  309         }
  310         FREE(s);
  311         FREE(strtab);
  312         si->swap.size = (unsigned long long)total * (unsigned long long)page_size;
  313         si->swap.usage.bytes = (unsigned long long)used * (unsigned long long)page_size;
  314 
  315         return true;
  316 }
  317 
  318 
  319 /**
  320  * This routine returns system/user CPU time in use.
  321  * @return: true if successful, false if failed (or not available)
  322  */
  323 bool used_system_cpu_sysdep(SystemInfo_T *si) {
  324         int             ncpu = 0, ncpus;
  325         long            cpu_user = 0, cpu_syst = 0, cpu_iowait = 0, total = 0, diff_total;
  326         kstat_ctl_t    *kctl;
  327         kstat_named_t  *knamed;
  328         kstat_t        *kstat;
  329         kstat_t       **cpu_ks;
  330         cpu_stat_t     *cpu_stat;
  331 
  332         si->cpu.usage.user = si->cpu.usage.system = si->cpu.usage.iowait = 0;
  333 
  334         kctl  = kstat_open();
  335         kstat = kstat_lookup(kctl, "unix", 0, "system_misc");
  336         if (kstat_read(kctl, kstat, 0) == -1) {
  337                 Log_error("system statistic -- failed to lookup unix::system_misc kstat\n");
  338                 goto error;
  339         }
  340 
  341         if (NULL == (knamed = kstat_data_lookup(kstat, "ncpus"))) {
  342                 Log_error("system statistic -- ncpus kstat lookup failed\n");
  343                 goto error;
  344         }
  345 
  346         if ((ncpus = knamed->value.ui32) == 0) {
  347                 Log_error("system statistic -- ncpus is 0\n");
  348                 goto error;
  349         }
  350 
  351         cpu_ks   = (kstat_t **)ALLOC(ncpus * sizeof(kstat_t *));
  352         cpu_stat = (cpu_stat_t *)ALLOC(ncpus * sizeof(cpu_stat_t));
  353 
  354         for (kstat = kctl->kc_chain; kstat; kstat = kstat->ks_next) {
  355                 if (strncmp(kstat->ks_name, "cpu_stat", 8) == 0) {
  356                         if (-1 == kstat_read(kctl, kstat, NULL)) {
  357                                 Log_error("system statistic -- failed to read cpu_stat kstat\n");
  358                                 goto error2;
  359                         }
  360                         cpu_ks[ncpu] = kstat;
  361                         if (++ncpu > ncpus) {
  362                                 Log_error("system statistic -- cpu count mismatch\n");
  363                                 goto error2;
  364                         }
  365                 }
  366         }
  367 
  368         for (int i = 0; i < ncpu; i++) {
  369                 if (-1 == kstat_read(kctl, cpu_ks[i], &cpu_stat[i])) {
  370                         Log_error("system statistic -- failed to read cpu_stat kstat for cpu %d\n", i);
  371                         goto error2;
  372                 }
  373                 cpu_user += cpu_stat[i].cpu_sysinfo.cpu[CPU_USER];
  374                 cpu_syst += cpu_stat[i].cpu_sysinfo.cpu[CPU_KERNEL];
  375                 cpu_iowait += cpu_stat[i].cpu_sysinfo.cpu[CPU_WAIT];
  376                 total    += (cpu_stat[i].cpu_sysinfo.cpu[0] + cpu_stat[i].cpu_sysinfo.cpu[1] + cpu_stat[i].cpu_sysinfo.cpu[2] + cpu_stat[i].cpu_sysinfo.cpu[3]);
  377         }
  378 
  379         if (old_total == 0) {
  380                 si->cpu.usage.user = si->cpu.usage.system = si->cpu.usage.iowait = -1.;
  381         } else if ((diff_total = total - old_total) > 0) {
  382                 si->cpu.usage.user = (100. * (cpu_user - old_cpu_user)) / diff_total;
  383                 si->cpu.usage.system = (100. * (cpu_syst - old_cpu_syst)) / diff_total;
  384                 si->cpu.usage.iowait = (100. * (cpu_iowait - old_cpu_iowait)) / diff_total;
  385         }
  386 
  387         old_cpu_user = cpu_user;
  388         old_cpu_syst = cpu_syst;
  389         old_cpu_iowait = cpu_iowait;
  390         old_total    = total;
  391 
  392         FREE(cpu_ks);
  393         FREE(cpu_stat);
  394         kstat_close(kctl);
  395         return true;
  396 
  397 error2:
  398         old_total = 0;
  399         FREE(cpu_ks);
  400         FREE(cpu_stat);
  401 
  402 error:
  403         kstat_close(kctl);
  404         return false;
  405 }
  406 
  407 
  408 bool used_system_filedescriptors_sysdep(__attribute__ ((unused)) SystemInfo_T *si) {
  409         // Not implemented
  410         return true;
  411 }
  412 
  413 
  414 bool available_statistics(SystemInfo_T *si) {
  415         si->statisticsAvailable = Statistics_CpuUser | Statistics_CpuSystem | Statistics_CpuIOWait;
  416         return true;
  417 }
  418