"Fossies" - the Fresh Open Source Software Archive

Member "atop-2.8.1/rawlog.c" (7 Jan 2023, 22962 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 "rawlog.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 2.7.1_vs_2.8.0.

    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 ** Author:      Gerlof Langeveld
    8 ** E-mail:      gerlof.langeveld@atoptool.nl
    9 ** Date:        September 2002
   10 ** --------------------------------------------------------------------------
   11 ** Copyright (C) 2000-2010 Gerlof Langeveld
   12 **
   13 ** This program is free software; you can redistribute it and/or modify it
   14 ** under the terms of the GNU General Public License as published by the
   15 ** Free Software Foundation; either version 2, or (at your option) any
   16 ** later version.
   17 **
   18 ** This program is distributed in the hope that it will be useful, but
   19 ** WITHOUT ANY WARRANTY; without even the implied warranty of
   20 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
   21 ** See the GNU General Public License for more details.
   22 **
   23 ** You should have received a copy of the GNU General Public License
   24 ** along with this program; if not, write to the Free Software
   25 ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   26 ** --------------------------------------------------------------------------
   27 */
   28 
   29 #include <sys/types.h>
   30 #include <sys/param.h>
   31 #include <sys/mman.h>
   32 #include <sys/stat.h>
   33 #include <time.h>
   34 #include <stdio.h>
   35 #include <errno.h>
   36 #include <fcntl.h>
   37 #include <stdlib.h>
   38 #include <signal.h>
   39 #include <ctype.h>
   40 #include <string.h>
   41 #include <sys/utsname.h>
   42 #include <string.h>
   43 #include <regex.h>
   44 #include <zlib.h>
   45 #include <sys/time.h>
   46 #include <sys/resource.h>
   47 #include <unistd.h>
   48 #include <sys/uio.h>
   49 
   50 #include "atop.h"
   51 #include "showgeneric.h"
   52 #include "photoproc.h"
   53 #include "photosyst.h"
   54 #include "rawlog.h"
   55 
   56 #define BASEPATH    "/var/log/atop"  
   57 #define BINPATH     "/usr/bin/atop"
   58 
   59 static int  getrawrec  (int, struct rawrecord *, int);
   60 static int  getrawsstat(int, struct sstat *, int);
   61 static int  getrawtstat(int, struct tstat *, int, int);
   62 static int  rawwopen(void);
   63 static int  readchunk(int, void *, int);
   64 static int  lookslikedatetome(char *);
   65 static void testcompval(int, char *);
   66 static void try_other_version(int, int);
   67 
   68 /*
   69 ** write a raw record to file
   70 ** (file is opened/created during the first call)
   71 */
   72 char
   73 rawwrite(time_t curtime, int numsecs, 
   74          struct devtstat *devtstat, struct sstat *sstat,
   75          int nexit, unsigned int noverflow, char flag)
   76 {
   77     static int      rawfd = -1;
   78     struct rawrecord    rr;
   79     int         rv;
   80     struct stat     filestat;
   81 
   82     Byte            scompbuf[sizeof(struct sstat)], *pcompbuf;
   83     unsigned long       scomplen = sizeof scompbuf;
   84     unsigned long       pcomplen = sizeof(struct tstat) *
   85                         devtstat->ntaskall;
   86     struct iovec        iov[3];
   87 
   88     /*
   89     ** first call:
   90     **  take care that the log file is opened
   91     */
   92     if (rawfd == -1)
   93         rawfd = rawwopen();
   94 
   95     /*
   96     ** register current size of file in order to "roll back"
   97     ** writes that have been done while not *all* writes could
   98     ** succeed, e.g. when file system full
   99     */
  100     (void) fstat(rawfd, &filestat);
  101 
  102     /*
  103     ** compress system- and process-level statistics
  104     */
  105     rv = compress(scompbuf, &scomplen,
  106                 (Byte *)sstat, (unsigned long)sizeof *sstat);
  107 
  108     testcompval(rv, "compress");
  109 
  110     pcompbuf = malloc(pcomplen);
  111 
  112     ptrverify(pcompbuf, "Malloc failed for compression buffer\n");
  113 
  114     rv = compress(pcompbuf, &pcomplen, (Byte *)devtstat->taskall,
  115                         (unsigned long)pcomplen);
  116 
  117     testcompval(rv, "compress");
  118 
  119     /*
  120     ** fill record header and write to file
  121     */
  122     memset(&rr, 0, sizeof rr);
  123 
  124     rr.curtime  = curtime;
  125     rr.interval = numsecs;
  126     rr.flags    = 0;
  127     rr.ndeviat  = devtstat->ntaskall;
  128     rr.nactproc = devtstat->nprocactive;
  129     rr.ntask    = devtstat->ntaskall;
  130     rr.nexit    = nexit;
  131     rr.noverflow    = noverflow;
  132     rr.totproc  = devtstat->nprocall;
  133     rr.totrun   = devtstat->totrun;
  134     rr.totslpi  = devtstat->totslpi;
  135     rr.totslpu  = devtstat->totslpu;
  136     rr.totzomb  = devtstat->totzombie;
  137     rr.scomplen = scomplen;
  138     rr.pcomplen = pcomplen;
  139 
  140     if (flag&RRBOOT)
  141         rr.flags |= RRBOOT;
  142 
  143     if (supportflags & ACCTACTIVE)
  144         rr.flags |= RRACCTACTIVE;
  145 
  146     if (supportflags & IOSTAT)
  147         rr.flags |= RRIOSTAT;
  148 
  149     if (supportflags & NETATOP)
  150         rr.flags |= RRNETATOP;
  151 
  152     if (supportflags & NETATOPD)
  153         rr.flags |= RRNETATOPD;
  154 
  155     if (supportflags & CGROUPV2)
  156         rr.flags |= RRCGRSTAT;
  157 
  158     if (supportflags & DOCKSTAT)
  159         rr.flags |= RRDOCKSTAT;
  160 
  161     if (supportflags & GPUSTAT)
  162         rr.flags |= RRGPUSTAT;
  163 
  164     /*
  165     ** use 1-writev to make record operation atomic
  166     ** to avoid write uncompleted record data.
  167     */
  168     iov[0].iov_base = &rr;
  169     iov[0].iov_len  = sizeof (rr);
  170 
  171     iov[1].iov_base = scompbuf;
  172     iov[1].iov_len  = scomplen;
  173 
  174     iov[2].iov_base = pcompbuf;
  175     iov[2].iov_len  = pcomplen;
  176 
  177     if ( writev(rawfd, iov, 3) == -1)
  178     {
  179         fprintf(stderr, "%s - ", rawname);
  180         if ( ftruncate(rawfd, filestat.st_size) == -1)
  181             mcleanstop(8,
  182                "failed to write raw/status/process record to %s\n",
  183                rawname);
  184 
  185         mcleanstop(7,
  186            "failed to write raw/status/process record to %s\n",
  187            rawname);
  188     }
  189 
  190     free(pcompbuf);
  191 
  192     return '\0';
  193 }
  194 
  195 
  196 /*
  197 ** open a raw file for writing
  198 **
  199 ** if the raw file exists already:
  200 **    - read and validate the header record (be sure it is an atop-file)
  201 **    - seek to the end of the file
  202 **
  203 ** if the raw file does not yet exist:
  204 **    - create the raw file
  205 **    - write a header record
  206 **
  207 ** return the filedescriptor of the raw file
  208 */
  209 static int
  210 rawwopen()
  211 {
  212     struct rawheader    rh;
  213     int         fd;
  214 
  215     /*
  216     ** check if the file exists already
  217     */
  218     if ( (fd = open(rawname, O_RDWR)) >= 0)
  219     {
  220         /*
  221         ** read and verify header record
  222         */
  223         if ( read(fd, &rh, sizeof rh) < sizeof rh)
  224             mcleanstop(7, "%s - cannot read header\n", rawname);
  225 
  226         if (rh.magic != MYMAGIC)
  227             mcleanstop(7, "file %s exists but does not contain raw "
  228                 "atop output (wrong magic number)\n", rawname);
  229 
  230         if ( rh.sstatlen    != sizeof(struct sstat)     ||
  231              rh.tstatlen    != sizeof(struct tstat)     ||
  232                  rh.rawheadlen  != sizeof(struct rawheader) ||
  233              rh.rawreclen   != sizeof(struct rawrecord)   )
  234         {
  235             fprintf(stderr,
  236                 "existing file %s has incompatible header\n",
  237                 rawname);
  238 
  239             if (rh.aversion & 0x8000 &&
  240                (rh.aversion & 0x7fff) != getnumvers())
  241             {
  242                 fprintf(stderr,
  243                     "(created by version %d.%d - "
  244                     "current version %d.%d)\n",
  245                     (rh.aversion >> 8) & 0x7f,
  246                      rh.aversion & 0xff,
  247                      getnumvers() >> 8,
  248                      getnumvers() & 0x7f);
  249             }
  250 
  251             cleanstop(7);
  252         }
  253 
  254         (void) lseek(fd, (off_t) 0, SEEK_END);
  255 
  256         return fd;
  257     }
  258 
  259     /*
  260     ** file does not exist (or can not be opened)
  261     */
  262     if ( (fd = creat(rawname, 0666)) == -1)
  263     {
  264         fprintf(stderr, "%s - ", rawname);
  265         perror("create raw file");
  266         cleanstop(7);
  267     }
  268 
  269     memset(&rh, 0, sizeof rh);
  270 
  271     rh.magic    = MYMAGIC;
  272     rh.aversion = getnumvers() | 0x8000;
  273     rh.sstatlen = sizeof(struct sstat);
  274     rh.tstatlen = sizeof(struct tstat);
  275     rh.rawheadlen   = sizeof(struct rawheader);
  276     rh.rawreclen    = sizeof(struct rawrecord);
  277     rh.supportflags = supportflags | RAWLOGNG;
  278     rh.osrel    = osrel;
  279     rh.osvers   = osvers;
  280     rh.ossub    = ossub;
  281     rh.hertz    = hertz;
  282     rh.pagesize = pagesize;
  283     rh.pidwidth = getpidwidth();
  284 
  285     memcpy(&rh.utsname, &utsname, sizeof rh.utsname);
  286 
  287     if ( write(fd, &rh, sizeof rh) == -1)
  288     {
  289         fprintf(stderr, "%s - ", rawname);
  290         perror("write raw header");
  291         cleanstop(7);
  292     }
  293 
  294     return fd;
  295 }
  296 
  297 /*
  298 ** read the contents of a raw file
  299 */
  300 #define OFFCHUNK    256
  301 
  302 int
  303 rawread(void)
  304 {
  305     int         i, j, rawfd, len, isregular = 1;
  306     char            *py;
  307     struct rawheader    rh;
  308     struct rawrecord    rr;
  309     struct sstat        sstat;
  310     static struct devtstat  devtstat;
  311 
  312     struct stat     filestat;
  313 
  314     /*
  315     ** variables to maintain the offsets of the raw records
  316     ** to be able to see previous samples again
  317     */
  318     off_t           *offlist = NULL;
  319     unsigned int        offsize = 0;
  320     unsigned int        offcur  = 0;
  321     char            lastcmd = 'X', flags;
  322 
  323     time_t          timenow;
  324     struct tm       *tp;
  325 
  326     switch ( len = strlen(rawname) )
  327     {
  328        /*
  329        ** if no filename is specified, assemble the name of the raw file
  330        */
  331        case 0:
  332         timenow = time(0);
  333         tp  = localtime(&timenow);
  334 
  335         snprintf(rawname, RAWNAMESZ, "%s/atop_%04d%02d%02d",
  336             BASEPATH, 
  337             tp->tm_year+1900,
  338             tp->tm_mon+1,
  339             tp->tm_mday);
  340 
  341         break;
  342 
  343        /*
  344        ** if date specified as filename in format YYYYMMDD, assemble
  345        ** the full pathname of the raw file
  346        */
  347        case 8:
  348         if ( access(rawname, F_OK) == 0) 
  349             break;      /* existing file */
  350 
  351         if (lookslikedatetome(rawname))
  352         {
  353             char    savedname[16];
  354 
  355             strcpy(savedname, rawname); // no overflow (len=8)
  356 
  357             snprintf(rawname, RAWNAMESZ, "%s/atop_%s",
  358                 BASEPATH, 
  359                 savedname);
  360             break;
  361         }
  362 
  363        /*
  364        ** if one or more 'y' (yesterday) characters are used and that
  365        ** string is not known as an existing file, the standard logfile
  366        ** is shown from N days ago (N is determined by the number
  367        ** of y's).
  368        */
  369        default:
  370         if ( access(rawname, F_OK) == 0) 
  371             break;      /* existing file */
  372 
  373         /*
  374         ** make a string existing of y's to compare with
  375         */
  376         py = malloc(len+1);
  377 
  378         ptrverify(py, "Malloc failed for 'yes' sequence\n");
  379 
  380         memset(py, 'y', len);
  381         *(py+len) = '\0';
  382 
  383         if ( strcmp(rawname, py) == 0 )
  384         {
  385             timenow  = time(0);
  386             timenow -= len*3600*24;
  387             tp   = localtime(&timenow);
  388 
  389             snprintf(rawname, RAWNAMESZ, "%s/atop_%04d%02d%02d",
  390                 BASEPATH, 
  391                 tp->tm_year+1900,
  392                 tp->tm_mon+1,
  393                 tp->tm_mday);
  394         }
  395 
  396         free(py);
  397     }
  398 
  399     /*
  400     ** make sure the file is a regular file (seekable) or
  401     ** a pipe (not seekable)
  402     */
  403     if (stat(rawname, &filestat) == -1)
  404     {
  405         fprintf(stderr, "%s - ", rawname);
  406         perror("stat raw file");
  407         cleanstop(7);
  408     }
  409 
  410     if (!S_ISREG(filestat.st_mode) && !S_ISFIFO(filestat.st_mode))
  411     {
  412         fprintf(stderr, "raw file must be a regular file or pipe\n");
  413         cleanstop(7);
  414     }
  415 
  416     isregular = S_ISREG(filestat.st_mode);
  417 
  418     /*
  419     ** open raw file
  420     */
  421     if ( (rawfd = open(rawname, O_RDONLY)) == -1)
  422     {
  423         char    command[512], tmpname1[200], tmpname2[200];
  424 
  425         /*
  426         ** check if a compressed raw file is present
  427         */
  428         snprintf(tmpname1, sizeof tmpname1, "%s.gz", rawname);
  429 
  430         if ( access(tmpname1, F_OK|R_OK) == -1)
  431         {
  432             fprintf(stderr, "%s - ", rawname);
  433             perror("open raw file");
  434             cleanstop(7);
  435         }
  436 
  437         /*
  438         ** compressed raw file to be decompressed via gunzip
  439         */
  440         fprintf(stderr, "Decompressing logfile ....\n");
  441         snprintf(tmpname2, sizeof tmpname2, "/tmp/atopwrkXXXXXX");
  442         rawfd = mkstemp(tmpname2);
  443         if (rawfd == -1)
  444         {
  445             fprintf(stderr, "%s - ", rawname);
  446             perror("creating decompression temp file");
  447             cleanstop(7);
  448         }
  449 
  450         snprintf(command,  sizeof command, "gunzip -c %s > %s",
  451                             tmpname1, tmpname2);
  452         const int system_res = system (command);
  453         unlink(tmpname2);
  454 
  455         if (system_res)
  456         {
  457             fprintf(stderr, "%s - gunzip failed", rawname);
  458             cleanstop(7);
  459         }
  460     }
  461 
  462     /* make the kernel readahead more effective, */
  463     if (isregular)
  464         posix_fadvise(rawfd, 0, 0, POSIX_FADV_SEQUENTIAL);
  465 
  466     /*
  467     ** read the raw header and verify the magic
  468     */
  469     if ( readchunk(rawfd, &rh, sizeof rh) < sizeof rh)
  470     {
  471         fprintf(stderr, "can not read raw file header\n");
  472         cleanstop(7);
  473     }
  474 
  475     if (rh.magic != MYMAGIC)
  476     {
  477         fprintf(stderr, "file %s does not contain raw atop/atopsar "
  478                 "output (wrong magic number)\n", rawname);
  479         cleanstop(7);
  480     }
  481 
  482     /*
  483     ** magic okay, but file-layout might have been modified
  484     */
  485     if (rh.sstatlen   != sizeof(struct sstat)       ||
  486         rh.tstatlen   != sizeof(struct tstat)       ||
  487         rh.rawheadlen != sizeof(struct rawheader)       ||
  488         rh.rawreclen  != sizeof(struct rawrecord)         )
  489     {
  490         fprintf(stderr,
  491             "raw file %s has incompatible format\n", rawname);
  492 
  493         if (rh.aversion & 0x8000 &&
  494                (rh.aversion & 0x7fff) != getnumvers())
  495         {
  496             fprintf(stderr,
  497                 "(created by version %d.%d - "
  498                 "current version %d.%d)\n",
  499                 (rh.aversion >> 8) & 0x7f,
  500                  rh.aversion       & 0xff,
  501                  getnumvers() >> 8,
  502                  getnumvers() & 0x7f);
  503         }
  504         else
  505         {
  506             fprintf(stderr,
  507                 "(files from other system architectures might"
  508                 " be binary incompatible)\n");
  509         }
  510 
  511         close(rawfd);
  512 
  513         if (((rh.aversion >> 8) & 0x7f) != (getnumvers()   >> 8) ||
  514              (rh.aversion       & 0xff) != (getnumvers() & 0x7f)   )
  515         {
  516             try_other_version((rh.aversion >> 8) & 0x7f,
  517                                rh.aversion       & 0xff);
  518         }
  519 
  520         cleanstop(7);
  521     }
  522 
  523     memcpy(&utsname, &rh.utsname, sizeof utsname);
  524     utsnodenamelen = strlen(utsname.nodename);
  525 
  526     supportflags = rh.supportflags;
  527     osrel        = rh.osrel;
  528     osvers       = rh.osvers;
  529     ossub        = rh.ossub;
  530     interval     = 0;
  531 
  532     if (rh.hertz)
  533         hertz    = rh.hertz;
  534 
  535     if (rh.pagesize)
  536         pagesize = rh.pagesize;
  537 
  538     if (rh.pidwidth)
  539         pidwidth = rh.pidwidth;
  540     else    
  541         pidwidth = 5;
  542 
  543     /*
  544     ** allocate a list for backtracking of rawrecord-offsets
  545     */
  546     if (isregular)
  547     {
  548         offlist = malloc(sizeof(off_t) * OFFCHUNK);
  549 
  550         ptrverify(offlist, "Malloc failed for backtrack list\n");
  551 
  552         offsize = OFFCHUNK;
  553 
  554         *offlist = lseek(rawfd, 0, SEEK_CUR);
  555         offcur   = 1;
  556     }
  557 
  558     /*
  559     ** read a raw record header until end-of-file
  560     */
  561     sampcnt = 0;
  562 
  563     while (lastcmd && lastcmd != 'q')
  564     {
  565         while ( getrawrec(rawfd, &rr, rh.rawreclen) == rh.rawreclen)
  566         {
  567             unsigned int    k, l;
  568 
  569             cursortime = rr.curtime;    // maintain current
  570 
  571             /*
  572             ** normalize the begintime and endtime if the
  573             ** format hh:mm has been used instead of an
  574             ** absolute date-time string
  575             ** (only happens for the first record)
  576             */
  577             if (begintime <= SECONDSINDAY)
  578                 begintime = normalize_epoch(cursortime,
  579                                 begintime);
  580 
  581             if (endtime && endtime <= SECONDSINDAY)
  582                 endtime = normalize_epoch(cursortime, endtime);
  583 
  584             /*
  585             ** store the offset of the raw record in the offset list
  586             ** in case of offset list overflow, extend the list
  587             */
  588             if (isregular)
  589             {
  590                 *(offlist+offcur) = lseek(rawfd, 0, SEEK_CUR) -
  591                                 rh.rawreclen;
  592 
  593                 if ( ++offcur >= offsize )
  594                 {
  595                     offlist = realloc(offlist,
  596                              (offsize+OFFCHUNK)*sizeof(off_t));
  597 
  598                     ptrverify(offlist,
  599                         "Realloc failed for backtrack list\n");
  600 
  601                     offsize+= OFFCHUNK;
  602                 }
  603             }
  604     
  605             /*
  606             ** check if this sample is within the time-range
  607             ** specified with the -b and -e flags (if any)
  608             */
  609             if ( (begintime > cursortime) )
  610             {
  611                 lastcmd = 1;
  612                         
  613                 if (isregular)
  614                 {
  615                     static off_t curr_pos = -1;
  616                     off_t next_pos;
  617 
  618                     lastcmd = 1;
  619                     next_pos = lseek(rawfd, rr.scomplen+rr.pcomplen, SEEK_CUR);
  620                     if ((curr_pos >> READAHEADOFF) != (next_pos >> READAHEADOFF))
  621                     {
  622                         int liResult;
  623                         /* just read READAHEADSIZE bytes into page cache */
  624                         char *buf = malloc(READAHEADSIZE);
  625                         ptrverify(buf, "Malloc failed for readahead");
  626                         liResult = pread(rawfd, buf, READAHEADSIZE, next_pos & ~(READAHEADSIZE - 1));
  627                         if(liResult == -1)
  628                         {
  629                             char lcMessage[64];
  630 
  631                             snprintf(lcMessage, sizeof(lcMessage) - 1,
  632                                   "%s:%d - Error %d in readahead\n",
  633                                       __FILE__, __LINE__, errno);
  634                             fprintf(stderr, "%s", lcMessage);
  635                         }
  636                         free(buf);
  637                     }
  638                     curr_pos = next_pos;
  639                     continue;
  640                 }
  641                 else    // named pipe not seekable
  642                 {
  643                     char *dummybuf =
  644                         malloc(rr.scomplen+rr.pcomplen);
  645 
  646                     ptrverify(dummybuf,
  647                         "Malloc rawlog pipe buffer failed\n");
  648 
  649                     readchunk(rawfd, dummybuf,
  650                         rr.scomplen+rr.pcomplen);
  651 
  652                     free(dummybuf);
  653                 }
  654 
  655                 continue;
  656             }
  657 
  658             begintime = 0;  // allow earlier times from now on
  659 
  660             if ( (endtime && endtime < cursortime) )
  661             {
  662                 if (isregular)
  663                     free(offlist);
  664 
  665                 close(rawfd);
  666                 return isregular;
  667             }
  668 
  669             /*
  670             ** allocate space, read compressed system-level
  671             ** statistics and decompress
  672             */
  673             if ( !getrawsstat(rawfd, &sstat, rr.scomplen) )
  674                 cleanstop(7);
  675 
  676             /*
  677             ** allocate space, read compressed process-level
  678             ** statistics and decompress
  679             */
  680             devtstat.taskall    = malloc(sizeof(struct tstat  )
  681                                 * rr.ndeviat);
  682 
  683             if (rr.totproc < rr.nactproc)   // compat old raw files
  684                 devtstat.procall = malloc(sizeof(struct tstat *)
  685                                 * rr.nactproc);
  686             else
  687                 devtstat.procall = malloc(sizeof(struct tstat *)
  688                                 * rr.totproc);
  689 
  690             devtstat.procactive = malloc(sizeof(struct tstat *) *
  691                                 rr.nactproc);
  692 
  693             ptrverify(devtstat.taskall,
  694                       "Malloc failed for %d stored tasks\n",
  695                       rr.ndeviat);
  696 
  697             ptrverify(devtstat.procall,
  698                       "Malloc failed for total %d processes\n",
  699                       rr.totproc);
  700 
  701             ptrverify(devtstat.procactive,
  702                       "Malloc failed for %d active processes\n",
  703                       rr.nactproc);
  704 
  705             if ( !getrawtstat(rawfd, devtstat.taskall,
  706                         rr.pcomplen, rr.ndeviat) )
  707                 cleanstop(7);
  708 
  709 
  710             for (i=j=k=l=0; i < rr.ndeviat; i++)
  711             {
  712                 if ( (devtstat.taskall+i)->gen.isproc)
  713                 {
  714                     devtstat.procall[j++] = devtstat.taskall+i;
  715 
  716                     if (! (devtstat.taskall+i)->gen.wasinactive)
  717                         devtstat.procactive[k++] = devtstat.taskall+i;
  718                 }
  719 
  720                 if (! (devtstat.taskall+i)->gen.wasinactive)
  721                     l++;
  722             }
  723 
  724             devtstat.ntaskall   = i;
  725             devtstat.nprocall   = j;
  726             devtstat.nprocactive    = k;
  727             devtstat.ntaskactive    = l;
  728 
  729             devtstat.totrun     = rr.totrun;
  730             devtstat.totslpi    = rr.totslpi;
  731             devtstat.totslpu    = rr.totslpu;
  732             devtstat.totzombie  = rr.totzomb;
  733 
  734             /*
  735             ** activate the installed print-function to visualize
  736             ** the system- and process-level statistics
  737             */
  738             sampcnt++;
  739 
  740             if ( (rh.supportflags & RAWLOGNG) == RAWLOGNG)
  741             {
  742                 if (rr.flags & RRACCTACTIVE)
  743                     supportflags |=  ACCTACTIVE;
  744                 else
  745                     supportflags &= ~ACCTACTIVE;
  746 
  747                 if (rr.flags & RRIOSTAT)
  748                     supportflags |=  IOSTAT;
  749                 else
  750                     supportflags &= ~IOSTAT;
  751             }
  752 
  753             if (rr.flags & RRNETATOP)
  754                 supportflags |=  NETATOP;
  755             else
  756                 supportflags &= ~NETATOP;
  757 
  758             if (rr.flags & RRNETATOPD)
  759                 supportflags |=  NETATOPD;
  760             else
  761                 supportflags &= ~NETATOPD;
  762 
  763             if (rr.flags & RRCGRSTAT)
  764                 supportflags |=  CGROUPV2;
  765             else
  766                 supportflags &= ~CGROUPV2;
  767 
  768             if (rr.flags & RRDOCKSTAT)
  769                 supportflags |=  DOCKSTAT;
  770             else
  771                 supportflags &= ~DOCKSTAT;
  772 
  773             if (rr.flags & RRGPUSTAT)
  774                 supportflags |=  GPUSTAT;
  775             else
  776                 supportflags &= ~GPUSTAT;
  777 
  778             flags = rr.flags & RRBOOT;
  779 
  780             nrgpus = sstat.gpu.nrgpus;
  781 
  782             if (isregular)
  783             {
  784                 (void) fstat(rawfd, &filestat);
  785 
  786                 if ( filestat.st_size -
  787                         lseek(rawfd, (off_t)0, SEEK_CUR)
  788                             <= rh.rawreclen)
  789                     flags |= RRLAST;
  790             }
  791 
  792             do
  793             {
  794                 lastcmd = (vis.show_samp)(rr.curtime,
  795                      rr.interval,
  796                          &devtstat, &sstat,
  797                          rr.nexit, rr.noverflow, flags);
  798             }
  799             while (!isregular &&
  800                 ( lastcmd == MSAMPPREV      ||
  801                   lastcmd == MRESET         ||
  802                  (lastcmd == MSAMPBRANCH &&
  803                         begintime < cursortime) ));
  804 
  805             free(devtstat.taskall);
  806             free(devtstat.procall);
  807             free(devtstat.procactive);
  808 
  809             switch (lastcmd)
  810             {
  811                case MSAMPPREV:
  812                 if (offcur >= 2)
  813                     offcur-= 2;
  814                 else
  815                     offcur = 0;
  816 
  817                 lseek(rawfd, *(offlist+offcur), SEEK_SET);
  818                 break;
  819 
  820                case MRESET:
  821                 lseek(rawfd, *offlist, SEEK_SET);
  822                 offcur = 1;
  823                 break;
  824 
  825                case MSAMPBRANCH:
  826                 if (begintime < cursortime && isregular)
  827                 {
  828                     lseek(rawfd, *offlist, SEEK_SET);
  829                     offcur = 1;
  830                 }
  831             }
  832         }
  833 
  834         begintime = 0;  // allow earlier times from now on
  835 
  836         if (isregular)
  837         {
  838             if (offcur >= 1)
  839                 offcur--;
  840 
  841             lseek(rawfd, *(offlist+offcur), SEEK_SET);
  842         }
  843         else
  844         {
  845             lastcmd = 'q';
  846         }
  847     }
  848 
  849     if (isregular)
  850         free(offlist);
  851 
  852     close(rawfd);
  853 
  854     return isregular;
  855 }
  856 
  857 /*
  858 ** read the next raw record from the raw logfile
  859 */
  860 static int
  861 getrawrec(int rawfd, struct rawrecord *prr, int rrlen)
  862 {
  863     return readchunk(rawfd, prr, rrlen);
  864 }
  865 
  866 /*
  867 ** read the system-level statistics from the current offset
  868 */
  869 static int
  870 getrawsstat(int rawfd, struct sstat *sp, int complen)
  871 {
  872     Byte        *compbuf;
  873     unsigned long   uncomplen = sizeof(struct sstat);
  874     int     rv;
  875 
  876     compbuf = malloc(complen);
  877 
  878     ptrverify(compbuf, "Malloc failed for reading compressed sysstats\n");
  879 
  880     if ( readchunk(rawfd, compbuf, complen) < complen)
  881     {
  882         free(compbuf);
  883         return 0;
  884     }
  885 
  886     rv = uncompress((Byte *)sp, &uncomplen, compbuf, complen);
  887 
  888     testcompval(rv, "uncompress");
  889 
  890     free(compbuf);
  891 
  892     return 1;
  893 }
  894 
  895 /*
  896 ** read the process-level statistics from the current offset
  897 */
  898 static int
  899 getrawtstat(int rawfd, struct tstat *pp, int complen, int ndeviat)
  900 {
  901     Byte        *compbuf;
  902     unsigned long   uncomplen = sizeof(struct tstat) * ndeviat;
  903     int     rv;
  904 
  905     compbuf = malloc(complen);
  906 
  907     ptrverify(compbuf, "Malloc failed for reading compressed procstats\n");
  908 
  909     if ( readchunk(rawfd, compbuf, complen) < complen)
  910     {
  911         free(compbuf);
  912         return 0;
  913     }
  914 
  915     rv = uncompress((Byte *)pp, &uncomplen, compbuf, complen);
  916 
  917     testcompval(rv, "uncompress");
  918 
  919     free(compbuf);
  920 
  921     return 1;
  922 }
  923 
  924 /* 
  925 ** verify if a particular ascii-string is in the format yyyymmdd
  926 */
  927 static int
  928 lookslikedatetome(char *p)
  929 {
  930     register int    i;
  931 
  932     for (i=0; i < 8; i++)
  933         if ( !isdigit(*(p+i)) )
  934             return 0;
  935 
  936     if (*p != '2')
  937         return 0;   /* adapt this in the year 3000 */
  938 
  939     if ( *(p+4) > '1')
  940         return 0;
  941 
  942     if ( *(p+6) > '3')
  943         return 0;
  944 
  945     return 1;   /* yes, looks like a date to me */
  946 }
  947 
  948 static void
  949 testcompval(int rv, char *func)
  950 {
  951     switch (rv)
  952     {
  953        case Z_OK:
  954        case Z_STREAM_END:
  955        case Z_NEED_DICT:
  956         break;
  957 
  958        case Z_MEM_ERROR:
  959         mcleanstop(7, "atop/atopsar - "
  960                 "%s: failed due to lack of memory\n", func);
  961 
  962        case Z_BUF_ERROR:
  963         mcleanstop(7, "atop/atopsar - "
  964             "%s: failed due to lack of room in buffer\n", func);
  965 
  966        case Z_DATA_ERROR:
  967         mcleanstop(7, "atop/atopsar - "
  968                 "%s: failed due to corrupted/incomplete data\n", func);
  969 
  970        default:
  971         mcleanstop(7, "atop/atopsar - "
  972                 "%s: unexpected error %d\n", func, rv);
  973     }
  974 }
  975 
  976 static int
  977 readchunk(int fd, void *buf, int len)
  978 {
  979     char    *p = buf;
  980     int n;
  981 
  982     while (len > 0)
  983     {
  984         switch (n = read(fd, p, len))
  985         {
  986            case 0:
  987             return 0;   // EOF
  988            case -1:
  989             perror("read raw file");
  990             cleanstop(9);
  991            default:
  992             len -= n;
  993             p   += n;
  994         }
  995     }
  996 
  997     return (char *)p - (char *)buf;
  998 }
  999 
 1000 /*
 1001 ** try to activate another atop- or atopsar-version
 1002 ** to read this logfile
 1003 */
 1004 static void
 1005 try_other_version(int majorversion, int minorversion)
 1006 {
 1007     char        tmpbuf[1024];
 1008     extern char **argvp;
 1009     int     fds;
 1010     struct rlimit   rlimit;
 1011     int         setresuid(uid_t, uid_t, uid_t);
 1012 
 1013     /*
 1014     ** prepare name of executable file
 1015     ** the current pathname (if any) is stripped off
 1016     */
 1017     snprintf(tmpbuf, sizeof tmpbuf, "%s-%d.%d",
 1018         BINPATH, majorversion, minorversion);
 1019 
 1020     fprintf(stderr, "trying to activate %s....\n", tmpbuf);
 1021 
 1022     /*
 1023     ** be sure no open file descriptors are passed
 1024     ** except stdin, stdout en stderr
 1025     */
 1026     (void) getrlimit(RLIMIT_NOFILE, &rlimit);
 1027 
 1028     for (fds=3; fds < rlimit.rlim_cur; fds++)
 1029         close(fds);
 1030 
 1031     /*
 1032     ** be absolutely sure not to pass setuid-root privileges
 1033     ** to the loaded program; errno EAGAIN and ENOMEM are not
 1034     ** acceptable!
 1035     */
 1036     if ( setresuid(getuid(), getuid(), getuid()) == -1 && errno != EPERM)
 1037     {
 1038         fprintf(stderr, "not possible to drop root-privileges!\n");
 1039         exit(1);
 1040     }
 1041 
 1042     /*
 1043     ** load alternative executable image
 1044     ** at this moment the saved-uid might still be set
 1045     ** to 'root' but this is reset at the moment of exec
 1046     */
 1047     (void) execvp(tmpbuf, argvp);
 1048 
 1049     /*
 1050     ** point of no return, except when exec failed
 1051     */
 1052     fprintf(stderr, "activation of %s failed!\n", tmpbuf);
 1053 }