diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c9bcdbe --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +SOURCES/sysstat-10.1.5.tar.bz2 diff --git a/.sysstat.metadata b/.sysstat.metadata new file mode 100644 index 0000000..3cf7ea8 --- /dev/null +++ b/.sysstat.metadata @@ -0,0 +1 @@ +637258b7881446317079a80be497a013105b2b20 SOURCES/sysstat-10.1.5.tar.bz2 diff --git a/SOURCES/0001-Added-filesystems-statistics-to-sar-part-1-Basic-def.patch b/SOURCES/0001-Added-filesystems-statistics-to-sar-part-1-Basic-def.patch new file mode 100644 index 0000000..ac89702 --- /dev/null +++ b/SOURCES/0001-Added-filesystems-statistics-to-sar-part-1-Basic-def.patch @@ -0,0 +1,452 @@ +From a0e0995fec1286374ffe260843fdb9b7b01f98fa Mon Sep 17 00:00:00 2001 +From: seb +Date: Mon, 29 Apr 2013 22:04:43 +0200 +Subject: [PATCH] Added filesystems statistics to sar (part 1): Basic + definitions and structures + +A new option (-F) has been added to sar. This option tells sar to display +filesystems statistics. +This first patch adds the corresponding structures, constants and the new +functions prototypes. +sar's help and usage messages have also been updated. + +(cherry picked from commit fe061c6377d8b4550b794f4bf7d6d0ca6d4de34b) +--- + activity.c | 34 +++++++++++++++++++++++++++++++++- + json_stats.c | 17 +++++++++++++++++ + json_stats.h | 2 ++ + pr_stats.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ + pr_stats.h | 4 ++++ + rd_stats.h | 12 ++++++++++++ + rndr_stats.c | 18 ++++++++++++++++++ + rndr_stats.h | 2 ++ + sa.h | 8 +++++++- + sa_common.c | 4 ++++ + sa_wrap.c | 43 +++++++++++++++++++++++++++++++++++++++++++ + sar.c | 3 ++- + xml_stats.c | 19 ++++++++++++++++++- + xml_stats.h | 2 ++ + 14 files changed, 217 insertions(+), 4 deletions(-) + +diff --git a/activity.c b/activity.c +index 103df7a..b1aba37 100644 +--- a/activity.c ++++ b/activity.c +@@ -1195,6 +1195,37 @@ struct activity pwr_usb_act = { + .bitmap = NULL + }; + ++/* Filesystem usage activity */ ++struct activity filesystem_act = { ++ .id = A_FILESYSTEM, ++ .options = AO_NULL, ++ .magic = ACTIVITY_MAGIC_BASE, ++ .group = G_DISK, ++#ifdef SOURCE_SADC ++ .f_count = wrap_get_filesystem_nr, ++ .f_count2 = NULL, ++ .f_read = wrap_read_filesystem, ++#endif ++#ifdef SOURCE_SAR ++ .f_print = print_filesystem_stats, ++ .f_print_avg = print_avg_filesystem_stats, ++#endif ++#ifdef SOURCE_SADF ++ .f_render = render_filesystem_stats, ++ .f_xml_print = xml_print_filesystem_stats, ++ .f_json_print = json_print_filesystem_stats, ++ .hdr_line = "Mbfsfree;Mbfsused;%fsused;%ufsused;Ifree;Iused;%Iused;FILESYSTEM", ++ .name = "A_FILESYSTEM", ++#endif ++ .nr = -1, ++ .nr2 = 1, ++ .fsize = STATS_FILESYSTEM_SIZE, ++ .msize = STATS_FILESYSTEM_SIZE, ++ .opt_flags = 0, ++ .buf = {NULL, NULL, NULL}, ++ .bitmap = NULL ++}; ++ + + /* + * Array of activities. +@@ -1239,6 +1270,7 @@ struct activity *act[NR_ACT] = { + &pwr_temp_act, + &pwr_in_act, + &pwr_wghfreq_act, +- &pwr_usb_act /* AO_CLOSE_MARKUP */ ++ &pwr_usb_act, /* AO_CLOSE_MARKUP */ + /* */ ++ &filesystem_act + }; +diff --git a/json_stats.c b/json_stats.c +index a75b422..10d88e9 100644 +--- a/json_stats.c ++++ b/json_stats.c +@@ -2085,3 +2085,20 @@ close_json_markup: + json_markup_power_management(tab, CLOSE_JSON_MARKUP); + } + } ++ ++/* ++ *************************************************************************** ++ * Display filesystems statistics in JSON. ++ * ++ * IN: ++ * @a Activity structure with statistics. ++ * @curr Index in array for current sample statistics. ++ * @tab Indentation in output. ++ * @itv Interval of time in jiffies. ++ *************************************************************************** ++ */ ++__print_funct_t json_print_filesystem_stats(struct activity *a, int curr, int tab, ++ unsigned long long itv) ++{ ++ /* FIXME */ ++} +diff --git a/json_stats.h b/json_stats.h +index 9f80445..9244931 100644 +--- a/json_stats.h ++++ b/json_stats.h +@@ -87,5 +87,7 @@ extern __print_funct_t json_print_pwr_wghfreq_stats + (struct activity *, int, int, unsigned long long); + extern __print_funct_t json_print_pwr_usb_stats + (struct activity *, int, int, unsigned long long); ++extern __print_funct_t json_print_filesystem_stats ++ (struct activity *, int, int, unsigned long long); + + #endif /* _XML_STATS_H */ +diff --git a/pr_stats.c b/pr_stats.c +index ab1b841..332b10e 100644 +--- a/pr_stats.c ++++ b/pr_stats.c +@@ -2437,3 +2437,56 @@ __print_funct_t print_avg_pwr_usb_stats(struct activity *a, int prev, int curr, + { + stub_print_pwr_usb_stats(a, 2, TRUE); + } ++ ++/* ++ *************************************************************************** ++ * Display filesystems statistics. This function is used to ++ * display instantaneous and average statistics. ++ * ++ * IN: ++ * @a Activity structure with statistics. ++ * @prev Index in array where stats used as reference are. ++ * @curr Index in array for current sample statistics. ++ * @itv Interval of time in jiffies. ++ * @dispavg TRUE if displaying average statistics. ++ *************************************************************************** ++ */ ++__print_funct_t stub_print_filesystem_stats(struct activity *a, int prev, int curr, ++ unsigned long long itv, int dispavg) ++{ ++ /* FIXME */ ++} ++ ++/* ++ *************************************************************************** ++ * Display filesystems statistics. ++ * ++ * IN: ++ * @a Activity structure with statistics. ++ * @prev Index in array where stats used as reference are. ++ * @curr Index in array for current sample statistics. ++ * @itv Interval of time in jiffies. ++ *************************************************************************** ++ */ ++__print_funct_t print_filesystem_stats(struct activity *a, int prev, int curr, ++ unsigned long long itv) ++{ ++ stub_print_filesystem_stats(a, prev, curr, itv, FALSE); ++} ++ ++/* ++ *************************************************************************** ++ * Display average filesystems statistics. ++ * ++ * IN: ++ * @a Activity structure with statistics. ++ * @prev Index in array where stats used as reference are. ++ * @curr Index in array for current sample statistics. ++ * @itv Interval of time in jiffies. ++ *************************************************************************** ++ */ ++__print_funct_t print_avg_filesystem_stats(struct activity *a, int prev, int curr, ++ unsigned long long itv) ++{ ++ stub_print_filesystem_stats(a, prev, curr, itv, TRUE); ++} +diff --git a/pr_stats.h b/pr_stats.h +index 0f54aab..52007f8 100644 +--- a/pr_stats.h ++++ b/pr_stats.h +@@ -88,6 +88,8 @@ extern __print_funct_t print_pwr_wghfreq_stats + (struct activity *, int, int, unsigned long long); + extern __print_funct_t print_pwr_usb_stats + (struct activity *, int, int, unsigned long long); ++extern __print_funct_t print_filesystem_stats ++ (struct activity *, int, int, unsigned long long); + + /* Functions used to display average statistics */ + extern __print_funct_t print_avg_memory_stats +@@ -112,5 +114,7 @@ extern __print_funct_t print_avg_huge_stats + (struct activity *, int, int, unsigned long long); + extern __print_funct_t print_avg_pwr_usb_stats + (struct activity *, int, int, unsigned long long); ++extern __print_funct_t print_avg_filesystem_stats ++ (struct activity *, int, int, unsigned long long); + + #endif /* _PR_STATS_H */ +diff --git a/rd_stats.h b/rd_stats.h +index 967f584..f941426 100644 +--- a/rd_stats.h ++++ b/rd_stats.h +@@ -56,6 +56,7 @@ + #define NET_SNMP "/proc/net/snmp" + #define NET_SNMP6 "/proc/net/snmp6" + #define CPUINFO "/proc/cpuinfo" ++#define MTAB "/etc/mtab" + + + /* +@@ -520,6 +521,17 @@ struct stats_pwr_usb { + + #define STATS_PWR_USB_SIZE (sizeof(struct stats_pwr_usb)) + ++/* Structure for filesystems statistics */ ++struct stats_filesystem { ++ unsigned long long f_blocks __attribute__ ((aligned (16))); ++ unsigned long long f_bfree __attribute__ ((aligned (16))); ++ unsigned long long f_bavail __attribute__ ((aligned (16))); ++ unsigned long long f_files __attribute__ ((aligned (16))); ++ unsigned long long f_ffree __attribute__ ((aligned (16))); ++}; ++ ++#define STATS_FILESYSTEM_SIZE (sizeof(struct stats_filesystem)) ++ + /* + *************************************************************************** + * Prototypes for functions used to read system statistics +diff --git a/rndr_stats.c b/rndr_stats.c +index 4195103..8349e9a 100644 +--- a/rndr_stats.c ++++ b/rndr_stats.c +@@ -2792,3 +2792,21 @@ __print_funct_t render_pwr_usb_stats(struct activity *a, int isdb, char *pre, + suc->product); + } + } ++ ++/* ++ *************************************************************************** ++ * Display filesystems statistics in selected format. ++ * ++ * IN: ++ * @a Activity structure with statistics. ++ * @isdb Flag, true if db printing, false if ppc printing. ++ * @pre Prefix string for output entries ++ * @curr Index in array for current sample statistics. ++ * @itv Interval of time in jiffies. ++ *************************************************************************** ++ */ ++__print_funct_t render_filesystem_stats(struct activity *a, int isdb, char *pre, ++ int curr, unsigned long long itv) ++{ ++ /* FIXME */ ++} +diff --git a/rndr_stats.h b/rndr_stats.h +index dbced25..ff6452a 100644 +--- a/rndr_stats.h ++++ b/rndr_stats.h +@@ -117,5 +117,7 @@ extern __print_funct_t render_pwr_wghfreq_stats + (struct activity *, int, char *, int, unsigned long long); + extern __print_funct_t render_pwr_usb_stats + (struct activity *, int, char *, int, unsigned long long); ++extern __print_funct_t render_filesystem_stats ++ (struct activity *, int, char *, int, unsigned long long); + + #endif /* _RNDR_STATS_H */ +diff --git a/sa.h b/sa.h +index c11dbe9..50349c8 100644 +--- a/sa.h ++++ b/sa.h +@@ -19,7 +19,7 @@ + */ + + /* Number of activities */ +-#define NR_ACT 36 ++#define NR_ACT 37 + + /* Activities */ + #define A_CPU 1 +@@ -58,6 +58,7 @@ + #define A_HUGE 34 + #define A_PWR_WGHFREQ 35 + #define A_PWR_USB 36 ++#define A_FILESYSTEM 37 + + + /* Macro used to flag an activity that should be collected */ +@@ -197,6 +198,7 @@ + #define NR_DISK_PREALLOC 3 + #define NR_FREQ_PREALLOC 0 + #define NR_USB_PREALLOC 5 ++#define NR_FILESYSTEM_PREALLOC 3 + + #define UTSNAME_LEN 65 + #define TIMESTAMP_LEN 64 +@@ -706,6 +708,8 @@ extern __nr_t + wrap_get_freq_nr(struct activity *); + extern __nr_t + wrap_get_usb_nr(struct activity *); ++extern __nr_t ++ wrap_get_filesystem_nr(struct activity *); + + /* Functions used to read activities statistics */ + extern __read_funct_t +@@ -780,6 +784,8 @@ extern __read_funct_t + wrap_read_time_in_state(struct activity *); + extern __read_funct_t + wrap_read_bus_usb_dev(struct activity *); ++extern __read_funct_t ++ wrap_read_filesystem(struct activity *); + + /* Other functions */ + extern void +diff --git a/sa_common.c b/sa_common.c +index 67c55db..3ccf24b 100644 +--- a/sa_common.c ++++ b/sa_common.c +@@ -1282,6 +1282,10 @@ int parse_sar_opt(char *argv[], int *opt, struct activity *act[], + SELECT_ACTIVITY(A_DISK); + break; + ++ case 'F': ++ SELECT_ACTIVITY(A_FILESYSTEM); ++ break; ++ + case 'H': + p = get_activity_position(act, A_HUGE); + act[p]->options |= AO_SELECTED; +diff --git a/sa_wrap.c b/sa_wrap.c +index 321b227..298f889 100644 +--- a/sa_wrap.c ++++ b/sa_wrap.c +@@ -847,6 +847,28 @@ __read_funct_t wrap_read_bus_usb_dev(struct activity *a) + return; + } + ++/* ++ *************************************************************************** ++ * Read filesystem statistics. ++ * ++ * IN: ++ * @a Activity structure. ++ * ++ * OUT: ++ * @a Activity structure with statistics. ++ *************************************************************************** ++ */ ++__read_funct_t wrap_read_filesystem(struct activity *a) ++{ ++ struct stats_filesystem *st_filesystem ++ = (struct stats_filesystem *) a->_buf0; ++ ++ /* Read filesystems from /etc/mtab */ ++ /* FIXME */ ++ ++ return; ++} ++ + /* + *************************************************************************** + * Count number of interrupts that are in /proc/stat file. +@@ -1049,3 +1071,24 @@ __nr_t wrap_get_usb_nr(struct activity *a) + + return 0; + } ++ ++/* ++ *************************************************************************** ++ * Get number of mounted filesystems from /etc/mtab. Don't take into account ++ * pseudo-filesystems. ++ * ++ * IN: ++ * @a Activity structure. ++ * ++ * RETURNS: ++ * Number of filesystems + a pre-allocation constant. ++ *************************************************************************** ++ */ ++__nr_t wrap_get_filesystem_nr(struct activity *a) ++{ ++ __nr_t n = 0; ++ ++ /* FIXME */ ++ ++ return 0; ++} +diff --git a/sar.c b/sar.c +index 8dd998b..2674810 100644 +--- a/sar.c ++++ b/sar.c +@@ -107,7 +107,7 @@ void usage(char *progname) + { + print_usage_title(stderr, progname); + fprintf(stderr, _("Options are:\n" +- "[ -A ] [ -B ] [ -b ] [ -C ] [ -d ] [ -H ] [ -h ] [ -p ] [ -q ] [ -R ]\n" ++ "[ -A ] [ -B ] [ -b ] [ -C ] [ -d ] [ -F ] [ -H ] [ -h ] [ -p ] [ -q ] [ -R ]\n" + "[ -r ] [ -S ] [ -t ] [ -u [ ALL ] ] [ -V ] [ -v ] [ -W ] [ -w ] [ -y ]\n" + "[ -I { [,...] | SUM | ALL | XALL } ] [ -P { [,...] | ALL } ]\n" + "[ -m { [,...] | ALL } ] [ -n { [,...] | ALL } ]\n" +@@ -132,6 +132,7 @@ void display_help(char *progname) + printf(_("\t-b\tI/O and transfer rate statistics\n")); + printf(_("\t-B\tPaging statistics\n")); + printf(_("\t-d\tBlock device statistics\n")); ++ printf(_("\t-F\tFilesystems statistics\n")); + printf(_("\t-H\tHugepages utilization statistics\n")); + printf(_("\t-I { | SUM | ALL | XALL }\n" + "\t\tInterrupts statistics\n")); +diff --git a/xml_stats.c b/xml_stats.c +index 66a6850..0a15f98 100644 +--- a/xml_stats.c ++++ b/xml_stats.c +@@ -1989,4 +1989,21 @@ close_xml_markup: + if (CLOSE_MARKUP(a->options)) { + xml_markup_power_management(tab, CLOSE_XML_MARKUP); + } +-} +\ No newline at end of file ++} ++ ++/* ++ *************************************************************************** ++ * Display filesystems statistics in XML. ++ * ++ * IN: ++ * @a Activity structure with statistics. ++ * @curr Index in array for current sample statistics. ++ * @tab Indentation in XML output. ++ * @itv Interval of time in jiffies. ++ *************************************************************************** ++ */ ++__print_funct_t xml_print_filesystem_stats(struct activity *a, int curr, int tab, ++ unsigned long long itv) ++{ ++ /* FIXME */ ++} +diff --git a/xml_stats.h b/xml_stats.h +index 3009860..6258703 100644 +--- a/xml_stats.h ++++ b/xml_stats.h +@@ -87,5 +87,7 @@ extern __print_funct_t xml_print_pwr_wghfreq_stats + (struct activity *, int, int, unsigned long long); + extern __print_funct_t xml_print_pwr_usb_stats + (struct activity *, int, int, unsigned long long); ++extern __print_funct_t xml_print_filesystem_stats ++ (struct activity *, int, int, unsigned long long); + + #endif /* _XML_STATS_H */ +-- +2.14.3 + diff --git a/SOURCES/0001-avoiding-triggering-automounts-bug-1670060.patch b/SOURCES/0001-avoiding-triggering-automounts-bug-1670060.patch new file mode 100644 index 0000000..f1627f3 --- /dev/null +++ b/SOURCES/0001-avoiding-triggering-automounts-bug-1670060.patch @@ -0,0 +1,26 @@ +From cc95940e4c0d5f8916d95e627a494c321b95d139 Mon Sep 17 00:00:00 2001 +From: Ondrej Dubaj +Date: Tue, 26 Feb 2019 08:36:14 +0100 +Subject: [PATCH] avoiding triggering automounts, bug #1670060 + +--- + sadc.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/sadc.c b/sadc.c +index fb3254d..cfb9809 100644 +--- a/sadc.c ++++ b/sadc.c +@@ -283,6 +283,9 @@ void sa_sys_init(void) + + for (i = 0; i < NR_ACT; i++) { + ++ if ( ! (act[i]->options & AO_COLLECTED ) ) ++ continue; ++ + if (act[i]->f_count) { + /* Number of items is not a constant and should be calculated */ + act[i]->nr = (*act[i]->f_count)(act[i]); +-- +2.17.1 + diff --git a/SOURCES/0001-ignoring-autofs-as-real-filesystem-by-counting-numbe.patch b/SOURCES/0001-ignoring-autofs-as-real-filesystem-by-counting-numbe.patch new file mode 100644 index 0000000..6d1fc4b --- /dev/null +++ b/SOURCES/0001-ignoring-autofs-as-real-filesystem-by-counting-numbe.patch @@ -0,0 +1,83 @@ +From f18b5d452e11bad46473d019e41fb7e43a5708ca Mon Sep 17 00:00:00 2001 +From: Ondrej Dubaj +Date: Thu, 28 Feb 2019 15:29:08 +0100 +Subject: [PATCH] ignoring autofs as real filesystem by counting number of + valid filesystems and getting all valid filesystems + +(cherry-picked from commit 5b5339d06c4f50730e5cc679e0854ce716f39117) +--- + rd_stats.c | 35 +++++++++++++++++++++++++++++++---- + 1 file changed, 31 insertions(+), 4 deletions(-) + +diff --git a/rd_stats.c b/rd_stats.c +index c054b58..8114428 100644 +--- a/rd_stats.c ++++ b/rd_stats.c +@@ -1915,9 +1915,9 @@ void read_bus_usb_dev(struct stats_pwr_usb *st_pwr_usb, int nbr) + void read_filesystem(struct stats_filesystem *st_filesystem, int nbr) + { + FILE *fp; +- char line[512], fs_name[128], mountp[256]; ++ char line[512], fs_name[128], mountp[256], type[128]; + int fs = 0, skip = 0, skip_next = 0; +- char *pos = 0; ++ char *pos = 0, *pos2 = NULL; + struct stats_filesystem *st_filesystem_i; + struct statvfs buf; + +@@ -1941,6 +1941,20 @@ void read_filesystem(struct stats_filesystem *st_filesystem, int nbr) + if (pos == NULL) + continue; + ++ /* ++ * Find second field separator position, ++ * read filesystem type, ++ * if filesystem type is autofs, skip it ++ */ ++ memset(type, 0, sizeof(type)); ++ pos2 = strchr(pos + 1, ' '); ++ if (pos2 == NULL) ++ continue; ++ ++ sscanf(pos2 + 1, "%127s", type); ++ if(strcmp(type, "autofs") == 0) ++ continue; ++ + /* Read current filesystem name */ + sscanf(line, "%127s", fs_name); + /* +@@ -2411,9 +2425,9 @@ int get_usb_nr(void) + int get_filesystem_nr(void) + { + FILE *fp; +- char line[512], fs_name[MAX_FS_LEN], mountp[256]; ++ char line[512], fs_name[MAX_FS_LEN], mountp[256], type[128]; + int fs = 0, skip = 0, skip_next = 0; +- char *pos = 0; ++ char *pos = 0, *pos2 = NULL; + + struct statvfs buf; + +@@ -2438,6 +2452,19 @@ int get_filesystem_nr(void) + pos = strchr(line, ' '); + if (pos == NULL) + continue; ++ /* ++ * Find second field separator position, ++ * read filesystem type, ++ * if filesystem type is autofs, skip it ++ */ ++ memset(type, 0, sizeof(type)); ++ pos2 = strchr(pos + 1, ' '); ++ if (pos2 == NULL) ++ continue; ++ ++ sscanf(pos2 + 1, "%127s", type); ++ if(strcmp(type, "autofs") == 0) ++ continue; + + /* Read filesystem name and mount point */ + sscanf(line, "%127s", fs_name); +-- +2.17.2 + diff --git a/SOURCES/0001-man-use-correct-preposition.patch b/SOURCES/0001-man-use-correct-preposition.patch new file mode 100644 index 0000000..4dcd9ff --- /dev/null +++ b/SOURCES/0001-man-use-correct-preposition.patch @@ -0,0 +1,25 @@ +From 7498b3b9ab25a0075a24bb30dfc08fa6a0f7f81a Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Thu, 28 Mar 2019 13:44:45 +0100 +Subject: [PATCH] man: use correct preposition + +--- + man/sar.in | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/man/sar.in b/man/sar.in +index 4ea6ca0..88181ce 100644 +--- a/man/sar.in ++++ b/man/sar.in +@@ -336,7 +336,7 @@ The following values are displayed: + .B MBfsfree + .RS + .RS +-Total amount a free space in megabytes (including space available only to privileged user). ++Total amount of free space in megabytes (including space available only to privileged user). + .RE + + .B MBfsused +-- +2.17.2 + diff --git a/SOURCES/0001-pidstat-Display-stats-since-boot-time-for-a-list-of-.patch b/SOURCES/0001-pidstat-Display-stats-since-boot-time-for-a-list-of-.patch new file mode 100644 index 0000000..662c6a1 --- /dev/null +++ b/SOURCES/0001-pidstat-Display-stats-since-boot-time-for-a-list-of-.patch @@ -0,0 +1,52 @@ +From b4cad00cfb3086490261db7202de8ed846e79344 Mon Sep 17 00:00:00 2001 +From: Sebastien GODARD +Date: Wed, 2 Oct 2013 09:55:38 +0200 +Subject: [PATCH] pidstat: Display stats since boot time for a list of given + processes + +pidstat displays statistics since system startup when the interval and +count parameters are not set on the command line (eg. entering "pidstat +-d" will display I/O statistics for all processes that have had I/O +activity since boot time). But pidstat couldn't display those stats when +some PID numbers were entered on the command line (eg. "pidstat -d -p +1234" to display I/O stats since system startup for process 1234). +This patch makes it possible now. + +Signed-off-by: Sebastien GODARD +(cherry picked from commit 18c7a03f52826942a720b2a0cc32e1f074784c6a) + +Resolves: #1448489 +--- + pidstat.c | 16 ++++++++++++---- + 1 file changed, 12 insertions(+), 4 deletions(-) + +diff --git a/pidstat.c b/pidstat.c +index 3bb98f2..85d4d98 100644 +--- a/pidstat.c ++++ b/pidstat.c +@@ -1048,10 +1048,18 @@ int get_pid_to_display(int prev, int curr, int p, unsigned int activity, + + else if (DISPLAY_PID(pidflag)) { + *pstp = st_pid_list[prev] + p; +- +- if (!(*pstp)->pid) +- /* PID no longer exists */ +- return 0; ++ if (!(*pstp)->pid) { ++ if (interval) ++ /* PID no longer exists */ ++ return 0; ++ else { ++ /* ++ * If interval is null, then we are trying to ++ * display stats for a given process since boot time. ++ */ ++ *pstp = &st_pid_null; ++ } ++ } + } + + if (COMMAND_STRING(pidflag)) { +-- +2.13.6 + diff --git a/SOURCES/0001-pidstat-Now-handle-processes-with-spaces-in-their-na.patch b/SOURCES/0001-pidstat-Now-handle-processes-with-spaces-in-their-na.patch new file mode 100644 index 0000000..0a99ef5 --- /dev/null +++ b/SOURCES/0001-pidstat-Now-handle-processes-with-spaces-in-their-na.patch @@ -0,0 +1,120 @@ +From c16eb6cf753d5df0779c284126d7356d2377fdb3 Mon Sep 17 00:00:00 2001 +From: Sebastien GODARD +Date: Mon, 22 Oct 2018 18:06:48 +0200 +Subject: [PATCH] pidstat: Now handle processes with spaces in their name + properly + +pidstat had a bug which made it unable to handle processes with spaces +in their name, eg: + +$ cat /proc/5768/stat +5768 (Plex New Transc) S 1264 1252 1252 0 -1 1077960704 17317 0 18 0 +9260 137 0 0 15 -5 8 0 1430749 186589184 16704 18446744073709551615 1 1 +0 0 0 0 0 0 8404998 18446744073709551615 0 0 17 1 0 0 22 0 0 0 0 0 0 0 0 +0 0 + +This patch fixes the problem. + +Reported by Chris Grindstaff (@cgrinds). + +Signed-off-by: Sebastien GODARD +--- + pidstat.c | 59 +++++++++++++++++++++++++++++++++++------------------------ + 1 file changed, 35 insertions(+), 24 deletions(-) + +diff --git a/pidstat.c b/pidstat.c +index bc22aa8..af48f29 100644 +--- a/pidstat.c ++++ b/pidstat.c +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -307,9 +308,10 @@ void read_proc_meminfo(void) + int read_proc_pid_stat(unsigned int pid, struct pid_stats *pst, + unsigned int *thread_nr, unsigned int tgid) + { +- FILE *fp; +- char filename[128], format[256], comm[MAX_COMM_LEN + 1]; +- size_t len; ++ int fd, sz, rc, commsz; ++ char filename[128]; ++ static char buffer[1024 + 1]; ++ char *start, *end; + + if (tgid) { + sprintf(filename, TASK_STAT, tgid, pid); +@@ -318,36 +320,45 @@ int read_proc_pid_stat(unsigned int pid, struct pid_stats *pst, + sprintf(filename, PID_STAT, pid); + } + +- if ((fp = fopen(filename, "r")) == NULL) ++ if ((fd = open(filename, O_RDONLY)) < 0) + /* No such process */ + return 1; + +- sprintf(format, "%%*d (%%%ds %%*s %%*d %%*d %%*d %%*d %%*d %%*u %%lu %%lu" +- " %%lu %%lu %%lu %%lu %%lu %%lu %%*d %%*d %%u %%*u %%*d %%lu %%lu" +- " %%*u %%*u %%*u %%*u %%*u %%*u %%*u %%*u %%*u %%*u %%*u %%*u %%*u" +- " %%*u %%u %%*u %%*u %%*u %%lu %%lu\\n", MAX_COMM_LEN); +- +- fscanf(fp, format, comm, +- &pst->minflt, &pst->cminflt, &pst->majflt, &pst->cmajflt, +- &pst->utime, &pst->stime, &pst->cutime, &pst->cstime, +- thread_nr, &pst->vsz, &pst->rss, &pst->processor, +- &pst->gtime, &pst->cgtime); ++ sz = read(fd, buffer, 1024); ++ close(fd); ++ if (sz <= 0) ++ return 1; ++ buffer[sz] = '\0'; + +- fclose(fp); ++ if ((start = strchr(buffer, '(')) == NULL) ++ return 1; ++ start += 1; ++ if ((end = strrchr(start, ')')) == NULL) ++ return 1; ++ commsz = end - start; ++ if (commsz >= MAX_COMM_LEN) ++ return 1; ++ memcpy(pst->comm, start, commsz); ++ pst->comm[commsz] = '\0'; ++ start = end + 2; ++ ++ rc = sscanf(start, ++ "%*s %*d %*d %*d %*d %*d %*u %lu %lu" ++ " %lu %lu %lu %lu %ld %ld %*d %*d %u %*u %*d %lu %lu" ++ " %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u" ++ " %*u %u %*u %*u %*lu %lu %ld\n", ++ &pst->minflt, &pst->cminflt, &pst->majflt, &pst->cmajflt, ++ &pst->utime, &pst->stime, &pst->cutime, &pst->cstime, ++ thread_nr, &pst->vsz, &pst->rss, &pst->processor, ++ &pst->gtime, &pst->cgtime); ++ ++ if (rc < 14) ++ return 1; + + /* Convert to kB */ + pst->vsz >>= 10; + pst->rss = PG_TO_KB(pst->rss); + +- strncpy(pst->comm, comm, MAX_COMM_LEN); +- pst->comm[MAX_COMM_LEN - 1] = '\0'; +- +- /* Remove trailing ')' */ +- len = strlen(pst->comm); +- if (len && (pst->comm[len - 1] == ')')) { +- pst->comm[len - 1] = '\0'; +- } +- + pst->pid = pid; + pst->tgid = tgid; + return 0; +-- +2.14.4 + diff --git a/SOURCES/0001-sadc-Add-a-f-flag-to-force-fdatasync-use.patch b/SOURCES/0001-sadc-Add-a-f-flag-to-force-fdatasync-use.patch new file mode 100644 index 0000000..b52ef6f --- /dev/null +++ b/SOURCES/0001-sadc-Add-a-f-flag-to-force-fdatasync-use.patch @@ -0,0 +1,108 @@ +From f44275403f866cd0a7e0e40714c249ec5903d356 Mon Sep 17 00:00:00 2001 +From: Kyle Walker +Date: Wed, 30 Jan 2019 07:50:55 -0500 +Subject: [PATCH] sadc: Add a -f flag to force fdatasync() use + +For quite some time, the sadc utility has not used fdatasync() when writing +stat information to disk. This resulted in instances where data files could +be corrupted or entries lost if a system encountered a sudden reset +condition. This change adds a "-f" flag which can be used to bring back the +previous behaviour if end users require it. + +Note, the fdatasync() lowers the likelihood of lost data, but does so at +the expense of performance within the write operation. + +(cherry picked from commit 560d88cb5a16636acb0e350d6997fe915cc4253e) +--- + man/sadc.in | 8 +++++++- + sa.h | 2 ++ + sadc.c | 13 ++++++++++++- + 3 files changed, 21 insertions(+), 2 deletions(-) + +diff --git a/man/sadc.in b/man/sadc.in +index 9b75754..d3574c1 100644 +--- a/man/sadc.in ++++ b/man/sadc.in +@@ -4,7 +4,7 @@ sadc \- System activity data collector. + .SH SYNOPSIS + .B @SA_LIB_DIR@/sadc [ -C + .I comment +-.B ] [ -F ] [ -L ] [ -V ] [ -S { INT | DISK | SNMP | IPV6 | POWER | XDISK | ALL | XALL } ] [ ++.B ] [ -F ] [ -L ] [ -V ] [ -f ] [ -S { INT | DISK | SNMP | IPV6 | POWER | XDISK | ALL | XALL } ] [ + .I interval + .B [ + .I count +@@ -85,6 +85,12 @@ then it will be truncated. This may be useful for daily data files + created by an older version of + .B sadc + and whose format is no longer compatible with current one. ++.IP -f ++fdatasync() will be used to ensure data is written to disk. This differs ++from the normal operation in that a sudden system reset is less likely to ++result in the saDD datafiles being corrupted. However, this is at the ++expense of performance within the sadc process as forward progress will be ++blocked while data is written to underlying disk instead of just to cache. + .IP -L + .B sadc + will try to get an exclusive lock on the +diff --git a/sa.h b/sa.h +index 54e7a4e..0c3b24c 100644 +--- a/sa.h ++++ b/sa.h +@@ -88,6 +88,7 @@ + #define S_F_COMMENT 0x00001000 + #define S_F_PERSIST_NAME 0x00002000 + #define S_F_LOCAL_TIME 0x00004000 ++#define S_F_FDATASYNC 0x00008000 + + #define WANT_SINCE_BOOT(m) (((m) & S_F_SINCE_BOOT) == S_F_SINCE_BOOT) + #define WANT_SA_ROTAT(m) (((m) & S_F_SA_ROTAT) == S_F_SA_ROTAT) +@@ -104,6 +105,7 @@ + #define DISPLAY_COMMENT(m) (((m) & S_F_COMMENT) == S_F_COMMENT) + #define DISPLAY_PERSIST_NAME_S(m) (((m) & S_F_PERSIST_NAME) == S_F_PERSIST_NAME) + #define PRINT_LOCAL_TIME(m) (((m) & S_F_LOCAL_TIME) == S_F_LOCAL_TIME) ++#define FDATASYNC(m) (((m) & S_F_FDATASYNC) == S_F_FDATASYNC) + + #define AO_F_NULL 0x00000000 + +diff --git a/sadc.c b/sadc.c +index fb3254d..bac28d4 100644 +--- a/sadc.c ++++ b/sadc.c +@@ -85,7 +85,7 @@ void usage(char *progname) + progname); + + fprintf(stderr, _("Options are:\n" +- "[ -C ] [ -F ] [ -L ] [ -V ]\n" ++ "[ -C ] [ -F ] [ -L ] [ -V ] [ -f ]\n" + "[ -S { INT | DISK | IPV6 | POWER | SNMP | XDISK | ALL | XALL } ]\n")); + exit(1); + } +@@ -991,6 +991,13 @@ void rw_sa_stat_loop(long count, struct tm *rectime, int stdfd, int ofd, + + /* Flush data */ + fflush(stdout); ++ if (FDATASYNC(flags)) { ++ /* Flush previous file */ ++ if (fdatasync(ofd) < 0) { ++ perror("fdatasync"); ++ exit(4); ++ } ++ } + + if (count > 0) { + count--; +@@ -1079,6 +1086,10 @@ int main(int argc, char **argv) + optz = 1; + } + ++ else if (!strcmp(argv[opt], "-f")) { ++ flags |= S_F_FDATASYNC; ++ } ++ + else if (!strcmp(argv[opt], "-C")) { + if (argv[++opt]) { + strncpy(comment, argv[opt], MAX_COMMENT_LEN); +-- +2.17.1 + diff --git a/SOURCES/0001-sar-Improve-cpuinfo-read-for-POWER-architecture.patch b/SOURCES/0001-sar-Improve-cpuinfo-read-for-POWER-architecture.patch new file mode 100644 index 0000000..97556de --- /dev/null +++ b/SOURCES/0001-sar-Improve-cpuinfo-read-for-POWER-architecture.patch @@ -0,0 +1,47 @@ +From 81ef06797b16d08a4558a41891b9d9421a0a96f8 Mon Sep 17 00:00:00 2001 +From: Breno Leitao +Date: Mon, 31 Oct 2016 09:23:59 -0400 +Subject: [PATCH] sar: Improve cpuinfo read for POWER architecture + +Currently CPU frequency is not being read properly on POWER archicture. +It shows the frequency as: + # sar -m CPU 1 5 +... + 06:30:28 AM CPU MHz + 06:30:36 AM all 0.00 + +This is caused because /proc/cpuinfo is differently between Intel and +POWER. +This patch simply fix the parsing function (read_cpuinfo). + +Signed-off-by: Breno Leitao + +Resolves: #1440000 +--- + rd_stats.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/rd_stats.c b/rd_stats.c +index dafd975..d8c337a 100644 +--- a/rd_stats.c ++++ b/rd_stats.c +@@ -1625,10 +1625,12 @@ void read_cpuinfo(struct stats_pwr_cpufreq *st_pwr_cpufreq, int nbr) + if (!strncmp(line, "processor\t", 10)) { + sscanf(strchr(line, ':') + 1, "%d", &proc_nb); + } +- +- else if (!strncmp(line, "cpu MHz\t", 8)) { +- sscanf(strchr(line, ':') + 1, "%u.%u", &ifreq, &dfreq); +- ++ ++ /* Entry in /proc/cpuinfo is different between Intel and Power architectures */ ++ else if (!strncmp(line, "cpu MHz\t", 8) || ++ !strncmp(line, "clock\t", 6)) { ++ sscanf(strchr(line, ':') + 1, "%u.%u", &ifreq, &dfreq); ++ + if (proc_nb < (nbr - 1)) { + /* Save current CPU frequency */ + st_pwr_cpufreq_i = st_pwr_cpufreq + proc_nb + 1; +-- +2.13.6 + diff --git a/SOURCES/0001-sar-make-buffers-that-hold-timestamps-bigger.patch b/SOURCES/0001-sar-make-buffers-that-hold-timestamps-bigger.patch new file mode 100644 index 0000000..786264a --- /dev/null +++ b/SOURCES/0001-sar-make-buffers-that-hold-timestamps-bigger.patch @@ -0,0 +1,68 @@ +From f3964e0fa19e0c33470f37014ebcebf0b4253363 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Fri, 30 Sep 2016 18:05:44 +0200 +Subject: [PATCH] sar: make buffers that hold timestamps bigger +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +On systems that use Korean UTF-8 locale sar will not print timestamp +because there is not enough space in the buffer. + +I bumped buffer size to 64 bytes because I figured out that 32 bytes is +still not enough to print out timestamp when using some glibc supported +locales. + +$ LC_TIME=ko_KR.UTF-8 ./sar 1 1 + +Before: +Linux 4.7.2-201.fc24.x86_64 (morgoth.usersys.redhat.com) 2016년 09월 30일 _x86_64_ (4 CPU) + + CPU %user %nice %system %iowait %steal %idle + all 4.51 0.00 2.51 0.00 0.00 92.98 +Average: all 4.51 0.00 2.51 0.00 0.00 92.98 + +After: +Linux 4.7.2-201.fc24.x86_64 (morgoth.usersys.redhat.com) 2016년 09월 30일 _x86_64_ (4 CPU) + +18시 18분 36초 CPU %user %nice %system %iowait %steal %idle +18시 18분 37초 all 3.76 0.00 2.26 0.00 0.00 93.98 +Average: all 3.76 0.00 2.26 0.00 0.00 93.98 +--- + sa.h | 2 +- + sar.c | 4 ++-- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/sa.h b/sa.h +index 54e7a4e..c11dbe9 100644 +--- a/sa.h ++++ b/sa.h +@@ -199,7 +199,7 @@ + #define NR_USB_PREALLOC 5 + + #define UTSNAME_LEN 65 +-#define TIMESTAMP_LEN 16 ++#define TIMESTAMP_LEN 64 + #define HEADER_LINE_LEN 512 + + /* Maximum number of args that can be passed to sadc */ +diff --git a/sar.c b/sar.c +index e8ad83e..8dd998b 100644 +--- a/sar.c ++++ b/sar.c +@@ -469,10 +469,10 @@ int write_stats(int curr, int read_from_file, long *cnt, int use_tm_start, + } + + /* Set previous timestamp */ +- if (set_record_timestamp_string(!curr, timestamp[!curr], 16)) ++ if (set_record_timestamp_string(!curr, timestamp[!curr], TIMESTAMP_LEN)) + return 0; + /* Set current timestamp */ +- if (set_record_timestamp_string(curr, timestamp[curr], 16)) ++ if (set_record_timestamp_string(curr, timestamp[curr], TIMESTAMP_LEN)) + return 0; + + /* Check if we are beginning a new day */ +-- +2.9.3 + diff --git a/SOURCES/0002-Filesystems-statistics-for-sar-part-2-Read-statistic.patch b/SOURCES/0002-Filesystems-statistics-for-sar-part-2-Read-statistic.patch new file mode 100644 index 0000000..da6ae03 --- /dev/null +++ b/SOURCES/0002-Filesystems-statistics-for-sar-part-2-Read-statistic.patch @@ -0,0 +1,202 @@ +From cea93dc1db568312987814b3cae0a6f837cfaa4e Mon Sep 17 00:00:00 2001 +From: seb +Date: Sun, 5 May 2013 17:42:03 +0200 +Subject: [PATCH] Filesystems statistics for sar (part 2): Read statistics + +This patch reads statistics for mounted filesystems except for +pseudo-filesystems which are ignored. +It also determines the number of filesystems for which stats will be +read. +Oh, and it adds another field to the stats_filesystem structure so that +filesystem name can be saved ;-) + +(cherry picked from commit 512bf2e7ebfa5e5fec757d96820b0b3f94341797) +--- + rd_stats.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + rd_stats.h | 17 ++++++++---- + sa_wrap.c | 5 ++-- + 3 files changed, 102 insertions(+), 7 deletions(-) + +diff --git a/rd_stats.c b/rd_stats.c +index d8c337a..829dae5 100644 +--- a/rd_stats.c ++++ b/rd_stats.c +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + #include + + #include "common.h" +@@ -1863,6 +1864,51 @@ void read_bus_usb_dev(struct stats_pwr_usb *st_pwr_usb, int nbr) + closedir(dir); + } + ++/* ++ *************************************************************************** ++ * Read filesystems statistics. ++ * ++ * IN: ++ * @st_filesystem Structure where stats will be saved. ++ * @nbr Total number of filesystems. ++ * ++ * OUT: ++ * @st_filesystem Structure with statistics. ++ *************************************************************************** ++ */ ++void read_filesystem(struct stats_filesystem *st_filesystem, int nbr) ++{ ++ FILE *fp; ++ char line[256], fs_name[MAX_FS_LEN], mountp[128]; ++ int fs = 0; ++ struct stats_filesystem *st_filesystem_i; ++ struct statfs buf; ++ ++ if ((fp = fopen(MTAB, "r")) == NULL) ++ return; ++ ++ while ((fgets(line, 256, fp) != NULL) && (fs < nbr)) { ++ if (line[0] == '/') { ++ ++ /* Read current filesystem name and mount point */ ++ sscanf(line, "%71s %127s", fs_name, mountp); ++ ++ if ((statfs(mountp, &buf) < 0) || (!buf.f_blocks)) ++ continue; ++ ++ st_filesystem_i = st_filesystem + fs++; ++ st_filesystem_i->f_blocks = buf.f_blocks * buf.f_bsize; ++ st_filesystem_i->f_bfree = buf.f_bfree * buf.f_bsize; ++ st_filesystem_i->f_bavail = buf.f_bavail * buf.f_bsize; ++ st_filesystem_i->f_files = buf.f_files; ++ st_filesystem_i->f_ffree = buf.f_ffree; ++ strcpy(st_filesystem_i->fs_name, fs_name); ++ } ++ } ++ ++ fclose(fp); ++} ++ + /* + *************************************************************************** + * Read machine uptime, independently of the number of processors. +@@ -2282,3 +2328,44 @@ int get_usb_nr(void) + + return usb; + } ++ ++/* ++ *************************************************************************** ++ * Find number of filesystems in /etc/mtab. Pseudo-filesystems are ignored. ++ * ++ * RETURNS: ++ * Number of filesystems. ++ *************************************************************************** ++ */ ++int get_filesystem_nr(void) ++{ ++ FILE *fp; ++ char line[256], fs_name[MAX_FS_LEN], mountp[128]; ++ int fs = 0; ++ struct statfs buf; ++ ++ if ((fp = fopen(MTAB, "r")) == NULL) ++ /* File non-existent */ ++ return 0; ++ ++ /* Get current filesystem */ ++ while (fgets(line, 256, fp) != NULL) { ++ if (line[0] == '/') { ++ ++ /* Read filesystem name and mount point */ ++ sscanf(line, "%71s %127s", fs_name, mountp); ++ ++ /* Check that total size is not null */ ++ if (statfs(mountp, &buf) < 0) ++ continue; ++ ++ if (buf.f_blocks) { ++ fs++; ++ } ++ } ++ } ++ ++ fclose(fp); ++ ++ return fs; ++} +diff --git a/rd_stats.h b/rd_stats.h +index f941426..3f1edde 100644 +--- a/rd_stats.h ++++ b/rd_stats.h +@@ -27,6 +27,8 @@ + #define MAX_MANUF_LEN 24 + /* Maximum length of USB product string */ + #define MAX_PROD_LEN 48 ++/* Maximum length of filesystem name */ ++#define MAX_FS_LEN 72 + + #define CNT_DEV 0 + #define CNT_PART 1 +@@ -523,11 +525,12 @@ struct stats_pwr_usb { + + /* Structure for filesystems statistics */ + struct stats_filesystem { +- unsigned long long f_blocks __attribute__ ((aligned (16))); +- unsigned long long f_bfree __attribute__ ((aligned (16))); +- unsigned long long f_bavail __attribute__ ((aligned (16))); +- unsigned long long f_files __attribute__ ((aligned (16))); +- unsigned long long f_ffree __attribute__ ((aligned (16))); ++ unsigned long long f_blocks __attribute__ ((aligned (16))); ++ unsigned long long f_bfree __attribute__ ((aligned (16))); ++ unsigned long long f_bavail __attribute__ ((aligned (16))); ++ unsigned long long f_files __attribute__ ((aligned (16))); ++ unsigned long long f_ffree __attribute__ ((aligned (16))); ++ char fs_name[MAX_FS_LEN] __attribute__ ((aligned (16))); + }; + + #define STATS_FILESYSTEM_SIZE (sizeof(struct stats_filesystem)) +@@ -607,6 +610,8 @@ extern void + read_time_in_state(struct stats_pwr_wghfreq *, int, int); + extern void + read_bus_usb_dev(struct stats_pwr_usb *, int); ++extern void ++ read_filesystem(struct stats_filesystem *, int); + + /* + *************************************************************************** +@@ -632,5 +637,7 @@ extern int + get_freq_nr(void); + extern int + get_usb_nr(void); ++extern int ++ get_filesystem_nr(void); + + #endif /* _RD_STATS_H */ +diff --git a/sa_wrap.c b/sa_wrap.c +index 298f889..6a829d7 100644 +--- a/sa_wrap.c ++++ b/sa_wrap.c +@@ -864,7 +864,7 @@ __read_funct_t wrap_read_filesystem(struct activity *a) + = (struct stats_filesystem *) a->_buf0; + + /* Read filesystems from /etc/mtab */ +- /* FIXME */ ++ read_filesystem(st_filesystem, a->nr); + + return; + } +@@ -1088,7 +1088,8 @@ __nr_t wrap_get_filesystem_nr(struct activity *a) + { + __nr_t n = 0; + +- /* FIXME */ ++ if ((n = get_filesystem_nr()) > 0) ++ return n + NR_FILESYSTEM_PREALLOC; + + return 0; + } +-- +2.14.3 + diff --git a/SOURCES/0003-Filesystems-statistics-for-sar-part-3-Display-statis.patch b/SOURCES/0003-Filesystems-statistics-for-sar-part-3-Display-statis.patch new file mode 100644 index 0000000..73425af --- /dev/null +++ b/SOURCES/0003-Filesystems-statistics-for-sar-part-3-Display-statis.patch @@ -0,0 +1,63 @@ +From 5c63cabf526ee93dec1aef7da6e17a46cbd5c562 Mon Sep 17 00:00:00 2001 +From: seb +Date: Mon, 6 May 2013 21:55:04 +0200 +Subject: [PATCH] Filesystems statistics for sar (part 3): Display statistics + +This patch makes sar display filesystems statistics collected by sadc. +No average statistics are calculated here (filesystems can be unmounted, +then mounted again, making average values meaningless). Instead, sar displays again +the list of filesystems. + +(cherry picked from commit c8afab03c6a6a28e303613b203bf6c186c168524) +--- + pr_stats.c | 34 +++++++++++++++++++++++++++++++++- + 1 file changed, 33 insertions(+), 1 deletion(-) + +diff --git a/pr_stats.c b/pr_stats.c +index 332b10e..85a3a20 100644 +--- a/pr_stats.c ++++ b/pr_stats.c +@@ -2454,7 +2454,39 @@ __print_funct_t print_avg_pwr_usb_stats(struct activity *a, int prev, int curr, + __print_funct_t stub_print_filesystem_stats(struct activity *a, int prev, int curr, + unsigned long long itv, int dispavg) + { +- /* FIXME */ ++ int i; ++ struct stats_filesystem *sfc; ++ ++ ++ if (dis) { ++ printf("\n%-11s MBfsfree MBfsused %%fsused %%ufsused" ++ " Ifree Iused %%Iused FILESYSTEM\n", ++ (dispavg ? _("Summary") : timestamp[!curr])); ++ } ++ ++ for (i = 0; i < a->nr; i++) { ++ sfc = (struct stats_filesystem *) ((char *) a->buf[curr] + i * a->msize); ++ ++ if (!sfc->f_blocks) ++ /* Size of filesystem is null: We are at the end of the list */ ++ break; ++ ++ printf("%-11s %9.0f %9.0f %6.2f %6.2f" ++ " %9llu %9llu %6.2f %s\n", ++ (dispavg ? _("Summary") : timestamp[curr]), ++ (double) sfc->f_bfree / 1024 / 1024, ++ (double) (sfc->f_blocks - sfc->f_bfree) / 1024 / 1024, ++ /* f_blocks is not null. But test it anyway ;-) */ ++ sfc->f_blocks ? SP_VALUE(sfc->f_bfree, sfc->f_blocks, sfc->f_blocks) ++ : 0.0, ++ sfc->f_blocks ? SP_VALUE(sfc->f_bavail, sfc->f_blocks, sfc->f_blocks) ++ : 0.0, ++ sfc->f_ffree, ++ sfc->f_files - sfc->f_ffree, ++ sfc->f_files ? SP_VALUE(sfc->f_ffree, sfc->f_files, sfc->f_files) ++ : 0.0, ++ sfc->fs_name); ++ } + } + + /* +-- +2.14.3 + diff --git a/SOURCES/0004-Filesystems-statistics-part-4-ppc-and-db-output-form.patch b/SOURCES/0004-Filesystems-statistics-part-4-ppc-and-db-output-form.patch new file mode 100644 index 0000000..f47b47a --- /dev/null +++ b/SOURCES/0004-Filesystems-statistics-part-4-ppc-and-db-output-form.patch @@ -0,0 +1,136 @@ +From b6905bafa7fc82ba22afaeb26ff46c900738e9d4 Mon Sep 17 00:00:00 2001 +From: Sebastien GODARD +Date: Sun, 12 May 2013 15:17:01 +0200 +Subject: [PATCH] Filesystems statistics (part 4): ppc and db output formats + +This patch adds ppc and database (CSV) output formats for filesystems +statistics. These formats can be displayed with sadf options -p and -d. + +Also add a new flag (PT_USERND) to the render() function so that +a statistic value can be rounded to the nearest integer value. + +(cherry picked from commit 37e6da76fd59dcdff84e216e2c8ef10c439d9f84) +--- + activity.c | 2 +- + rndr_stats.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- + rndr_stats.h | 1 + + 3 files changed, 75 insertions(+), 2 deletions(-) + +diff --git a/activity.c b/activity.c +index b1aba37..734df4a 100644 +--- a/activity.c ++++ b/activity.c +@@ -1214,7 +1214,7 @@ struct activity filesystem_act = { + .f_render = render_filesystem_stats, + .f_xml_print = xml_print_filesystem_stats, + .f_json_print = json_print_filesystem_stats, +- .hdr_line = "Mbfsfree;Mbfsused;%fsused;%ufsused;Ifree;Iused;%Iused;FILESYSTEM", ++ .hdr_line = "FILESYSTEM,MBfsfree;MBfsused;%fsused;%ufsused;Ifree;Iused;%Iused", + .name = "A_FILESYSTEM", + #endif + .nr = -1, +diff --git a/rndr_stats.c b/rndr_stats.c +index 8349e9a..a3dcb22 100644 +--- a/rndr_stats.c ++++ b/rndr_stats.c +@@ -147,6 +147,9 @@ static void render(int isdb, char *pre, int rflags, const char *pptxt, + else if (rflags & PT_USESTR) { + printf("%s%s", seps[isdb], sval); + } ++ else if (rflags & PT_USERND) { ++ printf("%s%.0f", seps[isdb], dval); ++ } + else { + printf("%s%.2f", seps[isdb], dval); + } +@@ -2808,5 +2811,74 @@ __print_funct_t render_pwr_usb_stats(struct activity *a, int isdb, char *pre, + __print_funct_t render_filesystem_stats(struct activity *a, int isdb, char *pre, + int curr, unsigned long long itv) + { +- /* FIXME */ ++ int i; ++ struct stats_filesystem *sfc; ++ ++ for (i = 0; i < a->nr; i++) { ++ sfc = (struct stats_filesystem *) ((char *) a->buf[curr] + i * a->msize); ++ ++ if (!sfc->f_blocks) ++ /* Size of filesystem is null: We are at the end of the list */ ++ break; ++ ++ render(isdb, pre, PT_USERND, ++ "%s\tMBfsfree", ++ "%s", ++ cons(sv, sfc->fs_name, NOVAL), ++ NOVAL, ++ (double) sfc->f_bfree / 1024 / 1024, ++ NULL); ++ ++ render(isdb, pre, PT_USERND, ++ "%s\tMBfsused", ++ NULL, ++ cons(sv, sfc->fs_name, NOVAL), ++ NOVAL, ++ (double) (sfc->f_blocks - sfc->f_bfree) / 1024 / 1024, ++ NULL); ++ ++ render(isdb, pre, PT_NOFLAG, ++ "%s\t%%fsused", ++ NULL, ++ cons(sv, sfc->fs_name, NOVAL), ++ NOVAL, ++ sfc->f_blocks ? SP_VALUE(sfc->f_bfree, sfc->f_blocks, sfc->f_blocks) ++ : 0.0, ++ NULL); ++ ++ render(isdb, pre, PT_NOFLAG, ++ "%s\t%%ufsused", ++ NULL, ++ cons(sv, sfc->fs_name, NOVAL), ++ NOVAL, ++ sfc->f_blocks ? SP_VALUE(sfc->f_bavail, sfc->f_blocks, sfc->f_blocks) ++ : 0.0, ++ NULL); ++ ++ render(isdb, pre, PT_USEINT, ++ "%s\tIfree", ++ NULL, ++ cons(sv, sfc->fs_name, NOVAL), ++ sfc->f_ffree, ++ NOVAL, ++ NULL); ++ ++ render(isdb, pre, PT_USEINT, ++ "%s\tIused", ++ NULL, ++ cons(sv, sfc->fs_name, NOVAL), ++ sfc->f_files - sfc->f_ffree, ++ NOVAL, ++ NULL); ++ ++ render(isdb, pre, ++ (DISPLAY_HORIZONTALLY(flags) ? PT_NOFLAG : PT_NEWLIN), ++ "%s\t%%Iused", ++ NULL, ++ cons(sv, sfc->fs_name, NOVAL), ++ NOVAL, ++ sfc->f_files ? SP_VALUE(sfc->f_ffree, sfc->f_files, sfc->f_files) ++ : 0.0, ++ NULL); ++ } + } +diff --git a/rndr_stats.h b/rndr_stats.h +index ff6452a..9de51b2 100644 +--- a/rndr_stats.h ++++ b/rndr_stats.h +@@ -18,6 +18,7 @@ + #define PT_USEINT 0x0001 /* Use the integer arg, not double nor string */ + #define PT_NEWLIN 0x0002 /* Terminate the current output line */ + #define PT_USESTR 0x0004 /* Use the string arg */ ++#define PT_USERND 0x0008 /* Double value, format %.0f */ + + #define NOVAL 0 /* For placeholder zeros */ + #define DNOVAL 0.0 /* Wilma! */ +-- +2.14.3 + diff --git a/SOURCES/0005-Filesystems-statistics-part-5-JSON-output-format.patch b/SOURCES/0005-Filesystems-statistics-part-5-JSON-output-format.patch new file mode 100644 index 0000000..bfb61f0 --- /dev/null +++ b/SOURCES/0005-Filesystems-statistics-part-5-JSON-output-format.patch @@ -0,0 +1,67 @@ +From 653c316533bbadd6e5f75abb69b3953dd43232d9 Mon Sep 17 00:00:00 2001 +From: Sebastien GODARD +Date: Sun, 12 May 2013 16:07:55 +0200 +Subject: [PATCH] Filesystems statistics (part 5): JSON output format + +This patch adds JSON output format for filesystems statistics. This +format can be displayed with sadf option -j. + +(cherry picked from commit 9a5447d081141289de2736f7f31f25b3b340ace9) +--- + json_stats.c | 42 +++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 41 insertions(+), 1 deletion(-) + +diff --git a/json_stats.c b/json_stats.c +index 10d88e9..a5b4dcd 100644 +--- a/json_stats.c ++++ b/json_stats.c +@@ -2100,5 +2100,45 @@ close_json_markup: + __print_funct_t json_print_filesystem_stats(struct activity *a, int curr, int tab, + unsigned long long itv) + { +- /* FIXME */ ++ int i; ++ struct stats_filesystem *sfc; ++ int sep = FALSE; ++ ++ xprintf(tab++, "\"filesystems\": ["); ++ ++ for (i = 0; i < a->nr; i++) { ++ sfc = (struct stats_filesystem *) ((char *) a->buf[curr] + i * a->msize); ++ ++ if (!sfc->f_blocks) ++ /* Size of filesystem is null: We are at the end of the list */ ++ break; ++ ++ if (sep) { ++ printf(",\n"); ++ } ++ sep = TRUE; ++ ++ xprintf0(tab, "{\"filesystem\": \"%s\", " ++ "\"MBfsfree\": %.0f, " ++ "\"MBfsused\": %.0f, " ++ "\"%%fsused\": %.2f, " ++ "\"%%ufsused\": %.2f, " ++ "\"Ifree\": %llu, " ++ "\"Iused\": %llu, " ++ "\"%%Iused\": %.2f}", ++ sfc->fs_name, ++ (double) sfc->f_bfree / 1024 / 1024, ++ (double) (sfc->f_blocks - sfc->f_bfree) / 1024 / 1024, ++ sfc->f_blocks ? SP_VALUE(sfc->f_bfree, sfc->f_blocks, sfc->f_blocks) ++ : 0.0, ++ sfc->f_blocks ? SP_VALUE(sfc->f_bavail, sfc->f_blocks, sfc->f_blocks) ++ : 0.0, ++ sfc->f_ffree, ++ sfc->f_files - sfc->f_ffree, ++ sfc->f_files ? SP_VALUE(sfc->f_ffree, sfc->f_files, sfc->f_files) ++ : 0.0); ++ } ++ ++ printf("\n"); ++ xprintf0(--tab, "]"); + } +-- +2.14.3 + diff --git a/SOURCES/0006-Filesystems-statistics-part-6-XML-output-format.patch b/SOURCES/0006-Filesystems-statistics-part-6-XML-output-format.patch new file mode 100644 index 0000000..9f794ed --- /dev/null +++ b/SOURCES/0006-Filesystems-statistics-part-6-XML-output-format.patch @@ -0,0 +1,165 @@ +From b3a0f481304e76b5fe3ec69025df20cea16e6f0e Mon Sep 17 00:00:00 2001 +From: Sebastien GODARD +Date: Sat, 18 May 2013 22:04:27 +0200 +Subject: [PATCH] Filesystems statistics (part 6): XML output format + +This patch adds XML output format for filesystems statistics. This +format can be displayed with sadf option -x. +DTD and XML Schema (xsd) documents have also been updated. + +(cherry picked from commit 1eddc64a1db0efd5cdffd5d272adb9f8d4ccb589) +--- + sadf.h | 2 +- + xml/{sysstat-2.15.dtd => sysstat-2.16.dtd} | 18 ++++++++++++-- + xml/sysstat.xsd | 22 ++++++++++++++++- + xml_stats.c | 38 +++++++++++++++++++++++++++++- + 4 files changed, 75 insertions(+), 5 deletions(-) + rename xml/{sysstat-2.15.dtd => sysstat-2.16.dtd} (96%) + +diff --git a/sadf.h b/sadf.h +index 786d3b0..198568a 100644 +--- a/sadf.h ++++ b/sadf.h +@@ -9,7 +9,7 @@ + #include "sa.h" + + /* DTD version for XML output */ +-#define XML_DTD_VERSION "2.15" ++#define XML_DTD_VERSION "2.16" + + /* Possible actions for functions used to display reports */ + #define F_BEGIN 0x01 +diff --git a/xml/sysstat-2.15.dtd b/xml/sysstat-2.16.dtd +similarity index 96% +rename from xml/sysstat-2.15.dtd +rename to xml/sysstat-2.16.dtd +index e0b7bfb..06faed2 100644 +--- a/xml/sysstat-2.15.dtd ++++ b/xml/sysstat-2.16.dtd +@@ -1,11 +1,11 @@ + +- ++ + + + + + +- ++ + + + +@@ -551,3 +551,17 @@ + manufact CDATA #REQUIRED + product CDATA #REQUIRED + > ++ ++ ++ ++ ++ +diff --git a/xml/sysstat.xsd b/xml/sysstat.xsd +index 8304ac5..09818f6 100644 +--- a/xml/sysstat.xsd ++++ b/xml/sysstat.xsd +@@ -1,7 +1,7 @@ + + + +- -- XML Schema v2.15 for sysstat. See sadf.h -- ++ -- XML Schema v2.16 for sysstat. See sadf.h -- + + + +@@ -97,6 +97,7 @@ + + + ++ + + + +@@ -723,4 +724,23 @@ + + + ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ + +diff --git a/xml_stats.c b/xml_stats.c +index 0a15f98..f41d520 100644 +--- a/xml_stats.c ++++ b/xml_stats.c +@@ -2005,5 +2005,41 @@ close_xml_markup: + __print_funct_t xml_print_filesystem_stats(struct activity *a, int curr, int tab, + unsigned long long itv) + { +- /* FIXME */ ++ int i; ++ struct stats_filesystem *sfc; ++ ++ xprintf(tab, ""); ++ tab++; ++ ++ for (i = 0; i < a->nr; i++) { ++ ++ sfc = (struct stats_filesystem *) ((char *) a->buf[curr] + i * a->msize); ++ ++ if (!sfc->f_blocks) ++ /* Size of filesystem is null: We are at the end of the list */ ++ break; ++ ++ xprintf(tab, "", ++ sfc->fs_name, ++ (double) sfc->f_bfree / 1024 / 1024, ++ (double) (sfc->f_blocks - sfc->f_bfree) / 1024 / 1024, ++ /* f_blocks is not null. But test it anyway ;-) */ ++ sfc->f_blocks ? SP_VALUE(sfc->f_bfree, sfc->f_blocks, sfc->f_blocks) ++ : 0.0, ++ sfc->f_blocks ? SP_VALUE(sfc->f_bavail, sfc->f_blocks, sfc->f_blocks) ++ : 0.0, ++ sfc->f_ffree, ++ sfc->f_files - sfc->f_ffree, ++ sfc->f_files ? SP_VALUE(sfc->f_ffree, sfc->f_files, sfc->f_files) ++ : 0.0); ++ } ++ ++ xprintf(--tab, ""); + } +-- +2.14.3 + diff --git a/SOURCES/0007-Filesystems-statistics-part-7-Documentation-updates.patch b/SOURCES/0007-Filesystems-statistics-part-7-Documentation-updates.patch new file mode 100644 index 0000000..f69c960 --- /dev/null +++ b/SOURCES/0007-Filesystems-statistics-part-7-Documentation-updates.patch @@ -0,0 +1,80 @@ +From 0df6019dfc15218785a7a684de06541d2bfa2449 Mon Sep 17 00:00:00 2001 +From: Sebastien GODARD +Date: Mon, 20 May 2013 14:57:39 +0200 +Subject: [PATCH] Filesystems statistics (part 7): Documentation updates + +This patch updates sar manual page to describe option -F used to display +filesystems statistics. +CHANGES file is also updated. + +(cherry picked from commit a1999309158fa089e4399ca7b88d0c5fa4c8fef3) +--- + man/sar.in | 45 ++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 44 insertions(+), 1 deletion(-) + +diff --git a/man/sar.in b/man/sar.in +index 1ef4f89..65c89cb 100644 +--- a/man/sar.in ++++ b/man/sar.in +@@ -2,7 +2,7 @@ + .SH NAME + sar \- Collect, report, or save system activity information. + .SH SYNOPSIS +-.B sar [ -A ] [ -B ] [ -b ] [ -C ] [ -d ] [ -H ] [ -h ] [ -p ] [ -q ] [ -R ] ++.B sar [ -A ] [ -B ] [ -b ] [ -C ] [ -d ] [ -F ] [ -H ] [ -h ] [ -p ] [ -q ] [ -R ] + .B [ -r ] [ -S ] [ -t ] [ -u [ ALL ] ] [ -V ] [ -v ] [ -W ] [ -w ] [ -y ] + .B [ -I { + .I int +@@ -320,6 +320,49 @@ or written to a file (options + or + .B -o + ). ++.IP -F ++Display statistics for currently mounted filesystems. Pseudo-filesystems are ++ignored. At the end of the report, ++.B sar ++will display a summary of all those filesystems. The following values are ++displayed: ++ ++.B MBfsfree ++.RS ++.RS ++Total amount a free space in megabytes (including space available only to privileged user). ++.RE ++ ++.B MBfsused ++.RS ++Total amount of space used in megabytes. ++.RE ++ ++.B %fsused ++.RS ++Percentage of filesystem space used, as seen by a privileged user. ++.RE ++ ++.B %ufsused ++.RS ++Percentage of filesystem space used, as seen by an unprivileged user. ++.RE ++ ++.B Ifree ++.RS ++Total number of free file nodes in filesystem. ++.RE ++ ++.B Iused ++.RS ++Total number of file nodes used in filesystem. ++.RE ++ ++.B %Iused ++.RS ++Percentage of file nodes used in filesystem. ++.RE ++.RE + .IP "-f [ filename ]" + Extract records from + .I filename +-- +2.14.3 + diff --git a/SOURCES/0008-Filesystems-stats-Display-unmounted-filesystems-in-s.patch b/SOURCES/0008-Filesystems-stats-Display-unmounted-filesystems-in-s.patch new file mode 100644 index 0000000..f6b7472 --- /dev/null +++ b/SOURCES/0008-Filesystems-stats-Display-unmounted-filesystems-in-s.patch @@ -0,0 +1,83 @@ +From f9752adcd732441cc2d5604cb9b24ecfc29a6acb Mon Sep 17 00:00:00 2001 +From: Sebastien GODARD +Date: Mon, 20 May 2013 17:14:05 +0200 +Subject: [PATCH] Filesystems stats: Display unmounted filesystems in summary + list + +This patch enables sar -F to display filesystems in its summary list (the +last stats displayed by sar) even if those filesystems have been +unmounted before the end of the report. + +(cherry picked from commit c8b1f890f7fc242eceafc94ab3ba117247f3d577) +--- + pr_stats.c | 30 ++++++++++++++++++++++-------- + 1 file changed, 22 insertions(+), 8 deletions(-) + +diff --git a/pr_stats.c b/pr_stats.c +index 85a3a20..d1edb5b 100644 +--- a/pr_stats.c ++++ b/pr_stats.c +@@ -2445,17 +2445,14 @@ __print_funct_t print_avg_pwr_usb_stats(struct activity *a, int prev, int curr, + * + * IN: + * @a Activity structure with statistics. +- * @prev Index in array where stats used as reference are. + * @curr Index in array for current sample statistics. +- * @itv Interval of time in jiffies. + * @dispavg TRUE if displaying average statistics. + *************************************************************************** + */ +-__print_funct_t stub_print_filesystem_stats(struct activity *a, int prev, int curr, +- unsigned long long itv, int dispavg) ++__print_funct_t stub_print_filesystem_stats(struct activity *a, int curr, int dispavg) + { +- int i; +- struct stats_filesystem *sfc; ++ int i, j; ++ struct stats_filesystem *sfc, *sfm; + + + if (dis) { +@@ -2486,6 +2483,23 @@ __print_funct_t stub_print_filesystem_stats(struct activity *a, int prev, int cu + sfc->f_files ? SP_VALUE(sfc->f_ffree, sfc->f_files, sfc->f_files) + : 0.0, + sfc->fs_name); ++ ++ if (!dispavg) { ++ /* Save current filesystem in summary list */ ++ for (j = 0; j < a->nr; j++) { ++ sfm = (struct stats_filesystem *) ((char *) a->buf[2] + j * a->msize); ++ ++ if (!strcmp(sfm->fs_name, sfc->fs_name) || ++ !sfm->f_blocks) { ++ /* ++ * Filesystem found in list (then save again its stats) ++ * or free slot (end of list). ++ */ ++ *sfm = *sfc; ++ break; ++ } ++ } ++ } + } + } + +@@ -2503,7 +2517,7 @@ __print_funct_t stub_print_filesystem_stats(struct activity *a, int prev, int cu + __print_funct_t print_filesystem_stats(struct activity *a, int prev, int curr, + unsigned long long itv) + { +- stub_print_filesystem_stats(a, prev, curr, itv, FALSE); ++ stub_print_filesystem_stats(a, curr, FALSE); + } + + /* +@@ -2520,5 +2534,5 @@ __print_funct_t print_filesystem_stats(struct activity *a, int prev, int curr, + __print_funct_t print_avg_filesystem_stats(struct activity *a, int prev, int curr, + unsigned long long itv) + { +- stub_print_filesystem_stats(a, prev, curr, itv, TRUE); ++ stub_print_filesystem_stats(a, 2, TRUE); + } +-- +2.14.3 + diff --git a/SOURCES/0009-Handle-octal-codes-in-filesystems-mount-point-names.patch b/SOURCES/0009-Handle-octal-codes-in-filesystems-mount-point-names.patch new file mode 100644 index 0000000..f1db439 --- /dev/null +++ b/SOURCES/0009-Handle-octal-codes-in-filesystems-mount-point-names.patch @@ -0,0 +1,99 @@ +From 446f287e43f87b090c65bb17e397bd5e73101e34 Mon Sep 17 00:00:00 2001 +From: Sebastien GODARD +Date: Thu, 30 May 2013 22:26:18 +0200 +Subject: [PATCH] Handle octal codes in filesystems mount point names + +sar -F was unable to get statistics about filesystems whose mount points +(as given by /etc/mtab file) had octal codes in their names. +So now sar replaces those octal codes with their corresponding +characters before trying to collect stats about them. + +(cherry picked from commit 919f10827b763d13427672515f18aa27c93c01bf) +--- + rd_stats.c | 42 ++++++++++++++++++++++++++++++++++++++++++ + rd_stats.h | 2 ++ + 2 files changed, 44 insertions(+) + +diff --git a/rd_stats.c b/rd_stats.c +index 829dae5..c3ef70f 100644 +--- a/rd_stats.c ++++ b/rd_stats.c +@@ -42,6 +42,42 @@ + #define _(string) (string) + #endif + ++/* ++ *************************************************************************** ++ * Replace octal codes in string with their corresponding characters. ++ * ++ * IN: ++ * str String to parse. ++ * ++ * OUT: ++ * @str String with octal codes replaced with characters. ++ *************************************************************************** ++ */ ++void oct2chr(char *str) ++{ ++ int i = 0; ++ int j, len; ++ ++ len = strlen(str); ++ ++ while (i < len - 3) { ++ if ((str[i] == '\\') && ++ (str[i + 1] >= '0') && (str[i + 1] <= '3') && ++ (str[i + 2] >= '0') && (str[i + 2] <= '7') && ++ (str[i + 3] >= '0') && (str[i + 3] <= '7')) { ++ /* Octal code found */ ++ str[i] = (str[i + 1] - 48) * 64 + ++ (str[i + 2] - 48) * 8 + ++ (str[i + 3] - 48); ++ for (j = i + 4; j <= len; j++) { ++ str[j - 3] = str[j]; ++ } ++ len -= 3; ++ } ++ i++; ++ } ++} ++ + /* + *************************************************************************** + * Read CPU statistics and machine uptime. +@@ -1893,6 +1929,9 @@ void read_filesystem(struct stats_filesystem *st_filesystem, int nbr) + /* Read current filesystem name and mount point */ + sscanf(line, "%71s %127s", fs_name, mountp); + ++ /* Replace octal codes */ ++ oct2chr(mountp); ++ + if ((statfs(mountp, &buf) < 0) || (!buf.f_blocks)) + continue; + +@@ -2354,6 +2393,9 @@ int get_filesystem_nr(void) + + /* Read filesystem name and mount point */ + sscanf(line, "%71s %127s", fs_name, mountp); ++ ++ /* Replace octal codes */ ++ oct2chr(mountp); + + /* Check that total size is not null */ + if (statfs(mountp, &buf) < 0) +diff --git a/rd_stats.h b/rd_stats.h +index 3f1edde..279178f 100644 +--- a/rd_stats.h ++++ b/rd_stats.h +@@ -541,6 +541,8 @@ struct stats_filesystem { + *************************************************************************** + */ + ++extern void ++ oct2chr(char *); + extern void + read_stat_cpu(struct stats_cpu *, int, + unsigned long long *, unsigned long long *); +-- +2.14.3 + diff --git a/SOURCES/0010-Collect-filesystems-stats-only-when-sadc-option-S-XD.patch b/SOURCES/0010-Collect-filesystems-stats-only-when-sadc-option-S-XD.patch new file mode 100644 index 0000000..c8fc6eb --- /dev/null +++ b/SOURCES/0010-Collect-filesystems-stats-only-when-sadc-option-S-XD.patch @@ -0,0 +1,121 @@ +From 3cba36331dd2ebd2fd6e34b63a1ed5036823c256 Mon Sep 17 00:00:00 2001 +From: Sebastien GODARD +Date: Wed, 12 Jun 2013 21:39:19 +0200 +Subject: [PATCH] Collect filesystems stats only when sadc option "-S XDISK" is + used + +Make sadc collect filesystems statistics (those displayed by sar option +-F) only when option "-S XDISK" is used. +Filesystems are actually closer to partitions than to disks. So it makes +more sense for sadc to collect them when option "-S XDISK" is used +rather than option "-S DISK". +Update sadc and sar manual pages to reflect the change. + +(cherry picked from commit 7557dfebffc9e6de26ff7a6b715792dfa5a715c1) +--- + activity.c | 2 +- + man/sadc.in | 4 ++-- + man/sar.in | 5 +++-- + sa.h | 1 + + sadc.c | 14 +++++++++++--- + 5 files changed, 18 insertions(+), 8 deletions(-) + +diff --git a/activity.c b/activity.c +index 734df4a..5b0d4a0 100644 +--- a/activity.c ++++ b/activity.c +@@ -1200,7 +1200,7 @@ struct activity filesystem_act = { + .id = A_FILESYSTEM, + .options = AO_NULL, + .magic = ACTIVITY_MAGIC_BASE, +- .group = G_DISK, ++ .group = G_XDISK, + #ifdef SOURCE_SADC + .f_count = wrap_get_filesystem_nr, + .f_count2 = NULL, +diff --git a/man/sadc.in b/man/sadc.in +index 9b75754..2e18999 100644 +--- a/man/sadc.in ++++ b/man/sadc.in +@@ -1,4 +1,4 @@ +-.TH SADC 8 "JULY 2012" Linux "Linux User's Manual" -*- nroff -*- ++.TH SADC 8 "JUNE 2013" Linux "Linux User's Manual" -*- nroff -*- + .SH NAME + sadc \- System activity data collector. + .SH SYNOPSIS +@@ -138,7 +138,7 @@ The + .B XDISK + keyword is an extension to the + .B DISK +-one and indicates that partition statistics should be collected by ++one and indicates that partitions and filesystems statistics should be collected by + .B sadc + in addition to disk statistics. This option works only with kernels 2.6.25 + and later. +diff --git a/man/sar.in b/man/sar.in +index 65c89cb..6f96093 100644 +--- a/man/sar.in ++++ b/man/sar.in +@@ -324,8 +324,9 @@ or + Display statistics for currently mounted filesystems. Pseudo-filesystems are + ignored. At the end of the report, + .B sar +-will display a summary of all those filesystems. The following values are +-displayed: ++will display a summary of all those filesystems. ++Note that filesystems statistics depend on sadc option "-S XDISK" to be collected. ++The following values are displayed: + + .B MBfsfree + .RS +diff --git a/sa.h b/sa.h +index 50349c8..eb2a426 100644 +--- a/sa.h ++++ b/sa.h +@@ -177,6 +177,7 @@ + #define G_SNMP 0x04 + #define G_IPV6 0x08 + #define G_POWER 0x10 ++#define G_XDISK 0x20 + + /* sadc program */ + #define SADC "sadc" +diff --git a/sadc.c b/sadc.c +index 73c15fa..39c95ee 100644 +--- a/sadc.c ++++ b/sadc.c +@@ -137,8 +137,8 @@ void parse_sadc_S_option(char *argv[], int opt) + collect_group_activities(G_DISK, AO_F_NULL); + } + else if (!strcmp(p, K_XDISK)) { +- /* Select group of disk and partition activities */ +- collect_group_activities(G_DISK, AO_F_DISK_PART); ++ /* Select group of disk and partition/filesystem activities */ ++ collect_group_activities(G_DISK + G_XDISK, AO_F_DISK_PART); + } + else if (!strcmp(p, K_SNMP)) { + /* Select group of SNMP activities */ +@@ -155,11 +155,19 @@ void parse_sadc_S_option(char *argv[], int opt) + else if (!strcmp(p, K_ALL) || !strcmp(p, K_XALL)) { + /* Select all activities */ + for (i = 0; i < NR_ACT; i++) { ++ ++ if (!strcmp(p, K_ALL) && (act[i]->group & G_XDISK)) ++ /* ++ * Don't select G_XDISK activities ++ * when option -S ALL is used. ++ */ ++ continue; ++ + act[i]->options |= AO_COLLECTED; + } + if (!strcmp(p, K_XALL)) { + /* Tell sadc to also collect partition statistics */ +- collect_group_activities(G_DISK, AO_F_DISK_PART); ++ collect_group_activities(G_DISK + G_XDISK, AO_F_DISK_PART); + } + } + else if (strspn(argv[opt], DIGITS) == strlen(argv[opt])) { +-- +2.14.3 + diff --git a/SOURCES/0011-Small-fix-for-sar-A-in-sar-manual-page.patch b/SOURCES/0011-Small-fix-for-sar-A-in-sar-manual-page.patch new file mode 100644 index 0000000..dfb75b7 --- /dev/null +++ b/SOURCES/0011-Small-fix-for-sar-A-in-sar-manual-page.patch @@ -0,0 +1,30 @@ +From 1952d089631dae9bfdd158343a97346fca6fd034 Mon Sep 17 00:00:00 2001 +From: Sebastien GODARD +Date: Wed, 26 Jun 2013 21:53:04 +0200 +Subject: [PATCH] Small fix for "sar -A" in sar manual page + +Indicate that filesystems statistics are also included in stats +displayed by sar -A (that is to say: option -F is also set when sar -A +is entered on the command line). + +(cherry picked from commit 43a66c5dfffd5e7e524a7c307da9078588f612eb) +--- + man/sar.in | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/man/sar.in b/man/sar.in +index 6f96093..6d964b3 100644 +--- a/man/sar.in ++++ b/man/sar.in +@@ -145,7 +145,7 @@ command only reports on local activities. + .SH OPTIONS + .IP -A + This is equivalent to specifying +-.BR "-bBdHqrRSuvwWy -I SUM -I XALL -m ALL -n ALL -u ALL -P ALL". ++.BR "-bBdFHqrRSuvwWy -I SUM -I XALL -m ALL -n ALL -u ALL -P ALL". + .IP -B + Report paging statistics. + The following values are displayed: +-- +2.14.3 + diff --git a/SOURCES/0012-Add-option-to-display-mountpoint-names-instead-of-fi.patch b/SOURCES/0012-Add-option-to-display-mountpoint-names-instead-of-fi.patch new file mode 100644 index 0000000..823fe61 --- /dev/null +++ b/SOURCES/0012-Add-option-to-display-mountpoint-names-instead-of-fi.patch @@ -0,0 +1,167 @@ +From b8eaf0cce7cbed0eb56e9fc509961269d718d096 Mon Sep 17 00:00:00 2001 +From: Steve Kay +Date: Fri, 13 Mar 2015 15:24:10 -0700 +Subject: [PATCH] Add option to display mountpoint names instead of filesystem + names. + +(cherry picked from commit d91ecce584d7dedf194714a4d189ecfba6276f6c) +--- + man/sar.in | 23 ++++++++++++++--------- + pr_stats.c | 11 ++++++----- + rd_stats.c | 1 + + rd_stats.h | 1 + + sa.h | 5 +++++ + sa_common.c | 6 ++++++ + sar.c | 5 +++-- + 7 files changed, 36 insertions(+), 16 deletions(-) + +diff --git a/man/sar.in b/man/sar.in +index 6d964b3..4ea6ca0 100644 +--- a/man/sar.in ++++ b/man/sar.in +@@ -315,17 +315,22 @@ value is close to 100%. + Set the ending time of the report. The default ending time is + 18:00:00. Hours must be given in 24-hour format. + This option can be used when data are read from +-or written to a file (options +-.B -f +-or +-.B -o +-). +-.IP -F ++or written to a file (options -f or -o). ++.IP "-F [ MOUNT ]" + Display statistics for currently mounted filesystems. Pseudo-filesystems are +-ignored. At the end of the report, +-.B sar ++ignored. At the end of the report, ++.B sar + will display a summary of all those filesystems. +-Note that filesystems statistics depend on sadc option "-S XDISK" to be collected. ++Note that filesystems statistics depend on ++.B sadc ++option ++.B "-S XDISK" ++to be collected. ++Use of the ++.B MOUNT ++parameter keyword indicates that mountpoint will be reported instead of ++filesystem device. ++ + The following values are displayed: + + .B MBfsfree +diff --git a/pr_stats.c b/pr_stats.c +index d1edb5b..5bee25f 100644 +--- a/pr_stats.c ++++ b/pr_stats.c +@@ -2454,11 +2454,11 @@ __print_funct_t stub_print_filesystem_stats(struct activity *a, int curr, int di + int i, j; + struct stats_filesystem *sfc, *sfm; + +- + if (dis) { + printf("\n%-11s MBfsfree MBfsused %%fsused %%ufsused" +- " Ifree Iused %%Iused FILESYSTEM\n", +- (dispavg ? _("Summary") : timestamp[!curr])); ++ " Ifree Iused %%Iused %s\n", ++ (dispavg ? _("Summary:") : timestamp[!curr]), ++ DISPLAY_MOUNT(a->opt_flags) ? _("MOUNTPOINT") : _("FILESYSTEM")); + } + + for (i = 0; i < a->nr; i++) { +@@ -2482,8 +2482,9 @@ __print_funct_t stub_print_filesystem_stats(struct activity *a, int curr, int di + sfc->f_files - sfc->f_ffree, + sfc->f_files ? SP_VALUE(sfc->f_ffree, sfc->f_files, sfc->f_files) + : 0.0, +- sfc->fs_name); +- ++ ++ DISPLAY_MOUNT(a->opt_flags) ? sfc->mountp : sfc->fs_name); ++ + if (!dispavg) { + /* Save current filesystem in summary list */ + for (j = 0; j < a->nr; j++) { +diff --git a/rd_stats.c b/rd_stats.c +index c3ef70f..24a98f7 100644 +--- a/rd_stats.c ++++ b/rd_stats.c +@@ -1942,6 +1942,7 @@ void read_filesystem(struct stats_filesystem *st_filesystem, int nbr) + st_filesystem_i->f_files = buf.f_files; + st_filesystem_i->f_ffree = buf.f_ffree; + strcpy(st_filesystem_i->fs_name, fs_name); ++ strcpy(st_filesystem_i->mountp, mountp); + } + } + +diff --git a/rd_stats.h b/rd_stats.h +index 279178f..d958104 100644 +--- a/rd_stats.h ++++ b/rd_stats.h +@@ -531,6 +531,7 @@ struct stats_filesystem { + unsigned long long f_files __attribute__ ((aligned (16))); + unsigned long long f_ffree __attribute__ ((aligned (16))); + char fs_name[MAX_FS_LEN] __attribute__ ((aligned (16))); ++ char mountp[MAX_FS_LEN] __attribute__ ((aligned (16))); + }; + + #define STATS_FILESYSTEM_SIZE (sizeof(struct stats_filesystem)) +diff --git a/sa.h b/sa.h +index eb2a426..7d24f2d 100644 +--- a/sa.h ++++ b/sa.h +@@ -129,6 +129,11 @@ + + #define COLLECT_PARTITIONS(m) (((m) & AO_F_DISK_PART) == AO_F_DISK_PART) + ++/* Output flags for option -F */ ++#define AO_F_MOUNT 0x00000001 ++ ++#define DISPLAY_MOUNT(m) (((m) & AO_F_MOUNT) == AO_F_MOUNT) ++ + /* + *************************************************************************** + * Various keywords and constants. +diff --git a/sa_common.c b/sa_common.c +index 3ccf24b..2206e9f 100644 +--- a/sa_common.c ++++ b/sa_common.c +@@ -1284,6 +1284,12 @@ int parse_sar_opt(char *argv[], int *opt, struct activity *act[], + + case 'F': + SELECT_ACTIVITY(A_FILESYSTEM); ++ p = get_activity_position(act, A_FILESYSTEM); ++ if (!*(argv[*opt] + i + 1) && argv[*opt + 1] && !strcmp(argv[*opt + 1], "MOUNT")) { ++ (*opt)++; ++ act[p]->opt_flags |= AO_F_MOUNT; ++ return 0; ++ } + break; + + case 'H': +diff --git a/sar.c b/sar.c +index 2674810..5dfd915 100644 +--- a/sar.c ++++ b/sar.c +@@ -107,7 +107,7 @@ void usage(char *progname) + { + print_usage_title(stderr, progname); + fprintf(stderr, _("Options are:\n" +- "[ -A ] [ -B ] [ -b ] [ -C ] [ -d ] [ -F ] [ -H ] [ -h ] [ -p ] [ -q ] [ -R ]\n" ++ "[ -A ] [ -B ] [ -b ] [ -C ] [ -d ] [ -F [ MOUNTS ] ] [ -H ] [ -h ] [ -p ] [ -q ] [ -R ]\n" + "[ -r ] [ -S ] [ -t ] [ -u [ ALL ] ] [ -V ] [ -v ] [ -W ] [ -w ] [ -y ]\n" + "[ -I { [,...] | SUM | ALL | XALL } ] [ -P { [,...] | ALL } ]\n" + "[ -m { [,...] | ALL } ] [ -n { [,...] | ALL } ]\n" +@@ -132,7 +132,8 @@ void display_help(char *progname) + printf(_("\t-b\tI/O and transfer rate statistics\n")); + printf(_("\t-B\tPaging statistics\n")); + printf(_("\t-d\tBlock device statistics\n")); +- printf(_("\t-F\tFilesystems statistics\n")); ++ printf(_("\t-F [ MOUNTS ]\n")); ++ printf(_("\t\tFilesystems statistics\n")); + printf(_("\t-H\tHugepages utilization statistics\n")); + printf(_("\t-I { | SUM | ALL | XALL }\n" + "\t\tInterrupts statistics\n")); +-- +2.14.3 + diff --git a/SOURCES/0013-Revise-sar-usage-messages-to-be-F-MOUNT-rather-than-.patch b/SOURCES/0013-Revise-sar-usage-messages-to-be-F-MOUNT-rather-than-.patch new file mode 100644 index 0000000..79d36c7 --- /dev/null +++ b/SOURCES/0013-Revise-sar-usage-messages-to-be-F-MOUNT-rather-than-.patch @@ -0,0 +1,36 @@ +From 403ee52b7908de615d0d8be955d9bdc00f419966 Mon Sep 17 00:00:00 2001 +From: Steve Kay +Date: Fri, 12 Jun 2015 14:45:36 -0700 +Subject: [PATCH] Revise sar usage messages to be -F MOUNT rather than -F + MOUNTS, in order to match man page and program functionality. + +(cherry picked from commit 7ebced008f9c067b0959944d6a97e789af905b7b) +--- + sar.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/sar.c b/sar.c +index 5dfd915..a28b739 100644 +--- a/sar.c ++++ b/sar.c +@@ -107,7 +107,7 @@ void usage(char *progname) + { + print_usage_title(stderr, progname); + fprintf(stderr, _("Options are:\n" +- "[ -A ] [ -B ] [ -b ] [ -C ] [ -d ] [ -F [ MOUNTS ] ] [ -H ] [ -h ] [ -p ] [ -q ] [ -R ]\n" ++ "[ -A ] [ -B ] [ -b ] [ -C ] [ -d ] [ -F [ MOUNT ] ] [ -H ] [ -h ] [ -p ] [ -q ] [ -R ]\n" + "[ -r ] [ -S ] [ -t ] [ -u [ ALL ] ] [ -V ] [ -v ] [ -W ] [ -w ] [ -y ]\n" + "[ -I { [,...] | SUM | ALL | XALL } ] [ -P { [,...] | ALL } ]\n" + "[ -m { [,...] | ALL } ] [ -n { [,...] | ALL } ]\n" +@@ -132,7 +132,7 @@ void display_help(char *progname) + printf(_("\t-b\tI/O and transfer rate statistics\n")); + printf(_("\t-B\tPaging statistics\n")); + printf(_("\t-d\tBlock device statistics\n")); +- printf(_("\t-F [ MOUNTS ]\n")); ++ printf(_("\t-F [ MOUNT ]\n")); + printf(_("\t\tFilesystems statistics\n")); + printf(_("\t-H\tHugepages utilization statistics\n")); + printf(_("\t-I { | SUM | ALL | XALL }\n" +-- +2.14.3 + diff --git a/SOURCES/0014-Use-statvfs-instead-of-statfs-system-call.patch b/SOURCES/0014-Use-statvfs-instead-of-statfs-system-call.patch new file mode 100644 index 0000000..e58e250 --- /dev/null +++ b/SOURCES/0014-Use-statvfs-instead-of-statfs-system-call.patch @@ -0,0 +1,80 @@ +From 9728faf84cdc4acc674cc862a99f57d4e6552beb Mon Sep 17 00:00:00 2001 +From: Sebastien GODARD +Date: Sun, 22 Jun 2014 16:09:18 +0200 +Subject: [PATCH] Use statvfs() instead of statfs() system call + +Use statvfs() system call instead of statfs() to get filesystems +statistics with sar since: +1) statfs() has been deprecated by the LSB (useful only to get fs +type which is not needed here), +2) statvfs() better handles large file sizes. + +Signed-off-by: Sebastien GODARD +(cherry picked from commit 0936618a799918422012036aecbf7a2b0ee32354) +--- + rd_stats.c | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +diff --git a/rd_stats.c b/rd_stats.c +index 24a98f7..9f7fc37 100644 +--- a/rd_stats.c ++++ b/rd_stats.c +@@ -27,7 +27,7 @@ + #include + #include + #include +-#include ++#include + #include + + #include "common.h" +@@ -1918,7 +1918,7 @@ void read_filesystem(struct stats_filesystem *st_filesystem, int nbr) + char line[256], fs_name[MAX_FS_LEN], mountp[128]; + int fs = 0; + struct stats_filesystem *st_filesystem_i; +- struct statfs buf; ++ struct statvfs buf; + + if ((fp = fopen(MTAB, "r")) == NULL) + return; +@@ -1931,14 +1931,14 @@ void read_filesystem(struct stats_filesystem *st_filesystem, int nbr) + + /* Replace octal codes */ + oct2chr(mountp); +- +- if ((statfs(mountp, &buf) < 0) || (!buf.f_blocks)) ++ ++ if ((statvfs(mountp, &buf) < 0) || (!buf.f_blocks)) + continue; + + st_filesystem_i = st_filesystem + fs++; +- st_filesystem_i->f_blocks = buf.f_blocks * buf.f_bsize; +- st_filesystem_i->f_bfree = buf.f_bfree * buf.f_bsize; +- st_filesystem_i->f_bavail = buf.f_bavail * buf.f_bsize; ++ st_filesystem_i->f_blocks = buf.f_blocks * buf.f_frsize; ++ st_filesystem_i->f_bfree = buf.f_bfree * buf.f_frsize; ++ st_filesystem_i->f_bavail = buf.f_bavail * buf.f_frsize; + st_filesystem_i->f_files = buf.f_files; + st_filesystem_i->f_ffree = buf.f_ffree; + strcpy(st_filesystem_i->fs_name, fs_name); +@@ -2382,7 +2382,7 @@ int get_filesystem_nr(void) + FILE *fp; + char line[256], fs_name[MAX_FS_LEN], mountp[128]; + int fs = 0; +- struct statfs buf; ++ struct statvfs buf; + + if ((fp = fopen(MTAB, "r")) == NULL) + /* File non-existent */ +@@ -2399,7 +2399,7 @@ int get_filesystem_nr(void) + oct2chr(mountp); + + /* Check that total size is not null */ +- if (statfs(mountp, &buf) < 0) ++ if (statvfs(mountp, &buf) < 0) + continue; + + if (buf.f_blocks) { +-- +2.14.3 + diff --git a/SOURCES/0015-Fix-issue-48-sar-skips-long-filesystem-names.patch b/SOURCES/0015-Fix-issue-48-sar-skips-long-filesystem-names.patch new file mode 100644 index 0000000..b535330 --- /dev/null +++ b/SOURCES/0015-Fix-issue-48-sar-skips-long-filesystem-names.patch @@ -0,0 +1,63 @@ +From f5b70d8a0a4439b9745680a2e4ab433e76f154d5 Mon Sep 17 00:00:00 2001 +From: Sebastien GODARD +Date: Fri, 20 Mar 2015 18:23:11 +0100 +Subject: [PATCH] Fix issue #48: sar skips long filesystem names + +If a filesystem had more than MAX_FS_LEN characters in length, sar +didn't display it. +This patch fixes the problem. + +Signed-off-by: Sebastien GODARD +(cherry picked from commit a82d6abce8ff35a5bf0d060456ca653f722a9f73) +--- + rd_stats.c | 24 +++++++++++++++++++----- + 1 file changed, 19 insertions(+), 5 deletions(-) + +diff --git a/rd_stats.c b/rd_stats.c +index 9f7fc37..eff0348 100644 +--- a/rd_stats.c ++++ b/rd_stats.c +@@ -1915,7 +1915,7 @@ void read_bus_usb_dev(struct stats_pwr_usb *st_pwr_usb, int nbr) + void read_filesystem(struct stats_filesystem *st_filesystem, int nbr) + { + FILE *fp; +- char line[256], fs_name[MAX_FS_LEN], mountp[128]; ++ char line[512], fs_name[MAX_FS_LEN], mountp[256]; + int fs = 0; + struct stats_filesystem *st_filesystem_i; + struct statvfs buf; +@@ -1925,13 +1925,27 @@ void read_filesystem(struct stats_filesystem *st_filesystem, int nbr) + + while ((fgets(line, 256, fp) != NULL) && (fs < nbr)) { + if (line[0] == '/') { +- +- /* Read current filesystem name and mount point */ +- sscanf(line, "%71s %127s", fs_name, mountp); +- ++ ++ /* Read current filesystem name */ ++ sscanf(line, "%127s", fs_name); ++ /* ++ * And now read the corresponding mount point. ++ * Read fs name and mount point in two distinct operations. ++ * Indeed, if fs name length is greater than 127 chars, ++ * previous scanf() will read only the first 127 chars, and ++ * mount point name will be read using the remaining chars ++ * from the fs name. This will result in a bogus name ++ * and following statvfs() function will always fail. ++ */ ++ sscanf(strchr(line, ' ') + 1, "%255s", mountp); ++ + /* Replace octal codes */ + oct2chr(mountp); + ++ /* ++ * It's important to have read the whole mount point name ++ * for statvfs() to work properly (see above). ++ */ + if ((statvfs(mountp, &buf) < 0) || (!buf.f_blocks)) + continue; + +-- +2.14.3 + diff --git a/SOURCES/0016-Fix-issue-48-for-good-sar-skips-long-filesystem-name.patch b/SOURCES/0016-Fix-issue-48-for-good-sar-skips-long-filesystem-name.patch new file mode 100644 index 0000000..7d7e00d --- /dev/null +++ b/SOURCES/0016-Fix-issue-48-for-good-sar-skips-long-filesystem-name.patch @@ -0,0 +1,40 @@ +From fca187ac9893a35f10d20b8d7cfbda00d79c20dd Mon Sep 17 00:00:00 2001 +From: Sebastien GODARD +Date: Tue, 24 Mar 2015 21:38:07 +0100 +Subject: [PATCH] Fix issue #48 for good: sar skips long filesystem names + +How the number of filesystems is counted should be consistent with +commit a82d6ab. + +Signed-off-by: Sebastien GODARD +(cherry picked from commit 1cf65800b12d015ed9add350a6e2b40e6bcd5267) +--- + rd_stats.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/rd_stats.c b/rd_stats.c +index eff0348..cb45d82 100644 +--- a/rd_stats.c ++++ b/rd_stats.c +@@ -2394,7 +2394,7 @@ int get_usb_nr(void) + int get_filesystem_nr(void) + { + FILE *fp; +- char line[256], fs_name[MAX_FS_LEN], mountp[128]; ++ char line[512], fs_name[MAX_FS_LEN], mountp[256]; + int fs = 0; + struct statvfs buf; + +@@ -2407,7 +2407,8 @@ int get_filesystem_nr(void) + if (line[0] == '/') { + + /* Read filesystem name and mount point */ +- sscanf(line, "%71s %127s", fs_name, mountp); ++ sscanf(line, "%127s", fs_name); ++ sscanf(strchr(line, ' ') + 1, "%255s", mountp); + + /* Replace octal codes */ + oct2chr(mountp); +-- +2.14.3 + diff --git a/SOURCES/0017-Use-proper-length-for-mountp-string.patch b/SOURCES/0017-Use-proper-length-for-mountp-string.patch new file mode 100644 index 0000000..e8c1427 --- /dev/null +++ b/SOURCES/0017-Use-proper-length-for-mountp-string.patch @@ -0,0 +1,33 @@ +From 41683b8609f5dea3cb3ae791a8889c86c668d205 Mon Sep 17 00:00:00 2001 +From: Sebastien GODARD +Date: Fri, 27 Mar 2015 16:52:27 +0100 +Subject: [PATCH] Use proper length for mountp string + +We read 256 chars for the mountpoint name to (try to) be sure to get it +all, and so ths statvfs() function won't fail in read_filesystem() +function. +Yet only MAX_FS_LEN chars should be saved in stats_filesystem structure. + +Signed-off-by: Sebastien GODARD +(cherry picked from commit 7d010b8b3646e1d87427aca13feb16ac890d7c4c) +--- + rd_stats.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/rd_stats.c b/rd_stats.c +index cb45d82..f288eb8 100644 +--- a/rd_stats.c ++++ b/rd_stats.c +@@ -1956,7 +1956,8 @@ void read_filesystem(struct stats_filesystem *st_filesystem, int nbr) + st_filesystem_i->f_files = buf.f_files; + st_filesystem_i->f_ffree = buf.f_ffree; + strcpy(st_filesystem_i->fs_name, fs_name); +- strcpy(st_filesystem_i->mountp, mountp); ++ strncpy(st_filesystem_i->mountp, mountp, MAX_FS_LEN); ++ st_filesystem_i->mountp[MAX_FS_LEN - 1] = '\0'; + } + } + +-- +2.14.3 + diff --git a/SOURCES/0018-Replace-strcpy-with-strncpy-to-avoid-buffer-overflow.patch b/SOURCES/0018-Replace-strcpy-with-strncpy-to-avoid-buffer-overflow.patch new file mode 100644 index 0000000..e094937 --- /dev/null +++ b/SOURCES/0018-Replace-strcpy-with-strncpy-to-avoid-buffer-overflow.patch @@ -0,0 +1,148 @@ +From cfaaf34550c5ea92ee9b74d969a0c56c826cd020 Mon Sep 17 00:00:00 2001 +From: Sebastien GODARD +Date: Thu, 11 Aug 2016 09:13:57 +0200 +Subject: [PATCH] Replace strcpy() with strncpy() to avoid buffer overflows + +Using strcpy() is not safe since destination buffer may overflow, for +example if the string being copied doesn't contain a terminator. +This patch replaces strcpy() with strncpy() to make sure no buffer +overflows happen. + +Signed-off-by: Sebastien GODARD +(cherry picked from commit 5aa69b67f03c00eded746c819eaa5b74a021ca1b) +--- + cifsiostat.c | 3 ++- + ioconf.c | 6 ++++-- + iostat.c | 6 ++++-- + rd_stats.c | 5 +++-- + sa_common.c | 8 ++++---- + 5 files changed, 17 insertions(+), 11 deletions(-) + +diff --git a/cifsiostat.c b/cifsiostat.c +index 09b60b2..bca6576 100644 +--- a/cifsiostat.c ++++ b/cifsiostat.c +@@ -345,7 +345,8 @@ void read_cifs_stat(int curr) + else { + start = 1; + } +- strcpy(cifs_name, name_tmp); ++ strncpy(cifs_name, name_tmp, MAX_NAME_LEN); ++ cifs_name[MAX_NAME_LEN - 1] = '\0'; + } + else { + if (!strncmp(line, "Reads:", 6)) { +diff --git a/ioconf.c b/ioconf.c +index 0011320..83008b1 100644 +--- a/ioconf.c ++++ b/ioconf.c +@@ -282,7 +282,8 @@ int ioc_init(void) + * exception info + */ + xblkp->ext_minor = iocp->ctrlno; +- strcpy(xblkp->ext_name, blkp->name); ++ strncpy(xblkp->ext_name, blkp->name, IOC_NAMELEN + 1); ++ xblkp->ext_name[IOC_NAMELEN] = '\0'; + xblkp->ext = 1; + continue; + } +@@ -393,7 +394,8 @@ char *ioc_name(unsigned int major, unsigned int minor) + + /* Is this an extension record? */ + if (p->blkp->ext && (p->blkp->ext_minor == minor)) { +- strcpy(name, p->blkp->ext_name); ++ strncpy(name, p->blkp->ext_name, IOC_DEVLEN + 1); ++ name[IOC_DEVLEN] = '\0'; + return (name); + } + +diff --git a/iostat.c b/iostat.c +index 308a9af..e49daa0 100644 +--- a/iostat.c ++++ b/iostat.c +@@ -366,7 +366,8 @@ void presave_device_list(void) + + /* Now save devices and group names in the io_hdr_stats structures */ + for (i = 0; (i < dlist_idx) && (i < iodev_nr); i++, shi++, sdli++) { +- strcpy(shi->name, sdli->dev_name); ++ strncpy(shi->name, sdli->dev_name, MAX_NAME_LEN); ++ shi->name[MAX_NAME_LEN - 1] = '\0'; + shi->used = TRUE; + if (shi->name[0] == ' ') { + /* Current device name is in fact the name of a group */ +@@ -385,7 +386,8 @@ void presave_device_list(void) + * included in that group. + */ + shi += iodev_nr - 1; +- strcpy(shi->name, group_name); ++ strncpy(shi->name, group_name, MAX_NAME_LEN); ++ shi->name[MAX_NAME_LEN - 1] = '\0'; + shi->used = TRUE; + shi->status = DISK_GROUP; + } +diff --git a/rd_stats.c b/rd_stats.c +index f288eb8..6aa8698 100644 +--- a/rd_stats.c ++++ b/rd_stats.c +@@ -1915,7 +1915,7 @@ void read_bus_usb_dev(struct stats_pwr_usb *st_pwr_usb, int nbr) + void read_filesystem(struct stats_filesystem *st_filesystem, int nbr) + { + FILE *fp; +- char line[512], fs_name[MAX_FS_LEN], mountp[256]; ++ char line[512], fs_name[128], mountp[256]; + int fs = 0; + struct stats_filesystem *st_filesystem_i; + struct statvfs buf; +@@ -1955,7 +1955,8 @@ void read_filesystem(struct stats_filesystem *st_filesystem, int nbr) + st_filesystem_i->f_bavail = buf.f_bavail * buf.f_frsize; + st_filesystem_i->f_files = buf.f_files; + st_filesystem_i->f_ffree = buf.f_ffree; +- strcpy(st_filesystem_i->fs_name, fs_name); ++ strncpy(st_filesystem_i->fs_name, fs_name, MAX_FS_LEN); ++ st_filesystem_i->fs_name[MAX_FS_LEN - 1] = '\0'; + strncpy(st_filesystem_i->mountp, mountp, MAX_FS_LEN); + st_filesystem_i->mountp[MAX_FS_LEN - 1] = '\0'; + } +diff --git a/sa_common.c b/sa_common.c +index 2206e9f..df7d38d 100644 +--- a/sa_common.c ++++ b/sa_common.c +@@ -549,7 +549,7 @@ unsigned int check_net_dev_reg(struct activity *a, int curr, int ref, + * actually unregistered. + */ + memset(sndp, 0, STATS_NET_DEV_SIZE); +- strcpy(sndp->interface, sndc->interface); ++ strncpy(sndp->interface, sndc->interface, MAX_IFACE_LEN - 1); + } + } + return index; +@@ -574,7 +574,7 @@ unsigned int check_net_dev_reg(struct activity *a, int curr, int ref, + sndp = (struct stats_net_dev *) a->buf[ref] + index; + /* Since the name is not the same, reset all the structure */ + memset(sndp, 0, STATS_NET_DEV_SIZE); +- strcpy(sndp->interface, sndc->interface); ++ strncpy(sndp->interface, sndc->interface, MAX_IFACE_LEN - 1); + + return index; + } +@@ -625,7 +625,7 @@ unsigned int check_net_edev_reg(struct activity *a, int curr, int ref, + * actually unregistered. + */ + memset(snedp, 0, STATS_NET_EDEV_SIZE); +- strcpy(snedp->interface, snedc->interface); ++ strncpy(snedp->interface, snedc->interface, MAX_IFACE_LEN - 1); + } + return index; + } +@@ -649,7 +649,7 @@ unsigned int check_net_edev_reg(struct activity *a, int curr, int ref, + snedp = (struct stats_net_edev *) a->buf[ref] + index; + /* Since the name is not the same, reset all the structure */ + memset(snedp, 0, STATS_NET_EDEV_SIZE); +- strcpy(snedp->interface, snedc->interface); ++ strncpy(snedp->interface, snedc->interface, MAX_IFACE_LEN - 1); + + return index; + } +-- +2.14.3 + diff --git a/SOURCES/0019-Cast-variables-to-target-type-before-use.patch b/SOURCES/0019-Cast-variables-to-target-type-before-use.patch new file mode 100644 index 0000000..5413bd5 --- /dev/null +++ b/SOURCES/0019-Cast-variables-to-target-type-before-use.patch @@ -0,0 +1,58 @@ +From abc147f28e5310df4a4c2327f59c7eb65b611254 Mon Sep 17 00:00:00 2001 +From: Sebastien GODARD +Date: Fri, 2 Jun 2017 09:38:40 +0200 +Subject: [PATCH] Cast variables to target type before use + +This patch casts some variables to target type before they are used. +Without this patch, problems may happen (like issue #150) notably on 32 +bit architectures where sizeof(long) is different from sizeof(long +long). + +Signed-off-by: Sebastien GODARD +(cherry picked from commit 7a8306ad184cc2c2e9339c428a98773a7f818e3b) +--- + rd_stats.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/rd_stats.c b/rd_stats.c +index 6aa8698..01276b6 100644 +--- a/rd_stats.c ++++ b/rd_stats.c +@@ -532,7 +532,7 @@ void read_diskstats_io(struct stats_io *st_io) + * OK: It's a (real) device and not a partition. + * Note: Structure should have been initialized first! + */ +- st_io->dk_drive += rd_ios + wr_ios; ++ st_io->dk_drive += (unsigned long long) rd_ios + (unsigned long long) wr_ios; + st_io->dk_drive_rio += rd_ios; + st_io->dk_drive_rblk += rd_sec; + st_io->dk_drive_wio += wr_ios; +@@ -586,7 +586,7 @@ void read_diskstats_disk(struct stats_disk *st_disk, int nbr, int read_part) + st_disk_i = st_disk + dsk++; + st_disk_i->major = major; + st_disk_i->minor = minor; +- st_disk_i->nr_ios = rd_ios + wr_ios; ++ st_disk_i->nr_ios = (unsigned long long) rd_ios + (unsigned long long) wr_ios; + st_disk_i->rd_sect = rd_sec; + st_disk_i->wr_sect = wr_sec; + st_disk_i->rd_ticks = rd_ticks; +@@ -1950,11 +1950,11 @@ void read_filesystem(struct stats_filesystem *st_filesystem, int nbr) + continue; + + st_filesystem_i = st_filesystem + fs++; +- st_filesystem_i->f_blocks = buf.f_blocks * buf.f_frsize; +- st_filesystem_i->f_bfree = buf.f_bfree * buf.f_frsize; +- st_filesystem_i->f_bavail = buf.f_bavail * buf.f_frsize; +- st_filesystem_i->f_files = buf.f_files; +- st_filesystem_i->f_ffree = buf.f_ffree; ++ st_filesystem_i->f_blocks = (unsigned long long) buf.f_blocks * (unsigned long long) buf.f_frsize; ++ st_filesystem_i->f_bfree = (unsigned long long) buf.f_bfree * (unsigned long long) buf.f_frsize; ++ st_filesystem_i->f_bavail = (unsigned long long) buf.f_bavail * (unsigned long long) buf.f_frsize; ++ st_filesystem_i->f_files = (unsigned long long) buf.f_files; ++ st_filesystem_i->f_ffree = (unsigned long long) buf.f_ffree; + strncpy(st_filesystem_i->fs_name, fs_name, MAX_FS_LEN); + st_filesystem_i->fs_name[MAX_FS_LEN - 1] = '\0'; + strncpy(st_filesystem_i->mountp, mountp, MAX_FS_LEN); +-- +2.14.3 + diff --git a/SOURCES/0020-Fix-162-sadc-crashes-on-a-mtab-file-with-really-long.patch b/SOURCES/0020-Fix-162-sadc-crashes-on-a-mtab-file-with-really-long.patch new file mode 100644 index 0000000..3097ab4 --- /dev/null +++ b/SOURCES/0020-Fix-162-sadc-crashes-on-a-mtab-file-with-really-long.patch @@ -0,0 +1,139 @@ +From 01efeb144322c61e53cc4e21783ce0a69ec28922 Mon Sep 17 00:00:00 2001 +From: Sebastien GODARD +Date: Sat, 26 Aug 2017 14:42:28 +0200 +Subject: [PATCH] Fix #162: sadc crashes on a mtab file with really long lines + +A segmentation fault may happen with "sadc -S DISK..." or +"sadc -S XDISK..." when lines longer than 512 bytes are read from +/etc/mtab. + +Such lines are possible for instance when overlay2 filesystem +with docker is used. In such a case a single mtab entry can look +like this (note that new line characters were added for readability, +the original entry contained only one '\n' at the end): + +overlay /var/lib/docker/overlay2/f23d2377a67b9ab1b49555ecd09b2ccdc03 +7e0ee5d9e54f87e59f07f4398e71f/merged overlay rw,relatime,lowerdir=/v +ar/lib/docker/overlay2/l/L6VKIYXWBQSJ5R7V35SS43R6Y6:/var/lib/docker/ +overlay2/l/UCCHKGXUJPWCMLHR36IZJNNIQP:/var/lib/docker/overlay2/l/RKV +YEXD2FH65FTMK76RDWPLESX:/var/lib/docker/overlay2/l/DX4JZRKTFP2GOO4V6 +OWQ6CPJFY:/var/lib/docker/overlay2/l/6CYNWDKADUPPDZJ5IHOH2R7Y5S:/var +/lib/docker/overlay2/l/JTPINUZIATXADL6XWFHG2OYGSF:/var/lib/docker/ov +erlay2/l/OTSTIV5TTRHF4IUD7BODQ2FUON:/var/lib/docker/overlay2/l/QFNH3 +EFS5EZGRTC4DPHU3PJ4TU:/var/lib/docker/overlay2/l/ZOOUKT2E5U4CSLP57Z7 +MXYX5CD:/var/lib/docker/overlay2/l/3LUU6IDR2HWPTVBARC5K6XSMRC:/var/l +ib/docker/overlay2/l/XOHYBP4RWXQKQZ43I7JKG24KE4:/var/lib/docker/over +lay2/l/MN5M5B7AY5LPXQQC6V2MBJWWBF:/var/lib/docker/overlay2/l/3DRMKQ3 +4AIZD2AROU3TVK3OCUT:/var/lib/docker/overlay2/l/73ZXDHBV6C53Q3SPXA57E +OLGHU:/var/lib/docker/overlay2/l/C2IZBQ55EUTGEAAORSLE73ZPNM:/var/lib +/docker/overlay2/l/ITHARNV7RPWN5S3BCZ2QDMZIMJ:/var/lib/docker/overla +y2/l/TQKUV4LEG4AFUUCMFHHRLDBHAH:/var/lib/docker/overlay2/l/N75JZWPPD +EKJ4DTN4GMEGTDIZL:/var/lib/docker/overlay2/l/QGUUYAETPMK643DG3AKWJAI +IZA,upperdir=/var/lib/docker/overlay2/f23d2377a67b9ab1b49555ecd09b2c +cdc037e0ee5d9e54f87e59f07f4398e71f/diff,workdir=/var/lib/docker/over +lay2/f23d2377a67b9ab1b49555ecd09b2ccdc037e0ee5d9e54f87e59f07f4398e71 +f/work 0 0 + +The crash occurs in the get_filesystem_nr() and read_filesystem() +functions which call strchr(line, ' ') but fail to check if the result +is not NULL. + +This patch adds this check, and when a single mtab entry requires more +that one call to fgets() (i.e. the entry is longer than 512 bytes), it +ignores outcome of the second and following calls. + +Bugs-Debian: https://bugs.debian.org/872926 +Signed-off-by: Robert Luberda +Signed-off-by: Sebastien GODARD +(cherry picked from commit d40c8ecc530303d7e802617f21a9ac85dbcd68bd) +--- + rd_stats.c | 41 ++++++++++++++++++++++++++++++++++++----- + 1 file changed, 36 insertions(+), 5 deletions(-) + +diff --git a/rd_stats.c b/rd_stats.c +index 01276b6..c054b58 100644 +--- a/rd_stats.c ++++ b/rd_stats.c +@@ -1916,15 +1916,30 @@ void read_filesystem(struct stats_filesystem *st_filesystem, int nbr) + { + FILE *fp; + char line[512], fs_name[128], mountp[256]; +- int fs = 0; ++ int fs = 0, skip = 0, skip_next = 0; ++ char *pos = 0; + struct stats_filesystem *st_filesystem_i; + struct statvfs buf; + + if ((fp = fopen(MTAB, "r")) == NULL) + return; + +- while ((fgets(line, 256, fp) != NULL) && (fs < nbr)) { ++ while ((fgets(line, sizeof(line), fp) != NULL) && (fs < nbr)) { ++ /* ++ * Ignore line if the preceding line did not contain '\n'. ++ * (Some very long lines may be found for instance when ++ * overlay2 filesystem with docker is used). ++ */ ++ skip = skip_next; ++ skip_next = (strchr(line, '\n') == NULL); ++ if (skip) ++ continue; ++ + if (line[0] == '/') { ++ /* Find field separator position */ ++ pos = strchr(line, ' '); ++ if (pos == NULL) ++ continue; + + /* Read current filesystem name */ + sscanf(line, "%127s", fs_name); +@@ -1937,7 +1952,7 @@ void read_filesystem(struct stats_filesystem *st_filesystem, int nbr) + * from the fs name. This will result in a bogus name + * and following statvfs() function will always fail. + */ +- sscanf(strchr(line, ' ') + 1, "%255s", mountp); ++ sscanf(pos + 1, "%255s", mountp); + + /* Replace octal codes */ + oct2chr(mountp); +@@ -2397,7 +2412,9 @@ int get_filesystem_nr(void) + { + FILE *fp; + char line[512], fs_name[MAX_FS_LEN], mountp[256]; +- int fs = 0; ++ int fs = 0, skip = 0, skip_next = 0; ++ char *pos = 0; ++ + struct statvfs buf; + + if ((fp = fopen(MTAB, "r")) == NULL) +@@ -2406,11 +2423,25 @@ int get_filesystem_nr(void) + + /* Get current filesystem */ + while (fgets(line, 256, fp) != NULL) { ++ /* ++ * Ignore line if the preceding line did not contain '\n'. ++ * (Some very long lines may be found for instance when ++ * overlay2 filesystem with docker is used). ++ */ ++ skip = skip_next; ++ skip_next = (strchr(line, '\n') == NULL); ++ if (skip) ++ continue; ++ + if (line[0] == '/') { ++ /* Find field separator position */ ++ pos = strchr(line, ' '); ++ if (pos == NULL) ++ continue; + + /* Read filesystem name and mount point */ + sscanf(line, "%127s", fs_name); +- sscanf(strchr(line, ' ') + 1, "%255s", mountp); ++ sscanf(pos + 1, "%255s", mountp); + + /* Replace octal codes */ + oct2chr(mountp); +-- +2.14.3 + diff --git a/SOURCES/0021-Increase-maximum-fs-name-length-to-128.patch b/SOURCES/0021-Increase-maximum-fs-name-length-to-128.patch new file mode 100644 index 0000000..fdb199f --- /dev/null +++ b/SOURCES/0021-Increase-maximum-fs-name-length-to-128.patch @@ -0,0 +1,29 @@ +From 781b16fc258de2d5f4e4fd6e096ce3d7b70caa51 Mon Sep 17 00:00:00 2001 +From: Sebastien GODARD +Date: Fri, 20 Mar 2015 17:10:16 +0100 +Subject: [PATCH] Increase maximum fs name length to 128 + +Previous value was 72 and was considered a bit too small. + +Signed-off-by: Sebastien GODARD +(cherry picked from commit 81d449c28e69ca4fce6009f32e3846bdc892ff64) +--- + rd_stats.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/rd_stats.h b/rd_stats.h +index d958104..9519f13 100644 +--- a/rd_stats.h ++++ b/rd_stats.h +@@ -28,7 +28,7 @@ + /* Maximum length of USB product string */ + #define MAX_PROD_LEN 48 + /* Maximum length of filesystem name */ +-#define MAX_FS_LEN 72 ++#define MAX_FS_LEN 128 + + #define CNT_DEV 0 + #define CNT_PART 1 +-- +2.14.3 + diff --git a/SOURCES/sysstat-10.0.0-makefile.patch b/SOURCES/sysstat-10.0.0-makefile.patch new file mode 100644 index 0000000..65f12c6 --- /dev/null +++ b/SOURCES/sysstat-10.0.0-makefile.patch @@ -0,0 +1,13 @@ +diff -up sysstat-10.0.0/Makefile.in.pom sysstat-10.0.0/Makefile.in +--- sysstat-10.0.0/Makefile.in.pom 2011-03-06 16:46:23.000000000 +0100 ++++ sysstat-10.0.0/Makefile.in 2011-04-04 10:23:02.000000000 +0200 +@@ -196,8 +196,8 @@ librdsensors.a: librdsensors.a(rd_sensor + + sadc.o: sadc.c sa.h version.h common.h ioconf.h sysconfig.h rd_stats.h rd_sensors.h + +-sadc: LFLAGS += $(LFSENSORS) + sadc: sadc.o act_sadc.o sa_wrap.o sa_common.o librdstats.a librdsensors.a libsyscom.a ++ $(CC) -o $@ $(CFLAGS) $^ $(LFLAGS) -lsensors + + sar.o: sar.c sa.h version.h common.h ioconf.h pr_stats.h sysconfig.h + diff --git a/SOURCES/sysstat-10.1.5-dyn-tick.patch b/SOURCES/sysstat-10.1.5-dyn-tick.patch new file mode 100644 index 0000000..133fa0d --- /dev/null +++ b/SOURCES/sysstat-10.1.5-dyn-tick.patch @@ -0,0 +1,48 @@ +diff -ur sysstat-10.1.5.orig/common.c sysstat-10.1.5/common.c +--- sysstat-10.1.5.orig/common.c 2013-03-23 17:31:46.000000000 +0100 ++++ sysstat-10.1.5/common.c 2014-09-01 22:29:48.173500407 +0200 +@@ -501,26 +501,13 @@ + hz = (unsigned int) ticks; + } + +-/* +- *************************************************************************** +- * Handle overflow conditions properly for counters which are read as +- * unsigned long long, but which can be unsigned long long or +- * unsigned long only depending on the kernel version used. +- * @value1 and @value2 being two values successively read for this +- * counter, if @value2 < @value1 and @value1 <= 0xffffffff, then we can +- * assume that the counter's type was unsigned long and has overflown, and +- * so the difference @value2 - @value1 must be casted to this type. +- * NOTE: These functions should no longer be necessary to handle a particular +- * stat counter when we can assume that everybody is using a recent kernel +- * (defining this counter as unsigned long long). +- *************************************************************************** +- */ + double ll_sp_value(unsigned long long value1, unsigned long long value2, + unsigned long long itv) + { +- if ((value2 < value1) && (value1 <= 0xffffffff)) +- /* Counter's type was unsigned long and has overflown */ +- return ((double) ((value2 - value1) & 0xffffffff)) / itv * 100; ++ /* Workaround: dyn-tick kernel has a race issue and /proc/stat values ++ could be backward. */ ++ if (value2 < value1) ++ return (double) 0; + else + return SP_VALUE(value1, value2, itv); + } +@@ -528,9 +515,10 @@ + double ll_s_value(unsigned long long value1, unsigned long long value2, + unsigned long long itv) + { +- if ((value2 < value1) && (value1 <= 0xffffffff)) +- /* Counter's type was unsigned long and has overflown */ +- return ((double) ((value2 - value1) & 0xffffffff)) / itv * HZ; ++ /* Workaround: dyn-tick kernel has a race issue and /proc/stat values ++ could be backward. */ ++ if (value2 < value1) ++ return (double) 0; + else + return S_VALUE(value1, value2, itv); + } diff --git a/SOURCES/sysstat-10.1.5-elapsed-time.patch b/SOURCES/sysstat-10.1.5-elapsed-time.patch new file mode 100644 index 0000000..6ecd64c --- /dev/null +++ b/SOURCES/sysstat-10.1.5-elapsed-time.patch @@ -0,0 +1,24 @@ +diff -ur sysstat-10.1.5.orig/man/iostat.in sysstat-10.1.5/man/iostat.in +--- sysstat-10.1.5.orig/man/iostat.in 2012-11-27 21:20:34.000000000 +0100 ++++ sysstat-10.1.5/man/iostat.in 2014-11-11 17:44:29.563840350 +0100 +@@ -264,7 +264,7 @@ + .RE + .B %util + .RS +-Percentage of CPU time during which I/O requests were issued to the device ++Percentage of elapsed time during which I/O requests were issued to the device + (bandwidth utilization for the device). Device saturation occurs when this + value is close to 100%. + .RE +diff -ur sysstat-10.1.5.orig/man/sar.in sysstat-10.1.5/man/sar.in +--- sysstat-10.1.5.orig/man/sar.in 2012-09-30 15:11:06.000000000 +0200 ++++ sysstat-10.1.5/man/sar.in 2014-11-11 17:45:00.682712161 +0100 +@@ -306,7 +306,7 @@ + + .B %util + .RS +-Percentage of CPU time during which I/O requests were issued to the device ++Percentage of elapsed time during which I/O requests were issued to the device + (bandwidth utilization for the device). Device saturation occurs when this + value is close to 100%. + .RE diff --git a/SOURCES/sysstat-10.1.5-int-handler.patch b/SOURCES/sysstat-10.1.5-int-handler.patch new file mode 100644 index 0000000..7a5f959 --- /dev/null +++ b/SOURCES/sysstat-10.1.5-int-handler.patch @@ -0,0 +1,27 @@ +diff -upr sysstat-10.1.5.orig/sadc.c sysstat-10.1.5/sadc.c +--- sysstat-10.1.5.orig/sadc.c 2013-03-23 17:31:46.000000000 +0100 ++++ sysstat-10.1.5/sadc.c 2016-04-29 17:52:11.438614928 +0200 +@@ -225,17 +225,19 @@ void alarm_handler(int sig) + */ + void int_handler(int sig) + { +- if (!optz) { +- /* sadc hasn't been called by sar */ ++ pid_t ppid = getppid(); ++ ++ if (!optz || (ppid == 1)) { ++ /* sadc hasn't been called by sar or sar process is already dead */ + exit(1); + } +- ++ + /* + * When starting sar then pressing ctrl/c, SIGINT is received + * by sadc, not sar. So send SIGINT to sar so that average stats + * can be displayed. + */ +- if (kill(getppid(), SIGINT) < 0) { ++ if (kill(ppid, SIGINT) < 0) { + exit(1); + } + } diff --git a/SOURCES/sysstat-10.1.5-max-cpus.patch b/SOURCES/sysstat-10.1.5-max-cpus.patch new file mode 100644 index 0000000..a593952 --- /dev/null +++ b/SOURCES/sysstat-10.1.5-max-cpus.patch @@ -0,0 +1,16 @@ +diff -upr sysstat-10.1.5.orig/common.h sysstat-10.1.5/common.h +--- sysstat-10.1.5.orig/common.h 2016-04-29 14:12:25.709765182 +0200 ++++ sysstat-10.1.5/common.h 2016-04-29 14:15:21.463578820 +0200 +@@ -28,10 +28,10 @@ + #define SEC_PER_DAY 3600 * 24 + + /* Maximum number of CPUs */ +-#if defined(__CPU_SETSIZE) && __CPU_SETSIZE > 2048 ++#if defined(__CPU_SETSIZE) && __CPU_SETSIZE > 8192 + #define NR_CPUS __CPU_SETSIZE + #else +-#define NR_CPUS 2048 ++#define NR_CPUS 8192 + #endif + + /* Maximum number of interrupts */ diff --git a/SOURCES/sysstat-10.1.5-max-name-len.patch b/SOURCES/sysstat-10.1.5-max-name-len.patch new file mode 100644 index 0000000..29fe860 --- /dev/null +++ b/SOURCES/sysstat-10.1.5-max-name-len.patch @@ -0,0 +1,35 @@ +diff -upr sysstat-10.1.5.orig/common.h sysstat-10.1.5/common.h +--- sysstat-10.1.5.orig/common.h 2016-04-29 14:29:24.298889634 +0200 ++++ sysstat-10.1.5/common.h 2016-04-29 14:30:10.589577176 +0200 +@@ -69,7 +69,7 @@ + #define MAX_FILE_LEN 256 + #define MAX_PF_NAME 1024 + #define DEFAULT_DEVMAP_MAJOR 253 +-#define MAX_NAME_LEN 72 ++#define MAX_NAME_LEN 128 + + #define IGNORE_VIRTUAL_DEVICES FALSE + #define ACCEPT_VIRTUAL_DEVICES TRUE +diff -upr sysstat-10.1.5.orig/iostat.c sysstat-10.1.5/iostat.c +--- sysstat-10.1.5.orig/iostat.c 2013-03-23 17:31:46.000000000 +0100 ++++ sysstat-10.1.5/iostat.c 2016-04-29 15:02:24.264492629 +0200 +@@ -748,7 +748,8 @@ void read_diskstats_stat(int curr) + * (if different from "nodev") works around known issues + * with EMC PowerPath. + */ +- strncpy(dev_name, ioc_dname, MAX_NAME_LEN); ++ strncpy(dev_name, ioc_dname, MAX_NAME_LEN - 1); ++ dev_name[MAX_NAME_LEN - 1] = '\0'; + } + } + +@@ -759,7 +760,8 @@ void read_diskstats_stat(int curr) + */ + dm_name = transform_devmapname(major, minor); + if (dm_name) { +- strncpy(dev_name, dm_name, MAX_NAME_LEN); ++ strncpy(dev_name, dm_name, MAX_NAME_LEN - 1); ++ dev_name[MAX_NAME_LEN - 1] = '\0'; + } + } + diff --git a/SOURCES/sysstat-10.1.5-nfsiostat.patch b/SOURCES/sysstat-10.1.5-nfsiostat.patch new file mode 100644 index 0000000..9e4a382 --- /dev/null +++ b/SOURCES/sysstat-10.1.5-nfsiostat.patch @@ -0,0 +1,2119 @@ +diff -uprN sysstat-10.1.5.orig/configure sysstat-10.1.5/configure +--- sysstat-10.1.5.orig/configure 2013-03-13 15:28:25.000000000 +0100 ++++ sysstat-10.1.5/configure 2016-05-24 18:25:16.209668309 +0200 +@@ -5388,7 +5388,7 @@ ac_config_files="$ac_config_files man/io + # File must be renamed + ac_config_files="$ac_config_files man/cifsiostat.1:man/cifsiostat.in" + # File must be renamed +-ac_config_files="$ac_config_files man/nfsiostat.1:man/nfsiostat.in" ++ac_config_files="$ac_config_files man/nfsiostat-sysstat.1:man/nfsiostat-sysstat.in" + # File must be renamed + ac_config_files="$ac_config_files contrib/isag/isag" + # Permissions must be changed +@@ -6120,7 +6120,7 @@ do + "man/sysstat.5") CONFIG_FILES="$CONFIG_FILES man/sysstat.5:man/sysstat.in" ;; + "man/iostat.1") CONFIG_FILES="$CONFIG_FILES man/iostat.1:man/iostat.in" ;; + "man/cifsiostat.1") CONFIG_FILES="$CONFIG_FILES man/cifsiostat.1:man/cifsiostat.in" ;; +- "man/nfsiostat.1") CONFIG_FILES="$CONFIG_FILES man/nfsiostat.1:man/nfsiostat.in" ;; ++ "man/nfsiostat-sysstat.1") CONFIG_FILES="$CONFIG_FILES man/nfsiostat-sysstat.1:man/nfsiostat-sysstat.in" ;; + "contrib/isag/isag") CONFIG_FILES="$CONFIG_FILES contrib/isag/isag" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + +diff -uprN sysstat-10.1.5.orig/configure.in sysstat-10.1.5/configure.in +--- sysstat-10.1.5.orig/configure.in 2013-03-13 15:28:17.000000000 +0100 ++++ sysstat-10.1.5/configure.in 2016-05-24 18:25:16.209668309 +0200 +@@ -580,7 +580,7 @@ AC_CONFIG_FILES([man/sar.1:man/sar.in]) + AC_CONFIG_FILES([man/sysstat.5:man/sysstat.in]) # File must be renamed + AC_CONFIG_FILES([man/iostat.1:man/iostat.in]) # File must be renamed + AC_CONFIG_FILES([man/cifsiostat.1:man/cifsiostat.in]) # File must be renamed +-AC_CONFIG_FILES([man/nfsiostat.1:man/nfsiostat.in]) # File must be renamed ++AC_CONFIG_FILES([man/nfsiostat-sysstat.1:man/nfsiostat-sysstat.in]) # File must be renamed + AC_CONFIG_FILES([contrib/isag/isag], [chmod +x contrib/isag/isag]) # Permissions must be changed + + AC_OUTPUT(Makefile) +diff -uprN sysstat-10.1.5.orig/Makefile.in sysstat-10.1.5/Makefile.in +--- sysstat-10.1.5.orig/Makefile.in 2016-05-24 18:33:48.438839524 +0200 ++++ sysstat-10.1.5/Makefile.in 2016-05-24 18:25:16.209668309 +0200 +@@ -160,7 +160,7 @@ NLSPOT= $(NLSPO:.po=.pot) + % : %.o + $(CC) -o $@ $(CFLAGS) $^ $(LFLAGS) + +-all: sadc sar sadf iostat mpstat pidstat nfsiostat cifsiostat locales ++all: sadc sar sadf iostat mpstat pidstat nfsiostat-sysstat cifsiostat locales + + common.o: common.c version.h common.h ioconf.h sysconfig.h + +@@ -229,9 +229,9 @@ mpstat.o: mpstat.c mpstat.h version.h co + + mpstat: mpstat.o librdstats.a libsyscom.a + +-nfsiostat.o: nfsiostat.c nfsiostat.h version.h common.h ++nfsiostat-sysstat.o: nfsiostat-sysstat.c nfsiostat-sysstat.h version.h common.h + +-nfsiostat: nfsiostat.o librdstats.a libsyscom.a ++nfsiostat-sysstat: nfsiostat-sysstat.o librdstats.a libsyscom.a + + cifsiostat.o: cifsiostat.c cifsiostat.h version.h common.h + +@@ -273,8 +273,8 @@ ifeq ($(INSTALL_DOC),y) + $(INSTALL_DATA) $(MANGRPARG) man/mpstat.1 $(DESTDIR)$(MAN1_DIR) + rm -f $(DESTDIR)$(MAN1_DIR)/pidstat.1* + $(INSTALL_DATA) $(MANGRPARG) man/pidstat.1 $(DESTDIR)$(MAN1_DIR) +- rm -f $(DESTDIR)$(MAN1_DIR)/nfsiostat.1* +- $(INSTALL_DATA) $(MANGRPARG) man/nfsiostat.1 $(DESTDIR)$(MAN1_DIR) ++ rm -f $(DESTDIR)$(MAN1_DIR)/nfsiostat-sysstat.1* ++ $(INSTALL_DATA) $(MANGRPARG) man/nfsiostat-sysstat.1 $(DESTDIR)$(MAN1_DIR) + rm -f $(DESTDIR)$(MAN1_DIR)/cifsiostat.1* + $(INSTALL_DATA) $(MANGRPARG) man/cifsiostat.1 $(DESTDIR)$(MAN1_DIR) + ifeq ($(INSTALL_ISAG),y) +@@ -290,7 +290,7 @@ ifeq ($(COMPRESS_MANPG),y) + $(ZIP) $(DESTDIR)$(MAN1_DIR)/iostat.1 + $(ZIP) $(DESTDIR)$(MAN1_DIR)/mpstat.1 + $(ZIP) $(DESTDIR)$(MAN1_DIR)/pidstat.1 +- $(ZIP) $(DESTDIR)$(MAN1_DIR)/nfsiostat.1 ++ $(ZIP) $(DESTDIR)$(MAN1_DIR)/nfsiostat-sysstat.1 + $(ZIP) $(DESTDIR)$(MAN1_DIR)/cifsiostat.1 + ifeq ($(INSTALL_ISAG),y) + $(ZIP) $(DESTDIR)$(MAN1_DIR)/isag.1 +@@ -330,7 +330,7 @@ endif + $(INSTALL_BIN) iostat $(DESTDIR)$(BIN_DIR) + $(INSTALL_BIN) mpstat $(DESTDIR)$(BIN_DIR) + $(INSTALL_BIN) pidstat $(DESTDIR)$(BIN_DIR) +- $(INSTALL_BIN) nfsiostat $(DESTDIR)$(BIN_DIR) ++ $(INSTALL_BIN) nfsiostat-sysstat $(DESTDIR)$(BIN_DIR) + $(INSTALL_BIN) cifsiostat $(DESTDIR)$(BIN_DIR) + ifeq ($(INSTALL_ISAG),y) + $(INSTALL_BIN) contrib/isag/isag $(DESTDIR)$(BIN_DIR) +@@ -397,7 +397,7 @@ ifeq ($(INSTALL_DOC),y) + rm -f $(DESTDIR)$(MAN1_DIR)/iostat.1* + rm -f $(DESTDIR)$(MAN1_DIR)/mpstat.1* + rm -f $(DESTDIR)$(MAN1_DIR)/pidstat.1* +- rm -f $(DESTDIR)$(MAN1_DIR)/nfsiostat.1* ++ rm -f $(DESTDIR)$(MAN1_DIR)/nfsiostat-sysstat.1* + rm -f $(DESTDIR)$(MAN1_DIR)/cifsiostat.1* + ifeq ($(INSTALL_ISAG),y) + rm -f $(DESTDIR)$(MAN1_DIR)/isag.1 +@@ -425,7 +425,7 @@ uninstall_base: uninstall_man uninstall_ + rm -f $(DESTDIR)$(BIN_DIR)/iostat + rm -f $(DESTDIR)$(BIN_DIR)/mpstat + rm -f $(DESTDIR)$(BIN_DIR)/pidstat +- rm -f $(DESTDIR)$(BIN_DIR)/nfsiostat ++ rm -f $(DESTDIR)$(BIN_DIR)/nfsiostat-sysstat + rm -f $(DESTDIR)$(BIN_DIR)/cifsiostat + ifeq ($(INSTALL_ISAG),y) + rm -f $(DESTDIR)$(BIN_DIR)/isag +@@ -487,7 +487,7 @@ po-files: + endif + + clean: +- rm -f sadc sar sadf iostat mpstat pidstat nfsiostat cifsiostat *.o *.a core TAGS ++ rm -f sadc sar sadf iostat mpstat pidstat nfsiostat-sysstat cifsiostat *.o *.a core TAGS + find nls -name "*.gmo" -exec rm -f {} \; + + almost-distclean: clean nls/sysstat.pot +@@ -496,7 +496,7 @@ almost-distclean: clean nls/sysstat.pot + rm -f cron/sysstat.cron.hourly cron/sysstat.crond.sample cron/sysstat.crond.sample.in + rm -f contrib/isag/isag + rm -f man/sa1.8 man/sa2.8 man/sadc.8 man/sadf.1 man/sar.1 man/iostat.1 man/sysstat.5 +- rm -f man/cifsiostat.1 man/nfsiostat.1 ++ rm -f man/cifsiostat.1 man/nfsiostat-sysstat.1 + rm -f *.log config.status + rm -rf autom4te.cache + rm -f *.save *.old .*.swp data +diff -uprN sysstat-10.1.5.orig/man/nfsiostat.in sysstat-10.1.5/man/nfsiostat.in +--- sysstat-10.1.5.orig/man/nfsiostat.in 2012-07-13 08:48:55.000000000 +0200 ++++ sysstat-10.1.5/man/nfsiostat.in 1970-01-01 01:00:00.000000000 +0100 +@@ -1,175 +0,0 @@ +-.TH NFSIOSTAT 1 "JULY 2012" Linux "Linux User's Manual" -*- nroff -*- +-.SH NAME +-nfsiostat \- Report input/output statistics for network filesystems (NFS). +-.SH SYNOPSIS +-.ie 'yes'@WITH_DEBUG@' \{ +-.B nfsiostat [ -h ] [ -k | -m ] [ -t ] [ -V ] [ --debuginfo ] [ +-.I interval +-.B [ +-.I count +-.B ] ] +-.\} +-.el \{ +-.B nfsiostat [ -h ] [ -k | -m ] [ -t ] [ -V ] [ +-.I interval +-.B [ +-.I count +-.B ] ] +-.\} +-.SH DESCRIPTION +-The +-.B nfsiostat +-command displays statistics about read and write operations +-on NFS filesystems. +- +-The +-.I interval +-parameter specifies the amount of time in seconds between +-each report. The first report contains statistics for the time since +-system startup (boot). Each subsequent report contains statistics +-collected during the interval since the previous report. +-A report consists of an NFS header row followed by +-a line of statistics for each network filesystem that is mounted. +-The +-.I count +-parameter can be specified in conjunction with the +-.I interval +-parameter. If the +-.I count +-parameter is specified, the value of +-.I count +-determines the number of reports generated at +-.I interval +-seconds apart. If the +-.I interval +-parameter is specified without the +-.I count +-parameter, the +-.B nfsiostat +-command generates reports continuously. +- +-.SH REPORT +-The Network Filesystem (NFS) report provides statistics for each mounted network filesystem. +-Transfer rates are shown in 1K blocks by default, unless the environment +-variable POSIXLY_CORRECT is set, in which case 512-byte blocks are used. +-The report shows the following fields: +- +-.B Filesystem: +-.RS +-This columns shows the hostname of the NFS server followed by a colon and +-by the directory name where the network filesystem is mounted. +- +-.RE +-.B rBlk_nor/s (rkB_nor/s, rMB_nor) +-.RS +-Indicate the number of blocks (kilobytes, megabytes) read by applications +-via the read(2) system +-call interface. A block has a size of 512 bytes. +- +-.RE +-.B wBlk_nor/s (wkB_nor/s, wMB_nor/s) +-.RS +-Indicate the number of blocks (kilobytes, megabytes) written by applications +-via the write(2) system +-call interface. +- +-.RE +-.B rBlk_dir/s (rkB_dir/s, rMB_dir/s) +-.RS +-Indicate the number of blocks (kilobytes, megabytes) read from files +-opened with the O_DIRECT flag. +- +-.RE +-.B wBlk_dir/s (wkB_dir/s, wMB_dir/s) +-.RS +-Indicate the number of blocks (kilobytes, megabytes) written to files +-opened with the O_DIRECT flag. +- +-.RE +-.B rBlk_svr/s (rkB_svr/s, rMB_svr/s) +-.RS +-Indicate the number of blocks (kilobytes, megabytes) read from the server +-by the NFS client via an NFS READ request. +- +-.RE +-.B wBlk_svr/s (wkB_svr/s, wMB_svr/s) +-.RS +-Indicate the number of blocks (kilobytes, megabytes) written to the server +-by the NFS client via an NFS WRITE request. +- +-.RE +-.B ops/s +-.RS +-Indicate the number of operations that were issued to the filesystem per second. +- +-.RE +-.B rops/s +-.RS +-Indicate the number of 'read' operations that were issued to the filesystem +-per second. +- +-.RE +-.B wops/s +-.RS +-Indicate the number of 'write' operations that were issued to the filesystem +-per second. +-.RE +-.RE +-.SH OPTIONS +-.if 'yes'@WITH_DEBUG@' \{ +-.IP --debuginfo +-Print debug output to stderr. +-.\} +-.IP -h +-Make the NFS report easier to read by a human. +-.IP -k +-Display statistics in kilobytes per second. +-.IP -m +-Display statistics in megabytes per second. +-.IP -t +-Print the time for each report displayed. The timestamp format may depend +-on the value of the S_TIME_FORMAT environment variable (see below). +-.IP -V +-Print version number then exit. +- +-.SH ENVIRONMENT +-The +-.B nfsiostat +-command takes into account the following environment variables: +- +-.IP S_TIME_FORMAT +-If this variable exists and its value is +-.BR ISO +-then the current locale will be ignored when printing the date in the report +-header. The +-.B nfsiostat +-command will use the ISO 8601 format (YYYY-MM-DD) instead. +-The timestamp displayed with option -t will also be compliant with ISO 8601 +-format. +- +-.IP POSIXLY_CORRECT +-When this variable is set, transfer rates are shown in 512-byte blocks instead +-of the default 1K blocks. +- +-.SH BUG +-.I /proc +-filesystem must be mounted for +-.B nfsiostat +-to work. +- +-.SH FILE +-.I /proc/self/mountstats +-contains statistics for network filesystems. +-.SH AUTHORS +-Written by Ivana Varekova (varekova redhat.com) +- +-Maintained by Sebastien Godard (sysstat orange.fr) +-.SH SEE ALSO +-.BR sar (1), +-.BR pidstat (1), +-.BR mpstat (1), +-.BR vmstat (8), +-.BR iostat (1), +-.BR cifsiostat (1) +- +-.I http://pagesperso-orange.fr/sebastien.godard/ +diff -uprN sysstat-10.1.5.orig/man/nfsiostat-sysstat.in sysstat-10.1.5/man/nfsiostat-sysstat.in +--- sysstat-10.1.5.orig/man/nfsiostat-sysstat.in 1970-01-01 01:00:00.000000000 +0100 ++++ sysstat-10.1.5/man/nfsiostat-sysstat.in 2016-05-24 18:25:16.209668309 +0200 +@@ -0,0 +1,187 @@ ++.TH NFSIOSTAT-SYSSTAT 1 "JANUARY 2014" Linux "Linux User's Manual" -*- nroff -*- ++.SH NAME ++nfsiostat-sysstat (the nfsiostat command from the sysstat package) \- Report input/output statistics for network filesystems (NFS). ++.SH SYNOPSIS ++.ie 'yes'@WITH_DEBUG@' \{ ++.B nfsiostat-sysstat [ -h ] [ -k | -m ] [ -t ] [ -V ] [ --debuginfo ] [ ++.I interval ++.B [ ++.I count ++.B ] ] ++.\} ++.el \{ ++.B nfsiostat-sysstat [ -h ] [ -k | -m ] [ -t ] [ -V ] [ ++.I interval ++.B [ ++.I count ++.B ] ] ++.\} ++.SH DESCRIPTION ++The ++.B nfsiostat-sysstat ++command displays statistics about read and write operations ++on NFS filesystems. ++ ++The ++.I interval ++parameter specifies the amount of time in seconds between ++each report. The first report contains statistics for the time since ++system startup (boot). Each subsequent report contains statistics ++collected during the interval since the previous report. ++A report consists of an NFS header row followed by ++a line of statistics for each network filesystem that is mounted. ++The ++.I count ++parameter can be specified in conjunction with the ++.I interval ++parameter. If the ++.I count ++parameter is specified, the value of ++.I count ++determines the number of reports generated at ++.I interval ++seconds apart. If the ++.I interval ++parameter is specified without the ++.I count ++parameter, the ++.B nfsiostat-sysstat ++command generates reports continuously. ++ ++.SH REPORT ++The Network Filesystem (NFS) report provides statistics for each mounted network filesystem. ++Transfer rates are shown in 1K blocks by default, unless the environment ++variable POSIXLY_CORRECT is set, in which case 512-byte blocks are used. ++The report shows the following fields: ++ ++.B Filesystem: ++.RS ++This columns shows the hostname of the NFS server followed by a colon and ++by the directory name where the network filesystem is mounted. ++ ++.RE ++.B rBlk_nor/s (rkB_nor/s, rMB_nor) ++.RS ++Indicate the number of blocks (kilobytes, megabytes) read by applications ++via the read(2) system ++call interface. A block has a size of 512 bytes. ++ ++.RE ++.B wBlk_nor/s (wkB_nor/s, wMB_nor/s) ++.RS ++Indicate the number of blocks (kilobytes, megabytes) written by applications ++via the write(2) system ++call interface. ++ ++.RE ++.B rBlk_dir/s (rkB_dir/s, rMB_dir/s) ++.RS ++Indicate the number of blocks (kilobytes, megabytes) read from files ++opened with the O_DIRECT flag. ++ ++.RE ++.B wBlk_dir/s (wkB_dir/s, wMB_dir/s) ++.RS ++Indicate the number of blocks (kilobytes, megabytes) written to files ++opened with the O_DIRECT flag. ++ ++.RE ++.B rBlk_svr/s (rkB_svr/s, rMB_svr/s) ++.RS ++Indicate the number of blocks (kilobytes, megabytes) read from the server ++by the NFS client via an NFS READ request. ++ ++.RE ++.B wBlk_svr/s (wkB_svr/s, wMB_svr/s) ++.RS ++Indicate the number of blocks (kilobytes, megabytes) written to the server ++by the NFS client via an NFS WRITE request. ++ ++.RE ++.B ops/s ++.RS ++Indicate the number of operations that were issued to the filesystem per second. ++ ++.RE ++.B rops/s ++.RS ++Indicate the number of 'read' operations that were issued to the filesystem ++per second. ++ ++.RE ++.B wops/s ++.RS ++Indicate the number of 'write' operations that were issued to the filesystem ++per second. ++.RE ++.RE ++.SH OPTIONS ++.if 'yes'@WITH_DEBUG@' \{ ++.IP --debuginfo ++Print debug output to stderr. ++.\} ++.IP -h ++Make the NFS report easier to read by a human. ++.IP -k ++Display statistics in kilobytes per second. ++.IP -m ++Display statistics in megabytes per second. ++.IP -t ++Print the time for each report displayed. The timestamp format may depend ++on the value of the S_TIME_FORMAT environment variable (see below). ++.IP -V ++Print version number then exit. ++ ++.SH ENVIRONMENT ++The ++.B nfsiostat-sysstat ++command takes into account the following environment variables: ++ ++.IP S_TIME_FORMAT ++If this variable exists and its value is ++.BR ISO ++then the current locale will be ignored when printing the date in the report ++header. The ++.B nfsiostat-sysstat ++command will use the ISO 8601 format (YYYY-MM-DD) instead. ++The timestamp displayed with option -t will also be compliant with ISO 8601 ++format. ++ ++.IP POSIXLY_CORRECT ++When this variable is set, transfer rates are shown in 512-byte blocks instead ++of the default 1K blocks. ++ ++.SH BUG ++.I /proc ++filesystem must be mounted for ++.B nfsiostat-sysstat ++to work. ++ ++.SH FILE ++.I /proc/self/mountstats ++contains statistics for network filesystems. ++ ++.SH WARNING ++The nfsiostat ++command from the sysstat package (nfsiostat-sysstat) is now obsolete and is no longer maintained. ++It will be removed in a future sysstat version. ++Please use now the ++.B nfsiostat ++command from the ++.I nfs-utils ++package. ++ ++.SH AUTHORS ++Written by Ivana Varekova (varekova redhat.com) ++ ++Maintained by Sebastien Godard (sysstat orange.fr) ++.SH SEE ALSO ++.BR nfsiostat (8), ++.BR sar (1), ++.BR pidstat (1), ++.BR mpstat (1), ++.BR vmstat (8), ++.BR iostat (1), ++.BR cifsiostat (1) ++ ++.I http://pagesperso-orange.fr/sebastien.godard/ +diff -uprN sysstat-10.1.5.orig/nfsiostat.c sysstat-10.1.5/nfsiostat.c +--- sysstat-10.1.5.orig/nfsiostat.c 2016-05-24 18:33:48.444839516 +0200 ++++ sysstat-10.1.5/nfsiostat.c 1970-01-01 01:00:00.000000000 +0100 +@@ -1,747 +0,0 @@ +-/* +- * nfsiostat: Report NFS I/O statistics +- * Copyright (C) 2010 Red Hat, Inc. All Rights Reserved +- * Written by Ivana Varekova +- * +- *************************************************************************** +- * This program is free software; you can redistribute it and/or modify it * +- * under the terms of the GNU General Public License as published by the * +- * Free Software Foundation; either version 2 of the License, or (at your * +- * option) any later version. * +- * * +- * This program is distributed in the hope that it will be useful, but * +- * WITHOUT ANY WARRANTY; without the implied warranty of MERCHANTABILITY * +- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * +- * for more details. * +- * * +- * You should have received a copy of the GNU General Public License along * +- * with this program; if not, write to the Free Software Foundation, Inc., * +- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * +- *************************************************************************** +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include "version.h" +-#include "nfsiostat.h" +-#include "common.h" +- +-#ifdef USE_NLS +-#include +-#include +-#define _(string) gettext(string) +-#else +-#define _(string) (string) +-#endif +- +-#define SCCSID "@(#)sysstat-" VERSION ": " __FILE__ " compiled " __DATE__ " " __TIME__ +-char *sccsid(void) { return (SCCSID); } +- +-unsigned long long uptime0[2] = {0, 0}; +-struct io_nfs_stats *st_ionfs[2]; +-struct io_hdr_stats *st_hdr_ionfs; +- +-int ionfs_nr = 0; /* Nb of NFS mounted directories found */ +-int cpu_nr = 0; /* Nb of processors on the machine */ +-int flags = 0; /* Flag for common options and system state */ +- +-long interval = 0; +-char timestamp[64]; +- +-struct sigaction alrm_act; +- +-/* +- *************************************************************************** +- * Print usage and exit. +- * +- * IN: +- * @progname Name of sysstat command. +- *************************************************************************** +- */ +-void usage(char *progname) +-{ +- fprintf(stderr, _("Usage: %s [ options ] [ [ ] ]\n"), +- progname); +- +-#ifdef DEBUG +- fprintf(stderr, _("Options are:\n" +- "[ -h ] [ -k | -m ] [ -t ] [ -V ] [ --debuginfo ]\n")); +-#else +- fprintf(stderr, _("Options are:\n" +- "[ -h ] [ -k | -m ] [ -t ] [ -V ]\n")); +-#endif +- exit(1); +-} +- +-/* +- *************************************************************************** +- * Set output unit. Unit will be kB/s unless POSIXLY_CORRECT +- * environment variable has been set, in which case the output will be +- * expressed in blocks/s. +- *************************************************************************** +- */ +-void set_output_unit(void) +-{ +- char *e; +- +- if (DISPLAY_KILOBYTES(flags) || DISPLAY_MEGABYTES(flags)) +- return; +- +- /* Check POSIXLY_CORRECT environment variable */ +- if ((e = getenv(ENV_POSIXLY_CORRECT)) == NULL) { +- /* Variable not set: Unit is kB/s and not blocks/s */ +- flags |= I_D_KILOBYTES; +- } +-} +- +-/* +- *************************************************************************** +- * SIGALRM signal handler. +- * +- * IN: +- * @sig Signal number. +- *************************************************************************** +- */ +-void alarm_handler(int sig) +-{ +- alarm(interval); +-} +- +-/* +- *************************************************************************** +- * Find number of NFS-mounted points that are registered in +- * /proc/self/mountstats. +- * +- * RETURNS: +- * Number of NFS-mounted points. +- *************************************************************************** +- */ +-int get_nfs_mount_nr(void) +-{ +- FILE *fp; +- char line[8192]; +- char type_name[10]; +- unsigned int nfs = 0; +- +- if ((fp = fopen(NFSMOUNTSTATS, "r")) == NULL) +- /* File non-existent */ +- return 0; +- +- while (fgets(line, 8192, fp) != NULL) { +- +- if ((strstr(line, "mounted")) && (strstr(line, "on")) && +- (strstr(line, "with")) && (strstr(line, "fstype"))) { +- +- sscanf(strstr(line, "fstype") + 6, "%9s", type_name); +- if ((!strncmp(type_name, "nfs", 3)) && (strncmp(type_name, "nfsd", 4))) { +- nfs ++; +- } +- } +- } +- +- fclose(fp); +- +- return nfs; +-} +- +-/* +- *************************************************************************** +- * Set every nfs_io entry to inactive state (unregistered). +- *************************************************************************** +- */ +-void set_entries_inactive(void) +-{ +- int i; +- struct io_hdr_stats *shi = st_hdr_ionfs; +- +- for (i = 0; i < ionfs_nr; i++, shi++) { +- shi->active = FALSE; +- } +-} +- +-/* +- *************************************************************************** +- * Free inactive entries (mark them as unused). +- *************************************************************************** +- */ +-void free_inactive_entries(void) +-{ +- int i; +- struct io_hdr_stats *shi = st_hdr_ionfs; +- +- for (i = 0; i < ionfs_nr; i++, shi++) { +- if (!shi->active) { +- shi->used = FALSE; +- } +- } +-} +- +-/* +- *************************************************************************** +- * Allocate and init structures, according to system state. +- *************************************************************************** +- */ +-void io_sys_init(void) +-{ +- int i; +- +- /* How many processors on this machine? */ +- cpu_nr = get_cpu_nr(~0); +- +- /* Get number of NFS directories in /proc/self/mountstats */ +- if ((ionfs_nr = get_nfs_mount_nr()) > 0) { +- ionfs_nr += NR_NFS_PREALLOC; +- } +- if ((st_hdr_ionfs = (struct io_hdr_stats *) calloc(ionfs_nr, IO_HDR_STATS_SIZE)) == NULL) { +- perror("malloc"); +- exit(4); +- } +- +- /* Allocate structures for number of NFS directories found */ +- for (i = 0; i < 2; i++) { +- if ((st_ionfs[i] = +- (struct io_nfs_stats *) calloc(ionfs_nr, IO_NFS_STATS_SIZE)) == NULL) { +- perror("malloc"); +- exit(4); +- } +- } +-} +- +-/* +- *************************************************************************** +- * Free various structures. +- *************************************************************************** +-*/ +-void io_sys_free(void) +-{ +- int i; +- +- /* Free I/O NFS directories structures */ +- for (i = 0; i < 2; i++) { +- +- if (st_ionfs[i]) { +- free(st_ionfs[i]); +- } +- } +- +- if (st_hdr_ionfs) { +- free(st_hdr_ionfs); +- } +-} +- +-/* +- *************************************************************************** +- * Save stats for current NFS filesystem. +- * +- * IN: +- * @name Name of NFS filesystem. +- * @curr Index in array for current sample statistics. +- * @st_io Structure with NFS statistics to save. +- * @ionfs_nr Number of NFS filesystems. +- * @st_hdr_ionfs Pointer on structures describing an NFS filesystem. +- * +- * OUT: +- * @st_hdr_ionfs Pointer on structures describing an NFS filesystem. +- *************************************************************************** +- */ +-void save_stats(char *name, int curr, void *st_io) +-{ +- int i, j; +- struct io_hdr_stats *st_hdr_ionfs_i; +- struct io_nfs_stats *st_ionfs_i; +- +- /* Look for NFS directory in data table */ +- for (i = 0; i < ionfs_nr; i++) { +- st_hdr_ionfs_i = st_hdr_ionfs + i; +- if ((st_hdr_ionfs_i->used) && +- (!strcmp(st_hdr_ionfs_i->name, name))) { +- break; +- } +- } +- +- if (i == ionfs_nr) { +- /* +- * This is a new filesystem: Look for an unused entry to store it. +- */ +- for (i = 0; i < ionfs_nr; i++) { +- st_hdr_ionfs_i = st_hdr_ionfs + i; +- if (!st_hdr_ionfs_i->used) { +- /* Unused entry found... */ +- st_hdr_ionfs_i->used = TRUE; /* Indicate it is now used */ +- st_hdr_ionfs_i->active = TRUE; +- +- strcpy(st_hdr_ionfs_i->name, name); +- st_ionfs_i = st_ionfs[curr] + i; +- memset(st_ionfs_i, 0, IO_NFS_STATS_SIZE); +- *st_ionfs_i = *((struct io_nfs_stats *) st_io); +- break; +- } +- } +- if (i == ionfs_nr) { +- /* All entries are used: The number has to be increased */ +- ionfs_nr = ionfs_nr + 5; +- +- /* Increase the size of st_hdr_ionfs buffer */ +- if ((st_hdr_ionfs = (struct io_hdr_stats *) +- realloc(st_hdr_ionfs, ionfs_nr * IO_HDR_STATS_SIZE)) == NULL) { +- perror("malloc"); +- exit(4); +- } +- +- /* Set the new entries inactive */ +- for (j = 0; j < 5; j++) { +- st_hdr_ionfs_i = st_hdr_ionfs + i + j; +- st_hdr_ionfs_i->used = FALSE; +- st_hdr_ionfs_i->active = FALSE; +- } +- +- /* Increase the size of st_hdr_ionfs buffer */ +- for (j = 0; j < 2; j++) { +- if ((st_ionfs[j] = (struct io_nfs_stats *) +- realloc(st_ionfs[j], ionfs_nr * IO_NFS_STATS_SIZE)) == NULL) { +- perror("malloc"); +- exit(4); +- } +- memset(st_ionfs[j] + i, 0, 5 * IO_NFS_STATS_SIZE); +- } +- +- /* Now i shows the first unused entry of the new block */ +- st_hdr_ionfs_i = st_hdr_ionfs + i; +- st_hdr_ionfs_i->used = TRUE; /* Indicate it is now used */ +- strcpy(st_hdr_ionfs_i->name, name); +- st_ionfs_i = st_ionfs[curr] + i; +- memset(st_ionfs_i, 0, IO_NFS_STATS_SIZE); +- } +- } else { +- st_hdr_ionfs_i = st_hdr_ionfs + i; +- st_hdr_ionfs_i->used = TRUE; +- st_hdr_ionfs_i->active = TRUE; +- st_ionfs_i = st_ionfs[curr] + i; +- *st_ionfs_i = *((struct io_nfs_stats *) st_io); +- } +- /* +- * else it was a new NFS directory +- * but there was no free structure to store it. +- */ +-} +- +-/* +- *************************************************************************** +- * Read NFS-mount directories stats from /proc/self/mountstats. +- * +- * IN: +- * @curr Index in array for current sample statistics. +- *************************************************************************** +- */ +-void read_nfs_stat(int curr) +-{ +- FILE *fp; +- int sw = 0; +- char line[256]; +- char *xprt_line; +- char *mount_part; +- char nfs_name[MAX_NAME_LEN]; +- char mount[10], on[10], prefix[10], aux[32]; +- char operation[16]; +- struct io_nfs_stats snfs; +- long int v1; +- +- /* Every I/O NFS entry is potentially unregistered */ +- set_entries_inactive(); +- +- if ((fp = fopen(NFSMOUNTSTATS, "r")) == NULL) +- return; +- +- sprintf(aux, "%%%ds", +- MAX_NAME_LEN < 200 ? MAX_NAME_LEN-1 : 200); +- +- while (fgets(line, 256, fp) != NULL) { +- /* Read NFS directory name */ +- if (!strncmp(line, "device", 6)) { +- sw = 0; +- sscanf(line + 6, aux, nfs_name); +- mount_part = strchr(line + 7, ' '); +- if (mount_part != NULL) { +- sscanf(mount_part, "%9s %9s", mount, on); +- if ((!strncmp(mount, "mounted", 7)) && (!strncmp(on, "on", 2))) { +- sw = 1; +- } +- } +- } +- +- sscanf(line, "%9s", prefix); +- if (sw && (!strncmp(prefix, "bytes:", 6))) { +- /* Read the stats for the last NFS-mounted directory */ +- sscanf(strstr(line, "bytes:") + 6, "%llu %llu %llu %llu %llu %llu", +- &snfs.rd_normal_bytes, &snfs.wr_normal_bytes, +- &snfs.rd_direct_bytes, &snfs.wr_direct_bytes, +- &snfs.rd_server_bytes, &snfs.wr_server_bytes); +- sw = 2; +- } +- +- if ((sw == 2) && (!strncmp(prefix, "xprt:", 5))) { +- /* +- * Read extended statistic for the last NFS-mounted directory +- * - number of sent rpc requests. +- */ +- xprt_line = (strstr(line, "xprt:") + 6); +- /* udp, tcp or rdma data */ +- if (!strncmp(xprt_line, "udp", 3)) { +- /* port bind_count sends recvs (bad_xids req_u bklog_u) */ +- sscanf(strstr(xprt_line, "udp") + 4, "%*u %*u %lu", +- &snfs.rpc_sends); +- } +- if (!strncmp(xprt_line, "tcp", 3)) { +- /* +- * port bind_counter connect_count connect_time idle_time +- * sends recvs (bad_xids req_u bklog_u) +- */ +- sscanf(strstr(xprt_line, "tcp") + 4, +- "%*u %*u %*u %*u %*d %lu", +- &snfs.rpc_sends); +- } +- if (!strncmp(xprt_line,"rdma", 4)) { +- /* +- * 0(port) bind_count connect_count connect_time idle_time +- * sends recvs (bad_xids req_u bklog_u...) +- */ +- sscanf(strstr(xprt_line, "rdma") + 5, +- "%*u %*u %*u %*u %*d %lu", +- &snfs.rpc_sends); +- } +- sw = 3; +- } +- +- if ((sw == 3) && (!strncmp(prefix, "per-op", 6))) { +- sw = 4; +- while (sw == 4) { +- fgets(line, 256, fp); +- sscanf(line, "%15s %lu", operation, &v1); +- if (!strncmp(operation, "READ:", 5)) { +- snfs.nfs_rops = v1; +- } +- else if (!strncmp(operation, "WRITE:", 6)) { +- snfs.nfs_wops = v1; +- +- save_stats(nfs_name, curr, &snfs); +- sw = 0; +- } +- } +- } +- } +- +- fclose(fp); +- +- /* Free structures corresponding to unregistered filesystems */ +- free_inactive_entries(); +-} +- +-/* +- *************************************************************************** +- * Display NFS stats header. +- * +- * OUT: +- * @fctr Conversion factor. +- *************************************************************************** +- */ +-void write_nfs_stat_header(int *fctr) +-{ +- printf("Filesystem: "); +- if (DISPLAY_KILOBYTES(flags)) { +- printf(" rkB_nor/s wkB_nor/s rkB_dir/s wkB_dir/s" +- " rkB_svr/s wkB_svr/s"); +- *fctr = 1024; +- } +- else if (DISPLAY_MEGABYTES(flags)) { +- printf(" rMB_nor/s wMB_nor/s rMB_dir/s wMB_dir/s" +- " rMB_svr/s wMB_svr/s"); +- *fctr = 1024 * 1024; +- } +- else { +- printf(" rBlk_nor/s wBlk_nor/s rBlk_dir/s wBlk_dir/s" +- " rBlk_svr/s wBlk_svr/s"); +- *fctr = 512; +- } +- printf(" ops/s rops/s wops/s\n"); +-} +- +-/* +- *************************************************************************** +- * Write NFS stats read from /proc/self/mountstats. +- * +- * IN: +- * @curr Index in array for current sample statistics. +- * @itv Interval of time. +- * @fctr Conversion factor. +- * @shi Structures describing the NFS filesystems. +- * @ioi Current sample statistics. +- * @ioj Previous sample statistics. +- *************************************************************************** +- */ +-void write_nfs_stat(int curr, unsigned long long itv, int fctr, +- struct io_hdr_stats *shi, struct io_nfs_stats *ioni, +- struct io_nfs_stats *ionj) +-{ +- if (DISPLAY_HUMAN_READ(flags)) { +- printf("%-22s\n%23s", shi->name, ""); +- } +- else { +- printf("%-22s ", shi->name); +- } +- printf("%12.2f %12.2f %12.2f %12.2f %12.2f %12.2f %9.2f %9.2f %9.2f\n", +- S_VALUE(ionj->rd_normal_bytes, ioni->rd_normal_bytes, itv) / fctr, +- S_VALUE(ionj->wr_normal_bytes, ioni->wr_normal_bytes, itv) / fctr, +- S_VALUE(ionj->rd_direct_bytes, ioni->rd_direct_bytes, itv) / fctr, +- S_VALUE(ionj->wr_direct_bytes, ioni->wr_direct_bytes, itv) / fctr, +- S_VALUE(ionj->rd_server_bytes, ioni->rd_server_bytes, itv) / fctr, +- S_VALUE(ionj->wr_server_bytes, ioni->wr_server_bytes, itv) / fctr, +- S_VALUE(ionj->rpc_sends, ioni->rpc_sends, itv), +- S_VALUE(ionj->nfs_rops, ioni->nfs_rops, itv), +- S_VALUE(ionj->nfs_wops, ioni->nfs_wops, itv)); +-} +- +-/* +- *************************************************************************** +- * Print everything now (stats and uptime). +- * +- * IN: +- * @curr Index in array for current sample statistics. +- * @rectime Current date and time. +- *************************************************************************** +- */ +-void write_stats(int curr, struct tm *rectime) +-{ +- int i, fctr = 1; +- unsigned long long itv; +- struct io_hdr_stats *shi; +- struct io_nfs_stats *ioni, *ionj; +- +- /* Test stdout */ +- TEST_STDOUT(STDOUT_FILENO); +- +- /* Print time stamp */ +- if (DISPLAY_TIMESTAMP(flags)) { +- if (DISPLAY_ISO(flags)) { +- strftime(timestamp, sizeof(timestamp), "%FT%T%z", rectime); +- } +- else { +- strftime(timestamp, sizeof(timestamp), "%x %X", rectime); +- } +- printf("%s\n", timestamp); +-#ifdef DEBUG +- if (DISPLAY_DEBUG(flags)) { +- fprintf(stderr, "%s\n", timestamp); +- } +-#endif +- } +- +- /* Interval of time, reduced to one processor */ +- itv = get_interval(uptime0[!curr], uptime0[curr]); +- +- shi = st_hdr_ionfs; +- +- /* Display NFS stats header */ +- write_nfs_stat_header(&fctr); +- +- for (i = 0; i < ionfs_nr; i++, shi++) { +- if (shi->used) { +- ioni = st_ionfs[curr] + i; +- ionj = st_ionfs[!curr] + i; +-#ifdef DEBUG +- if (DISPLAY_DEBUG(flags)) { +- /* Debug output */ +- fprintf(stderr, "name=%s itv=%llu fctr=%d ioni{ rd_normal_bytes=%llu " +- "wr_normal_bytes=%llu rd_direct_bytes=%llu wr_direct_bytes=%llu rd_server_bytes=%llu " +- "wr_server_bytes=%llu rpc_sends=%lu nfs_rops=%lu nfs_wops=%lu }\n", +- shi->name, itv, fctr, +- ioni->rd_normal_bytes, ioni->wr_normal_bytes, +- ioni->rd_direct_bytes, ioni->wr_direct_bytes, +- ioni->rd_server_bytes, ioni->wr_server_bytes, +- ioni->rpc_sends, +- ioni->nfs_rops, ioni->nfs_wops); +- } +-#endif +- write_nfs_stat(curr, itv, fctr, shi, ioni, ionj); +- } +- } +- printf("\n"); +-} +- +-/* +- *************************************************************************** +- * Main loop: Read stats from the relevant sources and display them. +- * +- * IN: +- * @count Number of lines of stats to print. +- * @rectime Current date and time. +- *************************************************************************** +- */ +-void rw_io_stat_loop(long int count, struct tm *rectime) +-{ +- int curr = 1; +- +- /* Don't buffer data if redirected to a pipe */ +- setbuf(stdout, NULL); +- +- do { +- /* Read system uptime (reduced to one processor) */ +- uptime0[curr] = 0; +- read_uptime(&(uptime0[curr])); +- if (!uptime0[curr]) +- /* Cannot read system uptime (/proc/uptime doesn't exist) */ +- exit(2); +- +- /* Read NFS directories stats */ +- read_nfs_stat(curr); +- +- /* Get time */ +- get_localtime(rectime, 0); +- +- /* Print results */ +- write_stats(curr, rectime); +- +- if (count > 0) { +- count--; +- } +- if (count) { +- curr ^= 1; +- pause(); +- } +- } +- while (count); +-} +- +-/* +- *************************************************************************** +- * Main entry to the nfsiostat program. +- *************************************************************************** +- */ +-int main(int argc, char **argv) +-{ +- int it = 0; +- int opt = 1; +- int i; +- long count = 1; +- struct utsname header; +- struct tm rectime; +- +-#ifdef USE_NLS +- /* Init National Language Support */ +- init_nls(); +-#endif +- +- /* Get HZ */ +- get_HZ(); +- +- /* Process args... */ +- while (opt < argc) { +- +-#ifdef DEBUG +- if (!strcmp(argv[opt], "--debuginfo")) { +- flags |= I_D_DEBUG; +- opt++; +- } else +-#endif +- if (!strncmp(argv[opt], "-", 1)) { +- for (i = 1; *(argv[opt] + i); i++) { +- +- switch (*(argv[opt] + i)) { +- +- case 'h': +- /* Display an easy-to-read NFS report */ +- flags |= I_D_HUMAN_READ; +- break; +- +- case 'k': +- if (DISPLAY_MEGABYTES(flags)) { +- usage(argv[0]); +- } +- /* Display stats in kB/s */ +- flags |= I_D_KILOBYTES; +- break; +- +- case 'm': +- if (DISPLAY_KILOBYTES(flags)) { +- usage(argv[0]); +- } +- /* Display stats in MB/s */ +- flags |= I_D_MEGABYTES; +- break; +- +- case 't': +- /* Display timestamp */ +- flags |= I_D_TIMESTAMP; +- break; +- +- case 'V': +- /* Print version number and exit */ +- print_version(); +- break; +- +- default: +- usage(argv[0]); +- } +- } +- opt++; +- } +- +- else if (!it) { +- interval = atol(argv[opt++]); +- if (interval < 0) { +- usage(argv[0]); +- } +- count = -1; +- it = 1; +- } +- +- else if (it > 0) { +- count = atol(argv[opt++]); +- if ((count < 1) || !interval) { +- usage(argv[0]); +- } +- it = -1; +- } +- else { +- usage(argv[0]); +- } +- } +- +- if (!interval) { +- count = 1; +- } +- +- /* Select output unit (kB/s or blocks/s) */ +- set_output_unit(); +- +- /* Init structures according to machine architecture */ +- io_sys_init(); +- +- get_localtime(&rectime, 0); +- +- /* Get system name, release number and hostname */ +- uname(&header); +- if (print_gal_header(&rectime, header.sysname, header.release, +- header.nodename, header.machine, cpu_nr)) { +- flags |= I_D_ISO; +- } +- printf("\n"); +- +- /* Set a handler for SIGALRM */ +- memset(&alrm_act, 0, sizeof(alrm_act)); +- alrm_act.sa_handler = (void *) alarm_handler; +- sigaction(SIGALRM, &alrm_act, NULL); +- alarm(interval); +- +- /* Main loop */ +- rw_io_stat_loop(count, &rectime); +- +- /* Free structures */ +- io_sys_free(); +- +- return 0; +-} +diff -uprN sysstat-10.1.5.orig/nfsiostat.h sysstat-10.1.5/nfsiostat.h +--- sysstat-10.1.5.orig/nfsiostat.h 2013-03-23 17:31:46.000000000 +0100 ++++ sysstat-10.1.5/nfsiostat.h 1970-01-01 01:00:00.000000000 +0100 +@@ -1,57 +0,0 @@ +-/* +- * nfsiostat: Report NFS I/O statistics +- * Copyright (C) 2010 Red Hat, Inc. All Rights Reserved +- * Written by Ivana Varekova +- */ +- +-#ifndef _NFSIOSTAT_H +-#define _NFSIOSTAT_H +- +-#include "common.h" +- +-#define NFSMOUNTSTATS "/proc/self/mountstats" +- +-/* I_: iostat - D_: Display - F_: Flag */ +-#define I_D_TIMESTAMP 0x001 +-#define I_D_KILOBYTES 0x002 +-#define I_D_MEGABYTES 0x004 +-#define I_D_ISO 0x008 +-#define I_D_HUMAN_READ 0x010 +-#define I_D_DEBUG 0x020 +- +-#define DISPLAY_TIMESTAMP(m) (((m) & I_D_TIMESTAMP) == I_D_TIMESTAMP) +-#define DISPLAY_KILOBYTES(m) (((m) & I_D_KILOBYTES) == I_D_KILOBYTES) +-#define DISPLAY_MEGABYTES(m) (((m) & I_D_MEGABYTES) == I_D_MEGABYTES) +-#define DISPLAY_ISO(m) (((m) & I_D_ISO) == I_D_ISO) +-#define DISPLAY_HUMAN_READ(m) (((m) & I_D_HUMAN_READ) == I_D_HUMAN_READ) +-#define DISPLAY_DEBUG(m) (((m) & I_D_DEBUG) == I_D_DEBUG) +- +-/* Environment variable */ +-#define ENV_POSIXLY_CORRECT "POSIXLY_CORRECT" +- +-/* Preallocation constats */ +-#define NR_NFS_PREALLOC 2 +- +-struct io_nfs_stats { +- unsigned long long rd_normal_bytes __attribute__ ((aligned (8))); +- unsigned long long wr_normal_bytes __attribute__ ((packed)); +- unsigned long long rd_direct_bytes __attribute__ ((packed)); +- unsigned long long wr_direct_bytes __attribute__ ((packed)); +- unsigned long long rd_server_bytes __attribute__ ((packed)); +- unsigned long long wr_server_bytes __attribute__ ((packed)); +- unsigned long rpc_sends __attribute__ ((packed)); +- unsigned long nfs_rops __attribute__ ((packed)); +- unsigned long nfs_wops __attribute__ ((packed)); +-}; +- +-#define IO_NFS_STATS_SIZE (sizeof(struct io_nfs_stats)) +- +-struct io_hdr_stats { +- unsigned int active __attribute__ ((aligned (4))); +- unsigned int used __attribute__ ((packed)); +- char name[MAX_NAME_LEN]; +-}; +- +-#define IO_HDR_STATS_SIZE (sizeof(struct io_hdr_stats)) +- +-#endif /* _NFSIOSTAT_H */ +diff -uprN sysstat-10.1.5.orig/nfsiostat-sysstat.c sysstat-10.1.5/nfsiostat-sysstat.c +--- sysstat-10.1.5.orig/nfsiostat-sysstat.c 1970-01-01 01:00:00.000000000 +0100 ++++ sysstat-10.1.5/nfsiostat-sysstat.c 2016-05-24 18:30:06.285162523 +0200 +@@ -0,0 +1,750 @@ ++/* ++ * nfsiostat-sysstat: Report NFS I/O statistics ++ * Copyright (C) 2010 Red Hat, Inc. All Rights Reserved ++ * Written by Ivana Varekova ++ * ++ *************************************************************************** ++ * This program is free software; you can redistribute it and/or modify it * ++ * under the terms of the GNU General Public License as published by the * ++ * Free Software Foundation; either version 2 of the License, or (at your * ++ * option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, but * ++ * WITHOUT ANY WARRANTY; without the implied warranty of MERCHANTABILITY * ++ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * ++ * for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License along * ++ * with this program; if not, write to the Free Software Foundation, Inc., * ++ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * ++ *************************************************************************** ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "version.h" ++#include "nfsiostat-sysstat.h" ++#include "common.h" ++ ++#ifdef USE_NLS ++#include ++#include ++#define _(string) gettext(string) ++#else ++#define _(string) (string) ++#endif ++ ++#define SCCSID "@(#)sysstat-" VERSION ": " __FILE__ " compiled " __DATE__ " " __TIME__ ++char *sccsid(void) { return (SCCSID); } ++ ++unsigned long long uptime0[2] = {0, 0}; ++struct io_nfs_stats *st_ionfs[2]; ++struct io_hdr_stats *st_hdr_ionfs; ++ ++int ionfs_nr = 0; /* Nb of NFS mounted directories found */ ++int cpu_nr = 0; /* Nb of processors on the machine */ ++int flags = 0; /* Flag for common options and system state */ ++ ++long interval = 0; ++char timestamp[64]; ++ ++struct sigaction alrm_act; ++ ++/* ++ *************************************************************************** ++ * Print usage and exit. ++ * ++ * IN: ++ * @progname Name of sysstat command. ++ *************************************************************************** ++ */ ++void usage(char *progname) ++{ ++ fprintf(stderr, _("Usage: %s [ options ] [ [ ] ]\n"), ++ progname); ++ ++#ifdef DEBUG ++ fprintf(stderr, _("Options are:\n" ++ "[ -h ] [ -k | -m ] [ -t ] [ -V ] [ --debuginfo ]\n")); ++#else ++ fprintf(stderr, _("Options are:\n" ++ "[ -h ] [ -k | -m ] [ -t ] [ -V ]\n")); ++#endif ++ exit(1); ++} ++ ++/* ++ *************************************************************************** ++ * Set output unit. Unit will be kB/s unless POSIXLY_CORRECT ++ * environment variable has been set, in which case the output will be ++ * expressed in blocks/s. ++ *************************************************************************** ++ */ ++void set_output_unit(void) ++{ ++ char *e; ++ ++ if (DISPLAY_KILOBYTES(flags) || DISPLAY_MEGABYTES(flags)) ++ return; ++ ++ /* Check POSIXLY_CORRECT environment variable */ ++ if ((e = getenv(ENV_POSIXLY_CORRECT)) == NULL) { ++ /* Variable not set: Unit is kB/s and not blocks/s */ ++ flags |= I_D_KILOBYTES; ++ } ++} ++ ++/* ++ *************************************************************************** ++ * SIGALRM signal handler. ++ * ++ * IN: ++ * @sig Signal number. ++ *************************************************************************** ++ */ ++void alarm_handler(int sig) ++{ ++ alarm(interval); ++} ++ ++/* ++ *************************************************************************** ++ * Find number of NFS-mounted points that are registered in ++ * /proc/self/mountstats. ++ * ++ * RETURNS: ++ * Number of NFS-mounted points. ++ *************************************************************************** ++ */ ++int get_nfs_mount_nr(void) ++{ ++ FILE *fp; ++ char line[8192]; ++ char type_name[10]; ++ unsigned int nfs = 0; ++ ++ if ((fp = fopen(NFSMOUNTSTATS, "r")) == NULL) ++ /* File non-existent */ ++ return 0; ++ ++ while (fgets(line, 8192, fp) != NULL) { ++ ++ if ((strstr(line, "mounted")) && (strstr(line, "on")) && ++ (strstr(line, "with")) && (strstr(line, "fstype"))) { ++ ++ sscanf(strstr(line, "fstype") + 6, "%9s", type_name); ++ if ((!strncmp(type_name, "nfs", 3)) && (strncmp(type_name, "nfsd", 4))) { ++ nfs ++; ++ } ++ } ++ } ++ ++ fclose(fp); ++ ++ return nfs; ++} ++ ++/* ++ *************************************************************************** ++ * Set every nfs_io entry to inactive state (unregistered). ++ *************************************************************************** ++ */ ++void set_entries_inactive(void) ++{ ++ int i; ++ struct io_hdr_stats *shi = st_hdr_ionfs; ++ ++ for (i = 0; i < ionfs_nr; i++, shi++) { ++ shi->active = FALSE; ++ } ++} ++ ++/* ++ *************************************************************************** ++ * Free inactive entries (mark them as unused). ++ *************************************************************************** ++ */ ++void free_inactive_entries(void) ++{ ++ int i; ++ struct io_hdr_stats *shi = st_hdr_ionfs; ++ ++ for (i = 0; i < ionfs_nr; i++, shi++) { ++ if (!shi->active) { ++ shi->used = FALSE; ++ } ++ } ++} ++ ++/* ++ *************************************************************************** ++ * Allocate and init structures, according to system state. ++ *************************************************************************** ++ */ ++void io_sys_init(void) ++{ ++ int i; ++ ++ /* How many processors on this machine? */ ++ cpu_nr = get_cpu_nr(~0); ++ ++ /* Get number of NFS directories in /proc/self/mountstats */ ++ if ((ionfs_nr = get_nfs_mount_nr()) > 0) { ++ ionfs_nr += NR_NFS_PREALLOC; ++ } ++ if ((st_hdr_ionfs = (struct io_hdr_stats *) calloc(ionfs_nr, IO_HDR_STATS_SIZE)) == NULL) { ++ perror("malloc"); ++ exit(4); ++ } ++ ++ /* Allocate structures for number of NFS directories found */ ++ for (i = 0; i < 2; i++) { ++ if ((st_ionfs[i] = ++ (struct io_nfs_stats *) calloc(ionfs_nr, IO_NFS_STATS_SIZE)) == NULL) { ++ perror("malloc"); ++ exit(4); ++ } ++ } ++} ++ ++/* ++ *************************************************************************** ++ * Free various structures. ++ *************************************************************************** ++*/ ++void io_sys_free(void) ++{ ++ int i; ++ ++ /* Free I/O NFS directories structures */ ++ for (i = 0; i < 2; i++) { ++ ++ if (st_ionfs[i]) { ++ free(st_ionfs[i]); ++ } ++ } ++ ++ if (st_hdr_ionfs) { ++ free(st_hdr_ionfs); ++ } ++} ++ ++/* ++ *************************************************************************** ++ * Save stats for current NFS filesystem. ++ * ++ * IN: ++ * @name Name of NFS filesystem. ++ * @curr Index in array for current sample statistics. ++ * @st_io Structure with NFS statistics to save. ++ * @ionfs_nr Number of NFS filesystems. ++ * @st_hdr_ionfs Pointer on structures describing an NFS filesystem. ++ * ++ * OUT: ++ * @st_hdr_ionfs Pointer on structures describing an NFS filesystem. ++ *************************************************************************** ++ */ ++void save_stats(char *name, int curr, void *st_io) ++{ ++ int i, j; ++ struct io_hdr_stats *st_hdr_ionfs_i; ++ struct io_nfs_stats *st_ionfs_i; ++ ++ /* Look for NFS directory in data table */ ++ for (i = 0; i < ionfs_nr; i++) { ++ st_hdr_ionfs_i = st_hdr_ionfs + i; ++ if ((st_hdr_ionfs_i->used) && ++ (!strcmp(st_hdr_ionfs_i->name, name))) { ++ break; ++ } ++ } ++ ++ if (i == ionfs_nr) { ++ /* ++ * This is a new filesystem: Look for an unused entry to store it. ++ */ ++ for (i = 0; i < ionfs_nr; i++) { ++ st_hdr_ionfs_i = st_hdr_ionfs + i; ++ if (!st_hdr_ionfs_i->used) { ++ /* Unused entry found... */ ++ st_hdr_ionfs_i->used = TRUE; /* Indicate it is now used */ ++ st_hdr_ionfs_i->active = TRUE; ++ ++ strncpy(st_hdr_ionfs_i->name, name, MAX_NAME_LEN - 1); ++ st_hdr_ionfs_i->name[MAX_NAME_LEN - 1] = '\0'; ++ st_ionfs_i = st_ionfs[curr] + i; ++ memset(st_ionfs_i, 0, IO_NFS_STATS_SIZE); ++ *st_ionfs_i = *((struct io_nfs_stats *) st_io); ++ break; ++ } ++ } ++ if (i == ionfs_nr) { ++ /* All entries are used: The number has to be increased */ ++ ionfs_nr = ionfs_nr + 5; ++ ++ /* Increase the size of st_hdr_ionfs buffer */ ++ if ((st_hdr_ionfs = (struct io_hdr_stats *) ++ realloc(st_hdr_ionfs, ionfs_nr * IO_HDR_STATS_SIZE)) == NULL) { ++ perror("malloc"); ++ exit(4); ++ } ++ ++ /* Set the new entries inactive */ ++ for (j = 0; j < 5; j++) { ++ st_hdr_ionfs_i = st_hdr_ionfs + i + j; ++ st_hdr_ionfs_i->used = FALSE; ++ st_hdr_ionfs_i->active = FALSE; ++ } ++ ++ /* Increase the size of st_hdr_ionfs buffer */ ++ for (j = 0; j < 2; j++) { ++ if ((st_ionfs[j] = (struct io_nfs_stats *) ++ realloc(st_ionfs[j], ionfs_nr * IO_NFS_STATS_SIZE)) == NULL) { ++ perror("malloc"); ++ exit(4); ++ } ++ memset(st_ionfs[j] + i, 0, 5 * IO_NFS_STATS_SIZE); ++ } ++ ++ /* Now i shows the first unused entry of the new block */ ++ st_hdr_ionfs_i = st_hdr_ionfs + i; ++ st_hdr_ionfs_i->used = TRUE; /* Indicate it is now used */ ++ strncpy(st_hdr_ionfs_i->name, name, MAX_NAME_LEN - 1); ++ st_hdr_ionfs_i->name[MAX_NAME_LEN - 1] = '\0'; ++ st_ionfs_i = st_ionfs[curr] + i; ++ memset(st_ionfs_i, 0, IO_NFS_STATS_SIZE); ++ } ++ } else { ++ st_hdr_ionfs_i = st_hdr_ionfs + i; ++ st_hdr_ionfs_i->used = TRUE; ++ st_hdr_ionfs_i->active = TRUE; ++ st_ionfs_i = st_ionfs[curr] + i; ++ *st_ionfs_i = *((struct io_nfs_stats *) st_io); ++ } ++ /* ++ * else it was a new NFS directory ++ * but there was no free structure to store it. ++ */ ++} ++ ++/* ++ *************************************************************************** ++ * Read NFS-mount directories stats from /proc/self/mountstats. ++ * ++ * IN: ++ * @curr Index in array for current sample statistics. ++ *************************************************************************** ++ */ ++void read_nfs_stat(int curr) ++{ ++ FILE *fp; ++ int sw = 0; ++ char line[256]; ++ char *xprt_line; ++ char *mount_part; ++ char nfs_name[MAX_NAME_LEN]; ++ char mount[10], on[10], prefix[10], aux[32]; ++ char operation[16]; ++ struct io_nfs_stats snfs; ++ long int v1; ++ ++ /* Every I/O NFS entry is potentially unregistered */ ++ set_entries_inactive(); ++ ++ if ((fp = fopen(NFSMOUNTSTATS, "r")) == NULL) ++ return; ++ ++ sprintf(aux, "%%%ds", ++ MAX_NAME_LEN < 200 ? MAX_NAME_LEN-1 : 200); ++ ++ while (fgets(line, 256, fp) != NULL) { ++ /* Read NFS directory name */ ++ if (!strncmp(line, "device", 6)) { ++ sw = 0; ++ sscanf(line + 6, aux, nfs_name); ++ mount_part = strchr(line + 7, ' '); ++ if (mount_part != NULL) { ++ sscanf(mount_part, "%9s %9s", mount, on); ++ if ((!strncmp(mount, "mounted", 7)) && (!strncmp(on, "on", 2))) { ++ sw = 1; ++ } ++ } ++ } ++ ++ sscanf(line, "%9s", prefix); ++ if (sw && (!strncmp(prefix, "bytes:", 6))) { ++ /* Read the stats for the last NFS-mounted directory */ ++ sscanf(strstr(line, "bytes:") + 6, "%llu %llu %llu %llu %llu %llu", ++ &snfs.rd_normal_bytes, &snfs.wr_normal_bytes, ++ &snfs.rd_direct_bytes, &snfs.wr_direct_bytes, ++ &snfs.rd_server_bytes, &snfs.wr_server_bytes); ++ sw = 2; ++ } ++ ++ if ((sw == 2) && (!strncmp(prefix, "xprt:", 5))) { ++ /* ++ * Read extended statistic for the last NFS-mounted directory ++ * - number of sent rpc requests. ++ */ ++ xprt_line = (strstr(line, "xprt:") + 6); ++ /* udp, tcp or rdma data */ ++ if (!strncmp(xprt_line, "udp", 3)) { ++ /* port bind_count sends recvs (bad_xids req_u bklog_u) */ ++ sscanf(strstr(xprt_line, "udp") + 4, "%*u %*u %lu", ++ &snfs.rpc_sends); ++ } ++ if (!strncmp(xprt_line, "tcp", 3)) { ++ /* ++ * port bind_counter connect_count connect_time idle_time ++ * sends recvs (bad_xids req_u bklog_u) ++ */ ++ sscanf(strstr(xprt_line, "tcp") + 4, ++ "%*u %*u %*u %*u %*d %lu", ++ &snfs.rpc_sends); ++ } ++ if (!strncmp(xprt_line,"rdma", 4)) { ++ /* ++ * 0(port) bind_count connect_count connect_time idle_time ++ * sends recvs (bad_xids req_u bklog_u...) ++ */ ++ sscanf(strstr(xprt_line, "rdma") + 5, ++ "%*u %*u %*u %*u %*d %lu", ++ &snfs.rpc_sends); ++ } ++ sw = 3; ++ } ++ ++ if ((sw == 3) && (!strncmp(prefix, "per-op", 6))) { ++ sw = 4; ++ while (sw == 4) { ++ if (fgets(line, sizeof(line), fp) == NULL) ++ break; ++ sscanf(line, "%15s %lu", operation, &v1); ++ if (!strncmp(operation, "READ:", 5)) { ++ snfs.nfs_rops = v1; ++ } ++ else if (!strncmp(operation, "WRITE:", 6)) { ++ snfs.nfs_wops = v1; ++ ++ save_stats(nfs_name, curr, &snfs); ++ sw = 0; ++ } ++ } ++ } ++ } ++ ++ fclose(fp); ++ ++ /* Free structures corresponding to unregistered filesystems */ ++ free_inactive_entries(); ++} ++ ++/* ++ *************************************************************************** ++ * Display NFS stats header. ++ * ++ * OUT: ++ * @fctr Conversion factor. ++ *************************************************************************** ++ */ ++void write_nfs_stat_header(int *fctr) ++{ ++ printf("Filesystem: "); ++ if (DISPLAY_KILOBYTES(flags)) { ++ printf(" rkB_nor/s wkB_nor/s rkB_dir/s wkB_dir/s" ++ " rkB_svr/s wkB_svr/s"); ++ *fctr = 1024; ++ } ++ else if (DISPLAY_MEGABYTES(flags)) { ++ printf(" rMB_nor/s wMB_nor/s rMB_dir/s wMB_dir/s" ++ " rMB_svr/s wMB_svr/s"); ++ *fctr = 1024 * 1024; ++ } ++ else { ++ printf(" rBlk_nor/s wBlk_nor/s rBlk_dir/s wBlk_dir/s" ++ " rBlk_svr/s wBlk_svr/s"); ++ *fctr = 512; ++ } ++ printf(" ops/s rops/s wops/s\n"); ++} ++ ++/* ++ *************************************************************************** ++ * Write NFS stats read from /proc/self/mountstats. ++ * ++ * IN: ++ * @curr Index in array for current sample statistics. ++ * @itv Interval of time. ++ * @fctr Conversion factor. ++ * @shi Structures describing the NFS filesystems. ++ * @ioi Current sample statistics. ++ * @ioj Previous sample statistics. ++ *************************************************************************** ++ */ ++void write_nfs_stat(int curr, unsigned long long itv, int fctr, ++ struct io_hdr_stats *shi, struct io_nfs_stats *ioni, ++ struct io_nfs_stats *ionj) ++{ ++ if (DISPLAY_HUMAN_READ(flags)) { ++ printf("%-22s\n%23s", shi->name, ""); ++ } ++ else { ++ printf("%-22s ", shi->name); ++ } ++ printf("%12.2f %12.2f %12.2f %12.2f %12.2f %12.2f %9.2f %9.2f %9.2f\n", ++ S_VALUE(ionj->rd_normal_bytes, ioni->rd_normal_bytes, itv) / fctr, ++ S_VALUE(ionj->wr_normal_bytes, ioni->wr_normal_bytes, itv) / fctr, ++ S_VALUE(ionj->rd_direct_bytes, ioni->rd_direct_bytes, itv) / fctr, ++ S_VALUE(ionj->wr_direct_bytes, ioni->wr_direct_bytes, itv) / fctr, ++ S_VALUE(ionj->rd_server_bytes, ioni->rd_server_bytes, itv) / fctr, ++ S_VALUE(ionj->wr_server_bytes, ioni->wr_server_bytes, itv) / fctr, ++ S_VALUE(ionj->rpc_sends, ioni->rpc_sends, itv), ++ S_VALUE(ionj->nfs_rops, ioni->nfs_rops, itv), ++ S_VALUE(ionj->nfs_wops, ioni->nfs_wops, itv)); ++} ++ ++/* ++ *************************************************************************** ++ * Print everything now (stats and uptime). ++ * ++ * IN: ++ * @curr Index in array for current sample statistics. ++ * @rectime Current date and time. ++ *************************************************************************** ++ */ ++void write_stats(int curr, struct tm *rectime) ++{ ++ int i, fctr = 1; ++ unsigned long long itv; ++ struct io_hdr_stats *shi; ++ struct io_nfs_stats *ioni, *ionj; ++ ++ /* Test stdout */ ++ TEST_STDOUT(STDOUT_FILENO); ++ ++ /* Print time stamp */ ++ if (DISPLAY_TIMESTAMP(flags)) { ++ if (DISPLAY_ISO(flags)) { ++ strftime(timestamp, sizeof(timestamp), "%FT%T%z", rectime); ++ } ++ else { ++ strftime(timestamp, sizeof(timestamp), "%x %X", rectime); ++ } ++ printf("%s\n", timestamp); ++#ifdef DEBUG ++ if (DISPLAY_DEBUG(flags)) { ++ fprintf(stderr, "%s\n", timestamp); ++ } ++#endif ++ } ++ ++ /* Interval of time, reduced to one processor */ ++ itv = get_interval(uptime0[!curr], uptime0[curr]); ++ ++ shi = st_hdr_ionfs; ++ ++ /* Display NFS stats header */ ++ write_nfs_stat_header(&fctr); ++ ++ for (i = 0; i < ionfs_nr; i++, shi++) { ++ if (shi->used) { ++ ioni = st_ionfs[curr] + i; ++ ionj = st_ionfs[!curr] + i; ++#ifdef DEBUG ++ if (DISPLAY_DEBUG(flags)) { ++ /* Debug output */ ++ fprintf(stderr, "name=%s itv=%llu fctr=%d ioni{ rd_normal_bytes=%llu " ++ "wr_normal_bytes=%llu rd_direct_bytes=%llu wr_direct_bytes=%llu rd_server_bytes=%llu " ++ "wr_server_bytes=%llu rpc_sends=%lu nfs_rops=%lu nfs_wops=%lu }\n", ++ shi->name, itv, fctr, ++ ioni->rd_normal_bytes, ioni->wr_normal_bytes, ++ ioni->rd_direct_bytes, ioni->wr_direct_bytes, ++ ioni->rd_server_bytes, ioni->wr_server_bytes, ++ ioni->rpc_sends, ++ ioni->nfs_rops, ioni->nfs_wops); ++ } ++#endif ++ write_nfs_stat(curr, itv, fctr, shi, ioni, ionj); ++ } ++ } ++ printf("\n"); ++} ++ ++/* ++ *************************************************************************** ++ * Main loop: Read stats from the relevant sources and display them. ++ * ++ * IN: ++ * @count Number of lines of stats to print. ++ * @rectime Current date and time. ++ *************************************************************************** ++ */ ++void rw_io_stat_loop(long int count, struct tm *rectime) ++{ ++ int curr = 1; ++ ++ /* Don't buffer data if redirected to a pipe */ ++ setbuf(stdout, NULL); ++ ++ do { ++ /* Read system uptime (reduced to one processor) */ ++ uptime0[curr] = 0; ++ read_uptime(&(uptime0[curr])); ++ if (!uptime0[curr]) ++ /* Cannot read system uptime (/proc/uptime doesn't exist) */ ++ exit(2); ++ ++ /* Read NFS directories stats */ ++ read_nfs_stat(curr); ++ ++ /* Get time */ ++ get_localtime(rectime, 0); ++ ++ /* Print results */ ++ write_stats(curr, rectime); ++ ++ if (count > 0) { ++ count--; ++ } ++ if (count) { ++ curr ^= 1; ++ pause(); ++ } ++ } ++ while (count); ++} ++ ++/* ++ *************************************************************************** ++ * Main entry to the nfsiostat-sysstat program. ++ *************************************************************************** ++ */ ++int main(int argc, char **argv) ++{ ++ int it = 0; ++ int opt = 1; ++ int i; ++ long count = 1; ++ struct utsname header; ++ struct tm rectime; ++ ++#ifdef USE_NLS ++ /* Init National Language Support */ ++ init_nls(); ++#endif ++ ++ /* Get HZ */ ++ get_HZ(); ++ ++ /* Process args... */ ++ while (opt < argc) { ++ ++#ifdef DEBUG ++ if (!strcmp(argv[opt], "--debuginfo")) { ++ flags |= I_D_DEBUG; ++ opt++; ++ } else ++#endif ++ if (!strncmp(argv[opt], "-", 1)) { ++ for (i = 1; *(argv[opt] + i); i++) { ++ ++ switch (*(argv[opt] + i)) { ++ ++ case 'h': ++ /* Display an easy-to-read NFS report */ ++ flags |= I_D_HUMAN_READ; ++ break; ++ ++ case 'k': ++ if (DISPLAY_MEGABYTES(flags)) { ++ usage(argv[0]); ++ } ++ /* Display stats in kB/s */ ++ flags |= I_D_KILOBYTES; ++ break; ++ ++ case 'm': ++ if (DISPLAY_KILOBYTES(flags)) { ++ usage(argv[0]); ++ } ++ /* Display stats in MB/s */ ++ flags |= I_D_MEGABYTES; ++ break; ++ ++ case 't': ++ /* Display timestamp */ ++ flags |= I_D_TIMESTAMP; ++ break; ++ ++ case 'V': ++ /* Print version number and exit */ ++ print_version(); ++ break; ++ ++ default: ++ usage(argv[0]); ++ } ++ } ++ opt++; ++ } ++ ++ else if (!it) { ++ interval = atol(argv[opt++]); ++ if (interval < 0) { ++ usage(argv[0]); ++ } ++ count = -1; ++ it = 1; ++ } ++ ++ else if (it > 0) { ++ count = atol(argv[opt++]); ++ if ((count < 1) || !interval) { ++ usage(argv[0]); ++ } ++ it = -1; ++ } ++ else { ++ usage(argv[0]); ++ } ++ } ++ ++ if (!interval) { ++ count = 1; ++ } ++ ++ /* Select output unit (kB/s or blocks/s) */ ++ set_output_unit(); ++ ++ /* Init structures according to machine architecture */ ++ io_sys_init(); ++ ++ get_localtime(&rectime, 0); ++ ++ /* Get system name, release number and hostname */ ++ uname(&header); ++ if (print_gal_header(&rectime, header.sysname, header.release, ++ header.nodename, header.machine, cpu_nr)) { ++ flags |= I_D_ISO; ++ } ++ printf("\n"); ++ ++ /* Set a handler for SIGALRM */ ++ memset(&alrm_act, 0, sizeof(alrm_act)); ++ alrm_act.sa_handler = (void *) alarm_handler; ++ sigaction(SIGALRM, &alrm_act, NULL); ++ alarm(interval); ++ ++ /* Main loop */ ++ rw_io_stat_loop(count, &rectime); ++ ++ /* Free structures */ ++ io_sys_free(); ++ ++ return 0; ++} +diff -uprN sysstat-10.1.5.orig/nfsiostat-sysstat.h sysstat-10.1.5/nfsiostat-sysstat.h +--- sysstat-10.1.5.orig/nfsiostat-sysstat.h 1970-01-01 01:00:00.000000000 +0100 ++++ sysstat-10.1.5/nfsiostat-sysstat.h 2016-05-24 18:25:16.210668308 +0200 +@@ -0,0 +1,57 @@ ++/* ++ * nfsiostat-sysstat: Report NFS I/O statistics ++ * Copyright (C) 2010 Red Hat, Inc. All Rights Reserved ++ * Written by Ivana Varekova ++ */ ++ ++#ifndef _NFSIOSTAT_SYSSTAT_H ++#define _NFSIOSTAT_SYSSTAT_H ++ ++#include "common.h" ++ ++#define NFSMOUNTSTATS "/proc/self/mountstats" ++ ++/* I_: iostat - D_: Display - F_: Flag */ ++#define I_D_TIMESTAMP 0x001 ++#define I_D_KILOBYTES 0x002 ++#define I_D_MEGABYTES 0x004 ++#define I_D_ISO 0x008 ++#define I_D_HUMAN_READ 0x010 ++#define I_D_DEBUG 0x020 ++ ++#define DISPLAY_TIMESTAMP(m) (((m) & I_D_TIMESTAMP) == I_D_TIMESTAMP) ++#define DISPLAY_KILOBYTES(m) (((m) & I_D_KILOBYTES) == I_D_KILOBYTES) ++#define DISPLAY_MEGABYTES(m) (((m) & I_D_MEGABYTES) == I_D_MEGABYTES) ++#define DISPLAY_ISO(m) (((m) & I_D_ISO) == I_D_ISO) ++#define DISPLAY_HUMAN_READ(m) (((m) & I_D_HUMAN_READ) == I_D_HUMAN_READ) ++#define DISPLAY_DEBUG(m) (((m) & I_D_DEBUG) == I_D_DEBUG) ++ ++/* Environment variable */ ++#define ENV_POSIXLY_CORRECT "POSIXLY_CORRECT" ++ ++/* Preallocation constats */ ++#define NR_NFS_PREALLOC 2 ++ ++struct io_nfs_stats { ++ unsigned long long rd_normal_bytes __attribute__ ((aligned (8))); ++ unsigned long long wr_normal_bytes __attribute__ ((packed)); ++ unsigned long long rd_direct_bytes __attribute__ ((packed)); ++ unsigned long long wr_direct_bytes __attribute__ ((packed)); ++ unsigned long long rd_server_bytes __attribute__ ((packed)); ++ unsigned long long wr_server_bytes __attribute__ ((packed)); ++ unsigned long rpc_sends __attribute__ ((packed)); ++ unsigned long nfs_rops __attribute__ ((packed)); ++ unsigned long nfs_wops __attribute__ ((packed)); ++}; ++ ++#define IO_NFS_STATS_SIZE (sizeof(struct io_nfs_stats)) ++ ++struct io_hdr_stats { ++ unsigned int active __attribute__ ((aligned (4))); ++ unsigned int used __attribute__ ((packed)); ++ char name[MAX_NAME_LEN]; ++}; ++ ++#define IO_HDR_STATS_SIZE (sizeof(struct io_hdr_stats)) ++ ++#endif /* _NFSIOSTAT_SYSSTAT_H */ diff --git a/SOURCES/sysstat-10.1.5-overwrite-sa.patch b/SOURCES/sysstat-10.1.5-overwrite-sa.patch new file mode 100644 index 0000000..1b72d7b --- /dev/null +++ b/SOURCES/sysstat-10.1.5-overwrite-sa.patch @@ -0,0 +1,37 @@ +diff -ur sysstat-10.1.5.orig/sa1.in sysstat-10.1.5/sa1.in +--- sysstat-10.1.5.orig/sa1.in 2012-05-13 15:00:56.000000000 +0200 ++++ sysstat-10.1.5/sa1.in 2014-09-01 21:56:13.197869126 +0200 +@@ -10,15 +10,15 @@ + # Used only if ${SYSCONFIG_DIR}/sysstat doesn't exist! + HISTORY=0 + SADC_OPTIONS="" +- ++DDIR=@SA_DIR@ ++DATE=`date +%d` ++CURRENTFILE=sa${DATE} ++CURRENTDIR=`date +%Y%m` + SYSCONFIG_DIR=@SYSCONFIG_DIR@ ++umask 0022 + [ -r ${SYSCONFIG_DIR}/sysstat ] && . ${SYSCONFIG_DIR}/sysstat + if [ ${HISTORY} -gt 28 ] + then +- CURRENTDIR=`date +%Y%m` +- DATE=`date +%d` +- CURRENTFILE=sa${DATE} +- DDIR=@SA_DIR@ + cd ${DDIR} || exit 1 + [ -d ${CURRENTDIR} ] || mkdir -p ${CURRENTDIR} + # If ${CURRENTFILE} exists and is a regular file, then make sure +@@ -33,8 +33,11 @@ + # the (new) current file + rm -f ${CURRENTFILE} + ln -s ${CURRENTDIR}/${CURRENTFILE} ${CURRENTFILE} ++else ++ # If ${CURRENTFILE} exists, is a regular file and is from a previous ++ # month then delete it so that it is recreated by sadc afresh ++ [ -f ${CURRENTFILE} ] && [ "`date +%Y%m -r ${CURRENTFILE}`" -lt "${CURRENTDIR}" ] && rm -f ${CURRENTFILE} + fi +-umask 0022 + ENDIR=@SA_LIB_DIR@ + cd ${ENDIR} + [ "$1" = "--boot" ] && shift && BOOT=y || BOOT=n diff --git a/SOURCES/sysstat-10.1.5-pids-prealloc.patch b/SOURCES/sysstat-10.1.5-pids-prealloc.patch new file mode 100644 index 0000000..23d9a59 --- /dev/null +++ b/SOURCES/sysstat-10.1.5-pids-prealloc.patch @@ -0,0 +1,209 @@ +diff -upr sysstat-10.1.5.orig/common.h sysstat-10.1.5/common.h +--- sysstat-10.1.5.orig/common.h 2013-03-23 17:31:46.000000000 +0100 ++++ sysstat-10.1.5/common.h 2016-04-29 12:47:09.285214132 +0200 +@@ -106,9 +106,12 @@ + * + * NB: Define SP_VALUE() to normalize to %; + * HZ is 1024 on IA64 and % should be normalized to 100. ++ * SP_VALUE_100() will not output value bigger than 100; this is needed for some ++ * corner cases, should be used with care. + */ + #define S_VALUE(m,n,p) (((double) ((n) - (m))) / (p) * HZ) + #define SP_VALUE(m,n,p) (((double) ((n) - (m))) / (p) * 100) ++#define SP_VALUE_100(m,n,p) MINIMUM((((double) ((n) - (m))) / (p) * 100),100) + + /* + * Under very special circumstances, STDOUT may become unavailable. +diff -upr sysstat-10.1.5.orig/pidstat.c sysstat-10.1.5/pidstat.c +--- sysstat-10.1.5.orig/pidstat.c 2013-03-23 17:31:46.000000000 +0100 ++++ sysstat-10.1.5/pidstat.c 2016-04-29 13:04:02.672402150 +0200 +@@ -152,15 +152,35 @@ void salloc_pid_array(unsigned int len) + */ + void salloc_pid(unsigned int len) + { +- int i; ++ short i; ++ ++ for (i = 0; i < 3; i++) { ++ if ((st_pid_list[i] = (struct pid_stats *) calloc(len, PID_STATS_SIZE)) == NULL) { ++ perror("calloc"); ++ exit(4); ++ } ++ } ++} ++ ++/* ++ *************************************************************************** ++ * Reallocate structures for PIDs to read. ++ *************************************************************************** ++ */ ++void realloc_pid(void) ++{ ++ short i; ++ unsigned int new_size = 2 * pid_nr; + + for (i = 0; i < 3; i++) { +- if ((st_pid_list[i] = (struct pid_stats *) malloc(PID_STATS_SIZE * len)) == NULL) { +- perror("malloc"); ++ if ((st_pid_list[i] = (struct pid_stats *) realloc(st_pid_list[i], PID_STATS_SIZE * new_size)) == NULL) { ++ perror("realloc"); + exit(4); + } +- memset(st_pid_list[i], 0, PID_STATS_SIZE * len); ++ memset(st_pid_list[i] + pid_nr, 0, PID_STATS_SIZE * (new_size - pid_nr)); + } ++ ++ pid_nr = new_size; + } + + /* +@@ -774,23 +794,22 @@ void read_task_stats(int curr, unsigned + if ((dir = opendir(filename)) == NULL) + return; + +- while (*index < pid_nr) { ++ while ((drp = readdir(dir)) != NULL) { ++ if (!isdigit(drp->d_name[0])) { ++ continue; ++ } + +- while ((drp = readdir(dir)) != NULL) { +- if (isdigit(drp->d_name[0])) +- break; ++ pst = st_pid_list[curr] + (*index)++; ++ if (read_pid_stats(atoi(drp->d_name), pst, &thr_nr, pid)) { ++ /* Thread no longer exists */ ++ pst->pid = 0; + } + +- if (drp) { +- pst = st_pid_list[curr] + (*index)++; +- if (read_pid_stats(atoi(drp->d_name), pst, &thr_nr, pid)) { +- /* Thread no longer exists */ +- pst->pid = 0; +- } ++ if (*index >= pid_nr) { ++ realloc_pid(); + } +- else +- break; + } ++ + closedir(dir); + } + +@@ -830,36 +849,34 @@ void read_stats(int curr) + exit(4); + } + +- while (p < pid_nr) { ++ /* Get directory entries */ ++ while ((drp = readdir(dir)) != NULL) { ++ if (!isdigit(drp->d_name[0])) { ++ continue; ++ } ++ ++ pst = st_pid_list[curr] + p++; ++ pid = atoi(drp->d_name); ++ ++ if (read_pid_stats(pid, pst, &thr_nr, 0)) { ++ /* Process has terminated */ ++ pst->pid = 0; ++ } else if (DISPLAY_TID(pidflag)) { ++ /* Read stats for threads in task subdirectory */ ++ read_task_stats(curr, pid, &p); + +- /* Get directory entries */ +- while ((drp = readdir(dir)) != NULL) { +- if (isdigit(drp->d_name[0])) +- break; +- } +- if (drp) { +- pst = st_pid_list[curr] + p++; +- pid = atoi(drp->d_name); +- +- if (read_pid_stats(pid, pst, &thr_nr, 0)) { +- /* Process has terminated */ +- pst->pid = 0; +- } +- +- else if (DISPLAY_TID(pidflag)) { +- /* Read stats for threads in task subdirectory */ +- read_task_stats(curr, pid, &p); +- } +- } +- else { +- for (q = p; q < pid_nr; q++) { +- pst = st_pid_list[curr] + q; +- pst->pid = 0; +- } +- break; + } ++ ++ if (p >= pid_nr) { ++ realloc_pid(); ++ } + } + ++ for (q = p; q < pid_nr; q++) { ++ pst = st_pid_list[curr] + q; ++ pst->pid = 0; ++ } ++ + /* Close /proc directory */ + closedir(dir); + } +@@ -1174,15 +1191,15 @@ int write_pid_task_all_stats(int prev, i + printf(" %7.2f %7.2f %7.2f %7.2f", + (pstc->utime - pstc->gtime) < (pstp->utime - pstp->gtime) ? + 0.0 : +- SP_VALUE(pstp->utime - pstp->gtime, ++ SP_VALUE_100(pstp->utime - pstp->gtime, + pstc->utime - pstc->gtime, itv), +- SP_VALUE(pstp->stime, pstc->stime, itv), +- SP_VALUE(pstp->gtime, pstc->gtime, itv), ++ SP_VALUE_100(pstp->stime, pstc->stime, itv), ++ SP_VALUE_100(pstp->gtime, pstc->gtime, itv), + /* User time already includes guest time */ + IRIX_MODE_OFF(pidflag) ? +- SP_VALUE(pstp->utime + pstp->stime, ++ SP_VALUE_100(pstp->utime + pstp->stime, + pstc->utime + pstc->stime, g_itv) : +- SP_VALUE(pstp->utime + pstp->stime, ++ SP_VALUE_100(pstp->utime + pstp->stime, + pstc->utime + pstc->stime, itv)); + + printf(" %3d", pstc->processor); +@@ -1351,15 +1368,15 @@ int write_pid_task_cpu_stats(int prev, i + printf(" %7.2f %7.2f %7.2f %7.2f", + (pstc->utime - pstc->gtime) < (pstp->utime - pstp->gtime) ? + 0.0 : +- SP_VALUE(pstp->utime - pstp->gtime, ++ SP_VALUE_100(pstp->utime - pstp->gtime, + pstc->utime - pstc->gtime, itv), +- SP_VALUE(pstp->stime, pstc->stime, itv), +- SP_VALUE(pstp->gtime, pstc->gtime, itv), ++ SP_VALUE_100(pstp->stime, pstc->stime, itv), ++ SP_VALUE_100(pstp->gtime, pstc->gtime, itv), + /* User time already includes guest time */ + IRIX_MODE_OFF(pidflag) ? +- SP_VALUE(pstp->utime + pstp->stime, ++ SP_VALUE_100(pstp->utime + pstp->stime, + pstc->utime + pstc->stime, g_itv) : +- SP_VALUE(pstp->utime + pstp->stime, ++ SP_VALUE_100(pstp->utime + pstp->stime, + pstc->utime + pstc->stime, itv)); + + if (!disp_avg) { +diff -upr sysstat-10.1.5.orig/pidstat.h sysstat-10.1.5/pidstat.h +--- sysstat-10.1.5.orig/pidstat.h 2013-03-23 17:31:46.000000000 +0100 ++++ sysstat-10.1.5/pidstat.h 2016-04-28 18:24:37.700124018 +0200 +@@ -13,7 +13,7 @@ + #define K_P_CHILD "CHILD" + #define K_P_ALL "ALL" + +-#define NR_PID_PREALLOC 10 ++#define NR_PID_PREALLOC 100 + + #define MAX_COMM_LEN 128 + #define MAX_CMDLINE_LEN 128 diff --git a/SOURCES/sysstat-10.1.5-sa2-xz.patch b/SOURCES/sysstat-10.1.5-sa2-xz.patch new file mode 100644 index 0000000..ea352d3 --- /dev/null +++ b/SOURCES/sysstat-10.1.5-sa2-xz.patch @@ -0,0 +1,12 @@ +diff -ur sysstat-10.1.5.orig/sa2.in sysstat-10.1.5/sa2.in +--- sysstat-10.1.5.orig/sa2.in 2012-03-15 16:48:56.000000000 +0100 ++++ sysstat-10.1.5/sa2.in 2014-09-01 22:10:39.901270008 +0200 +@@ -50,7 +50,7 @@ + cd ${ENDIR} + [ -L ${RPT} ] && rm -f ${RPT} + ${ENDIR}/sar $* -f ${DFILE} > ${RPT} +-find ${DDIR} \( -name 'sar??' -o -name 'sa??' -o -name 'sar??.gz' -o -name 'sa??.gz' -o -name 'sar??.bz2' -o -name 'sa??.bz2' \) \ ++find ${DDIR} \( -name 'sar??' -o -name 'sa??' -o -name 'sar??.xz' -o -name 'sa??.xz' -o -name 'sar??.gz' -o -name 'sa??.gz' -o -name 'sar??.bz2' -o -name 'sa??.bz2' \) \ + -mtime +"${HISTORY}" -exec rm -f {} \; + find ${DDIR} \( -name 'sar??' -o -name 'sa??' \) -type f -mtime +"${COMPRESSAFTER}" \ + -exec ${ZIP} {} \; > /dev/null 2>&1 diff --git a/SOURCES/sysstat-10.1.5-single-cpu-cifs.patch b/SOURCES/sysstat-10.1.5-single-cpu-cifs.patch new file mode 100644 index 0000000..a6c72a7 --- /dev/null +++ b/SOURCES/sysstat-10.1.5-single-cpu-cifs.patch @@ -0,0 +1,99 @@ +diff -upr sysstat-10.1.5.orig/cifsiostat.c sysstat-10.1.5/cifsiostat.c +--- sysstat-10.1.5.orig/cifsiostat.c 2013-03-23 17:31:46.000000000 +0100 ++++ sysstat-10.1.5/cifsiostat.c 2014-09-29 14:23:37.600574444 +0200 +@@ -43,7 +43,6 @@ + #define SCCSID "@(#)sysstat-" VERSION ": " __FILE__ " compiled " __DATE__ " " __TIME__ + char *sccsid(void) { return (SCCSID); } + +-unsigned long long uptime[2] = {0, 0}; + unsigned long long uptime0[2] = {0, 0}; + struct cifs_stats *st_cifs[2]; + struct io_hdr_stats *st_hdr_cifs; +@@ -474,13 +473,8 @@ void write_stats(int curr, struct tm *re + #endif + } + +- /* Interval is multiplied by the number of processors */ +- itv = get_interval(uptime[!curr], uptime[curr]); +- +- if (cpu_nr > 1) { +- /* On SMP machines, reduce itv to one processor (see note above) */ +- itv = get_interval(uptime0[!curr], uptime0[curr]); +- } ++ /* Interval of time, reduced to one processor */ ++ itv = get_interval(uptime0[!curr], uptime0[curr]); + + shi = st_hdr_cifs; + +@@ -527,15 +521,12 @@ void rw_io_stat_loop(long int count, str + setbuf(stdout, NULL); + + do { +- if (cpu_nr > 1) { +- /* +- * Read system uptime (only for SMP machines). +- * Init uptime0. So if /proc/uptime cannot fill it, +- * this will be done by /proc/stat. +- */ +- uptime0[curr] = 0; +- read_uptime(&(uptime0[curr])); +- } ++ /* Read system uptime (reduced to one processor) */ ++ uptime0[curr] = 0; ++ read_uptime(&(uptime0[curr])); ++ if (!uptime0[curr]) ++ /* Cannot read system uptime (/proc/uptime doesn't exist) */ ++ exit(2); + + /* Read CIFS stats */ + read_cifs_stat(curr); +diff -upr sysstat-10.1.5.orig/nfsiostat.c sysstat-10.1.5/nfsiostat.c +--- sysstat-10.1.5.orig/nfsiostat.c 2013-03-23 17:31:46.000000000 +0100 ++++ sysstat-10.1.5/nfsiostat.c 2014-09-29 14:23:37.601574440 +0200 +@@ -42,7 +42,6 @@ + #define SCCSID "@(#)sysstat-" VERSION ": " __FILE__ " compiled " __DATE__ " " __TIME__ + char *sccsid(void) { return (SCCSID); } + +-unsigned long long uptime[2] = {0, 0}; + unsigned long long uptime0[2] = {0, 0}; + struct io_nfs_stats *st_ionfs[2]; + struct io_hdr_stats *st_hdr_ionfs; +@@ -541,13 +540,8 @@ void write_stats(int curr, struct tm *re + #endif + } + +- /* Interval is multiplied by the number of processors */ +- itv = get_interval(uptime[!curr], uptime[curr]); +- +- if (cpu_nr > 1) { +- /* On SMP machines, reduce itv to one processor (see note above) */ +- itv = get_interval(uptime0[!curr], uptime0[curr]); +- } ++ /* Interval of time, reduced to one processor */ ++ itv = get_interval(uptime0[!curr], uptime0[curr]); + + shi = st_hdr_ionfs; + +@@ -595,15 +589,13 @@ void rw_io_stat_loop(long int count, str + setbuf(stdout, NULL); + + do { +- if (cpu_nr > 1) { +- /* +- * Read system uptime (only for SMP machines). +- * Init uptime0. So if /proc/uptime cannot fill it, +- * this will be done by /proc/stat. +- */ +- uptime0[curr] = 0; +- read_uptime(&(uptime0[curr])); +- } ++ /* Read system uptime (reduced to one processor) */ ++ uptime0[curr] = 0; ++ read_uptime(&(uptime0[curr])); ++ if (!uptime0[curr]) ++ /* Cannot read system uptime (/proc/uptime doesn't exist) */ ++ exit(2); ++ + /* Read NFS directories stats */ + read_nfs_stat(curr); + diff --git a/SOURCES/sysstat-10.1.5-sysstat-5.patch b/SOURCES/sysstat-10.1.5-sysstat-5.patch new file mode 100644 index 0000000..0818849 --- /dev/null +++ b/SOURCES/sysstat-10.1.5-sysstat-5.patch @@ -0,0 +1,118 @@ +diff -ur sysstat-10.1.5.orig/man/sysstat.in sysstat-10.1.5/man/sysstat.in +--- sysstat-10.1.5.orig/man/sysstat.in 2010-09-22 22:07:29.000000000 +0200 ++++ sysstat-10.1.5/man/sysstat.in 2014-09-01 22:50:58.614499671 +0200 +@@ -11,17 +11,99 @@ + configure sysstat logging. + The variables and their meanings are: + .TP ++.B COMPRESSAFTER ++Number of days after which daily data files are to be compressed. ++The compression program is given in the ++.B ZIP ++variable. ++ ++.TP + .B HISTORY + The number of days during which a daily data file or a report + should be kept. Data files or reports older than this number of + days will be removed by the + .BR sa2 (8) + shell script. ++Data files and reports are normally saved in the @SA_DIR@ directory, ++under the name ++.IR saDD ++(for data files) or ++.IR sarDD ++(for reports), where the DD parameter indicates the current day. + +-.TP +-.B COMPRESSAFTER +-Number of days after which daily data files are to be compressed, +-either by gzip or bzip2. ++The number of files actually kept in the @SA_DIR@ directory may be ++slightly higher than the ++.B HISTORY ++value due to the way the ++.B sa2 ++script figures ++out which files are to be removed (see below "How the ++.BR sa2 (8) ++script applies ++.B HISTORY ++value"). Using a value of 28 keeps a whole month's worth of data. ++ ++How the ++.BR sa2 (8) ++script applies ++.B HISTORY ++value ++ ++The ++.B sa2 ++script uses the "find" command with the "-mtime" option to figure ++out which files are to be removed. The "find" command interprets this value ++as "N 24 hour periods", ignoring any fractional part. This means that the ++last modified time of a given sa[r]DD data or report file, using a ++.B HISTORY ++of 1, has to have been modified at least two days ago before it will be ++removed. And for a ++.B HISTORY ++of 28 that would mean 29 days ago. ++ ++To figure out how a ++.B HISTORY ++of 28 is applied in practice, we need to ++consider that the ++.B sa2 ++script that issues the "find" command to remove the ++old files typically runs just before mid-night on a given system, and since ++the first record from ++.B sadc ++can also be written to the previous day's data file ++(thereby moving its modification time up a bit), the ++.B sa2 ++script will leave ++30 files untouched. So for a setting of 28, and counting the data file of ++the current day, there will always be 31 files (or 30 files, depending on the ++number of days in a month) in the @SA_DIR@ directory during the majority ++of a given day. E.g.: ++ ++April 30th: 31 files (Apr 30th-1st, Mar 31th) ++.br ++May 1st: 30 files (May 1st, Apr 30th-2nd) ++ ++Yet we can note the following exceptions (as inspected at Noon of the given ++day): ++ ++February 28th: 31 files (Feb 28th-1st, Jan 31st, 30th & 29th) ++.br ++March 1st: 30 files (Mar 1st, Feb 28th-2nd, Jan 31st & 30th) ++.br ++March 2nd: 29 files (Mar 1st & 2nd, Feb 28th-3rd, Jan. 31st) ++.br ++March 3rd: 28 files (Mar 1st-3rd, Feb 28th-4th) ++.br ++March 4th - March 28th: 28 files ++.br ++March 29th: 29 files ++.br ++March 30th: 30 files ++.br ++March 31st: 31 files ++ ++(Determining the number of files in March on a leap year is left as an ++exercise for the reader). + + .TP + .B SADC_OPTIONS +@@ -34,6 +116,10 @@ + These options are used only when a new data file is created. They will be + ignored with an already existing one. + ++.TP ++.B ZIP ++Program used to compress data and report files. ++ + .SH FILES + .IR @SYSCONFIG_DIR@/sysstat + diff --git a/SOURCES/sysstat-10.1.5-tapestat.patch b/SOURCES/sysstat-10.1.5-tapestat.patch new file mode 100644 index 0000000..50ab274 --- /dev/null +++ b/SOURCES/sysstat-10.1.5-tapestat.patch @@ -0,0 +1,1124 @@ +diff -uprN sysstat-10.1.5.orig/Makefile.in sysstat-10.1.5/Makefile.in +--- sysstat-10.1.5.orig/Makefile.in 2016-06-01 12:46:28.193462305 +0200 ++++ sysstat-10.1.5/Makefile.in 2016-06-01 12:46:52.027338556 +0200 +@@ -160,7 +160,7 @@ NLSPOT= $(NLSPO:.po=.pot) + % : %.o + $(CC) -o $@ $(CFLAGS) $^ $(LFLAGS) + +-all: sadc sar sadf iostat mpstat pidstat nfsiostat-sysstat cifsiostat locales ++all: sadc sar sadf iostat tapestat mpstat pidstat nfsiostat-sysstat cifsiostat locales + + common.o: common.c version.h common.h ioconf.h sysconfig.h + +@@ -221,6 +221,10 @@ iostat.o: iostat.c iostat.h version.h co + + iostat: iostat.o librdstats.a libsyscom.a + ++tapestat.o: tapestat.c tapestat.h version.h common.h ++ ++tapestat: tapestat.o librdstats.a libsyscom.a ++ + pidstat.o: pidstat.c pidstat.h version.h common.h rd_stats.h + + pidstat: pidstat.o librdstats.a libsyscom.a +@@ -269,6 +273,8 @@ ifeq ($(INSTALL_DOC),y) + $(INSTALL_DATA) $(MANGRPARG) man/sysstat.5 $(DESTDIR)$(MAN5_DIR) + rm -f $(DESTDIR)$(MAN1_DIR)/iostat.1* + $(INSTALL_DATA) $(MANGRPARG) man/iostat.1 $(DESTDIR)$(MAN1_DIR) ++ rm -f $(DESTDIR)$(MAN1_DIR)/tapestat.1* ++ $(INSTALL_DATA) $(MANGRPARG) man/tapestat.1 $(DESTDIR)$(MAN1_DIR) + rm -f $(DESTDIR)$(MAN1_DIR)/mpstat.1* + $(INSTALL_DATA) $(MANGRPARG) man/mpstat.1 $(DESTDIR)$(MAN1_DIR) + rm -f $(DESTDIR)$(MAN1_DIR)/pidstat.1* +@@ -288,6 +294,7 @@ ifeq ($(COMPRESS_MANPG),y) + $(ZIP) $(DESTDIR)$(MAN1_DIR)/sadf.1 + $(ZIP) $(DESTDIR)$(MAN5_DIR)/sysstat.5 + $(ZIP) $(DESTDIR)$(MAN1_DIR)/iostat.1 ++ $(ZIP) $(DESTDIR)$(MAN1_DIR)/tapestat.1 + $(ZIP) $(DESTDIR)$(MAN1_DIR)/mpstat.1 + $(ZIP) $(DESTDIR)$(MAN1_DIR)/pidstat.1 + $(ZIP) $(DESTDIR)$(MAN1_DIR)/nfsiostat-sysstat.1 +@@ -328,6 +335,7 @@ endif + $(INSTALL_BIN) sar $(DESTDIR)$(BIN_DIR) + $(INSTALL_BIN) sadf $(DESTDIR)$(BIN_DIR) + $(INSTALL_BIN) iostat $(DESTDIR)$(BIN_DIR) ++ $(INSTALL_BIN) tapestat $(DESTDIR)$(BIN_DIR) + $(INSTALL_BIN) mpstat $(DESTDIR)$(BIN_DIR) + $(INSTALL_BIN) pidstat $(DESTDIR)$(BIN_DIR) + $(INSTALL_BIN) nfsiostat-sysstat $(DESTDIR)$(BIN_DIR) +@@ -395,6 +403,7 @@ ifeq ($(INSTALL_DOC),y) + rm -f $(DESTDIR)$(MAN1_DIR)/sadf.1* + rm -f $(DESTDIR)$(MAN5_DIR)/sysstat.5* + rm -f $(DESTDIR)$(MAN1_DIR)/iostat.1* ++ rm -f $(DESTDIR)$(MAN1_DIR)/tapestat.1* + rm -f $(DESTDIR)$(MAN1_DIR)/mpstat.1* + rm -f $(DESTDIR)$(MAN1_DIR)/pidstat.1* + rm -f $(DESTDIR)$(MAN1_DIR)/nfsiostat-sysstat.1* +@@ -423,6 +432,7 @@ uninstall_base: uninstall_man uninstall_ + rm -f $(DESTDIR)$(BIN_DIR)/sar + rm -f $(DESTDIR)$(BIN_DIR)/sadf + rm -f $(DESTDIR)$(BIN_DIR)/iostat ++ rm -f $(DESTDIR)$(BIN_DIR)/tapestat + rm -f $(DESTDIR)$(BIN_DIR)/mpstat + rm -f $(DESTDIR)$(BIN_DIR)/pidstat + rm -f $(DESTDIR)$(BIN_DIR)/nfsiostat-sysstat +@@ -487,7 +497,7 @@ po-files: + endif + + clean: +- rm -f sadc sar sadf iostat mpstat pidstat nfsiostat-sysstat cifsiostat *.o *.a core TAGS ++ rm -f sadc sar sadf iostat tapestat mpstat pidstat nfsiostat-sysstat cifsiostat *.o *.a core TAGS + find nls -name "*.gmo" -exec rm -f {} \; + + almost-distclean: clean nls/sysstat.pot +diff -uprN sysstat-10.1.5.orig/man/tapestat.1 sysstat-10.1.5/man/tapestat.1 +--- sysstat-10.1.5.orig/man/tapestat.1 1970-01-01 01:00:00.000000000 +0100 ++++ sysstat-10.1.5/man/tapestat.1 2016-06-01 12:46:52.028338551 +0200 +@@ -0,0 +1,216 @@ ++.TH TAPESTAT 1 "MARCH 2016" Linux "Linux User's Manual" -*- nroff -*- ++.SH NAME ++tapestat \- Report tape statistics. ++.SH SYNOPSIS ++.B tapestat [ -k | -m ] [ -t ] [ -V ] [ -y ] [ -z ] [ ++.I interval ++.B [ ++.I count ++.B ] ] ++.SH DESCRIPTION ++The ++.B tapestat ++command is used for monitoring the activity of tape drives connected to a system. ++ ++The first report generated by the ++.B tapestat ++command provides statistics ++concerning the time since the system was booted, unless the ++.B -y ++option is used, when this first report is omitted. ++Each subsequent report ++covers the time since the previous report. ++ ++The ++.I interval ++parameter specifies the amount of time in seconds between ++each report. ++The ++.I count ++parameter can be specified in conjunction with the ++.I interval ++parameter. If the ++.I count ++parameter is specified, the value of ++.I count ++determines the number of reports generated at ++.I interval ++seconds apart. If the ++.I interval ++parameter is specified without the ++.I count ++parameter, the ++.B tapestat ++command generates reports continuously. ++ ++.SH REPORT ++The ++.B tapestat ++report provides statistics for each tape drive connected to the system. ++The following data are displayed: ++ ++.B r/s ++.RS ++The number of reads issued expressed as the number per second averaged over the interval. ++ ++.RE ++.B w/s ++.RS ++The number of writes issued expressed as the number per second averaged over the interval. ++ ++.RE ++.B kB_read/s | MB_read/s ++.RS ++The amount of data read expressed in kilobytes (by default or if option -k used) or ++megabytes (if option -m used) per second averaged over the interval. ++ ++.RE ++.B kB_wrtn/s | MB_wrtn/s ++.RS ++The amount of data written expressed in kilobytes (by default or if option -k used) or ++megabytes (if option -m used) per second averaged over the interval. ++ ++.RE ++.B %Rd ++.RS ++Read percentage wait - The percentage of time over the interval spent waiting for read requests ++to complete. ++The time is measured from when the request is dispatched to the SCSI mid-layer until it signals ++that it completed. ++ ++.RE ++.B %Wr ++.RS ++Write percentage wait - The percentage of time over the interval spent waiting for write requests ++to complete. The time is measured from when the request is dispatched to the SCSI mid-layer until ++it signals that it completed. ++ ++.RE ++.B %Oa ++.RS ++Overall percentage wait - The percentage of time over the interval spent waiting for any ++I/O request to complete (read, write, and other). ++ ++.RE ++.B Rs/s ++.RS ++The number of I/Os, expressed as the number per second averaged over the interval, where ++a non-zero residual value was encountered. ++ ++.RE ++.B Ot/s ++.RS ++The number of I/Os, expressed as the number per second averaged over the interval, that ++were included as "other". Other I/O includes ioctl calls made to the tape driver and ++implicit operations performed by the tape driver such as rewind on close ++(for tape devices that implement rewind on close). It does not include any I/O performed ++using methods outside of the tape driver (e.g. via sg ioctls). ++.RE ++.RE ++.SH OPTIONS ++.IP -k ++Show the amount of data written or read in kilobytes per second instead of megabytes. ++This option is mutually exclusive with -m. ++.IP -m ++Show the amount of data written or read in megabytes per second instead of kilobytes. ++This option is mutually exclusive with -k. ++.IP -t ++Display time stamps. The time stamp format may depend ++on the value of the S_TIME_FORMAT environment variable (see below). ++.IP -V ++Print version and exit. ++.IP -y ++Omit the initial statistic showing values since boot. ++.IP -z ++Tell ++.B tapestat ++to omit output for any tapes for which there was no activity ++during the sample period. ++ ++.SH CONSIDERATIONS ++It is possible for a percentage value (read, write, or other) to be greater than 100 percent ++(the ++.B tapestat ++command will never show a percentage value more than 999). ++If rewinding a tape takes 40 seconds where the interval time is 5 seconds the %Oa value ++would show as 0 in the intervals before the rewind completed and then show as approximately ++800 percent when the rewind completes. ++ ++Similar values will be observed for %Rd and %Wr if a tape drive stops reading or writing ++and then restarts (that is it stopped streaming). In such a case you may see the r/s or w/s drop to zero and the %Rd/%Wr value could be higher than 100 when reading or writing continues ++(depending on how long it takes to restart writing or reading). ++This is only an issue if it happens a lot as it may cause tape wear and will impact ++on the backup times. ++ ++For fast tape drives you may see low percentage wait times. ++This does not indicate an issue with the tape drive. For a slower tape drive (e.g. an older ++generation DDS drive) the speed of the tape (and tape drive) is much slower than filesystem I/O, ++percent wait times are likely to be higher. For faster tape drives (e.g. LTO) the percentage ++wait times are likely to be lower as program writing to or reading from tape is going ++to be doing a lot more filesystem I/O because of the higher throughput. ++ ++Although tape statistics are implemented in the kernel using atomic variables they cannot be ++read atomically as a group. All of the statistics values are read from different files under ++/sys, because of this there may be I/O completions while reading the different files for the ++one tape drive. This may result in a set of statistics for a device that contain some values ++before an I/O completed and some after. ++ ++This command uses rounding down as the rounding method when calculating per second statistics. ++If, for example, you are using dd to copy one tape to another and running ++.B tapestat ++with an interval of 5 seconds and over the interval there were 3210 writes and 3209 reads ++then w/s would show 642 and r/s 641 (641.8 rounded down to 641). In such a case if it was ++a tar archive being copied (with a 10k block size) you would also see a difference between ++the kB_read/s and kB_wrtn/s of 2 (one I/O 10k in size divided by the interval period of 5 ++seconds). If instead there were 3210 writes and 3211 reads both w/s and r/s would both show ++642 but you would still see a difference between the kB_read/s and kB_wrtn/s values of 2 kB/s. ++ ++This command is provided with an interval in seconds. However internally the interval is ++tracked per device and can potentially have an effect on the per second statistics reported. ++The time each set of statistics is captured is kept with those statistics. The difference ++between the current and previous time is converted to milliseconds for use in calculations. ++We can look at how this can impact the statistics reported if we use an example of a tar ++archive being copied between two tape drives using dd. If both devices reported 28900 kilobytes ++transferred and the reading tape drive had an interval of 5001 milliseconds and the writing ++tape drive 5000 milliseconds that would calculate out as 5778 kB_read/s and 5780 kB_wrtn/s. ++ ++The impact of some retrieving statistics during an I/O completion, rounding down, and small differences in the interval period on the statistics calculated should be minimal but may be non-zero. ++.SH ENVIRONMENT ++The ++.B tapestat ++command takes into account the following environment variable: ++ ++.IP S_TIME_FORMAT ++If this variable exists and its value is ++.BR ISO ++then the current locale will be ignored when printing the date in the report ++header. The ++.B tapestat ++command will use the ISO 8601 format (YYYY-MM-DD) instead. ++The timestamp displayed with option -t will also be compliant with ISO 8601 ++format. ++ ++.SH BUGS ++.I /sys ++filesystem must be mounted for ++.B tapestat ++to work. It will not work on kernels that do not have sysfs support ++ ++This command requires kernel version 4.2 or later ++(or tape statistics support backported for an earlier kernel version). ++ ++.SH FILES ++.I /sys/class/scsi_tape/st/stats/* ++Statistics files for tape devices. ++ ++.I /proc/uptime ++contains system uptime. ++.SH AUTHOR ++Initial revision by Shane M. SEYMOUR (shane.seymour hpe.com) ++.br ++Modified for sysstat by Sebastien Godard (sysstat orange.fr) ++.SH SEE ALSO ++.BR iostat (1), ++.BR mpstat (1) ++ ++.I http://pagesperso-orange.fr/sebastien.godard/ +diff -uprN sysstat-10.1.5.orig/tapestat.c sysstat-10.1.5/tapestat.c +--- sysstat-10.1.5.orig/tapestat.c 1970-01-01 01:00:00.000000000 +0100 ++++ sysstat-10.1.5/tapestat.c 2016-06-01 12:54:20.384015957 +0200 +@@ -0,0 +1,697 @@ ++/* ++ * tapestat: report tape statistics ++ * (C) 2015 Hewlett-Packard Development Company, L.P. ++ * ++ * Initial revision by Shane M. SEYMOUR (shane.seymour hpe.com) ++ * Modified for sysstat by Sebastien GODARD (sysstat orange.fr) ++ * ++ *************************************************************************** ++ * This program is free software; you can redistribute it and/or modify it * ++ * under the terms of the GNU General Public License as published by the * ++ * Free Software Foundation; either version 2 of the License, or (at your * ++ * option) any later version. * ++ * * ++ * This program is distributed in the hope that it will be useful, but * ++ * WITHOUT ANY WARRANTY; without the implied warranty of MERCHANTABILITY * ++ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * ++ * for more details. * ++ * * ++ * You should have received a copy of the GNU General Public License along * ++ * with this program; if not, write to the Free Software Foundation, Inc., * ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA * ++ *************************************************************************** ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#define __DO_NOT_DEFINE_COMPILE ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#undef HZ /* sys/param.h defines HZ but needed for MAXPATHLEN */ ++ ++#include "version.h" ++#include "tapestat.h" ++#include "common.h" ++ ++#ifdef USE_NLS ++#include ++#include ++#define _(string) gettext(string) ++#else ++#define _(string) (string) ++#endif ++ ++#define SCCSID "@(#)sysstat-" VERSION ": " __FILE__ " compiled " __DATE__ " " __TIME__ ++char *sccsid(void) { return (SCCSID); } ++ ++int cpu_nr = 0; /* Nb of processors on the machine */ ++int flags = 0; /* Flag for common options and system state */ ++ ++long interval = 0; ++char timestamp[64]; ++ ++struct sigaction alrm_act; ++ ++/* ++ * For tape stats - it would be extremely rare for there to be a very large ++ * number of tape drives attached to a system. I wouldn't expect to see more ++ * than 20-30 in a very large configuration and discontinguous ones should ++ * be even more rare. Because of this we keep the old and new data in a ++ * simple data structure with the tape index being the number after the tape ++ * drive, st0 at index 0, etc. ++ */ ++int max_tape_drives = 0; ++struct tape_stats *tape_new_stats = { NULL }; ++struct tape_stats *tape_old_stats = { NULL }; ++regex_t tape_reg; ++ ++/* ++ *************************************************************************** ++ * Print usage and exit. ++ * ++ * IN: ++ * @progname Name of sysstat command. ++ *************************************************************************** ++ */ ++void usage(char *progname) ++{ ++ fprintf(stderr, _("Usage: %s [ options ] [ [ ] ]\n"), ++ progname); ++ fprintf(stderr, _("Options are:\n" ++ "[ -k | -m ] [ -t ] [ -V ] [ -y ] [ -z ]\n")); ++ exit(1); ++} ++ ++/* ++ *************************************************************************** ++ * SIGALRM signal handler. No need to reset the handler here. ++ * ++ * IN: ++ * @sig Signal number. ++ *************************************************************************** ++ */ ++void alarm_handler(int sig) ++{ ++ alarm(interval); ++} ++ ++/* ++ *************************************************************************** ++ * Initialization. ++ *************************************************************************** ++ */ ++void tape_initialise(void) ++{ ++ /* How many processors on this machine? */ ++ cpu_nr = get_cpu_nr(~0); ++ ++ /* Compile regular expression for tape names */ ++ if (regcomp(&tape_reg, "^st[0-9]+$", REG_EXTENDED) != 0) { ++ exit(1); ++ } ++} ++ ++/* ++ *************************************************************************** ++ * Free structures. ++ *************************************************************************** ++ */ ++void tape_uninitialise(void) ++{ ++ regfree(&tape_reg); ++ if (tape_old_stats != NULL) { ++ free(tape_old_stats); ++ } ++ if (tape_new_stats != NULL) { ++ free(tape_new_stats); ++ } ++} ++ ++/* ++ *************************************************************************** ++ * Get maximum number of tapes in the system. ++ * ++ * RETURNS: ++ * Number of tapes found. ++ *************************************************************************** ++ */ ++int get_max_tape_drives(void) ++{ ++ DIR *dir; ++ struct dirent *entry; ++ int new_max_tape_drives, tmp, num_stats_dir = 0; ++ regmatch_t match; ++ char stats_dir[MAXPATHLEN + 1]; ++ struct stat stat_buf; ++ ++ new_max_tape_drives = max_tape_drives; ++ ++ /* Open sysfs tree */ ++ dir = opendir(SYSFS_CLASS_TAPE_DIR); ++ if (dir == NULL) ++ return 0; ++ ++ while ((entry = readdir(dir)) != NULL) { ++ if (regexec(&tape_reg, &entry->d_name[0], 1, &match, 0) == 0) { ++ /* d_name[2] to skip the st at the front */ ++ tmp = atoi(&entry->d_name[2]) + 1; ++ if (tmp > new_max_tape_drives) { ++ new_max_tape_drives = tmp; ++ } ++ } ++ snprintf(stats_dir, MAXPATHLEN, "%s/%s/%s", ++ SYSFS_CLASS_TAPE_DIR, &entry->d_name[0], "stats"); ++ if (stat(stats_dir, &stat_buf) == 0) { ++ if (S_ISDIR(stat_buf.st_mode)) { ++ num_stats_dir++; ++ } ++ } ++ } ++ closedir(dir); ++ ++ /* If there are no stats directories make the new number of tape drives 0 */ ++ if (num_stats_dir == 0) { ++ new_max_tape_drives = 0; ++ } ++ ++ return new_max_tape_drives; ++} ++ ++/* ++ *************************************************************************** ++ * Check if new tapes have been added and reallocate structures accordingly. ++ *************************************************************************** ++ */ ++void tape_check_tapes_and_realloc(void) ++{ ++ int new_max_tape_drives, i; ++ ++ /* Count again number of tapes */ ++ new_max_tape_drives = get_max_tape_drives(); ++ ++ if (new_max_tape_drives > max_tape_drives && new_max_tape_drives > 0) { ++ /* New tapes found: Realloc structures */ ++ struct tape_stats *tape_old_stats_t = (struct tape_stats *) ++ realloc(tape_old_stats, sizeof(struct tape_stats) * new_max_tape_drives); ++ struct tape_stats *tape_new_stats_t = (struct tape_stats *) ++ realloc(tape_new_stats, sizeof(struct tape_stats) * new_max_tape_drives); ++ if ((tape_old_stats_t == NULL) || (tape_new_stats_t == NULL)) { ++ if (tape_old_stats_t != NULL) { ++ free(tape_old_stats_t); ++ tape_old_stats_t = NULL; ++ } else { ++ free(tape_old_stats); ++ tape_old_stats = NULL; ++ } ++ if (tape_new_stats_t != NULL) { ++ free(tape_new_stats_t); ++ tape_new_stats_t = NULL; ++ } else { ++ free(tape_new_stats); ++ tape_new_stats = NULL; ++ } ++ ++ perror("realloc"); ++ exit(4); ++ } ++ ++ tape_old_stats = tape_old_stats_t; ++ tape_new_stats = tape_new_stats_t; ++ ++ for (i = max_tape_drives; i < new_max_tape_drives; i++) { ++ tape_old_stats[i].valid = TAPE_STATS_INVALID; ++ tape_new_stats[i].valid = TAPE_STATS_INVALID; ++ } ++ max_tape_drives = new_max_tape_drives; ++ } ++} ++ ++/* ++ *************************************************************************** ++ * Collect initial statistics for all existing tapes in the system. ++ * This function should be called only once. ++ *************************************************************************** ++ */ ++void tape_gather_initial_stats(void) ++{ ++ int new_max_tape_drives, i; ++ FILE *fp; ++ char filename[MAXPATHLEN + 1]; ++ ++ /* Get number of tapes in the system */ ++ new_max_tape_drives = get_max_tape_drives(); ++ ++ if (new_max_tape_drives == 0) { ++ /* No tapes found */ ++ fprintf(stderr, _("No tape drives with statistics found\n")); ++ exit(1); ++ } ++ else { ++ /* Allocate structures */ ++ if (tape_old_stats == NULL) { ++ tape_old_stats = (struct tape_stats *) ++ malloc(sizeof(struct tape_stats) * new_max_tape_drives); ++ tape_new_stats = (struct tape_stats *) ++ malloc(sizeof(struct tape_stats) * new_max_tape_drives); ++ for (i = 0; i < new_max_tape_drives; i++) { ++ tape_old_stats[i].valid = TAPE_STATS_INVALID; ++ tape_new_stats[i].valid = TAPE_STATS_INVALID; ++ } ++ max_tape_drives = new_max_tape_drives; ++ } else ++ /* This should only be called once */ ++ return; ++ } ++ ++ /* Read stats for each tape */ ++ for (i = 0; i < max_tape_drives; i++) { ++ /* ++ * Everything starts out valid but failing to open ++ * a file gets the tape drive marked invalid. ++ */ ++ tape_new_stats[i].valid = TAPE_STATS_VALID; ++ tape_old_stats[i].valid = TAPE_STATS_VALID; ++ ++ gettimeofday(&tape_old_stats[i].tv, NULL); ++ ++ tape_new_stats[i].tv.tv_sec = tape_old_stats[i].tv.tv_sec; ++ tape_new_stats[i].tv.tv_usec = tape_old_stats[i].tv.tv_usec; ++ ++ TAPE_STAT_FILE_VAL(TAPE_STAT_PATH "read_ns", read_time) ++ TAPE_STAT_FILE_VAL(TAPE_STAT_PATH "write_ns", write_time) ++ TAPE_STAT_FILE_VAL(TAPE_STAT_PATH "io_ns", other_time) ++ TAPE_STAT_FILE_VAL(TAPE_STAT_PATH "read_byte_cnt", read_bytes) ++ TAPE_STAT_FILE_VAL(TAPE_STAT_PATH "write_byte_cnt", write_bytes) ++ TAPE_STAT_FILE_VAL(TAPE_STAT_PATH "read_cnt", read_count) ++ TAPE_STAT_FILE_VAL(TAPE_STAT_PATH "write_cnt", write_count) ++ TAPE_STAT_FILE_VAL(TAPE_STAT_PATH "other_cnt", other_count) ++ TAPE_STAT_FILE_VAL(TAPE_STAT_PATH "resid_cnt", resid_count) ++ ++ tape_old_stats[i].read_time = 0; ++ tape_old_stats[i].write_time = 0; ++ tape_old_stats[i].other_time = 0; ++ tape_old_stats[i].read_bytes = 0; ++ tape_old_stats[i].write_bytes = 0; ++ tape_old_stats[i].read_count = 0; ++ tape_old_stats[i].write_count = 0; ++ tape_old_stats[i].other_count = 0; ++ tape_old_stats[i].resid_count = 0; ++ } ++} ++ ++/* ++ *************************************************************************** ++ * Collect a new sample of statistics for all existing tapes in the system. ++ *************************************************************************** ++ */ ++void tape_get_updated_stats(void) ++{ ++ int i; ++ FILE *fp; ++ char filename[MAXPATHLEN + 1] = { 0 }; ++ ++ /* Check tapes and realloc structures if needed */ ++ tape_check_tapes_and_realloc(); ++ ++ for (i = 0; i < max_tape_drives; i++) { ++ /* ++ * Everything starts out valid but failing ++ * to open a file gets the tape drive marked invalid. ++ */ ++ tape_new_stats[i].valid = TAPE_STATS_VALID; ++ gettimeofday(&tape_new_stats[i].tv, NULL); ++ ++ TAPE_STAT_FILE_VAL(TAPE_STAT_PATH "read_ns", read_time) ++ TAPE_STAT_FILE_VAL(TAPE_STAT_PATH "write_ns", write_time) ++ TAPE_STAT_FILE_VAL(TAPE_STAT_PATH "io_ns", other_time) ++ TAPE_STAT_FILE_VAL(TAPE_STAT_PATH "read_byte_cnt", read_bytes) ++ TAPE_STAT_FILE_VAL(TAPE_STAT_PATH "write_byte_cnt", write_bytes) ++ TAPE_STAT_FILE_VAL(TAPE_STAT_PATH "read_cnt", read_count) ++ TAPE_STAT_FILE_VAL(TAPE_STAT_PATH "write_cnt", write_count) ++ TAPE_STAT_FILE_VAL(TAPE_STAT_PATH "other_cnt", other_count) ++ TAPE_STAT_FILE_VAL(TAPE_STAT_PATH "resid_cnt", resid_count) ++ ++ if ((tape_new_stats[i].read_time < tape_old_stats[i].read_time) || ++ (tape_new_stats[i].write_time < tape_old_stats[i].write_time) || ++ (tape_new_stats[i].other_time < tape_old_stats[i].other_time)) { ++ tape_new_stats[i].valid = TAPE_STATS_INVALID; ++ } ++ } ++} ++ ++/* ++ *************************************************************************** ++ * Display tapes statistics headings. ++ *************************************************************************** ++ */ ++void tape_write_headings(void) ++{ ++ printf("Tape: r/s w/s "); ++ if (DISPLAY_MEGABYTES(flags)) { ++ printf("MB_read/s MB_wrtn/s"); ++ } else { ++ printf("kB_read/s kB_wrtn/s"); ++ } ++ printf(" %%Rd %%Wr %%Oa Rs/s Ot/s\n"); ++} ++ ++/* ++ *************************************************************************** ++ * Calculate statistics for current tape. ++ * ++ * IN: ++ * @i Index in array for current tape. ++ * ++ * OUT: ++ * @stats Statistics for current tape. ++ *************************************************************************** ++ */ ++void tape_calc_one_stats(struct calc_stats *stats, int i) ++{ ++ uint64_t duration; ++ double temp; ++ FILE *fp; ++ ++ /* Duration in ms done in ms to prevent rounding issues with using seconds */ ++ duration = (tape_new_stats[i].tv.tv_sec - ++ tape_old_stats[i].tv.tv_sec) * 1000; ++ duration -= tape_old_stats[i].tv.tv_usec / 1000; ++ duration += tape_new_stats[i].tv.tv_usec / 1000; ++ ++ /* If duration is zero we need to calculate the ms since boot time */ ++ if (duration == 0) { ++ fp = fopen("/proc/uptime", "r"); ++ ++ /* ++ * Get uptime from /proc/uptime and if we can't then just set duration to ++ * be 0 - it will mean that we don't calculate stats. ++ */ ++ if (fp == NULL) { ++ duration = 0; ++ } else { ++ if (fscanf(fp, "%lf", &temp) != 1) { ++ temp = 0; ++ } ++ duration = (uint64_t) (temp * 1000); ++ fclose(fp); ++ } ++ } ++ ++ /* The second value passed into the macro is the thing being calculated */ ++ CALC_STAT_CNT(read_count, reads_per_second) ++ CALC_STAT_CNT(write_count, writes_per_second) ++ CALC_STAT_CNT(other_count, other_per_second) ++ CALC_STAT_KB(read_bytes, kbytes_read_per_second) ++ CALC_STAT_KB(write_bytes, kbytes_written_per_second) ++ CALC_STAT_PCT(read_time, read_pct_wait) ++ CALC_STAT_PCT(write_time, write_pct_wait) ++ CALC_STAT_PCT(other_time, all_pct_wait) ++ CALC_STAT_CNT(resid_count, resids_per_second) ++} ++ ++/* ++ *************************************************************************** ++ * Display statistics for current tape. ++ * ++ * IN: ++ * @tape Statistics for current tape. ++ * @i Index in array for current tape. ++ *************************************************************************** ++ */ ++void tape_write_stats(struct calc_stats *tape, int i) ++{ ++ char buffer[32]; ++ uint64_t divisor = 1; ++ ++ if (DISPLAY_MEGABYTES(flags)) ++ divisor = 1024; ++ ++ sprintf(buffer, "st%i ", i); ++ buffer[5] = 0; ++ printf("%s%7"PRId64" %7"PRId64" %11"PRId64 ++ " %11"PRId64" %3"PRId64" %3"PRId64" %3"PRId64 ++ " %7"PRId64" %7"PRId64"\n", buffer, ++ tape->reads_per_second, tape->writes_per_second, ++ tape->kbytes_read_per_second / divisor, ++ tape->kbytes_written_per_second / divisor, ++ tape->read_pct_wait, tape->write_pct_wait, ++ tape->all_pct_wait, tape->resids_per_second, ++ tape->other_per_second); ++} ++ ++/* ++ *************************************************************************** ++ * Print everything now (stats and uptime). ++ * ++ * IN: ++ * @rectime Current date and time. ++ *************************************************************************** ++ */ ++void write_stats(struct tm *rectime) ++{ ++ int i; ++ struct calc_stats tape; ++ struct tape_stats *tmp; ++ ++ /* Test stdout */ ++ TEST_STDOUT(STDOUT_FILENO); ++ ++ /* Print time stamp */ ++ if (DISPLAY_TIMESTAMP(flags)) { ++ if (DISPLAY_ISO(flags)) { ++ strftime(timestamp, sizeof(timestamp), "%FT%T%z", rectime); ++ } ++ else { ++ strftime(timestamp, sizeof(timestamp), "%x %X", rectime); ++ } ++ printf("%s\n", timestamp); ++ } ++ ++ /* Print the headings */ ++ tape_write_headings(); ++ ++ /* ++ * If either new or old is invalid or the I/Os per second is 0 and ++ * zero omit is true then we print nothing. ++ */ ++ if (max_tape_drives > 0) { ++ ++ for (i = 0; i < max_tape_drives; i++) { ++ if ((tape_new_stats[i].valid == TAPE_STATS_VALID) && ++ (tape_old_stats[i].valid == TAPE_STATS_VALID)) { ++ tape_calc_one_stats(&tape, i); ++ if (!(DISPLAY_ZERO_OMIT(flags) ++ && (tape.other_per_second == 0) ++ && (tape.reads_per_second == 0) ++ && (tape.writes_per_second == 0) ++ && (tape.kbytes_read_per_second == 0) ++ && (tape.kbytes_written_per_second == 0) ++ && (tape.read_pct_wait == 0) ++ && (tape.write_pct_wait == 0) ++ && (tape.all_pct_wait == 0) ++ && (tape.resids_per_second == 0))) { ++ tape_write_stats(&tape, i); ++ } ++ } ++ } ++ /* ++ * Swap new and old so next time we compare against the new old stats. ++ * If a new tape drive appears it won't appear in the output until after ++ * the second time we gather information about it. ++ */ ++ tmp = tape_old_stats; ++ tape_old_stats = tape_new_stats; ++ tape_new_stats = tmp; ++ } ++ printf("\n"); ++} ++ ++/* ++ *************************************************************************** ++ * Main loop: Read tape stats from the relevant sources and display them. ++ * ++ * IN: ++ * @count Number of lines of stats to print. ++ * @rectime Current date and time. ++ *************************************************************************** ++ */ ++void rw_tape_stat_loop(long int count, struct tm *rectime) ++{ ++ struct tape_stats *tmp; ++ int skip = 0; ++ ++ /* Should we skip first report? */ ++ if (DISPLAY_OMIT_SINCE_BOOT(flags) && interval > 0) { ++ skip = 1; ++ } ++ ++ /* Don't buffer data if redirected to a pipe */ ++ setbuf(stdout, NULL); ++ ++ do { ++ ++ if (tape_new_stats == NULL) { ++ tape_gather_initial_stats(); ++ } else { ++ tape_get_updated_stats(); ++ } ++ ++ /* Get time */ ++ get_localtime(rectime, 0); ++ ++ /* Check whether we should skip first report */ ++ if (!skip) { ++ /* Print results */ ++ write_stats(rectime); ++ ++ if (count > 0) { ++ count--; ++ } ++ } ++ else { ++ skip = 0; ++ tmp = tape_old_stats; ++ tape_old_stats = tape_new_stats; ++ tape_new_stats = tmp; ++ } ++ ++ if (count) { ++ pause(); ++ } ++ } ++ while (count); ++} ++ ++/* ++ *************************************************************************** ++ * Main entry to the tapestat program. ++ *************************************************************************** ++ */ ++int main(int argc, char **argv) ++{ ++ int it = 0; ++ int opt = 1; ++ int i; ++ long count = 1; ++ struct utsname header; ++ struct tm rectime; ++ ++#ifdef USE_NLS ++ /* Init National Language Support */ ++ init_nls(); ++#endif ++ ++ /* Get HZ */ ++ get_HZ(); ++ ++ /* Process args... */ ++ while (opt < argc) { ++ if (!strncmp(argv[opt], "-", 1)) { ++ for (i = 1; *(argv[opt] + i); i++) { ++ ++ switch (*(argv[opt] + i)) { ++ ++ case 'k': ++ if (DISPLAY_MEGABYTES(flags)) { ++ usage(argv[0]); ++ } ++ /* Display stats in kB/s */ ++ flags |= T_D_KILOBYTES; ++ break; ++ ++ case 'm': ++ if (DISPLAY_KILOBYTES(flags)) { ++ usage(argv[0]); ++ } ++ /* Display stats in MB/s */ ++ flags |= T_D_MEGABYTES; ++ break; ++ ++ case 't': ++ /* Display timestamp */ ++ flags |= T_D_TIMESTAMP; ++ break; ++ ++ case 'y': ++ /* Don't display stats since system restart */ ++ flags |= T_D_OMIT_SINCE_BOOT; ++ break; ++ ++ case 'z': ++ /* Omit output for devices with no activity */ ++ flags |= T_D_ZERO_OMIT; ++ break; ++ ++ case 'V': ++ /* Print version number and exit */ ++ print_version(); ++ break; ++ ++ default: ++ usage(argv[0]); ++ } ++ } ++ opt++; ++ } ++ ++ else if (!it) { ++ interval = atol(argv[opt++]); ++ if (interval < 0) { ++ usage(argv[0]); ++ } ++ count = -1; ++ it = 1; ++ } ++ ++ else if (it > 0) { ++ count = atol(argv[opt++]); ++ if ((count < 1) || !interval) { ++ usage(argv[0]); ++ } ++ it = -1; ++ } ++ else { ++ usage(argv[0]); ++ } ++ } ++ ++ if (!interval) { ++ count = 1; ++ } ++ ++ tape_initialise(); ++ ++ get_localtime(&rectime, 0); ++ ++ /* Get system name, release number and hostname */ ++ uname(&header); ++ if (print_gal_header(&rectime, header.sysname, header.release, ++ header.nodename, header.machine, cpu_nr)) { ++ flags |= T_D_ISO; ++ } ++ printf("\n"); ++ ++ /* Set a handler for SIGALRM */ ++ memset(&alrm_act, 0, sizeof(alrm_act)); ++ alrm_act.sa_handler = alarm_handler; ++ sigaction(SIGALRM, &alrm_act, NULL); ++ alarm(interval); ++ ++ /* Main loop */ ++ rw_tape_stat_loop(count, &rectime); ++ ++ /* Free structures */ ++ tape_uninitialise(); ++ ++ return 0; ++} +diff -uprN sysstat-10.1.5.orig/tapestat.h sysstat-10.1.5/tapestat.h +--- sysstat-10.1.5.orig/tapestat.h 1970-01-01 01:00:00.000000000 +0100 ++++ sysstat-10.1.5/tapestat.h 2016-06-01 12:46:52.028338551 +0200 +@@ -0,0 +1,126 @@ ++/* ++ * tapestat: report tape statistics ++ * (C) 2015 Hewlett-Packard Development Company, L.P. ++ * ++ * Initial revision by Shane M. SEYMOUR (shane.seymour hpe.com) ++ * Modified for sysstat by Sebastien GODARD (sysstat orange.fr) ++ */ ++ ++#ifndef _TAPESTAT_H ++#define _TAPESTAT_H ++ ++/* T_: tapestat - D_: Display - F_: Flag */ ++#define T_D_TIMESTAMP 0x00001 ++#define T_D_KILOBYTES 0x00002 ++#define T_D_MEGABYTES 0x00004 ++#define T_D_OMIT_SINCE_BOOT 0x00008 ++#define T_D_ISO 0x00010 ++#define T_D_ZERO_OMIT 0x00020 ++ ++#define DISPLAY_TIMESTAMP(m) (((m) & T_D_TIMESTAMP) == T_D_TIMESTAMP) ++#define DISPLAY_KILOBYTES(m) (((m) & T_D_KILOBYTES) == T_D_KILOBYTES) ++#define DISPLAY_MEGABYTES(m) (((m) & T_D_MEGABYTES) == T_D_MEGABYTES) ++#define DISPLAY_OMIT_SINCE_BOOT(m) (((m) & T_D_OMIT_SINCE_BOOT) == T_D_OMIT_SINCE_BOOT) ++#define DISPLAY_ISO(m) (((m) & T_D_ISO) == T_D_ISO) ++#define DISPLAY_ZERO_OMIT(m) (((m) & T_D_ZERO_OMIT) == T_D_ZERO_OMIT) ++ ++ ++#define TAPE_STATS_VALID 1 ++#define TAPE_STATS_INVALID 0 ++ ++#define SYSFS_CLASS_TAPE_DIR "/sys/class/scsi_tape" ++#define TAPE_STAT_PATH "/sys/class/scsi_tape/st%i/stats/" ++ ++#define TAPE_STAT_FILE_VAL(A, B) \ ++ snprintf(filename, MAXPATHLEN, A, i); \ ++ if ((fp = fopen(filename, "r")) != NULL) { \ ++ if (fscanf(fp, "%"PRId64, &tape_new_stats[i].B) != 1) { \ ++ tape_new_stats[i].valid = TAPE_STATS_INVALID; \ ++ } \ ++ fclose(fp); \ ++ } else { \ ++ tape_new_stats[i].valid = TAPE_STATS_INVALID; \ ++ continue; \ ++ } ++ ++ ++/* ++ * A - tape_stats structure member name, e.g. read_count ++ * B - calc_stats structure member name, e.g. reads_per_second ++ * ++ * These macros are not selfcontained they depend on some other ++ * variables defined either as global or local to the function. ++ */ ++ ++#define CALC_STAT_CNT(A, B) \ ++ if ((tape_new_stats[i].A == tape_old_stats[i].A) || \ ++ (duration <= 0)) { \ ++ stats->B = 0; \ ++ } else { \ ++ temp = (double) (tape_new_stats[i].A - \ ++ tape_old_stats[i].A) \ ++ / (((double) duration) / 1000); \ ++ stats->B = (uint64_t) temp; \ ++ } ++#define CALC_STAT_KB(A, B) \ ++ if ((tape_new_stats[i].A == tape_old_stats[i].A) || \ ++ (duration <= 0)) { \ ++ stats->B = 0; \ ++ } else { \ ++ temp = (double) (tape_new_stats[i].A - \ ++ tape_old_stats[i].A) \ ++ / (((double) duration) / 1000.0); \ ++ stats->B = (uint64_t) (temp / 1024.0); \ ++ } ++ ++#define TAPE_MAX_PCT 999 ++ ++#define CALC_STAT_PCT(A, B) \ ++ if ((tape_new_stats[i].A == tape_old_stats[i].A) || \ ++ (duration <= 0)) { \ ++ stats->B = 0; \ ++ } else { \ ++ temp = (double) (tape_new_stats[i].A - \ ++ tape_old_stats[i].A) \ ++ / (((double) duration)); \ ++ stats->B = (uint64_t) (100.0 * temp / 1000000.0); \ ++ if (stats->B > TAPE_MAX_PCT) \ ++ stats->B = TAPE_MAX_PCT; \ ++ } ++ ++struct tape_stats { ++ uint64_t read_time; ++ uint64_t write_time; ++ uint64_t other_time; ++ uint64_t read_bytes; ++ uint64_t write_bytes; ++ uint64_t read_count; ++ uint64_t write_count; ++ uint64_t other_count; ++ uint64_t resid_count; ++ char valid; ++ struct timeval tv; ++}; ++struct calc_stats { ++ uint64_t reads_per_second; ++ uint64_t writes_per_second; ++ uint64_t other_per_second; ++ uint64_t kbytes_read_per_second; ++ uint64_t kbytes_written_per_second; ++ uint64_t read_pct_wait; ++ uint64_t write_pct_wait; ++ uint64_t all_pct_wait; ++ uint64_t resids_per_second; ++}; ++ ++void tape_get_updated_stats(void); ++void tape_gather_initial_stats(void); ++void tape_check_tapes_and_realloc(void); ++int get_max_tape_drives(void); ++void tape_uninitialise(void); ++void tape_initialise(void); ++void tape_calc_one_stats(struct calc_stats *, int); ++void tape_write_headings(void); ++void tape_write_stats(struct calc_stats *, int); ++ ++#endif /* _TAPESTAT_H */ diff --git a/SOURCES/sysstat-10.1.5-zip-conf.patch b/SOURCES/sysstat-10.1.5-zip-conf.patch new file mode 100644 index 0000000..7e4f7e3 --- /dev/null +++ b/SOURCES/sysstat-10.1.5-zip-conf.patch @@ -0,0 +1,10 @@ +diff -ur sysstat-10.1.5.orig/sysstat.sysconfig.in sysstat-10.1.5/sysstat.sysconfig.in +--- sysstat-10.1.5.orig/sysstat.sysconfig.in 2012-05-13 15:00:39.000000000 +0200 ++++ sysstat-10.1.5/sysstat.sysconfig.in 2014-09-01 23:08:48.412640491 +0200 +@@ -12,3 +12,6 @@ + # which are used for the generation of log files. + SADC_OPTIONS="@COLLECT_ALL@" + ++# Compression program to use. ++ZIP="@ZIP@" ++ diff --git a/SPECS/sysstat.spec b/SPECS/sysstat.spec new file mode 100644 index 0000000..8df4360 --- /dev/null +++ b/SPECS/sysstat.spec @@ -0,0 +1,751 @@ +Summary: Collection of performance monitoring tools for Linux +Name: sysstat +Version: 10.1.5 +Release: 18%{?dist} +License: GPLv2+ +Group: Applications/System +URL: http://sebastien.godard.pagesperso-orange.fr/ +Source: http://pagesperso-orange.fr/sebastien.godard/%{name}-%{version}.tar.bz2 + +Patch0: sysstat-10.0.0-makefile.patch +# fixes 1100365 +Patch1: sysstat-10.1.5-overwrite-sa.patch +# fixes 1097294 +Patch2: sysstat-10.1.5-sa2-xz.patch +# fixes 1128569 +Patch3: sysstat-10.1.5-dyn-tick.patch +# fixes 1110852 +Patch4: sysstat-10.1.5-sysstat-5.patch +# fixes 1102610 +Patch5: sysstat-10.1.5-zip-conf.patch +# fixes 1146081 +Patch6: sysstat-10.1.5-single-cpu-cifs.patch +# fixes 1162773 +Patch7: sysstat-10.1.5-elapsed-time.patch +# fixes 1224882 +Patch8: sysstat-10.1.5-pids-prealloc.patch +# fixes 1258990 +Patch9: sysstat-10.1.5-max-cpus.patch +# fixes 1267972 +Patch10: sysstat-10.1.5-max-name-len.patch +# fixes 1328490 +Patch11: sysstat-10.1.5-int-handler.patch +# fixes 846699 +Patch12: sysstat-10.1.5-nfsiostat.patch +# fixes 1332662 +Patch13: sysstat-10.1.5-tapestat.patch +# fixes 1381128 +Patch14: 0001-sar-make-buffers-that-hold-timestamps-bigger.patch +# fixes 1448489 +Patch15: 0001-pidstat-Display-stats-since-boot-time-for-a-list-of-.patch +# fixes 1440000 +Patch16: 0001-sar-Improve-cpuinfo-read-for-POWER-architecture.patch +# backport of -F flag +Patch17: 0001-Added-filesystems-statistics-to-sar-part-1-Basic-def.patch +Patch18: 0002-Filesystems-statistics-for-sar-part-2-Read-statistic.patch +Patch19: 0003-Filesystems-statistics-for-sar-part-3-Display-statis.patch +Patch20: 0004-Filesystems-statistics-part-4-ppc-and-db-output-form.patch +Patch21: 0005-Filesystems-statistics-part-5-JSON-output-format.patch +Patch22: 0006-Filesystems-statistics-part-6-XML-output-format.patch +Patch23: 0007-Filesystems-statistics-part-7-Documentation-updates.patch +Patch24: 0008-Filesystems-stats-Display-unmounted-filesystems-in-s.patch +Patch25: 0009-Handle-octal-codes-in-filesystems-mount-point-names.patch +Patch26: 0010-Collect-filesystems-stats-only-when-sadc-option-S-XD.patch +Patch27: 0011-Small-fix-for-sar-A-in-sar-manual-page.patch +Patch28: 0012-Add-option-to-display-mountpoint-names-instead-of-fi.patch +Patch29: 0013-Revise-sar-usage-messages-to-be-F-MOUNT-rather-than-.patch +Patch30: 0014-Use-statvfs-instead-of-statfs-system-call.patch +Patch31: 0015-Fix-issue-48-sar-skips-long-filesystem-names.patch +Patch32: 0016-Fix-issue-48-for-good-sar-skips-long-filesystem-name.patch +Patch33: 0017-Use-proper-length-for-mountp-string.patch +Patch34: 0018-Replace-strcpy-with-strncpy-to-avoid-buffer-overflow.patch +Patch35: 0019-Cast-variables-to-target-type-before-use.patch +Patch36: 0020-Fix-162-sadc-crashes-on-a-mtab-file-with-really-long.patch +Patch37: 0021-Increase-maximum-fs-name-length-to-128.patch +# backport -f flag (force fdatasync() after append to sa file) +Patch38: 0001-sadc-Add-a-f-flag-to-force-fdatasync-use.patch +# don't call filesystem count functions when we are not collecting fs statistics +Patch39: 0001-avoiding-triggering-automounts-bug-1670060.patch +# skip autofs when gathering filesystem statistics +Patch40: 0001-ignoring-autofs-as-real-filesystem-by-counting-numbe.patch +# small manpage fix +Patch41: 0001-man-use-correct-preposition.patch +# fix CPU usage reporting +Patch42: 0001-pidstat-Now-handle-processes-with-spaces-in-their-na.patch + +Requires: /etc/cron.d, fileutils, grep, sh-utils, textutils +Requires(post): systemd, systemd-sysv +Requires(preun): systemd +Requires(postun): systemd + +BuildRequires: %{_includedir}/linux/if.h, gettext, lm_sensors-devel, perl +BuildRequires: systemd + +%description +The sysstat package contains sar, sadf, mpstat, iostat, pidstat, nfsiostat-sysstat, +tapestat, cifsiostat and sa tools for Linux. +The sar command collects and reports system activity information. This +information can be saved in a file in a binary format for future inspection. The +statistics reported by sar concern I/O transfer rates, paging activity, +process-related activities, interrupts, network activity, memory and swap space +utilization, CPU utilization, kernel activities and TTY statistics, among +others. Both UP and SMP machines are fully supported. +The sadf command may be used to display data collected by sar in various formats +(CSV, XML, etc.). +The iostat command reports CPU utilization and I/O statistics for disks. +The tapestat command reports statistics for tapes connected to the system. +The mpstat command reports global and per-processor statistics. +The pidstat command reports statistics for Linux tasks (processes). +The nfsiostat-sysstat command reports I/O statistics for network file systems. +The cifsiostat command reports I/O statistics for CIFS file systems. + +%prep +%setup -q +%patch0 -p1 -b .ls +%patch1 -p1 -b .overwrite-sa +%patch2 -p1 -b .sa2-xz +%patch3 -p1 -b .dyn-tick +%patch4 -p1 -b .sysstat-5 +%patch5 -p1 -b .zip-conf +%patch6 -p1 -b .single-cpu-cifs +%patch7 -p1 -b .elapsed-time +%patch8 -p1 -b .pids-prealloc +%patch9 -p1 -b .max-cpus +%patch10 -p1 -b .max-name-len +%patch11 -p1 -b .int-handler +%patch12 -p1 -b .nfsiostat +%patch13 -p1 -b .tapestat +%patch14 -p1 -b .korean +%patch15 -p1 -b .pidstat +%patch16 -p1 -b .power +%patch17 -p1 +%patch18 -p1 +%patch19 -p1 +%patch20 -p1 +%patch21 -p1 +%patch22 -p1 +%patch23 -p1 +%patch24 -p1 +%patch25 -p1 +%patch26 -p1 +%patch27 -p1 +%patch28 -p1 +%patch29 -p1 +%patch30 -p1 +%patch31 -p1 +%patch32 -p1 +%patch33 -p1 +%patch34 -p1 +%patch35 -p1 +%patch36 -p1 +%patch37 -p1 +%patch38 -p1 +%patch39 -p1 +%patch40 -p1 +%patch41 -p1 +%patch42 -p1 + +iconv -f windows-1252 -t utf8 CREDITS > CREDITS.aux +mv CREDITS.aux CREDITS + +%build +%configure sa_lib_dir=%{_libdir}/sa history=28 compressafter=31 \ + --disable-man-group +%{__sed} -i 's/SADC_OPTIONS=""/SADC_OPTIONS="-S DISK"/' sysstat.sysconfig +CFLAGS="$RPM_OPT_FLAGS -DSADC_PATH=\\\"%{_libdir}/sa/sadc\\\"" +make CFLAGS="$CFLAGS" LFLAGS="" %{?_smp_mflags} + +%install +make install DESTDIR=%{buildroot} + +# Install cron file +mkdir -p %{buildroot}/%{_sysconfdir}/cron.d +install -m 0644 cron/sysstat.crond %{buildroot}/%{_sysconfdir}/cron.d/sysstat + +# Install service file +mkdir -p %{buildroot}%{_unitdir} +install -m 0644 sysstat.service %{buildroot}%{_unitdir}/ + +%find_lang %{name} + +%post +%systemd_post sysstat.service + +%preun +%systemd_preun sysstat.service +if [[ $1 -eq 0 ]]; then + # Remove sa logs if removing sysstat completely + rm -f %{_localstatedir}/log/sa/* +fi + +%postun +%systemd_postun sysstat.service + +%triggerun -- sysstat < 10.0.2-1 +# Save the current service runlevel info +# User must manually run systemd-sysv-convert --apply sysstat +# to migrate them to systemd targets +/usr/bin/systemd-sysv-convert --save sysstat >/dev/null 2>&1 ||: + +# Run these because the SysV package being removed won't do them +/sbin/chkconfig --del sysstat >/dev/null 2>&1 || : +/bin/systemctl try-restart sysstat.service >/dev/null 2>&1 || : + +%files -f %{name}.lang +%doc CHANGES COPYING CREDITS README FAQ +%config(noreplace) %attr(0600,-,-) %{_sysconfdir}/cron.d/sysstat +%config(noreplace) %{_sysconfdir}/sysconfig/sysstat +%config(noreplace) %{_sysconfdir}/sysconfig/sysstat.ioconf +%{_unitdir}/sysstat.service +%{_bindir}/* +%{_libdir}/sa +%{_mandir}/man1/* +%{_mandir}/man5/* +%{_mandir}/man8/* +%{_localstatedir}/log/sa + +%changelog +* Thu Mar 28 2019 Michal Sekletár - 10.1.5-18 +- add -f flag to force fdatasync() after sa file update (#1662094) +- don't call filesystem count functions when we are not collecting fs statistics (#1670060) +- skip autofs when gathering filesystem statistics (#1670060) +- fix use of incorrect preposition in sar man page (#1624410) +- fix CPU usage reporting (#1618688) + +* Mon Jun 25 2018 Michal Sekletar - 10.1.5-17 +- fix potential buffer overflow identified by cppcheck (#1543238) + +* Fri Jun 22 2018 Michal Sekletar - 10.1.5-16 +- apply previously added patches (#1543238) + +* Fri Jun 22 2018 Michal Sekletar - 10.1.5-15 +- backport some more follow-up bugfixes related to -F (#1543238) + +* Thu Jun 21 2018 Michal Sekletar - 10.1.5-14 +- backport -F switch for monitoring currently mounted filesystems (#1543238) + +* Wed Nov 08 2017 Michal Sekletar - 10.1.5-13 +- fix output of pidstat -p $PID (#1448489) +- improve reading of /proc/cpuinfo on Power (#1440000) + +* Wed Mar 29 2017 Michal Sekletar - 10.1.5-12 +- sar: output timestamps when running with ko_KR.UTF-8 locale (#1381128) + +* Wed Jun 01 2016 Peter Schiffer - 10.1.5-11 +- related: #1332662 + fixed more coverity issues + +* Tue May 31 2016 Peter Schiffer - 10.1.5-10 +- related: #846699, #1332662 + fixed coverity issues + +* Thu May 05 2016 Peter Schiffer - 10.1.5-9 +- related: #846699 + do the renaming of nfsiostat properly, with patch +- resolves: #1332662 + added tapestat utility for monitoring tape drives + +* Fri Apr 29 2016 Peter Schiffer - 10.1.5-8 +- resolves: #846699 + renamed nfsiostat to nfsiostat-sysstat, as nfsiostat is also provided + by the nfs-utils package +- resolves: #1224882 + fixed bug when pidstat could run out of pre-allocated space for PIDs +- resolves: #1258990 + added support for more CPUs +- resolves: #1267972 + fixed bug when iostat didn't display the full device name if it's too long +- resolves: #1328490 + fixed bug, when sadc could forward SIGINIT to init process and couse reboot + +* Wed Nov 12 2014 Peter Schiffer - 10.1.5-7 +- resolves: #1162773 + fixed incorrect description of util field on iostat(1) and sar(1) man pages + +* Mon Sep 29 2014 Peter Schiffer - 10.1.5-6 +- resolves: #1146081 + fixed issue when cifsiostat and nfsiostat were reporting incorrect statistics + on a single CPU machines + +* Mon Sep 1 2014 Peter Schiffer - 10.1.5-5 +- resolves: #1100365 + fixed issue when sa data files weren't correctly overwritten in some cases +- resolves: #1097294 + count with xz compressed files as well in sa2 script +- resolves: #1097292 + fix file mode of sysstat cron file +- resolves: #1128569 + added workaround for dyn-tick kernel feature which makes /proc/stat file + unreliable under certain circumstances +- resolves: #1110852 + added better explanation of HISTORY setting to sysstat(5) man page +- resolves: #1102610 + added possibility to set compress method in /etc/sysconfig/sysstat file + +* Fri Jan 24 2014 Daniel Mach - 10.1.5-4 +- Mass rebuild 2014-01-24 + +* Mon Jan 6 2014 Peter Schiffer - 10.1.5-3 +- resolves: #1048902 + added missing build requires on systemd + +* Fri Dec 27 2013 Daniel Mach - 10.1.5-2 +- Mass rebuild 2013-12-27 + +* Fri Apr 5 2013 Peter Schiffer - 10.1.5-1 +- resolves: #919581 + updated to 10.1.5 +- collect disk statistics by default + +* Fri Feb 15 2013 Fedora Release Engineering - 10.1.3-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild + +* Wed Jan 2 2013 Peter Schiffer - 10.1.3-1 +- resolves: #890425 + updated to 10.1.3 + +* Mon Dec 3 2012 Peter Schiffer - 10.1.2-2 +- added new -y option to iostat command to skip first since boot report if + displaying multiple reports + +* Tue Nov 13 2012 Peter Schiffer - 10.1.2-1 +- resolves: #863791 + updated to 10.1.2 +- resolves: #850333 + migrated to the new systemd-rpm macros +- cleaned .spec file + +* Wed Aug 01 2012 Peter Schiffer - 10.1.1-1 +- resolves: #844387 + update to 10.1.1 +- keep log files for 28 days instead of 7 +- collect all aditional statistics + +* Sat Jul 21 2012 Fedora Release Engineering - 10.0.5-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild + +* Tue Jun 19 2012 Peter Schiffer - 10.0.5-1 +- resolves: #822867 + update to 10.0.5 + +* Wed May 16 2012 Peter Schiffer - 10.0.4-1 +- resolves: #803032 + update to 10.0.4 +- resolves: #820725 + enable sysstat service by default + +* Sat Jan 14 2012 Fedora Release Engineering - 10.0.3-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild + +* Wed Nov 30 2011 Peter Schiffer - 10.0.3-1 +- resolves: #757687 + update to 10.0.3 + +* Tue Sep 13 2011 Tom Callaway - 10.0.2-2 +- fix libdir pathing in systemd service file + +* Mon Sep 12 2011 Tom Callaway - 10.0.2-1 +- update to 10.0.2 +- convert to systemd + +* Tue Jun 7 2011 Ivana Hutarova Varekova - 10.0.1-1 +- update to 10.0.1 +- remove useles patches + +* Wed May 4 2011 Ivana Hutarova Varekova - 10.0.0-4 +- close the file descriptor in a special situation in read_uoptime function +- fix the number on open files in cifsiostat output + +* Mon May 2 2011 Ivana Hutarova Varekova - 10.0.0-3 +- add -h optioon to iostat tool + (-h Make the disk stats report easier to read by a human.) + +* Mon Apr 4 2011 Ivana Hutarova Varekova - 10.0.0-2 +- remove unnecessary patch + +* Mon Apr 4 2011 Ivana Hutarova Varekova - 10.0.0-1 +- update to 10.0.0 + remove obsolete patches + remove autoreconfiguration + +* Wed Feb 09 2011 Fedora Release Engineering - 9.0.6.1-14 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild + +* Mon Nov 22 2010 Ivana Hutarova Varekova - 9.0.6.1-13 +- Resolves: #642280 + sar -u overflow problem - thanks Michal Srb + +* Thu Oct 7 2010 Ivana Hutarova Varekova - 9.0.6.1-12 +- improve sar thickless kernel support + (fix the output per separate cpu "-P ALL" option ) + +* Mon Oct 4 2010 Ivana Hutarova Varekova - 9.0.6.1-11 +- resolves: #635646 + test the output of localtime properly + +* Wed Sep 29 2010 jkeating - 9.0.6.1-10 +- Rebuilt for gcc bug 634757 + +* Thu Sep 23 2010 Ivana Hutarova Varekova - 9.0.6.1-9 +- add the mandir patch +- add the possibility to sed sadc cron options + +* Tue Sep 21 2010 Ivana Hutarova Varekova - 9.0.6.1-8 +- add necessary dependency (autoconf), necessary because of patch7 + +* Tue Sep 21 2010 Ivana Hutarova Varekova - 9.0.6.1-7 +- remove needless DOCDIR setting +- remove needless INIT_DIR setting +- fix the problem with --disable-man-group option + +* Wed Sep 8 2010 Ivana Hutarova Varekova - 9.0.6.1-6 +- fix the sar output on tickless kernel + +* Fri Aug 13 2010 Ivana Hutarova Varekova - 9.0.6.1-5 +- remove bogus links description + +* Mon Jul 19 2010 Ivana Hutarova Varekova - 9.0.6.1-4 +- fix sar problem - sysstat can not monitor system status every second + +* Mon Apr 19 2010 Ivana Hutarova Varekova - 9.0.6.1-3 +- fix mpstat tool (when the cpu is switched off) + +* Fri Apr 16 2010 Ivana Hutarova Varekova - 9.0.6.1-2 +- fix the mpstat output on tickless kernel + +* Tue Mar 2 2010 Ivana Hutarova Varekova - 9.0.6.1-1 +- update to 9.0.6.1 + +* Tue Feb 16 2010 Ivana Hutarova Varekova - 9.0.6-3 +- fix init script format + +* Fri Dec 11 2009 Ivana Hutarova Varekova - 9.0.6-2 +- fix the problem in get_nfs_mount_nr function + ( iostat -n causes stack smashing) + +* Wed Dec 2 2009 Ivana Hutarva Varekova - 9.0.6-1 +- update to 9.0.6 + +* Tue Sep 15 2009 Ivana Varekova - 9.0.4-4 +- fix init script + +* Mon Sep 14 2009 Ivana Varekova - 9.0.4-3 +- fix init script - add INIT INFO flags (#522740) + and add condrestart, try-restart and force-reload (#522743) + +* Sun Jul 26 2009 Fedora Release Engineering - 9.0.4-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild + +* Mon Jul 20 2009 Ivana Varekova - 9.0.4-1 +- update to 9.0.4 + +* Thu May 28 2009 Ivana Varekova - 9.0.3-1 +- update to 9.0.3 +- remove obsolete patches + +* Wed Feb 25 2009 Fedora Release Engineering - 8.0.4-7 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_11_Mass_Rebuild + +* Fri Dec 5 2008 Ivana Varekova - 8.0.4-6 +- add /proc/diskstats reading patch + +* Mon Sep 22 2008 Ivana Varekova - 8.0.4-5 +- Resolves: #463066 - Fix Patch0:/%%patch mismatch + +* Wed Apr 23 2008 Ivana Varekova - 8.0.4-4 +- Resolves: #442801 mpstat shows one extra cpu + thanks Chris Wright + +* Thu Mar 6 2008 Ivana Varekova - 8.0.4-3 +- add nfs extended statistic to iostat command + +* Thu Feb 28 2008 Ivana Varekova - 8.0.4-2 +- retry write functuon in sadc command - thanks Tomas Mraz + +* Fri Feb 8 2008 Ivana Varekova - 8.0.4-1 +- updated to 8.0.4 + +* Mon Dec 3 2007 Ivana Varekova - 8.0.3-1 +- updated to 8.0.3 + +* Fri Nov 9 2007 Ivana Varekova - 8.0.2-3 +- used macros instead of var, etc + +* Thu Nov 8 2007 Ivana Varekova - 8.0.2-2 +- change license tag +- remove sysstat.crond source (add -d) +- remove obsolete sysconfig file +- spec file cleanup + +* Mon Nov 5 2007 Ivana Varekova - 8.0.2-1 +- update 8.0.2 +- spec file cleanup + +* Wed Oct 24 2007 Ivana Varekova - 8.0.1-2 +- remove useless patches + +* Mon Oct 22 2007 Ivana Varekova - 8.0.1-1 +- update to 8.0.1 +- remove useless patches +- spec file cleanup +- remove smp build flag (ar problem) +- add libdir flags + +* Wed Aug 15 2007 Ivana Varekova - 7.0.4-3 +- fix cve-2007-3852 - + sysstat insecure temporary file usage + +* Fri Mar 23 2007 Ivana Varekova - 7.0.4-2 +- fix sa2 problem (sa2 works wrong when the /var/log/sa file is + a link to another directory) + +* Mon Feb 12 2007 Ivana Varekova - 7.0.4-1 +- update to 7.0.4 +- spec file cleanup + +* Tue Jan 30 2007 Ivana Varekova - 7.0.3-3 +- remove -s flag + +* Mon Dec 18 2006 Ivana Varekova - 7.0.3-1 +- update to 7.0.3 + +* Tue Nov 21 2006 Ivana Varekova - 7.0.2-3 +- update NFS mount statistic patch + +* Wed Nov 8 2006 Ivana Varekova - 7.0.2-1 +- update to 7.0.2 + +* Thu Oct 26 2006 Ivana Varekova - 7.0.0-3 +- move tmp file (#208433) + +* Mon Oct 9 2006 Ivana Varekova - 7.0.0-2 +- add NFS mount statistic (#184321) + +* Fri Jul 14 2006 Marcela Maslanova - 7.0.0-1 +- new version 7.0.0 + +* Wed Jul 12 2006 Jesse Keating - 6.0.2-2.1 +- rebuild + +* Mon Jun 5 2006 Jesse Keating 6.0.2-2 +- Add missing BR of gettext + +* Fri May 5 2006 Ivana Varekova 6.0.2-1 +- update to 6.0.2 +- remove asm/page.h used sysconf command to get PAGE_SIZE + +* Fri Feb 10 2006 Jesse Keating - 6.0.1-3.2.1 +- bump again for double-long bug on ppc(64) + +* Tue Feb 07 2006 Jesse Keating - 6.0.1-3.2 +- rebuilt for new gcc4.1 snapshot and glibc changes + +* Fri Dec 09 2005 Jesse Keating +- rebuilt + +* Tue Oct 11 2005 Ivana Varekova 6.0.1-3 +- add FAQ to documentation (bug 170158) + +* Mon Oct 10 2005 Ivana Varekova 6.0.1-2 +- fix chkconfig problem + +* Fri Oct 7 2005 Ivana Varekova 6.0.1-1 +- version 6.0.1 + +* Thu Aug 18 2005 Florian La Roche +- no need to kernel kernel 2.2 or newer anymore + +* Tue May 10 2005 Ivana Varekova 5.0.5-10.fc +- add debug files to debug_package + +* Mon Mar 7 2005 Ivana Varekova 5.0.5-9.fc +- rebuilt (add gcc4fix, update lib64ini) + +* Fri Mar 4 2005 Ivana Varekova 5.0.5-7.fc +- rebuilt + +* Thu Sep 30 2004 Charles Bennett 5.0.5-5.fc +- bring in filename and append-msg patch +- append-msg adds verbose text for when saNN data file cpu count +- does not match cpu count on the currently running system + +* Wed Jun 30 2004 Nils Philippsen +- version 5.0.5 +- remove some obsolete patches +- update statreset, overrun, lib64init patches +- renumber patches + +* Wed Jun 16 2004 Alan Cox +- Fix spew of crap to console at startup +- Fix order of startup (#124035) +- Fix array overrun (#117182) +- Fix interrupt buffer sizing (caused bogus irq info) + +* Tue Jun 15 2004 Elliot Lee +- rebuilt + +* Wed Mar 24 2004 Justin Forbes <64bit_fedora@comcast.net> 5.0.1-2 +- fix lib64 init + +* Tue Mar 02 2004 Elliot Lee +- rebuilt + +* Wed Feb 18 2004 Nils Philippsen 5.0.1-1 +- version 5.0.1 +- update statreset patch + +* Fri Feb 13 2004 Elliot Lee +- rebuilt + +* Thu Jan 22 2004 Nils Philippsen 5.0.0-0.6 +- let user configure how long to keep logs through /etc/sysconfig/sysstat + (#81294) +- reset stats at system boot (#102445) + +* Wed Jan 21 2004 Nils Philippsen 5.0.0-0.5 +- fix ifnamsiz patch for s390x (hopefully) + +* Tue Jan 20 2004 Nils Philippsen 5.0.0-0.4 +- fix insecure tmp files in scripts (#78212) +- require tools needed in scripts +- use IFNAMSIZ from {_includedir}/linux/if.h for maximum interface length + +* Mon Jan 12 2004 Nils Philippsen 5.0.0-0.3 +- Buildrequires: perl +- check for %%_lib == lib64 instead of specific arches + +* Mon Jan 12 2004 Nils Philippsen 5.0.0-0.2 +- fix dealing with lib64 case of cron.d file + +* Mon Jan 12 2004 Nils Philippsen 5.0.0-0.1 +- version 5.0.0 + +* Wed Jun 04 2003 Elliot Lee +- rebuilt + +* Mon Mar 3 2003 Joe Orton 4.0.7-4 +- really fix paths for multilib (#82913) + +* Wed Feb 19 2003 Bill Nottingham 4.0.7-3 +- fix paths on multilib arches (#82913) + +* Wed Jan 22 2003 Tim Powers +- rebuilt + +* Sat Nov 23 2002 Mike A. Harris 4.0.7-1 +- Updated to new upstream version 4.0.7 + +* Tue Nov 19 2002 Mike A. Harris 4.0.5-7 +- Fixed files installed in /usr/doc to be put in correct place + +* Tue Oct 8 2002 Mike A. Harris 4.0.5-6 +- All-arch rebuild + +* Tue Jul 23 2002 Trond Eivind Glomsrød 4.0.5-3 +- Rebuild + +* Fri Jun 21 2002 Tim Powers +- automated rebuild + +* Mon Jun 17 2002 Trond Eivind Glomsrød 4.0.5-1 +- 4.0.5-1 +- isag is no longer installed by default upstream, removing + requirement on gnuplot + +* Thu May 23 2002 Tim Powers +- automated rebuild + +* Mon Apr 22 2002 Trond Eivind Glomsrød 4.0.4-1 +- 4.0.4 +- Add an explicit requires on gnuplot (#63474) + +* Fri Apr 12 2002 Trond Eivind Glomsrød 4.0.3-2 +- Do the daily sa2 run just before midnight, not at 4AM... you'd + only get 4 hours worth of data that way (#63132) + +* Thu Feb 28 2002 Trond Eivind Glomsrød 4.0.3-1 +- 4.0.3 + +* Wed Feb 27 2002 Trond Eivind Glomsrød 4.0.2-3 +- Rebuild + +* Wed Jan 09 2002 Tim Powers +- automated rebuild + +* Wed Dec 12 2001 Trond Eivind Glomsrød 4.0.2-1 +- 4.0.2 +- the kernel patch for extended statistics is in, don't say it needs + applying in the man page + +* Mon Aug 13 2001 Preston Brown +- be more verbose about which files are corrupt (#47122) + +* Mon Jul 2 2001 Preston Brown +- run sa1 from cron.d to fix run-parts interaction problem (#37733) + +* Fri Jun 29 2001 Preston Brown +- upgrade to 4.0.1 stable release + +* Sun Jun 24 2001 Elliot Lee +- Bump release + rebuild. + +* Sun Apr 8 2001 Preston Brown +- explicitly set safe umask (#35142) + +* Fri Mar 9 2001 Preston Brown +- iostat disk utilization was off by a factor of 10. + +* Wed Feb 14 2001 Preston Brown +- 3.3.5 brings us full support for kernel IO stats + +* Tue Jan 30 2001 Preston Brown +- Summarize previous day's activity with sa2, not current day (which is only 4 hours of data when it gets run) (#24820) +- upgrade to 3.3.4 for full 2.4 compatibility and improved iostat + +* Wed Jan 17 2001 Preston Brown +- iostat man page fixes + +* Fri Jan 05 2001 Preston Brown +- 3.3.3, crontab fixes + +* Fri Dec 29 2000 Bill Nottingham +- fix prereqs + +* Fri Oct 13 2000 Preston Brown +- crontab entry was still incorrect. Fixed. + +* Mon Oct 09 2000 Preston Brown +- make sure disk accounting is enabled to fix iostat -l, -p (#16268) +- crontab entries were missing the user (root) to run as (#18212) + +* Tue Aug 22 2000 Preston Brown +- enable IO accounting now that kernel supports it + +* Wed Aug 16 2000 Nalin Dahyabhai +- fix buildrooting (#16271) + +* Tue Aug 08 2000 Preston Brown +- bugfixes in 3.2.4 cause our inclusion. :) + +* Wed Jul 12 2000 Prospector +- automatic rebuild + +* Thu Jun 29 2000 Preston Brown +- 3.2.3 fixes SMP race condition + +* Tue Jun 20 2000 Preston Brown +- FHS macros +- 3.2.2 + +* Fri May 26 2000 Preston Brown +- packaged for Winston +- change va patch to indicate kernel is not patched for iostat accounting. + re-enable if our stock kernel gets this patch. +- upgrade to 3.2. +- install crontab entry. + +* Sun Dec 12 1999 Ian Macdonald +- upgraded to 2.2 + +* Fri Oct 29 1999 Ian Macdonald +- first RPM release (2.1)