"Fossies" - the Fresh Open Source Software Archive

Member "monit-5.28.0/src/process/ProcessTree.c" (28 Mar 2021, 24711 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 "ProcessTree.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 #include "config.h"
   26 
   27 #ifdef HAVE_SYS_TYPES_H
   28 #include <sys/types.h>
   29 #endif
   30 
   31 #ifdef HAVE_SYS_STAT_H
   32 #include <sys/stat.h>
   33 #endif
   34 
   35 #ifdef HAVE_FCNTL_H
   36 #include <fcntl.h>
   37 #endif
   38 
   39 #ifdef HAVE_STDLIB_H
   40 #include <stdlib.h>
   41 #endif
   42 
   43 #ifdef HAVE_SYS_TIME_H
   44 #include <sys/time.h>
   45 #endif
   46 
   47 #ifdef HAVE_TIME_H
   48 #include <time.h>
   49 #endif
   50 
   51 #ifdef HAVE_STRING_H
   52 #include <string.h>
   53 #endif
   54 
   55 #ifdef HAVE_STDIO_H
   56 #include <stdio.h>
   57 #endif
   58 
   59 #ifdef HAVE_UNISTD_H
   60 #include <unistd.h>
   61 #endif
   62 
   63 #ifdef HAVE_COREFOUNDATION_COREFOUNDATION_H
   64 #include <CoreFoundation/CoreFoundation.h>
   65 #endif
   66 
   67 #include "monit.h"
   68 #include "event.h"
   69 #include "ProcessTree.h"
   70 #include "process_sysdep.h"
   71 #include "TextBox.h"
   72 #include "TextColor.h"
   73 
   74 // libmonit
   75 #include "system/Time.h"
   76 
   77 
   78 /**
   79  *  General purpose /proc methods.
   80  *
   81  *  @file
   82  */
   83 
   84 
   85 /* ------------------------------------------------------------- Definitions */
   86 
   87 
   88 static int ptreesize = 0;
   89 static ProcessTree_T *ptree = NULL;
   90 
   91 
   92 /* ----------------------------------------------------------------- Private */
   93 
   94 
   95 static void _delete(ProcessTree_T **pt, int *size) {
   96         ASSERT(pt);
   97         ProcessTree_T *_pt = *pt;
   98         if (_pt) {
   99                 for (int i = 0; i < *size; i++) {
  100                         FREE(_pt[i].cmdline);
  101                         FREE(_pt[i].children.list);
  102                         FREE(_pt[i].secattr);
  103                 }
  104                 FREE(_pt);
  105                 *pt = NULL;
  106                 *size = 0;
  107         }
  108 }
  109 
  110 
  111 /**
  112  * Search a leaf in the processtree
  113  * @param pid  pid of the process
  114  * @param pt  processtree
  115  * @param treesize  size of the processtree
  116  * @return process index if succeeded otherwise -1
  117  */
  118 static int _findProcess(int pid, ProcessTree_T *pt, int size) {
  119         if (size > 0) {
  120                 for (int i = 0; i < size; i++)
  121                         if (pid == pt[i].pid)
  122                                 return i;
  123         }
  124         return -1;
  125 }
  126 
  127 
  128 /**
  129  * Fill data in the process tree by recursively walking through it
  130  * @param pt process tree
  131  * @param i process index
  132  */
  133 static void _fillProcessTree(ProcessTree_T *pt, int index) {
  134         if (! pt[index].visited) {
  135                 pt[index].visited = true;
  136                 pt[index].children.total = pt[index].children.count;
  137                 pt[index].threads.children = 0;
  138                 pt[index].cpu.usage.children = 0.;
  139                 pt[index].memory.usage_total = pt[index].memory.usage;
  140                 pt[index].filedescriptors.usage_total = pt[index].filedescriptors.usage;
  141                 for (int i = 0; i < pt[index].children.count; i++) {
  142                         _fillProcessTree(pt, pt[index].children.list[i]);
  143                 }
  144                 if (pt[index].parent != -1 && pt[index].parent != index) {
  145                         ProcessTree_T *parent_pt = &pt[pt[index].parent];
  146                         parent_pt->children.total += pt[index].children.total;
  147                         parent_pt->threads.children += (pt[index].threads.self > 1 ? pt[index].threads.self : 1) + (pt[index].threads.children > 0 ? pt[index].threads.children : 0);
  148                         if (pt[index].cpu.usage.self >= 0) {
  149                                 parent_pt->cpu.usage.children += pt[index].cpu.usage.self;
  150                         }
  151                         if (pt[index].cpu.usage.children >= 0) {
  152                                 parent_pt->cpu.usage.children += pt[index].cpu.usage.children;
  153                         }
  154                         parent_pt->memory.usage_total     += pt[index].memory.usage_total;
  155                         parent_pt->filedescriptors.usage_total += pt[index].filedescriptors.usage_total;
  156                 }
  157         }
  158 }
  159 
  160 
  161 /**
  162  * Adjust the CPU usage based on the available system resources: number of CPU cores the application may utilize. Single threaded application may utilized only one CPU core, 4 threaded application 4 cores, etc.. If the application
  163  * has more threads then the machine has cores, it is limited by number of cores, not threads.
  164  * @param now Current process information
  165  * @param prev Process information from previous cycle
  166  * @param delta The delta of system time between current and previous cycle
  167  * @return Process's CPU usage [%] since last cycle
  168  */
  169 static float _cpuUsage(float rawUsage, unsigned int threads) {
  170         if (systeminfo.cpu.count > 0 && rawUsage > 0) {
  171                 int divisor;
  172                 if (threads > 1) {
  173                         if (threads >= (unsigned)systeminfo.cpu.count) {
  174                                 // Multithreaded application with more threads then CPU cores
  175                                 divisor = systeminfo.cpu.count;
  176                         } else {
  177                                 // Multithreaded application with less threads then CPU cores
  178                                 divisor = threads;
  179                         }
  180                 } else {
  181                         // Single threaded application
  182                         divisor = 1;
  183                 }
  184                 float usage = rawUsage / divisor;
  185                 return usage > 100. ? 100. : usage;
  186         }
  187         return 0.;
  188 }
  189 
  190 
  191 static int _match(regex_t *regex) {
  192         int found = -1;
  193         // Scan the whole process tree and find the oldest matching process whose parent doesn't match the pattern
  194         for (int i = 0; i < ptreesize; i++)
  195                 if (ptree[i].cmdline && regexec(regex, ptree[i].cmdline, 0, NULL, 0) == 0 && (i == ptree[i].parent || ! ptree[ptree[i].parent].cmdline || regexec(regex, ptree[ptree[i].parent].cmdline, 0, NULL, 0) != 0) && (found == -1 || ptree[found].uptime < ptree[i].uptime))
  196                         found = i;
  197         return found >= 0 ? ptree[found].pid : -1;
  198 }
  199 
  200 
  201 /* ------------------------------------------------------------------ Public */
  202 
  203 
  204 /**
  205  * Initialize the process tree
  206  * @return treesize >= 0 if succeeded otherwise < 0
  207  */
  208 int ProcessTree_init(ProcessEngine_Flags pflags) {
  209         ProcessTree_T *oldptree = ptree;
  210         int oldptreesize = ptreesize;
  211         if (oldptree) {
  212                 ptree = NULL;
  213                 ptreesize = 0;
  214                 // We need only process's cpu.time from the old ptree, so free dynamically allocated parts which we don't need before initializing new ptree (so the memory can be reused, otherwise the memory footprint will hold two ptrees)
  215                 for (int i = 0; i < oldptreesize; i++) {
  216                         FREE(oldptree[i].cmdline);
  217                         FREE(oldptree[i].children.list);
  218                         FREE(oldptree[i].secattr);
  219                 }
  220         }
  221 
  222         systeminfo.time_prev = systeminfo.time;
  223         systeminfo.time = Time_milli() / 100.;
  224         if ((ptreesize = initprocesstree_sysdep(&ptree, pflags)) <= 0 || ! ptree) {
  225                 DEBUG("System statistic -- cannot initialize the process tree -- process resource monitoring disabled\n");
  226                 Run.flags &= ~Run_ProcessEngineEnabled;
  227                 if (oldptree)
  228                         _delete(&oldptree, &oldptreesize);
  229                 return -1;
  230         } else if (! (Run.flags & Run_ProcessEngineEnabled)) {
  231                 DEBUG("System statistic -- initialization of the process tree succeeded -- process resource monitoring enabled\n");
  232                 Run.flags |= Run_ProcessEngineEnabled;
  233         }
  234 
  235         int root = -1; // Main process. Not all systems have main process with PID 1 (such as Solaris zones and FreeBSD jails), so we try to find process which is parent of itself
  236         ProcessTree_T *pt = ptree;
  237         double time_delta = systeminfo.time - systeminfo.time_prev;
  238         for (int i = 0; i < (volatile int)ptreesize; i ++) {
  239                 pt[i].cpu.usage.self = -1;
  240                 if (oldptree) {
  241                         int oldentry = _findProcess(pt[i].pid, oldptree, oldptreesize);
  242                         if (oldentry != -1) {
  243                                 if (systeminfo.cpu.count > 0 && time_delta > 0 && oldptree[oldentry].cpu.time >= 0 && pt[i].cpu.time >= oldptree[oldentry].cpu.time) {
  244                                         pt[i].cpu.usage.self = 100. * (pt[i].cpu.time - oldptree[oldentry].cpu.time) / time_delta;
  245                                 }
  246                         }
  247                 }
  248                 // Note: on DragonFly, main process is swapper with pid 0 and ppid -1, so take also this case into consideration
  249                 if ((pt[i].pid == pt[i].ppid) || (pt[i].ppid == -1)) {
  250                         root = pt[i].parent = i;
  251                 } else {
  252                         // Find this process's parent
  253                         int parent = _findProcess(pt[i].ppid, pt, ptreesize);
  254                         if (parent == -1) {
  255                                 /* Parent process wasn't found - on Linux this is normal: main process with PID 0 is not listed, similarly in FreeBSD jail.
  256                                  * We create virtual process entry for missing parent so we can have full tree-like structure with root. */
  257                                 parent = ptreesize++;
  258                                 pt = RESIZE(ptree, ptreesize * sizeof(ProcessTree_T));
  259                                 memset(&pt[parent], 0, sizeof(ProcessTree_T));
  260                                 root = pt[parent].ppid = pt[parent].pid = pt[i].ppid;
  261                         }
  262                         pt[i].parent = parent;
  263                         // Connect the child (this process) to the parent
  264                         RESIZE(pt[parent].children.list, sizeof(int) * (pt[parent].children.count + 1));
  265                         pt[parent].children.list[pt[parent].children.count] = i;
  266                         pt[parent].children.count++;
  267                 }
  268         }
  269         FREE(oldptree); // Free the rest of old ptree
  270         if (root == -1) {
  271                 DEBUG("System statistic error -- cannot find root process id\n");
  272                 _delete(&ptree, &ptreesize);
  273                 return -1;
  274         }
  275 
  276         _fillProcessTree(pt, root);
  277 
  278         return ptreesize;
  279 }
  280 
  281 
  282 /**
  283  * Delete the process tree
  284  */
  285 void ProcessTree_delete() {
  286         _delete(&ptree, &ptreesize);
  287 }
  288 
  289 
  290 bool ProcessTree_updateProcess(Service_T s, pid_t pid) {
  291         ASSERT(s);
  292 
  293         /* save the previous pid and set actual one */
  294         s->inf.process->_pid = s->inf.process->pid;
  295         s->inf.process->pid  = pid;
  296 
  297         int leaf = _findProcess(pid, ptree, ptreesize);
  298         if (leaf != -1) {
  299                 /* save the previous ppid and set actual one */
  300                 s->inf.process->_ppid             = s->inf.process->ppid;
  301                 s->inf.process->ppid              = ptree[leaf].ppid;
  302                 s->inf.process->uid               = ptree[leaf].cred.uid;
  303                 s->inf.process->euid              = ptree[leaf].cred.euid;
  304                 s->inf.process->gid               = ptree[leaf].cred.gid;
  305                 s->inf.process->uptime            = ptree[leaf].uptime;
  306                 s->inf.process->threads           = ptree[leaf].threads.self;
  307                 s->inf.process->children          = ptree[leaf].children.total;
  308                 s->inf.process->zombie            = ptree[leaf].zombie;
  309                 snprintf(s->inf.process->secattr, STRLEN, "%s", NVLSTR(ptree[leaf].secattr));
  310                 if (ptree[leaf].cpu.usage.self >= 0) {
  311                         // compute only if initialized (delta between current and previous snapshot is available)
  312                         s->inf.process->cpu_percent = _cpuUsage(ptree[leaf].cpu.usage.self, ptree[leaf].threads.self);
  313                         s->inf.process->total_cpu_percent = s->inf.process->cpu_percent + _cpuUsage(ptree[leaf].cpu.usage.children, ptree[leaf].threads.children);
  314                         if (s->inf.process->total_cpu_percent > 100.) {
  315                                 s->inf.process->total_cpu_percent = 100.;
  316                         }
  317                 } else {
  318                         s->inf.process->cpu_percent = -1;
  319                         s->inf.process->total_cpu_percent = -1;
  320                 }
  321                 s->inf.process->mem               = ptree[leaf].memory.usage;
  322                 s->inf.process->total_mem         = ptree[leaf].memory.usage_total;
  323                 s->inf.process->filedescriptors.open        = ptree[leaf].filedescriptors.usage;
  324                 s->inf.process->filedescriptors.openTotal   = ptree[leaf].filedescriptors.usage_total;
  325                 s->inf.process->filedescriptors.limit.soft  = ptree[leaf].filedescriptors.limit.soft;
  326                 s->inf.process->filedescriptors.limit.hard  = ptree[leaf].filedescriptors.limit.hard;
  327                 if (systeminfo.memory.size > 0) {
  328                         s->inf.process->total_mem_percent = ptree[leaf].memory.usage_total >= systeminfo.memory.size ? 100. : (100. * (double)ptree[leaf].memory.usage_total / (double)systeminfo.memory.size);
  329                         s->inf.process->mem_percent       = ptree[leaf].memory.usage >= systeminfo.memory.size ? 100. : (100. * (double)ptree[leaf].memory.usage / (double)systeminfo.memory.size);
  330                 }
  331                 if (ptree[leaf].read.bytes >= 0)
  332                         Statistics_update(&(s->inf.process->read.bytes), ptree[leaf].read.time, ptree[leaf].read.bytes);
  333                 if (ptree[leaf].read.bytesPhysical >= 0)
  334                         Statistics_update(&(s->inf.process->read.bytesPhysical), ptree[leaf].read.time, ptree[leaf].read.bytesPhysical);
  335                 if (ptree[leaf].read.operations >= 0)
  336                         Statistics_update(&(s->inf.process->read.operations), ptree[leaf].read.time, ptree[leaf].read.operations);
  337                 if (ptree[leaf].write.bytes >= 0)
  338                         Statistics_update(&(s->inf.process->write.bytes), ptree[leaf].write.time, ptree[leaf].write.bytes);
  339                 if (ptree[leaf].write.bytesPhysical >= 0)
  340                         Statistics_update(&(s->inf.process->write.bytesPhysical), ptree[leaf].write.time, ptree[leaf].write.bytesPhysical);
  341                 if (ptree[leaf].write.operations >= 0)
  342                         Statistics_update(&(s->inf.process->write.operations), ptree[leaf].write.time, ptree[leaf].write.operations);
  343                 return true;
  344         }
  345         Util_resetInfo(s);
  346         return false;
  347 }
  348 
  349 
  350 time_t ProcessTree_getProcessUptime(pid_t pid) {
  351         if (ptree) {
  352                 int leaf = _findProcess(pid, ptree, ptreesize);
  353                 return (time_t)((leaf >= 0 && leaf < ptreesize) ? ptree[leaf].uptime : -1);
  354         }
  355         return 0;
  356 }
  357 
  358 
  359 pid_t ProcessTree_findProcess(Service_T s) {
  360         ASSERT(s);
  361         // Test the cached PID first
  362         if (s->inf.process->pid > 0) {
  363                 errno = 0;
  364                 if (getpgid(s->inf.process->pid) > -1 || errno == EPERM)
  365                         return s->inf.process->pid;
  366         }
  367         // If the cached PID is not running, scan for the process again
  368         if (s->matchlist) {
  369                 // Update the process tree including command line
  370                 ProcessTree_init(ProcessEngine_CollectCommandLine);
  371                 if (Run.flags & Run_ProcessEngineEnabled) {
  372                         int pid = _match(s->matchlist->regex_comp);
  373                         if (pid >= 0)
  374                                 return pid;
  375                 } else {
  376                         DEBUG("Process information not available -- skipping service %s process existence check for this cycle\n", s->name);
  377                         // Return value is NOOP - it is based on existing errors bitmap so we don't generate false recovery/failures
  378                         return ! (s->error & Event_NonExist);
  379                 }
  380         } else {
  381                 pid_t pid = Util_getPid(s->path);
  382                 if (pid > 0) {
  383                         errno = 0;
  384                         if (getpgid(pid) > -1 || errno == EPERM)
  385                                 return pid;
  386                         DEBUG("'%s' process test failed [pid=%d] -- %s\n", s->name, pid, STRERROR);
  387                 }
  388         }
  389         Util_resetInfo(s);
  390         return 0;
  391 }
  392 
  393 
  394 void ProcessTree_testMatch(char *pattern) {
  395         regex_t *regex_comp;
  396         int reg_return;
  397 
  398         NEW(regex_comp);
  399         if ((reg_return = regcomp(regex_comp, pattern, REG_NOSUB|REG_EXTENDED))) {
  400                 char errbuf[STRLEN];
  401                 regerror(reg_return, regex_comp, errbuf, STRLEN);
  402                 regfree(regex_comp);
  403                 FREE(regex_comp);
  404                 printf("Regex %s parsing error: %s\n", pattern, errbuf);
  405                 exit(1);
  406         }
  407         ProcessTree_init(ProcessEngine_CollectCommandLine);
  408         if (Run.flags & Run_ProcessEngineEnabled) {
  409                 int count = 0;
  410                 printf("List of processes matching pattern \"%s\":\n", pattern);
  411                 StringBuffer_T output = StringBuffer_create(256);
  412                 TextBox_T t = TextBox_new(output, 4, (TextBoxColumn_T []){
  413                                 {.name = "",        .width = 1,  .wrap = false, .align = TextBoxAlign_Left},
  414                                 {.name = "PID",     .width = 8,  .wrap = false, .align = TextBoxAlign_Right},
  415                                 {.name = "PPID",    .width = 8,  .wrap = false, .align = TextBoxAlign_Right},
  416                                 {.name = "Command", .width = 50, .wrap = true,  .align = TextBoxAlign_Left}
  417                           }, true);
  418                 // Select the process matching the pattern
  419                 int pid = _match(regex_comp);
  420                 // Print all matching processes and highlight the one which is selected
  421                 for (int i = 0; i < ptreesize; i++) {
  422                         if (ptree[i].cmdline && ! strstr(ptree[i].cmdline, "procmatch")) {
  423                                 if (! regexec(regex_comp, ptree[i].cmdline, 0, NULL, 0)) {
  424                                         if (pid == ptree[i].pid) {
  425                                                 TextBox_setColumn(t, 1, COLOR_BOLD "*" COLOR_RESET);
  426                                                 TextBox_setColumn(t, 2, COLOR_BOLD "%d" COLOR_RESET, ptree[i].pid);
  427                                                 TextBox_setColumn(t, 3, COLOR_BOLD "%d" COLOR_RESET, ptree[i].ppid);
  428                                                 TextBox_setColumn(t, 4, COLOR_BOLD "%s" COLOR_RESET, ptree[i].cmdline);
  429                                         } else {
  430                                                 TextBox_setColumn(t, 2, "%d", ptree[i].pid);
  431                                                 TextBox_setColumn(t, 3, "%d", ptree[i].ppid);
  432                                                 TextBox_setColumn(t, 4, "%s", ptree[i].cmdline);
  433                                         }
  434                                         TextBox_printRow(t);
  435                                         count++;
  436                                 }
  437                         }
  438                 }
  439                 TextBox_free(&t);
  440                 if (Run.flags & Run_Batch || ! TextColor_support())
  441                         TextColor_strip(TextBox_strip((char *)StringBuffer_toString(output)));
  442                 printf("%s", StringBuffer_toString(output));
  443                 StringBuffer_free(&output);
  444                 printf("Total matches: %d\n", count);
  445                 if (count > 1)
  446                         printf("\n"
  447                                "WARNING:\n"
  448                                "Multiple processes match the pattern. Monit will select the process with the\n"
  449                                "highest uptime, the one highlighted.\n");
  450         }
  451         regfree(regex_comp);
  452         FREE(regex_comp);
  453 }
  454 
  455 
  456 //FIXME: move to standalone system class
  457 bool init_system_info(void) {
  458         memset(&systeminfo, 0, sizeof(SystemInfo_T));
  459         gettimeofday(&systeminfo.collected, NULL);
  460         if (uname(&systeminfo.uname) < 0) {
  461                 Log_error("'%s' resource monitoring initialization error -- uname failed: %s\n", Run.system->name, STRERROR);
  462                 return false;
  463         }
  464 #ifdef HAVE_COREFOUNDATION_COREFOUNDATION_H
  465         CFURLRef url = CFURLCreateWithFileSystemPath(NULL, CFSTR("/System/Library/CoreServices/SystemVersion.plist"), kCFURLPOSIXPathStyle, false);
  466         if (url) {
  467                 CFReadStreamRef stream = CFReadStreamCreateWithFile(NULL, url);
  468                 if (stream) {
  469                         if (CFReadStreamOpen(stream)) {
  470                                 CFPropertyListRef propertyList = CFPropertyListCreateWithStream(NULL, stream, 0, kCFPropertyListImmutable, NULL, NULL);
  471                                 if (propertyList) {
  472                                         CFStringRef value = CFDictionaryGetValue(propertyList, CFSTR("ProductName"));
  473                                         if (value) {
  474                                                 CFStringGetCString(value, systeminfo.uname.sysname, sizeof(systeminfo.uname.sysname), CFStringGetSystemEncoding());
  475                                         }
  476                                         value = CFDictionaryGetValue(propertyList, CFSTR("ProductVersion"));
  477                                         if (value) {
  478                                                 CFStringGetCString(value, systeminfo.uname.release, sizeof(systeminfo.uname.release), CFStringGetSystemEncoding());
  479                                         }
  480                                         CFRelease(propertyList);
  481                                 }
  482                                 CFReadStreamClose(stream);
  483                         }
  484                         CFRelease(stream);
  485                 }
  486                 CFRelease(url);
  487         }
  488 #endif
  489         systeminfo.cpu.usage.user = -1.;
  490         systeminfo.cpu.usage.system = -1.;
  491         systeminfo.cpu.usage.iowait = -1.;
  492         return (init_process_info_sysdep());
  493 }
  494 
  495 
  496 //FIXME: move to standalone system class
  497 bool update_system_info() {
  498         if (getloadavg_sysdep(systeminfo.loadavg, 3) == -1) {
  499                 Log_error("'%s' statistic error -- load average data collection failed\n", Run.system->name);
  500                 goto error1;
  501         }
  502 
  503         if (! used_system_memory_sysdep(&systeminfo)) {
  504                 Log_error("'%s' statistic error -- memory usage data collection failed\n", Run.system->name);
  505                 goto error2;
  506         }
  507         systeminfo.memory.usage.percent  = systeminfo.memory.size > 0ULL ? (100. * (double)systeminfo.memory.usage.bytes / (double)systeminfo.memory.size) : 0.;
  508         systeminfo.swap.usage.percent = systeminfo.swap.size > 0ULL ? (100. * (double)systeminfo.swap.usage.bytes / (double)systeminfo.swap.size) : 0.;
  509 
  510         if (! used_system_cpu_sysdep(&systeminfo)) {
  511                 Log_error("'%s' statistic error -- cpu usage data collection failed\n", Run.system->name);
  512                 goto error3;
  513         }
  514 
  515         if (! used_system_filedescriptors_sysdep(&systeminfo)) {
  516                 Log_error("'%s' statistic error -- filedescriptors usage data collection failed\n", Run.system->name);
  517                 goto error4;
  518         }
  519 
  520         return true;
  521 
  522 error1:
  523         systeminfo.loadavg[0] = 0;
  524         systeminfo.loadavg[1] = 0;
  525         systeminfo.loadavg[2] = 0;
  526 error2:
  527         systeminfo.memory.usage.bytes = 0ULL;
  528         systeminfo.memory.usage.percent = 0.;
  529         systeminfo.swap.usage.bytes = 0ULL;
  530         systeminfo.swap.usage.percent = 0.;
  531 error3:
  532         systeminfo.cpu.usage.user = 0.;
  533         systeminfo.cpu.usage.system = 0.;
  534         systeminfo.cpu.usage.iowait = 0.;
  535 error4:
  536         systeminfo.filedescriptors.allocated = 0LL;
  537         systeminfo.filedescriptors.unused = 0LL;
  538         systeminfo.filedescriptors.maximum = 0LL;
  539 
  540         return false;
  541 }
  542 
  543