2 * sar and sadf 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 ***************************************************************************
27 #include <unistd.h> /* For STDOUT_FILENO, among others */
31 #include <sys/types.h>
44 #define _(string) gettext(string)
46 #define _(string) (string)
49 int default_file_used = FALSE;
50 extern struct act_bitmap cpu_bitmap;
53 ***************************************************************************
54 * Init a bitmap (CPU, IRQ, etc.).
57 * @value Value used to init bitmap.
58 * @sz Size of the bitmap in bytes.
61 * @bitmap Bitmap initialized.
62 ***************************************************************************
64 void set_bitmap(unsigned char bitmap[], unsigned char value, unsigned int sz)
68 for (i = 0; i < sz; i++) {
74 ***************************************************************************
75 * Allocate structures.
78 * @act Array of activities.
79 ***************************************************************************
81 void allocate_structures(struct activity *act[])
85 for (i = 0; i < NR_ACT; i++) {
87 for (j = 0; j < 3; j++) {
88 SREALLOC(act[i]->buf[j], void,
89 (size_t) act[i]->msize * (size_t) act[i]->nr * (size_t) act[i]->nr2);
96 ***************************************************************************
100 * @act Array of activities.
101 ***************************************************************************
103 void free_structures(struct activity *act[])
107 for (i = 0; i < NR_ACT; i++) {
108 if (act[i]->nr > 0) {
109 for (j = 0; j < 3; j++) {
110 if (act[i]->buf[j]) {
111 free(act[i]->buf[j]);
112 act[i]->buf[j] = NULL;
120 ***************************************************************************
121 * Try to get device real name from sysfs tree.
124 * @major Major number of the device.
125 * @minor Minor number of the device.
128 * The name of the device, which may be the real name (as it appears in /dev)
130 ***************************************************************************
132 char *get_devname_from_sysfs(unsigned int major, unsigned int minor)
134 static char link[32], target[PATH_MAX];
138 snprintf(link, 32, "%s/%u:%u", SYSFS_DEV_BLOCK, major, minor);
140 /* Get full path to device knowing its major and minor numbers */
141 r = readlink(link, target, PATH_MAX);
142 if (r <= 0 || r >= PATH_MAX) {
148 /* Get device name */
149 devname = basename(target);
150 if (!devname || strnlen(devname, FILENAME_MAX) == 0) {
158 ***************************************************************************
159 * Get device real name if possible.
160 * Warning: This routine may return a bad name on 2.4 kernels where
161 * disk activities are read from /proc/stat.
164 * @major Major number of the device.
165 * @minor Minor number of the device.
166 * @pretty TRUE if the real name of the device (as it appears in /dev)
167 * should be returned.
170 * The name of the device, which may be the real name (as it appears in /dev)
171 * or a string with the following format devM-n.
172 ***************************************************************************
174 char *get_devname(unsigned int major, unsigned int minor, int pretty)
179 snprintf(buf, 32, "dev%u-%u", major, minor);
184 name = get_devname_from_sysfs(major, minor);
188 name = ioc_name(major, minor);
189 if ((name != NULL) && strcmp(name, K_NODEV))
196 ***************************************************************************
197 * Check if we are close enough to desired interval.
200 * @uptime_ref Uptime used as reference. This is the system uptime for the
201 * first sample statistics, or the first system uptime after a
203 * @uptime Current system uptime.
204 * @reset TRUE if @last_uptime should be reset with @uptime_ref.
205 * @interval Interval of time.
208 * 1 if we are actually close enough to desired interval, 0 otherwise.
209 ***************************************************************************
211 int next_slice(unsigned long long uptime_ref, unsigned long long uptime,
212 int reset, long interval)
214 unsigned long file_interval, entry;
215 static unsigned long long last_uptime = 0;
216 int min, max, pt1, pt2;
219 /* uptime is expressed in jiffies (basis of 1 processor) */
220 if (!last_uptime || reset) {
221 last_uptime = uptime_ref;
224 /* Interval cannot be greater than 0xffffffff here */
225 f = ((double) ((uptime - last_uptime) & 0xffffffff)) / HZ;
226 file_interval = (unsigned long) f;
227 if ((f * 10) - (file_interval * 10) >= 5) {
228 file_interval++; /* Rounding to correct value */
231 last_uptime = uptime;
234 * A few notes about the "algorithm" used here to display selected entries
235 * from the system activity file (option -f with -i flag):
236 * Let 'Iu' be the interval value given by the user on the command line,
237 * 'If' the interval between current and previous line in the system
239 * and 'En' the nth entry (identified by its time stamp) of the file.
240 * We choose In = [ En - If/2, En + If/2 [ if If is even,
241 * or In = [ En - If/2, En + If/2 ] if not.
242 * En will be displayed if
243 * (Pn * Iu) or (P'n * Iu) belongs to In
244 * with Pn = En / Iu and P'n = En / Iu + 1
246 f = ((double) ((uptime - uptime_ref) & 0xffffffff)) / HZ;
247 entry = (unsigned long) f;
248 if ((f * 10) - (entry * 10) >= 5) {
252 min = entry - (file_interval / 2);
253 max = entry + (file_interval / 2) + (file_interval & 0x1);
254 pt1 = (entry / interval) * interval;
255 pt2 = ((entry / interval) + 1) * interval;
257 return (((pt1 >= min) && (pt1 < max)) || ((pt2 >= min) && (pt2 < max)));
261 ***************************************************************************
262 * Use time stamp to fill tstamp structure.
265 * @timestamp Timestamp to decode (format: HH:MM:SS).
268 * @tse Structure containing the decoded timestamp.
271 * 0 if the timestamp has been successfully decoded, 1 otherwise.
272 ***************************************************************************
274 int decode_timestamp(char timestamp[], struct tstamp *tse)
276 timestamp[2] = timestamp[5] = '\0';
277 tse->tm_sec = atoi(×tamp[6]);
278 tse->tm_min = atoi(×tamp[3]);
279 tse->tm_hour = atoi(timestamp);
281 if ((tse->tm_sec < 0) || (tse->tm_sec > 59) ||
282 (tse->tm_min < 0) || (tse->tm_min > 59) ||
283 (tse->tm_hour < 0) || (tse->tm_hour > 23))
292 ***************************************************************************
293 * Compare two timestamps.
296 * @rectime Date and time for current sample.
297 * @tse Timestamp used as reference.
300 * A positive value if @rectime is greater than @tse,
301 * a negative one otherwise.
302 ***************************************************************************
304 int datecmp(struct tm *rectime, struct tstamp *tse)
306 if (rectime->tm_hour == tse->tm_hour) {
307 if (rectime->tm_min == tse->tm_min)
308 return (rectime->tm_sec - tse->tm_sec);
310 return (rectime->tm_min - tse->tm_min);
313 return (rectime->tm_hour - tse->tm_hour);
317 ***************************************************************************
318 * Parse a timestamp entered on the command line (hh:mm[:ss]) and decode it.
321 * @argv Arguments list.
322 * @opt Index in the arguments list.
323 * @def_timestamp Default timestamp to use.
326 * @tse Structure containing the decoded timestamp.
329 * 0 if the timestamp has been successfully decoded, 1 otherwise.
330 ***************************************************************************
332 int parse_timestamp(char *argv[], int *opt, struct tstamp *tse,
333 const char *def_timestamp)
337 if (argv[++(*opt)]) {
338 switch (strlen(argv[*opt])) {
341 strncpy(timestamp, argv[(*opt)++], 5);
342 strcat(timestamp,":00");
346 strncpy(timestamp, argv[(*opt)++], 8);
350 strncpy(timestamp, def_timestamp, 8);
354 strncpy(timestamp, def_timestamp, 8);
358 return decode_timestamp(timestamp, tse);
362 ***************************************************************************
363 * Look for the most recent of saDD and saYYYYMMDD to decide which one to
364 * use. If neither exists then use saDD by default.
367 * @sa_dir Directory where standard daily data files are saved.
368 * @rectime Structure containing the current date.
371 * @sa_name 0 to use saDD data files,
372 * 1 to use saYYYYMMDD data files.
373 ***************************************************************************
375 void guess_sa_name(char *sa_dir, struct tm *rectime, int *sa_name)
377 char filename[MAX_FILE_LEN];
381 /* Use saDD by default */
384 /* Look for saYYYYMMDD */
385 snprintf(filename, MAX_FILE_LEN,
386 "%s/sa%04d%02d%02d", sa_dir,
387 rectime->tm_year + 1900,
390 filename[MAX_FILE_LEN - 1] = '\0';
392 if (stat(filename, &sb) < 0)
393 /* Cannot find or access saYYYYMMDD, so use saDD */
395 sa_mtime = sb.st_mtime;
398 snprintf(filename, MAX_FILE_LEN,
401 filename[MAX_FILE_LEN - 1] = '\0';
403 if (stat(filename, &sb) < 0) {
404 /* Cannot find or access saDD, so use saYYYYMMDD */
409 if (sa_mtime > sb.st_mtime) {
410 /* saYYYYMMDD is more recent than saDD, so use it */
416 ***************************************************************************
417 * Set current daily data file name.
420 * @datafile If not an empty string then this is the alternate directory
421 * location where daily data files will be saved.
422 * @d_off Day offset (number of days to go back in the past).
423 * @sa_name 0 for saDD data files,
424 * 1 for saYYYYMMDD data files,
425 * -1 if unknown. In this case, will look for the most recent
426 * of saDD and saYYYYMMDD and use it.
429 * @datafile Name of daily data file.
430 ***************************************************************************
432 void set_default_file(char *datafile, int d_off, int sa_name)
434 char sa_dir[MAX_FILE_LEN];
435 struct tm rectime = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL};
437 /* Set directory where daily data files will be saved */
439 strncpy(sa_dir, datafile, MAX_FILE_LEN);
442 strncpy(sa_dir, SA_DIR, MAX_FILE_LEN);
444 sa_dir[MAX_FILE_LEN - 1] = '\0';
446 get_time(&rectime, d_off);
449 * Look for the most recent of saDD and saYYYYMMDD
450 * and use it. If neither exists then use saDD.
451 * sa_name is set accordingly.
453 guess_sa_name(sa_dir, &rectime, &sa_name);
456 /* Using saYYYYMMDD data files */
457 snprintf(datafile, MAX_FILE_LEN,
458 "%s/sa%04d%02d%02d", sa_dir,
459 rectime.tm_year + 1900,
464 /* Using saDD data files */
465 snprintf(datafile, MAX_FILE_LEN,
469 datafile[MAX_FILE_LEN - 1] = '\0';
470 default_file_used = TRUE;
474 ***************************************************************************
475 * Check data file type. If it is a directory then this is the alternate
476 * location where daily data files will be saved.
479 * @datafile Name of the daily data file. May be a directory.
480 * @d_off Day offset (number of days to go back in the past).
481 * @sa_name 0 for saDD data files,
482 * 1 for saYYYYMMDD data files,
483 * -1 if unknown. In this case, will look for the most recent
484 * of saDD and saYYYYMMDD and use it.
488 * @datafile Name of the daily data file. This is now a plain file, not
492 * 1 if @datafile was a directory, and 0 otherwise.
493 ***************************************************************************
495 int check_alt_sa_dir(char *datafile, int d_off, int sa_name)
499 if (stat(datafile, &sb) == 0) {
500 if (S_ISDIR(sb.st_mode)) {
502 * This is a directory: So append
503 * the default file name to it.
505 set_default_file(datafile, d_off, sa_name);
514 ***************************************************************************
515 * Set interval value.
518 * @record_hdr_curr Record with current sample statistics.
519 * @record_hdr_prev Record with previous sample statistics.
520 * @nr_proc Number of CPU, including CPU "all".
523 * @itv Interval in jiffies.
524 * @g_itv Interval in jiffies multiplied by the # of proc.
525 ***************************************************************************
527 void get_itv_value(struct record_header *record_hdr_curr,
528 struct record_header *record_hdr_prev,
529 unsigned int nr_proc,
530 unsigned long long *itv, unsigned long long *g_itv)
532 /* Interval value in jiffies */
533 *g_itv = get_interval(record_hdr_prev->uptime,
534 record_hdr_curr->uptime);
537 *itv = get_interval(record_hdr_prev->uptime0,
538 record_hdr_curr->uptime0);
546 ***************************************************************************
547 * Fill the rectime structure with the file's creation date, based on file's
548 * time data saved in file header.
549 * The resulting timestamp is expressed in the locale of the file creator or
550 * in the user's own locale, depending on whether option -t has been used
554 * @flags Flags for common options and system state.
555 * @file_hdr System activity file standard header.
558 * @rectime Date (and possibly time) from file header. Only the date,
559 * not the time, should be used by the caller.
560 ***************************************************************************
562 void get_file_timestamp_struct(unsigned int flags, struct tm *rectime,
563 struct file_header *file_hdr)
567 if (PRINT_TRUE_TIME(flags)) {
568 /* Get local time. This is just to fill fields with a default value. */
569 get_time(rectime, 0);
571 rectime->tm_mday = file_hdr->sa_day;
572 rectime->tm_mon = file_hdr->sa_month;
573 rectime->tm_year = file_hdr->sa_year;
575 * Call mktime() to set DST (Daylight Saving Time) flag.
576 * Has anyone a better way to do it?
578 rectime->tm_hour = rectime->tm_min = rectime->tm_sec = 0;
582 if ((loc_t = localtime((const time_t *) &file_hdr->sa_ust_time)) != NULL) {
589 ***************************************************************************
590 * Print report header.
593 * @flags Flags for common options and system state.
594 * @file_hdr System activity file standard header.
595 * @cpu_nr Number of CPU (value in [1, NR_CPUS + 1]).
596 * 1 means that there is only one proc and non SMP kernel.
597 * 2 means one proc and SMP kernel.
601 * @rectime Date and time from file header.
602 ***************************************************************************
604 void print_report_hdr(unsigned int flags, struct tm *rectime,
605 struct file_header *file_hdr, int cpu_nr)
608 /* Get date of file creation */
609 get_file_timestamp_struct(flags, rectime, file_hdr);
611 /* Display the header */
612 print_gal_header(rectime, file_hdr->sa_sysname, file_hdr->sa_release,
613 file_hdr->sa_nodename, file_hdr->sa_machine,
614 cpu_nr > 1 ? cpu_nr - 1 : 1);
618 ***************************************************************************
619 * Network interfaces may now be registered (and unregistered) dynamically.
620 * This is what we try to guess here.
623 * @a Activity structure with statistics.
624 * @curr Index in array for current sample statistics.
625 * @ref Index in array for sample statistics used as reference.
626 * @pos Index on current network interface.
629 * Position of current network interface in array of sample statistics used
631 ***************************************************************************
633 unsigned int check_net_dev_reg(struct activity *a, int curr, int ref,
636 struct stats_net_dev *sndc, *sndp;
637 unsigned int index = 0;
639 sndc = (struct stats_net_dev *) ((char *) a->buf[curr] + pos * a->msize);
641 while (index < a->nr) {
642 sndp = (struct stats_net_dev *) ((char *) a->buf[ref] + index * a->msize);
643 if (!strcmp(sndc->interface, sndp->interface)) {
645 * Network interface found.
646 * If a counter has decreased, then we may assume that the
647 * corresponding interface was unregistered, then registered again.
649 if ((sndc->rx_packets < sndp->rx_packets) ||
650 (sndc->tx_packets < sndp->tx_packets) ||
651 (sndc->rx_bytes < sndp->rx_bytes) ||
652 (sndc->tx_bytes < sndp->tx_bytes) ||
653 (sndc->rx_compressed < sndp->rx_compressed) ||
654 (sndc->tx_compressed < sndp->tx_compressed) ||
655 (sndc->multicast < sndp->multicast)) {
658 * Special processing for rx_bytes (_packets) and
659 * tx_bytes (_packets) counters: If the number of
660 * bytes (packets) has decreased, whereas the number of
661 * packets (bytes) has increased, then assume that the
662 * relevant counter has met an overflow condition, and that
663 * the interface was not unregistered, which is all the
664 * more plausible that the previous value for the counter
666 * NB: the average value displayed will be wrong in this case...
668 * If such an overflow is detected, just set the flag. There is no
669 * need to handle this in a special way: the difference is still
670 * properly calculated if the result is of the same type (i.e.
671 * unsigned long) as the two values.
675 if ((sndc->rx_bytes < sndp->rx_bytes) &&
676 (sndc->rx_packets > sndp->rx_packets) &&
677 (sndp->rx_bytes > (~0UL >> 1))) {
680 if ((sndc->tx_bytes < sndp->tx_bytes) &&
681 (sndc->tx_packets > sndp->tx_packets) &&
682 (sndp->tx_bytes > (~0UL >> 1))) {
685 if ((sndc->rx_packets < sndp->rx_packets) &&
686 (sndc->rx_bytes > sndp->rx_bytes) &&
687 (sndp->rx_packets > (~0UL >> 1))) {
690 if ((sndc->tx_packets < sndp->tx_packets) &&
691 (sndc->tx_bytes > sndp->tx_bytes) &&
692 (sndp->tx_packets > (~0UL >> 1))) {
698 * OK: assume here that the device was
699 * actually unregistered.
701 memset(sndp, 0, STATS_NET_DEV_SIZE);
702 strcpy(sndp->interface, sndc->interface);
710 /* Network interface not found: Look for the first free structure */
711 for (index = 0; index < a->nr; index++) {
712 sndp = (struct stats_net_dev *) ((char *) a->buf[ref] + index * a->msize);
713 if (!strcmp(sndp->interface, ""))
716 if (index >= a->nr) {
717 /* No free structure: Default is structure of same rank */
721 sndp = (struct stats_net_dev *) ((char *) a->buf[ref] + index * a->msize);
722 /* Since the name is not the same, reset all the structure */
723 memset(sndp, 0, STATS_NET_DEV_SIZE);
724 strcpy(sndp->interface, sndc->interface);
730 ***************************************************************************
731 * Network interfaces may now be registered (and unregistered) dynamically.
732 * This is what we try to guess here.
735 * @a Activity structure with statistics.
736 * @curr Index in array for current sample statistics.
737 * @ref Index in array for sample statistics used as reference.
738 * @pos Index on current network interface.
741 * Position of current network interface in array of sample statistics used
743 ***************************************************************************
745 unsigned int check_net_edev_reg(struct activity *a, int curr, int ref,
748 struct stats_net_edev *snedc, *snedp;
749 unsigned int index = 0;
751 snedc = (struct stats_net_edev *) ((char *) a->buf[curr] + pos * a->msize);
753 while (index < a->nr) {
754 snedp = (struct stats_net_edev *) ((char *) a->buf[ref] + index * a->msize);
755 if (!strcmp(snedc->interface, snedp->interface)) {
757 * Network interface found.
758 * If a counter has decreased, then we may assume that the
759 * corresponding interface was unregistered, then registered again.
761 if ((snedc->tx_errors < snedp->tx_errors) ||
762 (snedc->collisions < snedp->collisions) ||
763 (snedc->rx_dropped < snedp->rx_dropped) ||
764 (snedc->tx_dropped < snedp->tx_dropped) ||
765 (snedc->tx_carrier_errors < snedp->tx_carrier_errors) ||
766 (snedc->rx_frame_errors < snedp->rx_frame_errors) ||
767 (snedc->rx_fifo_errors < snedp->rx_fifo_errors) ||
768 (snedc->tx_fifo_errors < snedp->tx_fifo_errors)) {
771 * OK: assume here that the device was
772 * actually unregistered.
774 memset(snedp, 0, STATS_NET_EDEV_SIZE);
775 strcpy(snedp->interface, snedc->interface);
782 /* Network interface not found: Look for the first free structure */
783 for (index = 0; index < a->nr; index++) {
784 snedp = (struct stats_net_edev *) ((char *) a->buf[ref] + index * a->msize);
785 if (!strcmp(snedp->interface, ""))
788 if (index >= a->nr) {
789 /* No free structure: Default is structure of same rank */
793 snedp = (struct stats_net_edev *) ((char *) a->buf[ref] + index * a->msize);
794 /* Since the name is not the same, reset all the structure */
795 memset(snedp, 0, STATS_NET_EDEV_SIZE);
796 strcpy(snedp->interface, snedc->interface);
802 ***************************************************************************
803 * Disks may be registered dynamically (true in /proc/stat file).
804 * This is what we try to guess here.
807 * @a Activity structure with statistics.
808 * @curr Index in array for current sample statistics.
809 * @ref Index in array for sample statistics used as reference.
810 * @pos Index on current disk.
813 * Position of current disk in array of sample statistics used as reference.
814 ***************************************************************************
816 int check_disk_reg(struct activity *a, int curr, int ref, int pos)
818 struct stats_disk *sdc, *sdp;
821 sdc = (struct stats_disk *) ((char *) a->buf[curr] + pos * a->msize);
823 while (index < a->nr) {
824 sdp = (struct stats_disk *) ((char *) a->buf[ref] + index * a->msize);
825 if ((sdc->major == sdp->major) &&
826 (sdc->minor == sdp->minor)) {
829 * If all the counters have decreased then the likelyhood
830 * is that the disk has been unregistered and a new disk inserted.
831 * If only one or two have decreased then the likelyhood
832 * is that the counter has simply wrapped.
834 if ((sdc->nr_ios < sdp->nr_ios) &&
835 (sdc->rd_sect < sdp->rd_sect) &&
836 (sdc->wr_sect < sdp->wr_sect)) {
838 memset(sdp, 0, STATS_DISK_SIZE);
839 sdp->major = sdc->major;
840 sdp->minor = sdc->minor;
847 /* Disk not found: Look for the first free structure */
848 for (index = 0; index < a->nr; index++) {
849 sdp = (struct stats_disk *) ((char *) a->buf[ref] + index * a->msize);
850 if (!(sdp->major + sdp->minor))
853 if (index >= a->nr) {
854 /* No free structure found: Default is structure of same rank */
858 sdp = (struct stats_disk *) ((char *) a->buf[ref] + index * a->msize);
859 /* Since the device is not the same, reset all the structure */
860 memset(sdp, 0, STATS_DISK_SIZE);
861 sdp->major = sdc->major;
862 sdp->minor = sdc->minor;
868 ***************************************************************************
869 * Allocate bitmaps for activities that have one.
872 * @act Array of activities.
873 ***************************************************************************
875 void allocate_bitmaps(struct activity *act[])
879 for (i = 0; i < NR_ACT; i++) {
881 * If current activity has a bitmap which has not already
882 * been allocated, then allocate it.
883 * Note that a same bitmap may be used by several activities.
885 if (act[i]->bitmap && !act[i]->bitmap->b_array) {
886 SREALLOC(act[i]->bitmap->b_array, unsigned char,
887 BITMAP_SIZE(act[i]->bitmap->b_size));
893 ***************************************************************************
894 * Free bitmaps for activities that have one.
897 * @act Array of activities.
898 ***************************************************************************
900 void free_bitmaps(struct activity *act[])
904 for (i = 0; i < NR_ACT; i++) {
905 if (act[i]->bitmap && act[i]->bitmap->b_array) {
906 free(act[i]->bitmap->b_array);
907 /* Set pointer to NULL to prevent it from being freed again */
908 act[i]->bitmap->b_array = NULL;
914 ***************************************************************************
915 * Look for activity in array.
918 * @act Array of activities.
919 * @act_flag Activity flag to look for.
920 * @stop TRUE if sysstat should exit when activity is not found.
923 * Position of activity in array, or -1 if not found (this may happen when
924 * reading data from a system activity file created by another version of
926 ***************************************************************************
928 int get_activity_position(struct activity *act[], unsigned int act_flag, int stop)
932 for (i = 0; i < NR_ACT; i++) {
933 if (act[i]->id == act_flag)
938 PANIC((int) act_flag);
945 ***************************************************************************
946 * Count number of activities with given option.
949 * @act Array of activities.
950 * @option Option that activities should have to be counted
951 * (eg. AO_COLLECTED...)
952 * @count_outputs TRUE if each output should be counted for activities with
956 * Number of selected activities
957 ***************************************************************************
959 int get_activity_nr(struct activity *act[], unsigned int option, int count_outputs)
964 for (i = 0; i < NR_ACT; i++) {
965 if ((act[i]->options & option) == option) {
967 if (HAS_MULTIPLE_OUTPUTS(act[i]->options) && count_outputs) {
968 for (msk = 1; msk < 0x100; msk <<= 1) {
969 if ((act[i]->opt_flags & 0xff) & msk) {
984 ***************************************************************************
985 * Select all activities, even if they have no associated items.
988 * @act Array of activities.
991 * @act Array of activities, all of the being selected.
992 ***************************************************************************
994 void select_all_activities(struct activity *act[])
998 for (i = 0; i < NR_ACT; i++) {
999 act[i]->options |= AO_SELECTED;
1004 ***************************************************************************
1005 * Select CPU activity if no other activities have been explicitly selected.
1006 * Also select CPU "all" if no other CPU has been selected.
1009 * @act Array of activities.
1012 * @act Array of activities with CPU activity selected if needed.
1013 ***************************************************************************
1015 void select_default_activity(struct activity *act[])
1019 p = get_activity_position(act, A_CPU, EXIT_IF_NOT_FOUND);
1021 /* Default is CPU activity... */
1022 if (!get_activity_nr(act, AO_SELECTED, COUNT_ACTIVITIES)) {
1024 * Still OK even when reading stats from a file
1025 * since A_CPU activity is always recorded.
1027 act[p]->options |= AO_SELECTED;
1031 * If no CPU's have been selected then select CPU "all".
1032 * cpu_bitmap bitmap may be used by several activities (A_CPU, A_PWR_CPUFREQ...)
1034 if (!count_bits(cpu_bitmap.b_array, BITMAP_SIZE(cpu_bitmap.b_size))) {
1035 cpu_bitmap.b_array[0] |= 0x01;
1040 ***************************************************************************
1041 * Read data from a system activity data file.
1044 * @ifd Input file descriptor.
1045 * @buffer Buffer where data are read.
1046 * @size Number of bytes to read.
1047 * @mode If set to HARD_SIZE, indicate that an EOF should be considered
1051 * 1 if EOF has been reached, 0 otherwise.
1052 ***************************************************************************
1054 int sa_fread(int ifd, void *buffer, int size, int mode)
1058 if ((n = read(ifd, buffer, size)) < 0) {
1059 fprintf(stderr, _("Error while reading system activity file: %s\n"),
1065 if (!n && (mode == SOFT_SIZE))
1069 fprintf(stderr, _("End of system activity file unexpected\n"));
1078 ***************************************************************************
1079 * Display sysstat version used to create system activity data file.
1082 * @st Output stream (stderr or stdout).
1083 * @file_magic File magic header.
1084 ***************************************************************************
1086 void display_sa_file_version(FILE *st, struct file_magic *file_magic)
1088 fprintf(st, _("File created by sar/sadc from sysstat version %d.%d.%d"),
1089 file_magic->sysstat_version,
1090 file_magic->sysstat_patchlevel,
1091 file_magic->sysstat_sublevel);
1093 if (file_magic->sysstat_extraversion) {
1094 fprintf(st, ".%d", file_magic->sysstat_extraversion);
1100 ***************************************************************************
1101 * An invalid system activity file has been opened for reading.
1102 * If this file was created by an old version of sysstat, tell it to the
1106 * @fd Descriptor of the file that has been opened.
1107 * @file_magic file_magic structure filled with file magic header data.
1108 * May contain invalid data.
1109 * @file Name of the file being read.
1110 * @n Number of bytes read while reading file magic header.
1111 * This function may also be called after failing to read file
1112 * standard header, or if CPU activity has not been found in
1113 * file. In this case, n is set to 0.
1114 ***************************************************************************
1116 void handle_invalid_sa_file(int *fd, struct file_magic *file_magic, char *file,
1121 fprintf(stderr, _("Invalid system activity file: %s\n"), file);
1123 if (n == FILE_MAGIC_SIZE) {
1124 sm = (file_magic->sysstat_magic << 8) | (file_magic->sysstat_magic >> 8);
1125 if ((file_magic->sysstat_magic == SYSSTAT_MAGIC) || (sm == SYSSTAT_MAGIC)) {
1127 * This is a sysstat file, but this file has an old format
1128 * or its internal endian format doesn't match.
1130 display_sa_file_version(stderr, file_magic);
1132 if (sm == SYSSTAT_MAGIC) {
1133 fprintf(stderr, _("Endian format mismatch\n"));
1137 _("Current sysstat version cannot read the format of this file (%#x)\n"),
1138 file_magic->format_magic);
1148 ***************************************************************************
1149 * Move structures data.
1152 * @act Array of activities.
1153 * @id_seq Activity sequence in file.
1154 * @record_hdr Current record header.
1155 * @dest Index in array where stats have to be copied to.
1156 * @src Index in array where stats to copy are.
1157 ***************************************************************************
1159 void copy_structures(struct activity *act[], unsigned int id_seq[],
1160 struct record_header record_hdr[], int dest, int src)
1164 memcpy(&record_hdr[dest], &record_hdr[src], RECORD_HEADER_SIZE);
1166 for (i = 0; i < NR_ACT; i++) {
1171 p = get_activity_position(act, id_seq[i], EXIT_IF_NOT_FOUND);
1172 if ((act[p]->nr < 1) || (act[p]->nr2 < 1)) {
1176 memcpy(act[p]->buf[dest], act[p]->buf[src],
1177 (size_t) act[p]->msize * (size_t) act[p]->nr * (size_t) act[p]->nr2);
1182 ***************************************************************************
1183 * Read varying part of the statistics from a daily data file.
1186 * @act Array of activities.
1187 * @curr Index in array for current sample statistics.
1188 * @ifd Input file descriptor.
1189 * @act_nr Number of activities in file.
1190 * @file_actlst Activity list in file.
1191 ***************************************************************************
1193 void read_file_stat_bunch(struct activity *act[], int curr, int ifd, int act_nr,
1194 struct file_activity *file_actlst)
1197 struct file_activity *fal = file_actlst;
1200 for (i = 0; i < act_nr; i++, fal++) {
1202 if (((p = get_activity_position(act, fal->id, RESUME_IF_NOT_FOUND)) < 0) ||
1203 (act[p]->magic != fal->magic)) {
1205 * Ignore current activity in file, which is unknown to
1206 * current sysstat version or has an unknown format.
1208 offset = (off_t) fal->size * (off_t) fal->nr * (off_t) fal->nr2;
1209 if (lseek(ifd, offset, SEEK_CUR) < offset) {
1215 else if ((act[p]->nr > 0) &&
1216 ((act[p]->nr > 1) || (act[p]->nr2 > 1)) &&
1217 (act[p]->msize > act[p]->fsize)) {
1218 for (j = 0; j < act[p]->nr; j++) {
1219 for (k = 0; k < act[p]->nr2; k++) {
1221 (char *) act[p]->buf[curr] + (j * act[p]->nr2 + k) * act[p]->msize,
1222 act[p]->fsize, HARD_SIZE);
1226 else if (act[p]->nr > 0) {
1227 sa_fread(ifd, act[p]->buf[curr], act[p]->fsize * act[p]->nr * act[p]->nr2, HARD_SIZE);
1236 ***************************************************************************
1237 * Open a sysstat activity data file and read its magic structure.
1240 * @dfile Name of system activity data file.
1241 * @ignore Set to 1 if a true sysstat activity file but with a bad
1242 * format should not yield an error message. Useful with
1243 * sadf -H and sadf -c.
1246 * @fd System activity data file descriptor.
1247 * @file_magic file_magic structure containing data read from file magic
1251 * -1 if data file is a sysstat file with an old format, 0 otherwise.
1252 ***************************************************************************
1254 int sa_open_read_magic(int *fd, char *dfile, struct file_magic *file_magic,
1259 /* Open sa data file */
1260 if ((*fd = open(dfile, O_RDONLY)) < 0) {
1261 int saved_errno = errno;
1263 fprintf(stderr, _("Cannot open %s: %s\n"), dfile, strerror(errno));
1265 if ((saved_errno == ENOENT) && default_file_used) {
1266 fprintf(stderr, _("Please check if data collecting is enabled\n"));
1271 /* Read file magic data */
1272 n = read(*fd, file_magic, FILE_MAGIC_SIZE);
1274 if ((n != FILE_MAGIC_SIZE) ||
1275 (file_magic->sysstat_magic != SYSSTAT_MAGIC) ||
1276 ((file_magic->format_magic != FORMAT_MAGIC) && !ignore) ||
1277 (file_magic->header_size < MIN_FILE_HEADER_SIZE) ||
1278 (file_magic->header_size > MAX_FILE_HEADER_SIZE) ||
1279 ((file_magic->header_size < FILE_HEADER_SIZE) && !ignore)) {
1280 /* Display error message and exit */
1281 handle_invalid_sa_file(fd, file_magic, dfile, n);
1283 if (file_magic->format_magic != FORMAT_MAGIC)
1284 /* This is an old sa datafile format */
1291 ***************************************************************************
1292 * Open a data file, and perform various checks before reading.
1295 * @dfile Name of system activity data file.
1296 * @act Array of activities.
1297 * @ignore Set to 1 if a true sysstat activity file but with a bad
1298 * format should not yield an error message. Useful with
1299 * sadf -H and sadf -c.
1302 * @ifd System activity data file descriptor.
1303 * @file_magic file_magic structure containing data read from file magic
1305 * @file_hdr file_hdr structure containing data read from file standard
1307 * @file_actlst Acvtivity list in file.
1308 * @id_seq Activity sequence.
1309 ***************************************************************************
1311 void check_file_actlst(int *ifd, char *dfile, struct activity *act[],
1312 struct file_magic *file_magic, struct file_header *file_hdr,
1313 struct file_activity **file_actlst, unsigned int id_seq[],
1317 unsigned int a_cpu = FALSE;
1318 struct file_activity *fal;
1319 void *buffer = NULL;
1321 /* Open sa data file and read its magic structure */
1322 if (sa_open_read_magic(ifd, dfile, file_magic, ignore) < 0)
1325 SREALLOC(buffer, char, file_magic->header_size);
1327 /* Read sa data file standard header and allocate activity list */
1328 sa_fread(*ifd, buffer, file_magic->header_size, HARD_SIZE);
1330 * Data file header size may be greater than FILE_HEADER_SIZE, but
1331 * anyway only the first FILE_HEADER_SIZE bytes can be interpreted.
1333 memcpy(file_hdr, buffer, FILE_HEADER_SIZE);
1338 * Compare against MAX_NR_ACT and not NR_ACT because
1339 * we are maybe reading a datafile from a future sysstat version
1340 * with more activities than known today.
1342 if (file_hdr->sa_act_nr > MAX_NR_ACT) {
1343 /* Maybe a "false positive" sysstat datafile? */
1344 handle_invalid_sa_file(ifd, file_magic, dfile, 0);
1347 SREALLOC(*file_actlst, struct file_activity, FILE_ACTIVITY_SIZE * file_hdr->sa_act_nr);
1350 /* Read activity list */
1352 for (i = 0; i < file_hdr->sa_act_nr; i++, fal++) {
1354 sa_fread(*ifd, fal, FILE_ACTIVITY_SIZE, HARD_SIZE);
1357 * Every activity, known or unknown, should have
1358 * at least one item and sub-item.
1359 * Also check that the number of items and sub-items
1360 * doesn't exceed a max value. This is necessary
1361 * because we will use @nr and @nr2 to
1362 * allocate memory to read the file contents. So we
1363 * must make sure the file is not corrupted.
1364 * NB: Another check will be made below for known
1365 * activities which have each a specific max value.
1367 if ((fal->nr < 1) || (fal->nr2 < 1) ||
1368 (fal->nr > NR_MAX) || (fal->nr2 > NR2_MAX)) {
1369 handle_invalid_sa_file(ifd, file_magic, dfile, 0);
1372 if ((p = get_activity_position(act, fal->id, RESUME_IF_NOT_FOUND)) < 0)
1373 /* Unknown activity */
1376 if (act[p]->magic != fal->magic) {
1377 /* Bad magical number */
1380 * This is how sadf -H knows that this
1381 * activity has an unknown format.
1383 act[p]->magic = ACTIVITY_MAGIC_UNKNOWN;
1389 /* Check max value for known activities */
1390 if (fal->nr > act[p]->nr_max) {
1391 handle_invalid_sa_file(ifd, file_magic, dfile, 0);
1394 if (fal->id == A_CPU) {
1398 if (fal->size > act[p]->msize) {
1399 act[p]->msize = fal->size;
1403 * If current activity is a volatile one then fal->nr is the
1404 * number of items (CPU at the present time as only CPU related
1405 * activities are volatile today) for the statistics located
1406 * between the start of the data file and the first restart mark.
1407 * Volatile activities have a number of items which can vary
1408 * in file. In this case, a RESTART record is followed by the
1409 * volatile activity structures.
1411 act[p]->nr = fal->nr;
1412 act[p]->nr2 = fal->nr2;
1413 act[p]->fsize = fal->size;
1415 * This is a known activity with a known format
1416 * (magical number). Only such activities will be displayed.
1417 * (Well, this may also be an unknown format if we have entered sadf -H.)
1419 id_seq[j++] = fal->id;
1424 * CPU activity should always be in file
1425 * and have a known format (expected magical number).
1427 handle_invalid_sa_file(ifd, file_magic, dfile, 0);
1430 while (j < NR_ACT) {
1434 /* Check that at least one selected activity is available in file */
1435 for (i = 0; i < NR_ACT; i++) {
1437 if (!IS_SELECTED(act[i]->options))
1440 /* Here is a selected activity: Does it exist in file? */
1442 for (j = 0; j < file_hdr->sa_act_nr; j++, fal++) {
1443 if (act[i]->id == fal->id)
1446 if (j == file_hdr->sa_act_nr) {
1447 /* No: Unselect it */
1448 act[i]->options &= ~AO_SELECTED;
1451 if (!get_activity_nr(act, AO_SELECTED, COUNT_ACTIVITIES)) {
1452 fprintf(stderr, _("Requested activities not available in file %s\n"),
1460 ***************************************************************************
1461 * Set number of items for current volatile activity and reallocate its
1462 * structures accordingly.
1463 * NB: As only activities related to CPU can be volatile, the number of
1464 * items corresponds in fact to the number of CPU.
1467 * @act Array of activities.
1468 * @act_nr Number of items for current volatile activity.
1469 * @act_id Activity identification for current volatile activity.
1472 * -1 if unknown activity and 0 otherwise.
1473 ***************************************************************************
1475 int reallocate_vol_act_structures(struct activity *act[], unsigned int act_nr,
1476 unsigned int act_id)
1480 if ((p = get_activity_position(act, act_id, RESUME_IF_NOT_FOUND)) < 0)
1481 /* Ignore unknown activity */
1484 act[p]->nr = act_nr;
1486 for (j = 0; j < 3; j++) {
1487 SREALLOC(act[p]->buf[j], void,
1488 (size_t) act[p]->msize * (size_t) act[p]->nr * (size_t) act[p]->nr2);
1495 ***************************************************************************
1496 * Read the volatile activities structures following a RESTART record.
1497 * Then set number of items for each corresponding activity and reallocate
1501 * @ifd Input file descriptor.
1502 * @act Array of activities.
1503 * @file Name of file being read.
1504 * @file_magic file_magic structure filled with file magic header data.
1505 * @vol_act_nr Number of volatile activities structures to read.
1508 * New number of items.
1510 * NB: As only activities related to CPU can be volatile, the new number of
1511 * items corresponds in fact to the new number of CPU.
1512 ***************************************************************************
1514 __nr_t read_vol_act_structures(int ifd, struct activity *act[], char *file,
1515 struct file_magic *file_magic,
1516 unsigned int vol_act_nr)
1518 struct file_activity file_act;
1522 for (i = 0; i < vol_act_nr; i++) {
1524 sa_fread(ifd, &file_act, FILE_ACTIVITY_SIZE, HARD_SIZE);
1527 rc = reallocate_vol_act_structures(act, file_act.nr, file_act.id);
1528 if ((rc == 0) && !item_nr) {
1529 item_nr = file_act.nr;
1532 /* else ignore empty structures that may exist */
1536 /* All volatile activities structures cannot be empty */
1537 handle_invalid_sa_file(&ifd, file_magic, file, 0);
1544 ***************************************************************************
1545 * Parse sar activities options (also used by sadf).
1548 * @argv Arguments list.
1549 * @opt Index in list of arguments.
1550 * @caller Indicate whether it's sar or sadf that called this function.
1553 * @act Array of selected activities.
1554 * @flags Common flags and system state.
1558 ***************************************************************************
1560 int parse_sar_opt(char *argv[], int *opt, struct activity *act[],
1561 unsigned int *flags, int caller)
1565 for (i = 1; *(argv[*opt] + i); i++) {
1567 * Note: argv[*opt] contains something like "-BruW"
1568 * *(argv[*opt] + i) will contain 'B', 'r', etc.
1571 switch (*(argv[*opt] + i)) {
1574 select_all_activities(act);
1576 /* Force '-P ALL -I XALL -r ALL -u ALL' */
1578 p = get_activity_position(act, A_MEMORY, EXIT_IF_NOT_FOUND);
1579 act[p]->opt_flags |= AO_F_MEM_AMT + AO_F_MEM_DIA +
1580 AO_F_MEM_SWAP + AO_F_MEM_ALL;
1582 p = get_activity_position(act, A_IRQ, EXIT_IF_NOT_FOUND);
1583 set_bitmap(act[p]->bitmap->b_array, ~0,
1584 BITMAP_SIZE(act[p]->bitmap->b_size));
1586 p = get_activity_position(act, A_CPU, EXIT_IF_NOT_FOUND);
1587 set_bitmap(act[p]->bitmap->b_array, ~0,
1588 BITMAP_SIZE(act[p]->bitmap->b_size));
1589 act[p]->opt_flags = AO_F_CPU_ALL;
1593 SELECT_ACTIVITY(A_PAGE);
1597 SELECT_ACTIVITY(A_IO);
1601 *flags |= S_F_COMMENT;
1605 SELECT_ACTIVITY(A_DISK);
1609 p = get_activity_position(act, A_FILESYSTEM, EXIT_IF_NOT_FOUND);
1610 act[p]->options |= AO_SELECTED;
1611 if (!*(argv[*opt] + i + 1) && argv[*opt + 1] && !strcmp(argv[*opt + 1], K_MOUNT)) {
1613 act[p]->opt_flags |= AO_F_MOUNT;
1619 p = get_activity_position(act, A_HUGE, EXIT_IF_NOT_FOUND);
1620 act[p]->options |= AO_SELECTED;
1624 if (argv[*opt + 1]) {
1626 if (strnlen(argv[*opt], MAX_FILE_LEN) >= MAX_FILE_LEN - 1)
1629 strncpy(persistent_name_type, argv[*opt], MAX_FILE_LEN - 1);
1630 persistent_name_type[MAX_FILE_LEN - 1] = '\0';
1631 strtolower(persistent_name_type);
1632 if (!get_persistent_type_dir(persistent_name_type)) {
1633 fprintf(stderr, _("Invalid type of persistent device name\n"));
1637 * If persistent device name doesn't exist for device, use
1640 *flags |= S_F_PERSIST_NAME + S_F_DEV_PRETTY;
1649 *flags |= S_F_DEV_PRETTY;
1653 SELECT_ACTIVITY(A_QUEUE);
1657 p = get_activity_position(act, A_MEMORY, EXIT_IF_NOT_FOUND);
1658 act[p]->options |= AO_SELECTED;
1659 act[p]->opt_flags |= AO_F_MEM_AMT;
1660 if (!*(argv[*opt] + i + 1) && argv[*opt + 1] && !strcmp(argv[*opt + 1], K_ALL)) {
1662 act[p]->opt_flags |= AO_F_MEM_ALL;
1668 p = get_activity_position(act, A_MEMORY, EXIT_IF_NOT_FOUND);
1669 act[p]->options |= AO_SELECTED;
1670 act[p]->opt_flags |= AO_F_MEM_DIA;
1674 p = get_activity_position(act, A_MEMORY, EXIT_IF_NOT_FOUND);
1675 act[p]->options |= AO_SELECTED;
1676 act[p]->opt_flags |= AO_F_MEM_SWAP;
1681 * Check sar option -t here (as it can be combined
1682 * with other ones, eg. "sar -rtu ..."
1683 * But sadf option -t is checked in sadf.c as it won't
1684 * be entered as a sar option after "--".
1686 if (caller == C_SAR) {
1687 *flags |= S_F_TRUE_TIME;
1694 p = get_activity_position(act, A_CPU, EXIT_IF_NOT_FOUND);
1695 act[p]->options |= AO_SELECTED;
1696 if (!*(argv[*opt] + i + 1) && argv[*opt + 1] && !strcmp(argv[*opt + 1], K_ALL)) {
1698 act[p]->opt_flags = AO_F_CPU_ALL;
1702 act[p]->opt_flags = AO_F_CPU_DEF;
1707 SELECT_ACTIVITY(A_KTABLES);
1711 SELECT_ACTIVITY(A_PCSW);
1715 SELECT_ACTIVITY(A_SWAP);
1719 SELECT_ACTIVITY(A_SERIAL);
1734 ***************************************************************************
1735 * Parse sar "-m" option.
1738 * @argv Arguments list.
1739 * @opt Index in list of arguments.
1742 * @act Array of selected activities.
1745 * 0 on success, 1 otherwise.
1746 ***************************************************************************
1748 int parse_sar_m_opt(char *argv[], int *opt, struct activity *act[])
1752 for (t = strtok(argv[*opt], ","); t; t = strtok(NULL, ",")) {
1753 if (!strcmp(t, K_CPU)) {
1754 SELECT_ACTIVITY(A_PWR_CPUFREQ);
1756 else if (!strcmp(t, K_FAN)) {
1757 SELECT_ACTIVITY(A_PWR_FAN);
1759 else if (!strcmp(t, K_IN)) {
1760 SELECT_ACTIVITY(A_PWR_IN);
1762 else if (!strcmp(t, K_TEMP)) {
1763 SELECT_ACTIVITY(A_PWR_TEMP);
1765 else if (!strcmp(t, K_FREQ)) {
1766 SELECT_ACTIVITY(A_PWR_WGHFREQ);
1768 else if (!strcmp(t, K_USB)) {
1769 SELECT_ACTIVITY(A_PWR_USB);
1771 else if (!strcmp(t, K_ALL)) {
1772 SELECT_ACTIVITY(A_PWR_CPUFREQ);
1773 SELECT_ACTIVITY(A_PWR_FAN);
1774 SELECT_ACTIVITY(A_PWR_IN);
1775 SELECT_ACTIVITY(A_PWR_TEMP);
1776 SELECT_ACTIVITY(A_PWR_WGHFREQ);
1777 SELECT_ACTIVITY(A_PWR_USB);
1788 ***************************************************************************
1789 * Parse sar "-n" option.
1792 * @argv Arguments list.
1793 * @opt Index in list of arguments.
1796 * @act Array of selected activities.
1799 * 0 on success, 1 otherwise.
1800 ***************************************************************************
1802 int parse_sar_n_opt(char *argv[], int *opt, struct activity *act[])
1806 for (t = strtok(argv[*opt], ","); t; t = strtok(NULL, ",")) {
1807 if (!strcmp(t, K_DEV)) {
1808 SELECT_ACTIVITY(A_NET_DEV);
1810 else if (!strcmp(t, K_EDEV)) {
1811 SELECT_ACTIVITY(A_NET_EDEV);
1813 else if (!strcmp(t, K_SOCK)) {
1814 SELECT_ACTIVITY(A_NET_SOCK);
1816 else if (!strcmp(t, K_NFS)) {
1817 SELECT_ACTIVITY(A_NET_NFS);
1819 else if (!strcmp(t, K_NFSD)) {
1820 SELECT_ACTIVITY(A_NET_NFSD);
1822 else if (!strcmp(t, K_IP)) {
1823 SELECT_ACTIVITY(A_NET_IP);
1825 else if (!strcmp(t, K_EIP)) {
1826 SELECT_ACTIVITY(A_NET_EIP);
1828 else if (!strcmp(t, K_ICMP)) {
1829 SELECT_ACTIVITY(A_NET_ICMP);
1831 else if (!strcmp(t, K_EICMP)) {
1832 SELECT_ACTIVITY(A_NET_EICMP);
1834 else if (!strcmp(t, K_TCP)) {
1835 SELECT_ACTIVITY(A_NET_TCP);
1837 else if (!strcmp(t, K_ETCP)) {
1838 SELECT_ACTIVITY(A_NET_ETCP);
1840 else if (!strcmp(t, K_UDP)) {
1841 SELECT_ACTIVITY(A_NET_UDP);
1843 else if (!strcmp(t, K_SOCK6)) {
1844 SELECT_ACTIVITY(A_NET_SOCK6);
1846 else if (!strcmp(t, K_IP6)) {
1847 SELECT_ACTIVITY(A_NET_IP6);
1849 else if (!strcmp(t, K_EIP6)) {
1850 SELECT_ACTIVITY(A_NET_EIP6);
1852 else if (!strcmp(t, K_ICMP6)) {
1853 SELECT_ACTIVITY(A_NET_ICMP6);
1855 else if (!strcmp(t, K_EICMP6)) {
1856 SELECT_ACTIVITY(A_NET_EICMP6);
1858 else if (!strcmp(t, K_UDP6)) {
1859 SELECT_ACTIVITY(A_NET_UDP6);
1861 else if (!strcmp(t, K_FC)) {
1862 SELECT_ACTIVITY(A_NET_FC);
1864 else if (!strcmp(t, K_ALL)) {
1865 SELECT_ACTIVITY(A_NET_DEV);
1866 SELECT_ACTIVITY(A_NET_EDEV);
1867 SELECT_ACTIVITY(A_NET_SOCK);
1868 SELECT_ACTIVITY(A_NET_NFS);
1869 SELECT_ACTIVITY(A_NET_NFSD);
1870 SELECT_ACTIVITY(A_NET_IP);
1871 SELECT_ACTIVITY(A_NET_EIP);
1872 SELECT_ACTIVITY(A_NET_ICMP);
1873 SELECT_ACTIVITY(A_NET_EICMP);
1874 SELECT_ACTIVITY(A_NET_TCP);
1875 SELECT_ACTIVITY(A_NET_ETCP);
1876 SELECT_ACTIVITY(A_NET_UDP);
1877 SELECT_ACTIVITY(A_NET_SOCK6);
1878 SELECT_ACTIVITY(A_NET_IP6);
1879 SELECT_ACTIVITY(A_NET_EIP6);
1880 SELECT_ACTIVITY(A_NET_ICMP6);
1881 SELECT_ACTIVITY(A_NET_EICMP6);
1882 SELECT_ACTIVITY(A_NET_UDP6);
1883 SELECT_ACTIVITY(A_NET_FC);
1894 ***************************************************************************
1895 * Parse sar "-I" option.
1898 * @argv Arguments list.
1899 * @opt Index in list of arguments.
1900 * @act Array of activities.
1903 * @act Array of activities, with interrupts activity selected.
1906 * 0 on success, 1 otherwise.
1907 ***************************************************************************
1909 int parse_sar_I_opt(char *argv[], int *opt, struct activity *act[])
1915 /* Select interrupt activity */
1916 p = get_activity_position(act, A_IRQ, EXIT_IF_NOT_FOUND);
1917 act[p]->options |= AO_SELECTED;
1919 for (t = strtok(argv[*opt], ","); t; t = strtok(NULL, ",")) {
1920 if (!strcmp(t, K_SUM)) {
1921 /* Select total number of interrupts */
1922 act[p]->bitmap->b_array[0] |= 0x01;
1924 else if (!strcmp(t, K_ALL)) {
1925 /* Set bit for the first 16 individual interrupts */
1926 act[p]->bitmap->b_array[0] |= 0xfe;
1927 act[p]->bitmap->b_array[1] |= 0xff;
1928 act[p]->bitmap->b_array[2] |= 0x01;
1930 else if (!strcmp(t, K_XALL)) {
1931 /* Set every bit except for total number of interrupts */
1932 c = act[p]->bitmap->b_array[0];
1933 set_bitmap(act[p]->bitmap->b_array, ~0,
1934 BITMAP_SIZE(act[p]->bitmap->b_size));
1935 act[p]->bitmap->b_array[0] = 0xfe | c;
1938 /* Get irq number */
1939 if (strspn(t, DIGITS) != strlen(t))
1942 if ((i < 0) || (i >= act[p]->bitmap->b_size))
1944 act[p]->bitmap->b_array[(i + 1) >> 3] |= 1 << ((i + 1) & 0x07);
1953 ***************************************************************************
1954 * Parse sar and sadf "-P" option.
1957 * @argv Arguments list.
1958 * @opt Index in list of arguments.
1959 * @act Array of activities.
1962 * @flags Common flags and system state.
1963 * @act Array of activities, with CPUs selected.
1966 * 0 on success, 1 otherwise.
1967 ***************************************************************************
1969 int parse_sa_P_opt(char *argv[], int *opt, unsigned int *flags, struct activity *act[])
1974 p = get_activity_position(act, A_CPU, EXIT_IF_NOT_FOUND);
1976 if (argv[++(*opt)]) {
1978 for (t = strtok(argv[*opt], ","); t; t = strtok(NULL, ",")) {
1979 if (!strcmp(t, K_ALL)) {
1981 * Set bit for every processor.
1982 * We still don't know if we are going to read stats
1983 * from a file or not...
1985 set_bitmap(act[p]->bitmap->b_array, ~0,
1986 BITMAP_SIZE(act[p]->bitmap->b_size));
1989 /* Get cpu number */
1990 if (strspn(t, DIGITS) != strlen(t))
1993 if ((i < 0) || (i >= act[p]->bitmap->b_size))
1995 act[p]->bitmap->b_array[(i + 1) >> 3] |= 1 << ((i + 1) & 0x07);
2007 ***************************************************************************
2008 * Compute network interface utilization.
2011 * @st_net_dev Structure with network interface stats.
2012 * @rx Number of bytes received per second.
2013 * @tx Number of bytes transmitted per second.
2016 * NIC utilization (0-100%).
2017 ***************************************************************************
2019 double compute_ifutil(struct stats_net_dev *st_net_dev, double rx, double tx)
2021 unsigned long long speed;
2023 if (st_net_dev->speed) {
2025 speed = (unsigned long long) st_net_dev->speed * 1000000;
2027 if (st_net_dev->duplex == C_DUPLEX_FULL) {
2030 return (rx * 800 / speed);
2033 return (tx * 800 / speed);
2038 return ((rx + tx) * 800 / speed);
2046 ***************************************************************************
2047 * Fill system activity file magic header.
2050 * @file_magic System activity file magic header.
2051 ***************************************************************************
2053 void enum_version_nr(struct file_magic *fm)
2058 fm->sysstat_extraversion = 0;
2060 strcpy(version, VERSION);
2062 /* Get version number */
2063 if ((v = strtok(version, ".")) == NULL)
2065 fm->sysstat_version = atoi(v) & 0xff;
2067 /* Get patchlevel number */
2068 if ((v = strtok(NULL, ".")) == NULL)
2070 fm->sysstat_patchlevel = atoi(v) & 0xff;
2072 /* Get sublevel number */
2073 if ((v = strtok(NULL, ".")) == NULL)
2075 fm->sysstat_sublevel = atoi(v) & 0xff;
2077 /* Get extraversion number. Don't necessarily exist */
2078 if ((v = strtok(NULL, ".")) == NULL)
2080 fm->sysstat_extraversion = atoi(v) & 0xff;
2084 ***************************************************************************
2085 * Read and replace unprintable characters in comment with ".".
2088 * @ifd Input file descriptor.
2090 ***************************************************************************
2092 void replace_nonprintable_char(int ifd, char *comment)
2097 sa_fread(ifd, comment, MAX_COMMENT_LEN, HARD_SIZE);
2098 comment[MAX_COMMENT_LEN - 1] = '\0';
2100 /* Replace non printable chars */
2101 for (i = 0; i < strlen(comment); i++) {
2102 if (!isprint(comment[i]))
2108 ***************************************************************************
2109 * Fill the rectime and loctime structures with current record's date and
2110 * time, based on current record's "number of seconds since the epoch" saved
2112 * For loctime (if given): The timestamp is expressed in local time.
2113 * For rectime: The timestamp is expressed in UTC, in local time, or in the
2114 * time of the file's creator depending on options entered by the user on the
2118 * @l_flags Flags indicating the type of time expected by the user.
2119 * S_F_LOCAL_TIME means time should be expressed in local time.
2120 * S_F_TRUE_TIME means time should be expressed in time of
2122 * Default is time expressed in UTC (except for sar, where it
2124 * @record_hdr Record header containing the number of seconds since the
2125 * epoch, and the HH:MM:SS of the file's creator.
2128 * @rectime Structure where timestamp for current record has been saved
2129 * (in local time or in UTC depending on options used).
2130 * @loctime If given, structure where timestamp for current record has
2131 * been saved (expressed in local time). This field will be used
2132 * for time comparison if options -s and/or -e have been used.
2135 * 1 if an error was detected, or 0 otherwise.
2136 ***************************************************************************
2138 int sa_get_record_timestamp_struct(unsigned int l_flags, struct record_header *record_hdr,
2139 struct tm *rectime, struct tm *loctime)
2141 struct tm *ltm = NULL;
2144 /* Fill localtime structure if given */
2146 if ((ltm = localtime((const time_t *) &(record_hdr->ust_time))) != NULL) {
2154 /* Fill generic rectime structure */
2155 if (PRINT_LOCAL_TIME(l_flags) && !ltm) {
2156 /* Get local time if not already done */
2157 ltm = localtime((const time_t *) &(record_hdr->ust_time));
2160 if (!PRINT_LOCAL_TIME(l_flags) && !PRINT_TRUE_TIME(l_flags)) {
2163 * (the user doesn't want local time nor time of file's creator).
2165 ltm = gmtime((const time_t *) &(record_hdr->ust_time));
2169 /* Done even in true time mode so that we have some default values */
2176 if (PRINT_TRUE_TIME(l_flags)) {
2177 /* Time of file's creator */
2178 rectime->tm_hour = record_hdr->hour;
2179 rectime->tm_min = record_hdr->minute;
2180 rectime->tm_sec = record_hdr->second;
2187 ***************************************************************************
2188 * Set current record's timestamp strings (date and time) using the time
2189 * data saved in @rectime structure. The string may be the number of seconds
2190 * since the epoch if flag S_F_SEC_EPOCH has been set.
2193 * @l_flags Flags indicating the type of time expected by the user.
2194 * S_F_SEC_EPOCH means the time should be expressed in seconds
2195 * since the epoch (01/01/1970).
2196 * @record_hdr Record header containing the number of seconds since the
2198 * @cur_date String where timestamp's date will be saved. May be NULL.
2199 * @cur_time String where timestamp's time will be saved.
2200 * @len Maximum length of timestamp strings.
2201 * @rectime Structure with current timestamp (expressed in local time or
2202 * in UTC depending on whether options -T or -t have been used
2203 * or not) that should be broken down in date and time strings.
2206 * @cur_date Timestamp's date string (if expected).
2207 * @cur_time Timestamp's time string. May contain the number of seconds
2208 * since the epoch (01-01-1970) if corresponding option has
2210 ***************************************************************************
2212 void set_record_timestamp_string(unsigned int l_flags, struct record_header *record_hdr,
2213 char *cur_date, char *cur_time, int len, struct tm *rectime)
2215 /* Set cur_time date value */
2216 if (PRINT_SEC_EPOCH(l_flags) && cur_date) {
2217 sprintf(cur_time, "%ld", record_hdr->ust_time);
2218 strcpy(cur_date, "");
2222 * If options -T or -t have been used then cur_time is
2223 * expressed in local time. Else it is expressed in UTC.
2226 strftime(cur_date, len, "%Y-%m-%d", rectime);
2228 if (USE_PREFD_TIME_OUTPUT(l_flags)) {
2229 strftime(cur_time, len, "%X", rectime);
2232 strftime(cur_time, len, "%H:%M:%S", rectime);
2238 ***************************************************************************
2239 * Print contents of a special (RESTART or COMMENT) record.
2242 * @record_hdr Current record header.
2243 * @l_flags Flags for common options.
2244 * @tm_start Structure filled when option -s has been used.
2245 * @tm_end Structure filled when option -e has been used.
2246 * @rtype Record type (R_RESTART or R_COMMENT).
2247 * @ifd Input file descriptor.
2248 * @rectime Structure where timestamp (expressed in local time or in UTC
2249 * depending on whether options -T/-t have been used or not) can
2250 * be saved for current record.
2251 * @loctime Structure where timestamp (expressed in local time) can be
2252 * saved for current record. May be NULL.
2253 * @file Name of file being read.
2254 * @tab Number of tabulations to print.
2255 * @file_magic file_magic structure filled with file magic header data.
2256 * @file_hdr System activity file standard header.
2257 * @act Array of activities.
2258 * @ofmt Pointer on report output format structure.
2261 * @rectime Structure where timestamp (expressed in local time
2262 * or in UTC) has been saved.
2263 * @loctime Structure where timestamp (expressed in local time)
2264 * has been saved (if requested).
2267 * 1 if the record has been successfully displayed, and 0 otherwise.
2268 ***************************************************************************
2270 int print_special_record(struct record_header *record_hdr, unsigned int l_flags,
2271 struct tstamp *tm_start, struct tstamp *tm_end, int rtype, int ifd,
2272 struct tm *rectime, struct tm *loctime, char *file, int tab,
2273 struct file_magic *file_magic, struct file_header *file_hdr,
2274 struct activity *act[], struct report_format *ofmt)
2276 char cur_date[32], cur_time[32];
2278 unsigned int new_cpu_nr;
2280 /* Fill timestamp structure (rectime) for current record */
2281 if (sa_get_record_timestamp_struct(l_flags, record_hdr, rectime, loctime))
2284 /* If loctime is NULL, then use rectime for comparison */
2289 /* The record must be in the interval specified by -s/-e options */
2290 if ((tm_start->use && (datecmp(loctime, tm_start) < 0)) ||
2291 (tm_end->use && (datecmp(loctime, tm_end) > 0))) {
2292 /* Will not display the special record */
2296 /* Set date and time strings to be displayed for current record */
2297 set_record_timestamp_string(l_flags, record_hdr,
2298 cur_date, cur_time, 32, rectime);
2301 if (rtype == R_RESTART) {
2302 /* Don't forget to read the volatile activities structures */
2303 new_cpu_nr = read_vol_act_structures(ifd, act, file, file_magic,
2304 file_hdr->sa_vol_act_nr);
2309 if (*ofmt->f_restart) {
2310 (*ofmt->f_restart)(&tab, F_MAIN, cur_date, cur_time,
2311 !PRINT_LOCAL_TIME(l_flags) &&
2312 !PRINT_TRUE_TIME(l_flags), file_hdr,
2316 else if (rtype == R_COMMENT) {
2317 char file_comment[MAX_COMMENT_LEN];
2319 /* Read and replace non printable chars in comment */
2320 replace_nonprintable_char(ifd, file_comment);
2322 if (!dp || !DISPLAY_COMMENT(l_flags))
2325 if (*ofmt->f_comment) {
2326 (*ofmt->f_comment)(&tab, F_MAIN, cur_date, cur_time,
2327 !PRINT_LOCAL_TIME(l_flags) &&
2328 !PRINT_TRUE_TIME(l_flags), file_comment,