2 * sar, sadc, sadf, mpstat and iostat common routines.
3 * (C) 1999-2016 by Sebastien GODARD (sysstat <at> orange.fr)
5 ***************************************************************************
6 * This program is free software; you can redistribute it and/or modify it *
7 * under the terms of the GNU General Public License as published by the *
8 * Free Software Foundation; either version 2 of the License, or (at your *
9 * option) any later version. *
11 * This program is distributed in the hope that it will be useful, but *
12 * WITHOUT ANY WARRANTY; without the implied warranty of MERCHANTABILITY *
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License *
16 * You should have received a copy of the GNU General Public License along *
17 * with this program; if not, write to the Free Software Foundation, Inc., *
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA *
19 ***************************************************************************
29 #include <unistd.h> /* For STDOUT_FILENO, among others */
30 #include <sys/ioctl.h>
31 #include <sys/types.h>
44 #define _(string) gettext(string)
46 #define _(string) (string)
49 /* Number of ticks per second */
51 /* Number of bit shifts to convert pages to kB */
52 unsigned int kb_shift;
55 char sc_percent_high[MAX_SGR_LEN] = C_BOLD_RED;
56 char sc_percent_low[MAX_SGR_LEN] = C_BOLD_BLUE;
57 char sc_zero_int_stat[MAX_SGR_LEN] = C_LIGHT_YELLOW;
58 char sc_int_stat[MAX_SGR_LEN] = C_BOLD_YELLOW;
59 char sc_item_name[MAX_SGR_LEN] = C_LIGHT_GREEN;
60 char sc_sa_restart[MAX_SGR_LEN] = C_LIGHT_RED;
61 char sc_sa_comment[MAX_SGR_LEN] = C_LIGHT_CYAN;
62 char sc_normal[MAX_SGR_LEN] = C_NORMAL;
64 /* Type of persistent device names used in sar and iostat */
65 char persistent_name_type[MAX_FILE_LEN];
68 ***************************************************************************
69 * Print sysstat version number and exit.
70 ***************************************************************************
72 void print_version(void)
74 printf(_("sysstat version %s\n"), VERSION);
75 printf("(C) Sebastien Godard (sysstat <at> orange.fr)\n");
80 ***************************************************************************
81 * Get local date and time.
84 * @d_off Day offset (number of days to go back in the past).
87 * @rectime Current local date and time.
90 * Value of time in seconds since the Epoch.
91 ***************************************************************************
93 time_t get_localtime(struct tm *rectime, int d_off)
99 timer -= SEC_PER_DAY * d_off;
100 ltm = localtime(&timer);
109 ***************************************************************************
110 * Get date and time expressed in UTC.
113 * @d_off Day offset (number of days to go back in the past).
116 * @rectime Current date and time expressed in UTC.
119 * Value of time in seconds since the Epoch.
120 ***************************************************************************
122 time_t get_gmtime(struct tm *rectime, int d_off)
128 timer -= SEC_PER_DAY * d_off;
129 ltm = gmtime(&timer);
138 ***************************************************************************
139 * Get date and time and take into account <ENV_TIME_DEFTM> variable.
142 * @d_off Day offset (number of days to go back in the past).
145 * @rectime Current date and time.
148 * Value of time in seconds since the Epoch.
149 ***************************************************************************
151 time_t get_time(struct tm *rectime, int d_off)
157 /* Read environment variable value once */
158 if ((e = getenv(ENV_TIME_DEFTM)) != NULL) {
159 utc = !strcmp(e, K_UTC);
165 return get_gmtime(rectime, d_off);
167 return get_localtime(rectime, d_off);
171 ***************************************************************************
172 * Count number of comma-separated values in arguments list. For example,
173 * the number will be 3 for the list "foobar -p 1 -p 2,3,4 2 5".
176 * @arg_c Number of arguments in the list.
177 * @arg_v Arguments list.
180 * Number of comma-separated values in the list.
181 ***************************************************************************
183 int count_csvalues(int arg_c, char **arg_v)
189 while (opt < arg_c) {
190 if (strchr(arg_v[opt], ',')) {
191 for (t = arg_v[opt]; t; t = strchr(t + 1, ',')) {
202 ***************************************************************************
203 * Look for partitions of a given block device in /sys filesystem.
206 * @dev_name Name of the block device.
209 * Number of partitions for the given block device.
210 ***************************************************************************
212 int get_dev_part_nr(char *dev_name)
216 char dfile[MAX_PF_NAME], line[MAX_PF_NAME];
219 snprintf(dfile, MAX_PF_NAME, "%s/%s", SYSFS_BLOCK, dev_name);
220 dfile[MAX_PF_NAME - 1] = '\0';
222 /* Open current device directory in /sys/block */
223 if ((dir = opendir(dfile)) == NULL)
226 /* Get current file entry */
227 while ((drd = readdir(dir)) != NULL) {
228 if (!strcmp(drd->d_name, ".") || !strcmp(drd->d_name, ".."))
230 snprintf(line, MAX_PF_NAME, "%s/%s/%s", dfile, drd->d_name, S_STAT);
231 line[MAX_PF_NAME - 1] = '\0';
233 /* Try to guess if current entry is a directory containing a stat file */
234 if (!access(line, R_OK)) {
240 /* Close directory */
247 ***************************************************************************
248 * Look for block devices present in /sys/ filesystem:
249 * Check first that sysfs is mounted (done by trying to open /sys/block
250 * directory), then find number of devices registered.
253 * @display_partitions Set to TRUE if partitions must also be counted.
256 * Total number of block devices (and partitions if @display_partitions was
258 ***************************************************************************
260 int get_sysfs_dev_nr(int display_partitions)
264 char line[MAX_PF_NAME];
267 /* Open /sys/block directory */
268 if ((dir = opendir(SYSFS_BLOCK)) == NULL)
269 /* sysfs not mounted, or perhaps this is an old kernel */
272 /* Get current file entry in /sys/block directory */
273 while ((drd = readdir(dir)) != NULL) {
274 if (!strcmp(drd->d_name, ".") || !strcmp(drd->d_name, ".."))
276 snprintf(line, MAX_PF_NAME, "%s/%s/%s", SYSFS_BLOCK, drd->d_name, S_STAT);
277 line[MAX_PF_NAME - 1] = '\0';
279 /* Try to guess if current entry is a directory containing a stat file */
280 if (!access(line, R_OK)) {
284 if (display_partitions) {
285 /* We also want the number of partitions for this device */
286 dev += get_dev_part_nr(drd->d_name);
291 /* Close /sys/block directory */
298 ***************************************************************************
299 * Read /proc/devices file and get device-mapper major number.
300 * If device-mapper entry is not found in file, assume it's not active.
303 * Device-mapper major number.
304 ***************************************************************************
306 unsigned int get_devmap_major(void)
311 * Linux uses 12 bits for the major number,
312 * so this shouldn't match any real device.
314 unsigned int dm_major = ~0U;
316 if ((fp = fopen(DEVICES, "r")) == NULL)
319 while (fgets(line, sizeof(line), fp) != NULL) {
321 if (strstr(line, "device-mapper")) {
322 /* Read device-mapper major number */
323 sscanf(line, "%u", &dm_major);
333 ***************************************************************************
334 * Returns whether S_TIME_FORMAT is set to ISO.
337 * TRUE if S_TIME_FORMAT is set to ISO, or FALSE otherwise.
338 ***************************************************************************
340 int is_iso_time_fmt(void)
342 static int is_iso = -1;
346 is_iso = (((e = getenv(ENV_TIME_FMT)) != NULL) && !strcmp(e, K_ISO));
352 ***************************************************************************
356 * @nr_tab Number of tabs to print.
357 ***************************************************************************
359 void prtab(int nr_tab)
363 for (i = 0; i < nr_tab; i++) {
369 ***************************************************************************
370 * printf() function modified for XML-like output. Don't print a CR at the
374 * @nr_tab Number of tabs to print.
375 * @fmtf printf() format.
376 ***************************************************************************
378 void xprintf0(int nr_tab, const char *fmtf, ...)
380 static char buf[1024];
383 va_start(args, fmtf);
384 vsnprintf(buf, sizeof(buf), fmtf, args);
392 ***************************************************************************
393 * printf() function modified for XML-like output. Print a CR at the end of
397 * @nr_tab Number of tabs to print.
398 * @fmtf printf() format.
399 ***************************************************************************
401 void xprintf(int nr_tab, const char *fmtf, ...)
403 static char buf[1024];
406 va_start(args, fmtf);
407 vsnprintf(buf, sizeof(buf), fmtf, args);
415 ***************************************************************************
419 * @rectime Date to display (don't use time fields).
420 * @sysname System name to display.
421 * @release System release number to display.
422 * @nodename Hostname to display.
423 * @machine Machine architecture to display.
424 * @cpu_nr Number of CPU.
425 * @format Set to FALSE for (default) plain output, and to TRUE for
426 * JSON format output.
429 * TRUE if S_TIME_FORMAT is set to ISO, or FALSE otherwise.
430 ***************************************************************************
432 int print_gal_header(struct tm *rectime, char *sysname, char *release,
433 char *nodename, char *machine, int cpu_nr, int format)
435 char cur_date[TIMESTAMP_LEN];
438 if (rectime == NULL) {
439 strcpy(cur_date, "?/?/?");
441 else if (is_iso_time_fmt()) {
442 strftime(cur_date, sizeof(cur_date), "%Y-%m-%d", rectime);
446 strftime(cur_date, sizeof(cur_date), "%x", rectime);
449 if (format == PLAIN_OUTPUT) {
451 printf("%s %s (%s) \t%s \t_%s_\t(%d CPU)\n", sysname, release, nodename,
452 cur_date, machine, cpu_nr);
456 xprintf(0, "{\"sysstat\": {");
457 xprintf(1, "\"hosts\": [");
459 xprintf(3, "\"nodename\": \"%s\",", nodename);
460 xprintf(3, "\"sysname\": \"%s\",", sysname);
461 xprintf(3, "\"release\": \"%s\",", release);
462 xprintf(3, "\"machine\": \"%s\",", machine);
463 xprintf(3, "\"number-of-cpus\": %d,", cpu_nr);
464 xprintf(3, "\"date\": \"%s\",", cur_date);
465 xprintf(3, "\"statistics\": [");
473 ***************************************************************************
474 * Init National Language Support.
475 ***************************************************************************
479 setlocale(LC_MESSAGES, "");
480 setlocale(LC_CTYPE, "");
481 setlocale(LC_TIME, "");
482 setlocale(LC_NUMERIC, "");
484 bindtextdomain(PACKAGE, LOCALEDIR);
490 ***************************************************************************
491 * Get number of rows for current window.
495 ***************************************************************************
497 int get_win_height(void)
501 * This default value will be used whenever STDOUT
502 * is redirected to a pipe or a file
504 int rows = 3600 * 24;
506 if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &win) != -1) {
507 if (win.ws_row > 2) {
508 rows = win.ws_row - 2;
515 ***************************************************************************
516 * Canonicalize and remove /dev from path name.
519 * @name Device name (may begin with "/dev/" or can be a symlink).
523 ***************************************************************************
525 char *device_name(char *name)
527 static char out[MAX_FILE_LEN];
531 /* realpath() creates new string, so we need to free it later */
532 resolved_name = realpath(name, NULL);
534 /* If path doesn't exist, just return input */
535 if (!resolved_name) {
539 if (!strncmp(resolved_name, "/dev/", 5)) {
542 strncpy(out, resolved_name + i, MAX_FILE_LEN);
543 out[MAX_FILE_LEN - 1] = '\0';
551 ***************************************************************************
552 * Test whether given name is a device or a partition, using sysfs.
553 * This is more straightforward that using ioc_iswhole() function from
554 * ioconf.c which should be used only with kernels that don't have sysfs.
557 * @name Device or partition name.
558 * @allow_virtual TRUE if virtual devices are also accepted.
559 * The device is assumed to be virtual if no
560 * /sys/block/<device>/device link exists.
563 * TRUE if @name is not a partition.
564 ***************************************************************************
566 int is_device(char *name, int allow_virtual)
568 char syspath[PATH_MAX];
571 /* Some devices may have a slash in their name (eg. cciss/c0d0...) */
572 while ((slash = strchr(name, '/'))) {
575 snprintf(syspath, sizeof(syspath), "%s/%s%s", SYSFS_BLOCK, name,
576 allow_virtual ? "" : "/device");
578 return !(access(syspath, F_OK));
582 ***************************************************************************
583 * Get page shift in kB.
584 ***************************************************************************
586 void get_kb_shift(void)
591 /* One can also use getpagesize() to get the size of a page */
592 if ((size = sysconf(_SC_PAGESIZE)) == -1) {
596 size >>= 10; /* Assume that a page has a minimum size of 1 kB */
603 kb_shift = (unsigned int) shift;
607 ***************************************************************************
608 * Get number of clock ticks per second.
609 ***************************************************************************
615 if ((ticks = sysconf(_SC_CLK_TCK)) == -1) {
619 hz = (unsigned int) ticks;
623 ***************************************************************************
624 * Workaround for CPU counters read from /proc/stat: Dyn-tick kernels
625 * have a race issue that can make those counters go backward.
626 ***************************************************************************
628 double ll_sp_value(unsigned long long value1, unsigned long long value2,
629 unsigned long long itv)
634 return SP_VALUE(value1, value2, itv);
638 ***************************************************************************
639 * Compute time interval.
642 * @prev_uptime Previous uptime value in jiffies.
643 * @curr_uptime Current uptime value in jiffies.
646 * Interval of time in jiffies.
647 ***************************************************************************
649 unsigned long long get_interval(unsigned long long prev_uptime,
650 unsigned long long curr_uptime)
652 unsigned long long itv;
654 /* prev_time=0 when displaying stats since system startup */
655 itv = curr_uptime - prev_uptime;
657 if (!itv) { /* Paranoia checking */
665 ***************************************************************************
666 * Since ticks may vary slightly from CPU to CPU, we'll want
667 * to recalculate itv based on this CPU's tick count, rather
668 * than that reported by the "cpu" line. Otherwise we
669 * occasionally end up with slightly skewed figures, with
670 * the skew being greater as the time interval grows shorter.
673 * @scc Current sample statistics for current CPU.
674 * @scp Previous sample statistics for current CPU.
677 * Interval of time based on current CPU.
678 ***************************************************************************
680 unsigned long long get_per_cpu_interval(struct stats_cpu *scc,
681 struct stats_cpu *scp)
683 unsigned long long ishift = 0LL;
685 if ((scc->cpu_user - scc->cpu_guest) < (scp->cpu_user - scp->cpu_guest)) {
687 * Sometimes the nr of jiffies spent in guest mode given by the guest
688 * counter in /proc/stat is slightly higher than that included in
689 * the user counter. Update the interval value accordingly.
691 ishift += (scp->cpu_user - scp->cpu_guest) -
692 (scc->cpu_user - scc->cpu_guest);
694 if ((scc->cpu_nice - scc->cpu_guest_nice) < (scp->cpu_nice - scp->cpu_guest_nice)) {
696 * Idem for nr of jiffies spent in guest_nice mode.
698 ishift += (scp->cpu_nice - scp->cpu_guest_nice) -
699 (scc->cpu_nice - scc->cpu_guest_nice);
703 * Don't take cpu_guest and cpu_guest_nice into account
704 * because cpu_user and cpu_nice already include them.
706 return ((scc->cpu_user + scc->cpu_nice +
707 scc->cpu_sys + scc->cpu_iowait +
708 scc->cpu_idle + scc->cpu_steal +
709 scc->cpu_hardirq + scc->cpu_softirq) -
710 (scp->cpu_user + scp->cpu_nice +
711 scp->cpu_sys + scp->cpu_iowait +
712 scp->cpu_idle + scp->cpu_steal +
713 scp->cpu_hardirq + scp->cpu_softirq) +
718 ***************************************************************************
719 * Unhandled situation: Panic and exit. Should never happen.
722 * @function Function name where situation occured.
723 * @error_code Error code.
724 ***************************************************************************
726 void sysstat_panic(const char *function, int error_code)
728 fprintf(stderr, "sysstat: %s[%d]: Internal error...\n",
729 function, error_code);
734 ***************************************************************************
735 * Count number of bits set in an array.
738 * @ptr Pointer to array.
739 * @size Size of array in bytes.
742 * Number of bits set in the array.
743 ***************************************************************************
745 int count_bits(void *ptr, int size)
751 for (i = 0; i < size; i++, p++) {
764 ***************************************************************************
765 * Compute "extended" device statistics (service time, etc.).
768 * @sdc Structure with current device statistics.
769 * @sdp Structure with previous device statistics.
770 * @itv Interval of time in jiffies.
773 * @xds Structure with extended statistics.
774 ***************************************************************************
776 void compute_ext_disk_stats(struct stats_disk *sdc, struct stats_disk *sdp,
777 unsigned long long itv, struct ext_disk_stats *xds)
780 = ((double) (sdc->nr_ios - sdp->nr_ios)) * HZ / itv;
782 xds->util = S_VALUE(sdp->tot_ticks, sdc->tot_ticks, itv);
783 xds->svctm = tput ? xds->util / tput : 0.0;
785 * Kernel gives ticks already in milliseconds for all platforms
786 * => no need for further scaling.
788 xds->await = (sdc->nr_ios - sdp->nr_ios) ?
789 ((sdc->rd_ticks - sdp->rd_ticks) + (sdc->wr_ticks - sdp->wr_ticks)) /
790 ((double) (sdc->nr_ios - sdp->nr_ios)) : 0.0;
791 xds->arqsz = (sdc->nr_ios - sdp->nr_ios) ?
792 ((sdc->rd_sect - sdp->rd_sect) + (sdc->wr_sect - sdp->wr_sect)) /
793 ((double) (sdc->nr_ios - sdp->nr_ios)) : 0.0;
797 ***************************************************************************
798 * Convert in-place input string to lowercase.
801 * @str String to be converted.
804 * @str String in lowercase.
807 * String in lowercase.
808 ***************************************************************************
810 char *strtolower(char *str)
823 ***************************************************************************
824 * Get persistent type name directory from type.
827 * @type Persistent type name (UUID, LABEL, etc.)
830 * Path to the persistent type name directory, or NULL if access is denied.
831 ***************************************************************************
833 char *get_persistent_type_dir(char *type)
837 snprintf(dir, 32, "%s-%s", DEV_DISK_BY, type);
839 if (access(dir, R_OK)) {
847 ***************************************************************************
848 * Get persistent name absolute path.
851 * @name Persistent name.
854 * Path to the persistent name, or NULL if file doesn't exist.
855 ***************************************************************************
857 char *get_persistent_name_path(char *name)
859 static char path[PATH_MAX];
861 snprintf(path, PATH_MAX, "%s/%s",
862 get_persistent_type_dir(persistent_name_type), name);
864 if (access(path, F_OK)) {
872 ***************************************************************************
873 * Get files from persistent type name directory.
876 * List of files in the persistent type name directory in alphabetical order.
877 ***************************************************************************
879 char **get_persistent_names(void)
884 struct dirent **namelist;
886 /* Get directory name for selected persistent type */
887 dir = get_persistent_type_dir(persistent_name_type);
891 n = scandir(dir, &namelist, NULL, alphasort);
895 /* If directory is empty, it contains 2 entries: "." and ".." */
897 /* Free list and return NULL */
900 /* Ignore the "." and "..", but keep place for one last NULL. */
901 files = (char **) calloc(n - 1, sizeof(char *));
906 * i is for traversing namelist, k is for files.
907 * i != k because we are ignoring "." and ".." entries.
909 for (i = 0; i < n; i++) {
910 /* Ignore "." and "..". */
911 if (!strcmp(".", namelist[i]->d_name) ||
912 !strcmp("..", namelist[i]->d_name))
915 files[k] = (char *) calloc(strlen(namelist[i]->d_name) + 1, sizeof(char));
919 strcpy(files[k++], namelist[i]->d_name);
925 for (i = 0; i < n; i++) {
934 ***************************************************************************
935 * Get persistent name from pretty name.
938 * @pretty Pretty name (e.g. sda, sda1, ..).
942 ***************************************************************************
944 char *get_persistent_name_from_pretty(char *pretty)
949 char **persist_names;
950 char target[PATH_MAX];
951 static char persist_name[FILENAME_MAX];
953 persist_name[0] = '\0';
955 /* Get list of files from persistent type name directory */
956 persist_names = get_persistent_names();
960 while (persist_names[++i]) {
961 /* Get absolute path for current persistent name */
962 link = get_persistent_name_path(persist_names[i]);
966 /* Persistent name is usually a symlink: Read it... */
967 r = readlink(link, target, PATH_MAX);
968 if ((r <= 0) || (r >= PATH_MAX))
973 /* ... and get device pretty name it points at */
974 name = basename(target);
975 if (!name || (name[0] == '\0'))
978 if (!strncmp(name, pretty, FILENAME_MAX)) {
979 /* We have found pretty name for current persistent one */
980 strncpy(persist_name, persist_names[i], FILENAME_MAX);
981 persist_name[FILENAME_MAX - 1] = '\0';
987 while (persist_names[++i]) {
988 free (persist_names[i]);
990 free (persist_names);
992 if (strlen(persist_name) <= 0)
999 ***************************************************************************
1000 * Get pretty name (sda, sda1...) from persistent name.
1003 * @persistent Persistent name.
1007 ***************************************************************************
1009 char *get_pretty_name_from_persistent(char *persistent)
1012 char *link, *pretty, target[PATH_MAX];
1014 /* Get absolute path for persistent name */
1015 link = get_persistent_name_path(persistent);
1019 /* Persistent name is usually a symlink: Read it... */
1020 r = readlink(link, target, PATH_MAX);
1021 if ((r <= 0) || (r >= PATH_MAX))
1026 /* ... and get device pretty name it points at */
1027 pretty = basename(target);
1028 if (!pretty || (pretty[0] == '\0'))
1035 ***************************************************************************
1036 * Init color strings.
1037 ***************************************************************************
1039 void init_colors(void)
1044 /* Read S_COLORS environment variable */
1045 if (((e = getenv(ENV_COLORS)) == NULL) ||
1046 !strcmp(e, C_NEVER) ||
1047 (strcmp(e, C_ALWAYS) && !isatty(STDOUT_FILENO))) {
1049 * Environment variable not set, or set to "never",
1050 * or set to "auto" and stdout is not a terminal:
1051 * Unset color strings.
1053 strcpy(sc_percent_high, "");
1054 strcpy(sc_percent_low, "");
1055 strcpy(sc_zero_int_stat, "");
1056 strcpy(sc_int_stat, "");
1057 strcpy(sc_item_name, "");
1058 strcpy(sc_sa_comment, "");
1059 strcpy(sc_sa_restart, "");
1060 strcpy(sc_normal, "");
1065 /* Read S_COLORS_SGR environment variable */
1066 if ((e = getenv(ENV_COLORS_SGR)) == NULL)
1067 /* Environment variable not set */
1070 for (p = strtok(e, ":"); p; p =strtok(NULL, ":")) {
1073 if ((len > 7) || (len < 3) || (*(p + 1) != '=') ||
1074 (strspn(p + 2, ";0123456789") != (len - 2)))
1075 /* Ignore malformed codes */
1080 snprintf(sc_percent_high, MAX_SGR_LEN, "\e[%sm", p + 2);
1083 snprintf(sc_percent_low, MAX_SGR_LEN, "\e[%sm", p + 2);
1086 snprintf(sc_zero_int_stat, MAX_SGR_LEN, "\e[%sm", p + 2);
1089 snprintf(sc_int_stat, MAX_SGR_LEN, "\e[%sm", p + 2);
1092 snprintf(sc_item_name, MAX_SGR_LEN, "\e[%sm", p + 2);
1095 snprintf(sc_sa_comment, MAX_SGR_LEN, "\e[%sm", p + 2);
1098 snprintf(sc_sa_restart, MAX_SGR_LEN, "\e[%sm", p + 2);
1105 ***************************************************************************
1106 * Print 64 bit unsigned values using colors.
1109 * @num Number of values to print.
1110 * @width Output width.
1111 ***************************************************************************
1113 void cprintf_u64(int num, int width, ...)
1119 va_start(args, width);
1121 for (i = 0; i < num; i++) {
1122 val = va_arg(args, unsigned long long);
1124 printf("%s", sc_zero_int_stat);
1127 printf("%s", sc_int_stat);
1129 printf(" %*"PRIu64, width, val);
1130 printf("%s", sc_normal);
1137 ***************************************************************************
1138 * Print hex values using colors.
1141 * @num Number of values to print.
1142 * @width Output width.
1143 ***************************************************************************
1145 void cprintf_x(int num, int width, ...)
1151 va_start(args, width);
1153 for (i = 0; i < num; i++) {
1154 val = va_arg(args, unsigned int);
1155 printf("%s", sc_int_stat);
1156 printf(" %*x", width, val);
1157 printf("%s", sc_normal);
1164 ***************************************************************************
1165 * Print "double" statistics values using colors.
1168 * @num Number of values to print.
1169 * @width Output width.
1170 * @wd Number of decimal places.
1171 ***************************************************************************
1173 void cprintf_f(int num, int wi, int wd, ...)
1181 for (i = 0; i < num; i++) {
1182 val = va_arg(args, double);
1183 if (((val < 0.005) && (val > -0.005)) ||
1184 ((wd == 0) && (val < 0.5))) {
1185 printf("%s", sc_zero_int_stat);
1188 printf("%s", sc_int_stat);
1190 printf(" %*.*f", wi, wd, val);
1191 printf("%s", sc_normal);
1198 ***************************************************************************
1199 * Print "percent" statistics values using colors.
1202 * @num Number of values to print.
1203 * @width Output width.
1204 * @wd Number of decimal places.
1205 ***************************************************************************
1207 void cprintf_pc(int num, int wi, int wd, ...)
1215 for (i = 0; i < num; i++) {
1216 val = va_arg(args, double);
1217 if (val >= PERCENT_LIMIT_HIGH) {
1218 printf("%s", sc_percent_high);
1220 else if (val >= PERCENT_LIMIT_LOW) {
1221 printf("%s", sc_percent_low);
1223 else if (val < 0.005) {
1224 printf("%s", sc_zero_int_stat);
1227 printf("%s", sc_int_stat);
1229 printf(" %*.*f", wi, wd, val);
1230 printf("%s", sc_normal);
1237 ***************************************************************************
1238 * Print item name using selected color.
1239 * Only one name can be displayed. Name can be an integer or a string.
1242 * @type 0 if name is an int, 1 if name is a string
1243 * @format Output format.
1244 * @item_string Item name (given as a string of characters).
1245 * @item_int Item name (given as an integer value).
1246 ***************************************************************************
1248 void cprintf_in(int type, char *format, char *item_string, int item_int)
1250 printf("%s", sc_item_name);
1252 printf(format, item_string);
1255 printf(format, item_int);
1257 printf("%s", sc_normal);
1261 ***************************************************************************
1262 * Print a string using selected color.
1265 * @type Type of string to display.
1266 * @format Output format.
1267 * @string String to display.
1268 ***************************************************************************
1270 void cprintf_s(int type, char *format, char *string)
1272 if (type == IS_STR) {
1273 printf("%s", sc_int_stat);
1275 else if (type == IS_ZERO) {
1276 printf("%s", sc_zero_int_stat);
1278 else if (type == IS_RESTART) {
1279 printf("%s", sc_sa_restart);
1283 printf("%s", sc_sa_comment);
1285 printf(format, string);
1286 printf("%s", sc_normal);