"Fossies" - the Fresh Open Source Software Archive

Member "atop-2.8.1/various.c" (7 Jan 2023, 22054 Bytes) of package /linux/misc/atop-2.8.1.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 "various.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.8.0_vs_2.8.1.

    1 /*
    2 ** ATOP - System & Process Monitor
    3 **
    4 ** The program 'atop' offers the possibility to view the activity of
    5 ** the system on system-level as well as process-level.
    6 **
    7 ** This source-file contains various functions to a.o. format the
    8 ** time-of-day, the cpu-time consumption and the memory-occupation. 
    9 ** ==========================================================================
   10 ** Author:      Gerlof Langeveld
   11 ** E-mail:      gerlof.langeveld@atoptool.nl
   12 ** Date:        November 1996
   13 ** LINUX-port:  June 2000
   14 ** --------------------------------------------------------------------------
   15 ** Copyright (C) 2000-2022 Gerlof Langeveld
   16 **
   17 ** This program is free software; you can redistribute it and/or modify it
   18 ** under the terms of the GNU General Public License as published by the
   19 ** Free Software Foundation; either version 2, or (at your option) any
   20 ** later version.
   21 **
   22 ** This program is distributed in the hope that it will be useful, but
   23 ** WITHOUT ANY WARRANTY; without even the implied warranty of
   24 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
   25 ** See the GNU General Public License for more details.
   26 **
   27 ** You should have received a copy of the GNU General Public License
   28 ** along with this program; if not, write to the Free Software
   29 ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   30 ** --------------------------------------------------------------------------
   31 **
   32 ** $Log: various.c,v $
   33 ** Revision 1.21  2010/11/12 06:16:16  gerlof
   34 ** Show all parts of timestamp in header line, even when zero.
   35 **
   36 ** Revision 1.20  2010/05/18 19:21:08  gerlof
   37 ** Introduce CPU frequency and scaling (JC van Winkel).
   38 **
   39 ** Revision 1.19  2010/04/28 18:21:11  gerlof
   40 ** Cast value larger than 4GB to long long.
   41 **
   42 ** Revision 1.18  2010/04/23 12:19:35  gerlof
   43 ** Modified mail-address in header.
   44 **
   45 ** Revision 1.17  2010/03/26 11:52:45  gerlof
   46 ** Introduced unit of Tbytes for memory-usage.
   47 **
   48 ** Revision 1.16  2009/12/17 08:28:38  gerlof
   49 ** Express CPU-time usage in days and hours for large values.
   50 **
   51 ** Revision 1.15  2009/12/10 08:50:39  gerlof
   52 ** Introduction of a new function to convert number of seconds
   53 ** to a string indicating days, hours, minutes and seconds.
   54 **
   55 ** Revision 1.14  2007/02/13 10:32:47  gerlof
   56 ** Removal of external declarations.
   57 ** Removal of function getpagesz().
   58 **
   59 ** Revision 1.13  2006/02/07 08:27:21  gerlof
   60 ** Add possibility to show counters per second.
   61 ** Modify presentation of CPU-values.
   62 **
   63 ** Revision 1.12  2005/10/31 12:26:09  gerlof
   64 ** Modified date-format to yyyy/mm/dd.
   65 **
   66 ** Revision 1.11  2005/10/21 09:51:29  gerlof
   67 ** Per-user accumulation of resource consumption.
   68 **
   69 ** Revision 1.10  2004/05/06 09:46:24  gerlof
   70 ** Ported to kernel-version 2.6.
   71 **
   72 ** Revision 1.9  2003/07/07 09:27:46  gerlof
   73 ** Cleanup code (-Wall proof).
   74 **
   75 ** Revision 1.8  2003/07/03 11:16:59  gerlof
   76 ** Minor bug solutions.
   77 **
   78 ** Revision 1.7  2003/06/30 11:31:17  gerlof
   79 ** Enlarge counters to 'long long'.
   80 **
   81 ** Revision 1.6  2003/06/24 06:22:24  gerlof
   82 ** Limit number of system resource lines.
   83 **
   84 ** Revision 1.5  2002/08/30 07:49:09  gerlof
   85 ** Convert a hh:mm string into a number of seconds since 00:00.
   86 **
   87 ** Revision 1.4  2002/08/27 12:08:37  gerlof
   88 ** Modified date format (from yyyy/mm/dd to mm/dd/yyyy).
   89 **
   90 ** Revision 1.3  2002/07/24 11:14:05  gerlof
   91 ** Changed to ease porting to other UNIX-platforms.
   92 **
   93 ** Revision 1.2  2002/07/11 09:43:36  root
   94 ** Modified HZ into sysconf(_SC_CLK_TCK).
   95 **
   96 ** Revision 1.1  2001/10/02 10:43:36  gerlof
   97 ** Initial revision
   98 **
   99 */
  100 
  101 #include <sys/types.h>
  102 #include <sys/param.h>
  103 #include <sys/stat.h>
  104 #include <sys/times.h>
  105 #include <signal.h>
  106 #include <time.h>
  107 #include <math.h>
  108 #include <stdio.h>
  109 #include <unistd.h>
  110 #include <ctype.h>
  111 #include <stdlib.h>
  112 #include <errno.h>
  113 #include <stdarg.h>
  114 #include <string.h>
  115 #include <fcntl.h>
  116 
  117 #include "atop.h"
  118 #include "acctproc.h"
  119 
  120 /*
  121 ** Function convtime() converts a value (number of seconds since
  122 ** 1-1-1970) to an ascii-string in the format hh:mm:ss, stored in
  123 ** chartim (9 bytes long).
  124 */
  125 char *
  126 convtime(time_t utime, char *chartim)
  127 {
  128     struct tm   *tt;
  129 
  130     tt = localtime(&utime);
  131 
  132     snprintf(chartim, 9, "%02d:%02d:%02d", tt->tm_hour, tt->tm_min, tt->tm_sec);
  133 
  134     return chartim;
  135 }
  136 
  137 /*
  138 ** Function convdate() converts a value (number of seconds since
  139 ** 1-1-1970) to an ascii-string in the format yyyy/mm/dd, stored in
  140 ** chardat (11 bytes long).
  141 */
  142 char *
  143 convdate(time_t utime, char *chardat)
  144 {
  145     struct tm   *tt;
  146 
  147     tt = localtime(&utime);
  148 
  149     snprintf(chardat, 11, "%04u/%02u/%02u",
  150         (tt->tm_year+1900)%10000, (tt->tm_mon+1)%100, tt->tm_mday%100);
  151 
  152     return chardat;
  153 }
  154 
  155 
  156 /*
  157 ** Convert a string in format [YYYYMMDD]hh[:]mm into an epoch time value or
  158 ** when only the value hh[:]mm was given, take this time from midnight.
  159 **
  160 ** Arguments:       String with date-time in format [YYYYMMDD]hh[:]mm
  161 **          or hh[:]mm.
  162 **
  163 **          Pointer to time_t containing 0 or current epoch time.
  164 **
  165 ** Return-value:    0 - Wrong input-format
  166 **          1 - Success
  167 */
  168 int
  169 getbranchtime(char *itim, time_t *newtime)
  170 {
  171     register int    ilen = strlen(itim);
  172     int     hours, minutes;
  173     time_t      epoch;
  174     struct tm   tm;
  175 
  176     memset(&tm, 0, sizeof tm);
  177 
  178     /*
  179     ** verify length of input string
  180     */
  181     if (ilen != 4 && ilen != 5 && ilen != 12 && ilen != 13)
  182         return 0;       // wrong date-time format
  183 
  184     /*
  185     ** check string syntax for absolute time specified as
  186     ** YYYYMMDDhh:mm or YYYYMMDDhhmm
  187     */
  188     if ( sscanf(itim, "%4d%2d%2d%2d:%2d", &tm.tm_year, &tm.tm_mon,
  189                 &tm.tm_mday,  &tm.tm_hour, &tm.tm_min) == 5 ||
  190          sscanf(itim, "%4d%2d%2d%2d%2d",  &tm.tm_year, &tm.tm_mon,
  191                 &tm.tm_mday,  &tm.tm_hour, &tm.tm_min) == 5   )
  192     {
  193         tm.tm_year -= 1900;
  194         tm.tm_mon  -= 1;
  195 
  196         if (tm.tm_year < 100 || tm.tm_mon  < 0  || tm.tm_mon > 11 ||
  197                     tm.tm_mday < 1   || tm.tm_mday > 31 || 
  198             tm.tm_hour < 0   || tm.tm_hour > 23 ||
  199             tm.tm_min  < 0   || tm.tm_min  > 59   )
  200         {
  201             return 0;   // wrong date-time format
  202         }
  203 
  204         tm.tm_isdst = -1;
  205 
  206         if ((epoch = mktime(&tm)) == -1)
  207             return 0;   // wrong date-time format
  208 
  209         // correct date-time format
  210         *newtime = epoch;
  211         return 1;
  212     }
  213 
  214     /*
  215     ** check string syntax for relative time specified as
  216     ** hh:mm or hhmm
  217     */
  218     if ( sscanf(itim, "%2d:%2d", &hours, &minutes) == 2 ||
  219          sscanf(itim, "%2d%2d",  &hours, &minutes) == 2       )
  220     {
  221         if ( hours < 0 || hours > 23 || minutes < 0 || minutes > 59 )
  222             return 0;   // wrong date-time format
  223 
  224         /*
  225         ** when the new time is already filled with an epoch time,
  226         ** the relative time will be on the same day as indicated by
  227         ** that epoch time
  228         ** when the new time is the time within a day or 0, the new
  229         ** time will be stored again as the time within a day.
  230         */
  231         if (*newtime <= SECONDSINDAY)   // time within the day?
  232         {
  233             *newtime = (hours * 3600) + (minutes * 60);
  234 
  235             if (*newtime >= SECONDSINDAY)
  236                 *newtime = SECONDSINDAY-1;
  237 
  238             return 1;
  239         }
  240         else
  241         {
  242             *newtime = normalize_epoch(*newtime,
  243                         (hours*3600) + (minutes*60));
  244             return 1;
  245         }
  246     }
  247 
  248     return 0;   // wrong date-time format
  249 }
  250 
  251 
  252 /*
  253 ** Normalize an epoch time with the number of seconds within a day
  254 ** Return-value:        Normalized epoch 
  255 */
  256 time_t
  257 normalize_epoch(time_t epoch, long secondsinday)
  258 {
  259     struct tm   tm;
  260 
  261     localtime_r(&epoch, &tm);   // convert epoch to tm
  262 
  263     tm.tm_hour   = 0;   
  264     tm.tm_min    = 0;   
  265     tm.tm_sec    = secondsinday;    
  266     tm.tm_isdst  = -1;
  267 
  268     return mktime(&tm);     // convert tm to epoch
  269 }
  270 
  271 
  272 /*
  273 ** Function val2valstr() converts a positive value to an ascii-string of a 
  274 ** fixed number of positions; if the value does not fit, it will be formatted
  275 ** to exponent-notation (as short as possible, so not via the standard printf-
  276 ** formatters %f or %e). The offered buffer should have a length of width+1.
  277 ** The value might even be printed as an average for the interval-time.
  278 */
  279 char *
  280 val2valstr(count_t value, char *strvalue, int width, int avg, int nsecs)
  281 {
  282     count_t     maxval, remain = 0;
  283     unsigned short  exp     = 0;
  284     char        *suffix = "";
  285     int     strsize = width+1;
  286 
  287     if (avg && nsecs)
  288     {
  289         value  = (value + (nsecs/2)) / nsecs;     /* rounded value */
  290         width  = width - 2; /* subtract two positions for '/s' */
  291         suffix = "/s";
  292     }
  293 
  294     if (value < 0)      // no negative value expected
  295     {
  296         snprintf(strvalue, strsize, "%*s%s", width, "?", suffix);
  297         return strvalue;
  298     }
  299 
  300     maxval = pow(10.0, width) - 1;
  301 
  302     if (value < maxval)
  303     {
  304         snprintf(strvalue, strsize, "%*lld%s", width, value, suffix);
  305     }
  306     else
  307     {
  308         if (width < 3)
  309         {
  310             /*
  311             ** cannot avoid ignoring width
  312             */
  313             snprintf(strvalue, strsize, "%lld%s", value, suffix);
  314         }
  315         else
  316         {
  317             /*
  318             ** calculate new maximum value for the string,
  319             ** calculating space for 'e' (exponent) + one digit
  320             */
  321             width -= 2;
  322             maxval = pow(10.0, width) - 1;
  323 
  324             while (value > maxval)
  325             {
  326                 exp++;
  327                 remain = value % 10;
  328                 value /= 10;
  329             }
  330 
  331             if (remain >= 5 && value < maxval)
  332                 value++;
  333 
  334             snprintf(strvalue, strsize, "%*llde%hd%s",
  335                     width%100, value, exp%100, suffix);
  336         }
  337     }
  338 
  339     return strvalue;
  340 }
  341 
  342 #define DAYSECS     (24*60*60)
  343 #define HOURSECS    (60*60)
  344 #define MINSECS     (60)
  345 
  346 /*
  347 ** Function val2elapstr() converts a value (number of seconds)
  348 ** to an ascii-string of up to max 13 positions in NNNdNNhNNmNNs
  349 ** stored in strvalue (at least 14 positions).
  350 ** returnvalue: number of bytes stored
  351 */
  352 int
  353 val2elapstr(int value, char *strvalue)
  354 {
  355         char    *p = strvalue;
  356     int rv, n = 14;
  357 
  358         if (value >= DAYSECS) 
  359         {
  360                 rv = snprintf(p, n, "%dd", value/DAYSECS);
  361         p += rv;
  362         n -= rv;
  363         }
  364 
  365         if (value >= HOURSECS) 
  366         {
  367                 rv = snprintf(p, n, "%dh", (value%DAYSECS)/HOURSECS);
  368         p += rv;
  369         n -= rv;
  370         }
  371 
  372         if (value >= MINSECS) 
  373         {
  374                 rv = snprintf(p, n, "%dm", (value%HOURSECS)/MINSECS);
  375         p += rv;
  376         n -= rv;
  377         }
  378 
  379         rv = snprintf(p, n, "%ds", (value%MINSECS));
  380     p += rv;
  381     n -= rv;
  382 
  383         return p - strvalue;
  384 }
  385 
  386 
  387 /*
  388 ** Function val2cpustr() converts a value (number of milliseconds)
  389 ** to an ascii-string of 6 positions in milliseconds or minute-seconds or
  390 ** hours-minutes, stored in strvalue (at least 7 positions).
  391 */
  392 #define MAXMSEC     (count_t)100000
  393 #define MAXSEC      (count_t)6000
  394 #define MAXMIN      (count_t)6000
  395 
  396 char *
  397 val2cpustr(count_t value, char *strvalue)
  398 {
  399     if (value < MAXMSEC)
  400     {
  401         snprintf(strvalue, 7, "%2llu.%02llus",
  402                 (value/1000)%100, value%1000/10);
  403     }
  404     else
  405     {
  406             /*
  407             ** millisecs irrelevant; round to seconds
  408             */
  409             value = (value + 500) / 1000;
  410 
  411             if (value < MAXSEC) 
  412             {
  413                     snprintf(strvalue, 7, "%2llum%02llus",
  414                         (value/60)%100, value%60);
  415         }
  416         else
  417         {
  418             /*
  419             ** seconds irrelevant; round to minutes
  420             */
  421             value = (value + 30) / 60;
  422 
  423             if (value < MAXMIN) 
  424             {
  425                 snprintf(strvalue, 7, "%2lluh%02llum",
  426                         (value/60)%100, value%60);
  427             }
  428             else
  429             {
  430                 /*
  431                 ** minutes irrelevant; round to hours
  432                 */
  433                 value = (value + 30) / 60;
  434 
  435                 snprintf(strvalue, 7, "%2llud%02lluh",
  436                         (value/24)%100, value%24);
  437             }
  438         }
  439     }
  440 
  441     return strvalue;
  442 }
  443 
  444 /*
  445 ** Function val2Hzstr() converts a value (in MHz) 
  446 ** to an ascii-string.
  447 ** The result-string is placed in the area pointed to strvalue,
  448 ** which should be able to contain 7 positions plus null byte.
  449 */
  450 char *
  451 val2Hzstr(count_t value, char *strvalue)
  452 {
  453     char *fformat;
  454 
  455         if (value < 1000)
  456         {
  457                 snprintf(strvalue, 8, "%4lluMHz", value%10000);
  458         }
  459         else
  460         {
  461                 double fval=value/1000.0;      // fval is double in GHz
  462                 char prefix='G';
  463 
  464                 if (fval >= 1000.0)            // prepare for the future
  465                 {
  466                         prefix='T';        
  467                         fval /= 1000.0;
  468                 }
  469 
  470                 if (fval < 10.0)
  471         {
  472              fformat = "%4.2f%cHz";
  473         }
  474         else
  475         {
  476             if (fval < 100.0)
  477                 fformat = "%4.1f%cHz";
  478                     else
  479                 fformat = "%4.0f%cHz";
  480         }
  481 
  482                 snprintf(strvalue, 8, fformat, fval, prefix);
  483         }
  484 
  485     return strvalue;
  486 }
  487 
  488 
  489 /*
  490 ** Function val2memstr() converts a value (number of bytes)
  491 ** to an ascii-string in a specific format (indicated by pformat).
  492 ** The result-string is placed in the area pointed to strvalue,
  493 ** which should be able to contain at least 7 positions.
  494 */
  495 #define ONEKBYTE    1024
  496 #define ONEMBYTE    1048576
  497 #define ONEGBYTE    1073741824L
  498 #define ONETBYTE    1099511627776LL
  499 #define ONEPBYTE    1125899906842624LL
  500 
  501 #define MAXBYTE     999
  502 #define MAXKBYTE    ONEKBYTE*999L
  503 #define MAXKBYTE9   ONEKBYTE*9L
  504 #define MAXMBYTE    ONEMBYTE*999L
  505 #define MAXMBYTE9   ONEMBYTE*9L
  506 #define MAXGBYTE    ONEGBYTE*999LL
  507 #define MAXGBYTE9   ONEGBYTE*9LL
  508 #define MAXTBYTE    ONETBYTE*999LL
  509 #define MAXTBYTE9   ONETBYTE*9LL
  510 #define MAXPBYTE9   ONEPBYTE*9LL
  511 
  512 char *
  513 val2memstr(count_t value, char *strvalue, int pformat, int avgval, int nsecs)
  514 {
  515     char    aformat;    /* advised format       */
  516     count_t verifyval;
  517     char    *suffix = "";
  518     int basewidth = 6;
  519 
  520     /*
  521     ** notice that the value can be negative, in which case the
  522     ** modulo-value should be evaluated and an extra position should
  523     ** be reserved for the sign
  524     */
  525     if (value < 0)
  526         verifyval = -value * 10;
  527     else
  528         verifyval =  value;
  529 
  530     /*
  531     ** verify if printed value is required per second (average) or total
  532     */
  533     if (avgval && nsecs)
  534     {
  535         value         = llround((double)((double)value/(double)nsecs));
  536         verifyval     = llround((double)((double)verifyval/(double)nsecs));
  537         basewidth    -= 2;
  538         suffix        = "/s";
  539 
  540         if (verifyval <= MAXBYTE)   /* bytes ? */
  541             aformat = BFORMAT;
  542         else
  543             if (verifyval <= MAXKBYTE9) /* kbytes 1-9 ? */
  544                 aformat = KBFORMAT;
  545             else
  546                 if (verifyval <= MAXKBYTE)    /* kbytes ? */
  547                     aformat = KBFORMAT_INT;
  548                 else
  549                     if (verifyval <= MAXMBYTE9)    /* mbytes 1-9 ? */
  550                         aformat = MBFORMAT;
  551                     else
  552                         if (verifyval <= MAXMBYTE)    /* mbytes 10-999 ? */
  553                             aformat = MBFORMAT_INT;
  554                         else
  555                             if (verifyval <= MAXGBYTE9)    /* gbytes 1-9 ? */
  556                                 aformat = GBFORMAT;
  557                             else
  558                                 if (verifyval <= MAXGBYTE)    /* gbytes 10-999 ? */
  559                                     aformat = GBFORMAT_INT;
  560                                 else
  561                                     if (verifyval <= MAXTBYTE9)    /* tbytes 1-9 ? */
  562                                         aformat = TBFORMAT;
  563                                     else
  564                                         if (verifyval <= MAXTBYTE)    /* tbytes 10-999? */
  565                                             aformat = TBFORMAT_INT;
  566                                         else
  567                                             if (verifyval <= MAXPBYTE9)    /* pbytes 1-9 ? */
  568                                                 aformat = PBFORMAT;
  569                                             else
  570                                                 aformat = PBFORMAT_INT;    /* pbytes! */
  571     } else 
  572     /*
  573     ** printed value per interval (normal mode) 
  574     */
  575     {
  576         /*
  577         ** determine which format will be used on bases of the value itself
  578         */
  579         if (verifyval <= MAXBYTE)   /* bytes ? */
  580             aformat = BFORMAT;
  581         else
  582             if (verifyval <= MAXKBYTE)  /* kbytes ? */
  583                 aformat = KBFORMAT;
  584             else
  585                 if (verifyval <= MAXMBYTE)  /* mbytes ? */
  586                     aformat = MBFORMAT;
  587                 else
  588                     if (verifyval <= MAXGBYTE)  /* gbytes ? */
  589                         aformat = GBFORMAT;
  590                     else
  591                         if (verifyval <= MAXTBYTE)    /* tbytes? */
  592                             aformat = TBFORMAT;
  593                         else
  594                             aformat = PBFORMAT;   /* pbytes! */
  595     }
  596 
  597 
  598     /*
  599     ** check if this is also the preferred format
  600     */
  601     if (aformat <= pformat)
  602         aformat = pformat;
  603 
  604     switch (aformat)
  605     {
  606        case BFORMAT:
  607         snprintf(strvalue, 7, "%*lldB%s",
  608                 basewidth-1, value, suffix);
  609         break;
  610 
  611        case KBFORMAT:
  612         snprintf(strvalue, 7, "%*.1lfK%s",
  613             basewidth-1, (double)((double)value/ONEKBYTE), suffix); 
  614         break;
  615 
  616        case KBFORMAT_INT:
  617         snprintf(strvalue, 7, "%*lldK%s",
  618                 basewidth-1, llround((double)((double)value/ONEKBYTE)), suffix);
  619         break;
  620 
  621        case MBFORMAT:
  622         snprintf(strvalue, 7, "%*.1lfM%s",
  623             basewidth-1, (double)((double)value/ONEMBYTE), suffix); 
  624         break;
  625 
  626        case MBFORMAT_INT:
  627         snprintf(strvalue, 7, "%*lldM%s",
  628             basewidth-1, llround((double)((double)value/ONEMBYTE)), suffix); 
  629         break;
  630 
  631        case GBFORMAT:
  632         snprintf(strvalue, 7, "%*.1lfG%s",
  633             basewidth-1, (double)((double)value/ONEGBYTE), suffix);
  634         break;
  635 
  636        case GBFORMAT_INT:
  637         snprintf(strvalue, 7, "%*lldG%s",
  638             basewidth-1, llround((double)((double)value/ONEGBYTE)), suffix);
  639         break;
  640 
  641        case TBFORMAT:
  642         snprintf(strvalue, 7, "%*.1lfT%s",
  643             basewidth-1, (double)((double)value/ONETBYTE), suffix);
  644         break;
  645 
  646        case TBFORMAT_INT:
  647         snprintf(strvalue, 7, "%*lldT%s",
  648             basewidth-1, llround((double)((double)value/ONETBYTE)), suffix);
  649         break;
  650 
  651        case PBFORMAT:
  652         snprintf(strvalue, 7, "%*.1lfP%s",
  653             basewidth-1, (double)((double)value/ONEPBYTE), suffix);
  654         break;
  655 
  656        case PBFORMAT_INT:
  657         snprintf(strvalue, 7, "%*lldP%s",
  658             basewidth-1, llround((double)((double)value/ONEPBYTE)), suffix);
  659         break;
  660 
  661        default:
  662         snprintf(strvalue, 7, "!TILT!");
  663     }
  664 
  665     // check if overflow occurred during the formatting
  666     // by checking the last byte of the formatted string
  667     //
  668     switch ( *(strvalue+5) )
  669     {
  670        case 's':        // in case of per-second value
  671        case 'B':
  672        case 'K':
  673        case 'M':
  674        case 'G':
  675        case 'T':
  676        case 'P':
  677         break;
  678 
  679        default:
  680         snprintf(strvalue, 7, "OVFLOW");
  681     }
  682 
  683     return strvalue;
  684 }
  685 
  686 
  687 /*
  688 ** Function numeric() checks if the ascii-string contains 
  689 ** a numeric (positive) value.
  690 ** Returns 1 (true) if so, or 0 (false).
  691 */
  692 int
  693 numeric(char *ns)
  694 {
  695     register char *s = ns;
  696 
  697     while (*s)
  698         if (*s < '0' || *s > '9')
  699             return(0);      /* false */
  700         else
  701             s++;
  702     return(1);              /* true  */
  703 }
  704 
  705 
  706 /*
  707 ** Function getboot() returns the boot-time of this system 
  708 ** as number of jiffies since 1-1-1970.
  709 */
  710 unsigned long long
  711 getboot(void)
  712 {
  713     static unsigned long long   boottime;
  714     unsigned long long      getbootlinux(long);
  715 
  716     if (!boottime)      /* do this only once */
  717         boottime = getbootlinux(hertz);
  718 
  719     return boottime;
  720 }
  721 
  722 /*
  723 ** generic pointer verification after malloc
  724 */
  725 void
  726 ptrverify(const void *ptr, const char *errormsg, ...)
  727 {
  728     if (!ptr)
  729     {
  730         va_list args;
  731 
  732         acctswoff();
  733         netatop_signoff();
  734 
  735         if (vis.show_end)
  736             (vis.show_end)();
  737 
  738         va_start(args, errormsg);
  739         vfprintf(stderr, errormsg, args);
  740         va_end(args);
  741 
  742         exit(13);
  743     }
  744 }
  745 
  746 /*
  747 ** cleanup, give error message and exit
  748 */
  749 void
  750 mcleanstop(int exitcode, const char *errormsg, ...)
  751 {
  752     va_list args;
  753 
  754     acctswoff();
  755     netatop_signoff();
  756     (vis.show_end)();
  757 
  758     va_start(args, errormsg);
  759     vfprintf(stderr, errormsg, args);
  760     va_end(args);
  761 
  762     exit(exitcode);
  763 }
  764 
  765 /*
  766 ** cleanup, give error message and exit
  767 */
  768 void
  769 cleanstop(int exitcode)
  770 {
  771     acctswoff();
  772     netatop_signoff();
  773     (vis.show_end)();
  774 
  775     exit(exitcode);
  776 }
  777 
  778 /*
  779 ** drop the root privileges that might be obtained via setuid-bit
  780 **
  781 ** this action may only fail with errno EPERM (normal situation when
  782 ** atop has not been started with setuid-root privs); when this
  783 ** action fails with EAGAIN or ENOMEM, atop should not continue
  784 ** without root privs being dropped...
  785 */
  786 int
  787 droprootprivs(void)
  788 {
  789     if (seteuid( getuid() ) == -1 && errno != EPERM)
  790         return 0;   /* false */
  791     else
  792         return 1;   /* true  */
  793 }
  794 
  795 /*
  796 ** regain the root privileges that might be dropped earlier
  797 */
  798 void
  799 regainrootprivs(void)
  800 {
  801     int liResult;
  802 
  803     // this will fail for non-privileged processes
  804     liResult = seteuid(0);
  805 
  806     if (liResult != 0)
  807     {
  808     }
  809 }
  810 
  811 /*
  812 ** try to set the highest OOM priority
  813 */
  814 void
  815 set_oom_score_adj(void)
  816 {
  817     int fd;
  818     char val[] = "-1000";   /* suggested by Gerlof, always set -1000 */
  819 
  820     /*
  821      ** set OOM score adj to avoid to lost necessary log of system.
  822      ** ignored if not running under superuser privileges!
  823      */
  824     fd = open("/proc/self/oom_score_adj", O_RDWR);
  825     if ( fd < 0 ) {
  826         return;
  827     }
  828 
  829     if ( write(fd, val, strlen(val)) < 0 )
  830         ;
  831 
  832     close(fd);
  833 }
  834 
  835 /* hypervisor enum, move this into header if actually in use */
  836 enum {
  837     HYPER_NONE  = 0,
  838     HYPER_XEN,
  839     HYPER_KVM,
  840     HYPER_MSHV,
  841     HYPER_VMWARE,
  842     HYPER_IBM,
  843     HYPER_VSERVER,
  844     HYPER_UML,
  845     HYPER_INNOTEK,
  846     HYPER_HITACHI,
  847     HYPER_PARALLELS,
  848     HYPER_VBOX,
  849     HYPER_OS400,
  850     HYPER_PHYP,
  851     HYPER_SPAR,
  852     HYPER_WSL,
  853 };
  854 
  855 #if defined(__x86_64__) || defined(__i386__)
  856 #define HYPERVISOR_INFO_LEAF   0x40000000
  857 
  858 static inline void
  859 x86_cpuid(unsigned int op, unsigned int *eax, unsigned int *ebx,
  860              unsigned int *ecx, unsigned int *edx)
  861 {
  862     __asm__(
  863 #if defined(__PIC__) && defined(__i386__)
  864         "xchg %%ebx, %%esi;"
  865         "cpuid;"
  866         "xchg %%esi, %%ebx;"
  867         : "=S" (*ebx),
  868 #else
  869         "cpuid;"
  870         : "=b" (*ebx),
  871 #endif
  872           "=a" (*eax),
  873           "=c" (*ecx),
  874           "=d" (*edx)
  875         : "1" (op), "c"(0));
  876 }
  877 
  878 static int
  879 get_hypervisor(void)
  880 {
  881     unsigned int eax = 0, ebx = 0, ecx = 0, edx = 0, hyper = HYPER_NONE;
  882     char hyper_vendor_id[13];
  883 
  884     memset(hyper_vendor_id, 0, sizeof(hyper_vendor_id));
  885 
  886     x86_cpuid(HYPERVISOR_INFO_LEAF, &eax, &ebx, &ecx, &edx);
  887     memcpy(hyper_vendor_id + 0, &ebx, 4);
  888     memcpy(hyper_vendor_id + 4, &ecx, 4);
  889     memcpy(hyper_vendor_id + 8, &edx, 4);
  890     hyper_vendor_id[12] = '\0';
  891 
  892     if (!hyper_vendor_id[0])
  893         return hyper;
  894 
  895     if (!strncmp("XenVMMXenVMM", hyper_vendor_id, 12))
  896         hyper = HYPER_XEN;
  897     else if (!strncmp("KVMKVMKVM", hyper_vendor_id, 9))
  898         hyper = HYPER_KVM;
  899     else if (!strncmp("Microsoft Hv", hyper_vendor_id, 12))
  900         hyper = HYPER_MSHV;
  901     else if (!strncmp("VMwareVMware", hyper_vendor_id, 12))
  902         hyper = HYPER_VMWARE;
  903     else if (!strncmp("UnisysSpar64", hyper_vendor_id, 12))
  904         hyper = HYPER_SPAR;
  905 
  906     return hyper;
  907 }
  908 #else /* ! (__x86_64__ || __i386__) */
  909 static int
  910 get_hypervisor(void)
  911 {
  912     return HYPER_NONE;
  913 }
  914 #endif
  915 
  916 int
  917 run_in_guest(void)
  918 {
  919     return get_hypervisor() != HYPER_NONE;
  920 }
  921 
  922 /*
  923 ** return maximum number of digits for PID/TID
  924 */
  925 int
  926 getpidwidth(void)
  927 {
  928     FILE    *fp;
  929     char    linebuf[64];
  930     int numdigits = 5;
  931 
  932         if ( (fp = fopen("/proc/sys/kernel/pid_max", "r")) != NULL)
  933         {
  934                 if ( fgets(linebuf, sizeof(linebuf), fp) != NULL)
  935                 {
  936                         numdigits = strlen(linebuf) - 1;
  937                 }
  938 
  939                 fclose(fp);
  940         }
  941 
  942     return numdigits;
  943 }