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