"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 }