From 685a6000077bd7c0d5b4f1001096a17acb23fa76 Mon Sep 17 00:00:00 2001 From: Jaromir Capik Date: Wed, 5 Feb 2014 12:53:25 +0100 Subject: [PATCH] - Support for timestamps & wide diskstat (#1053428, #1025833) - Fixing fd leak in watch --- procps-ng.spec | 10 +- vmstat-timestamps.patch | 386 ++++++++++++++++++++++++++++++++++++++++ watch-fd-leak.patch | 34 ++++ 3 files changed, 429 insertions(+), 1 deletion(-) create mode 100644 vmstat-timestamps.patch create mode 100644 watch-fd-leak.patch diff --git a/procps-ng.spec b/procps-ng.spec index b45eb4f..d9e31f3 100644 --- a/procps-ng.spec +++ b/procps-ng.spec @@ -4,7 +4,7 @@ Summary: System and process monitoring utilities Name: procps-ng Version: 3.3.9 -Release: 4%{?dist} +Release: 5%{?dist} License: GPL+ and GPLv2 and GPLv2+ and GPLv3+ and LGPLv2+ Group: Applications/System URL: https://sourceforge.net/projects/procps-ng/ @@ -13,6 +13,8 @@ Source0: http://downloads.sourceforge.net/%{name}/%{name}-%{version}.tar.xz Patch0: vmstat-wide-not-wide-enough.patch Patch1: ksh-skip-trailing-zeros.patch +Patch2: vmstat-timestamps.patch +Patch3: watch-fd-leak.patch Requires(post): /sbin/ldconfig Requires(postun): /sbin/ldconfig @@ -78,6 +80,8 @@ System and process monitoring utilities development headers %patch0 -p1 %patch1 -p1 +%patch2 -p1 +%patch3 -p1 %build @@ -147,6 +151,10 @@ ln -s %{_bindir}/pidof %{buildroot}%{_sbindir}/pidof %{_includedir}/proc %changelog +* Wed Feb 05 2014 Jaromir Capik - 3.3.9-5 +- Support for timestamps & wide diskstat (#1053428, #1025833) +- Fixing fd leak in watch + * Fri Jan 24 2014 Jaromir Capik - 3.3.9-4 - Skipping trailing zeros in read_unvectored (#1057600) diff --git a/vmstat-timestamps.patch b/vmstat-timestamps.patch new file mode 100644 index 0000000..de894d2 --- /dev/null +++ b/vmstat-timestamps.patch @@ -0,0 +1,386 @@ +From 4fcd56bf582ee2ef5b205625ca3d1bfed90364e9 Mon Sep 17 00:00:00 2001 +From: Jaromir Capik +Date: Tue, 4 Feb 2014 19:10:42 +0100 +Subject: [PATCH] vmstat: Support for timestamps with '-t' & fix for '-wd' + +From now the vmstat can append a timestamp to each line in the +VMSTAT and DISKSTAT mode. You can achieve that with the '-t' +switch. +The '-w' switch now works in the DISKSTAT mode too. +--- + vmstat.8 | 3 + + vmstat.c | 197 ++++++++++++++++++++++++++++++++++++++++++++++++++++----------- + 2 files changed, 167 insertions(+), 33 deletions(-) + +diff --git a/vmstat.8 b/vmstat.8 +index ef6cbe9..420d9f3 100644 +--- a/vmstat.8 ++++ b/vmstat.8 +@@ -74,6 +74,9 @@ or 1048576 + bytes. Note this does not change the swap (si/so) or block (bi/bo) + fields. + .TP ++\fB\-t\fR, \fB\-\-timestamp\fR ++Append timestamp to each line ++.TP + \fB\-w\fR, \fB\-\-wide\fR + Wide output mode (useful for systems with higher amount of memory, + where the default output mode suffers from unwanted column breakage). +diff --git a/vmstat.c b/vmstat.c +index c01351d..a84d2d2 100644 +--- a/vmstat.c ++++ b/vmstat.c +@@ -43,6 +43,7 @@ + #include + #include + #include ++#include + + #include "c.h" + #include "fileutils.h" +@@ -75,6 +76,9 @@ static int a_option; + /* "-w" means "wide output" */ + static int w_option; + ++/* "-t" means "show timestamp" */ ++static int t_option; ++ + static unsigned sleep_time = 1; + static int infinite_updates = 0; + static unsigned long num_updates; +@@ -100,6 +104,7 @@ static void __attribute__ ((__noreturn__)) + fputs(_(" -p, --partition partition specific statistics\n"), out); + fputs(_(" -S, --unit define display unit\n"), out); + fputs(_(" -w, --wide wide output\n"), out); ++ fputs(_(" -t, --timestamp show timestamp\n"), out); + fputs(USAGE_SEPARATOR, out); + fputs(USAGE_HELP, out); + fputs(USAGE_VERSION, out); +@@ -180,21 +185,33 @@ static int format_1000(unsigned long long val64, char *restrict dst) + + static void new_header(void) + { ++ struct tm *tm_ptr; ++ time_t the_time; ++ char timebuf[32]; ++ + /* Translation Hint: Translating folloging header & fields + * that follow (marked with max x chars) might not work, + * unless manual page is translated as well. */ +- +- const char header[] = +- "procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----\n"; +- const char wide_header[] = +- "procs -----------------------memory---------------------- ---swap-- -----io---- -system-- --------cpu--------\n"; ++ const char *header = ++ _("procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----"); ++ const char *wide_header = ++ _("procs -----------------------memory---------------------- ---swap-- -----io---- -system-- --------cpu--------"); ++ const char *timestamp_header = _(" -----timestamp-----"); + + const char format[] = +- "%2s %2s %6s %6s %6s %6s %4s %4s %5s %5s %4s %4s %2s %2s %2s %2s %2s\n"; ++ "%2s %2s %6s %6s %6s %6s %4s %4s %5s %5s %4s %4s %2s %2s %2s %2s %2s"; + const char wide_format[] = +- "%2s %2s %12s %12s %12s %12s %4s %4s %5s %5s %4s %4s %3s %3s %3s %3s %3s\n"; ++ "%2s %2s %12s %12s %12s %12s %4s %4s %5s %5s %4s %4s %3s %3s %3s %3s %3s"; ++ ++ ++ printf(w_option ? wide_header : header); ++ ++ if (t_option) { ++ printf(timestamp_header); ++ } ++ ++ printf("\n"); + +- printf(w_option ? _(wide_header) : _(header)); + printf( + w_option ? wide_format : format, + /* Translation Hint: max 2 chars */ +@@ -235,6 +252,19 @@ static void new_header(void) + _("wa"), + /* Translation Hint: max 2 chars */ + _("st")); ++ ++ if (t_option) { ++ (void) time( &the_time ); ++ tm_ptr = localtime( &the_time ); ++ if (strftime(timebuf, sizeof(timebuf), "%Z", tm_ptr)) { ++ timebuf[strlen(timestamp_header) - 1] = '\0'; ++ } else { ++ timebuf[0] = '\0'; ++ } ++ printf(" %*s", (int)(strlen(timestamp_header) - 1), timebuf); ++ } ++ ++ printf("\n"); + } + + static unsigned long unitConvert(unsigned long size) +@@ -247,9 +277,9 @@ static unsigned long unitConvert(unsigned long size) + static void new_format(void) + { + const char format[] = +- "%2u %2u %6lu %6lu %6lu %6lu %4u %4u %5u %5u %4u %4u %2u %2u %2u %2u %2u\n"; ++ "%2u %2u %6lu %6lu %6lu %6lu %4u %4u %5u %5u %4u %4u %2u %2u %2u %2u %2u"; + const char wide_format[] = +- "%2u %2u %12lu %12lu %12lu %12lu %4u %4u %5u %5u %4u %4u %3u %3u %3u %3u %3u\n"; ++ "%2u %2u %12lu %12lu %12lu %12lu %4u %4u %5u %5u %4u %4u %3u %3u %3u %3u %3u"; + + unsigned int tog = 0; /* toggle switch for cleaner code */ + unsigned int i; +@@ -263,6 +293,9 @@ static void new_format(void) + unsigned int sleep_half; + unsigned long kb_per_page = sysconf(_SC_PAGESIZE) / 1024ul; + int debt = 0; /* handle idle ticks running backwards */ ++ struct tm *tm_ptr; ++ time_t the_time; ++ char timebuf[32]; + + sleep_half = (sleep_time / 2); + new_header(); +@@ -272,6 +305,12 @@ static void new_format(void) + cpu_zzz, pgpgin, pgpgout, pswpin, pswpout, intr, ctxt, &running, + &blocked, &dummy_1, &dummy_2); + ++ if (t_option) { ++ (void) time( &the_time ); ++ tm_ptr = localtime( &the_time ); ++ strftime(timebuf, sizeof(timebuf), "%Y-%m-%d %H:%M:%S", tm_ptr); ++ } ++ + duse = *cpu_use + *cpu_nic; + dsys = *cpu_sys + *cpu_xxx + *cpu_yyy; + didl = *cpu_idl; +@@ -298,6 +337,12 @@ static void new_format(void) + (unsigned)( (100*dstl + divo2) / Div ) + ); + ++ if (t_option) { ++ printf(" %s", timebuf); ++ } ++ ++ printf("\n"); ++ + /* main loop */ + for (i = 1; infinite_updates || i < num_updates; i++) { + sleep(sleep_time); +@@ -313,6 +358,12 @@ static void new_format(void) + pgpgout + tog, pswpin + tog, pswpout + tog, intr + tog, + ctxt + tog, &running, &blocked, &dummy_1, &dummy_2); + ++ if (t_option) { ++ (void) time( &the_time ); ++ tm_ptr = localtime( &the_time ); ++ strftime(timebuf, sizeof(timebuf), "%Y-%m-%d %H:%M:%S", tm_ptr); ++ } ++ + duse = + cpu_use[tog] - cpu_use[!tog] + cpu_nic[tog] - cpu_nic[!tog]; + dsys = +@@ -364,6 +415,12 @@ static void new_format(void) + /* st */ + (unsigned)( (100*dstl+divo2)/Div ) + ); ++ ++ if (t_option) { ++ printf(" %s", timebuf); ++ } ++ ++ printf("\n"); + } + } + +@@ -453,11 +510,33 @@ static int diskpartition_format(const char *partition_name) + + static void diskheader(void) + { ++ struct tm *tm_ptr; ++ time_t the_time; ++ char timebuf[32]; ++ + /* Translation Hint: Translating folloging header & fields + * that follow (marked with max x chars) might not work, + * unless manual page is translated as well. */ +- printf(_("disk- ------------reads------------ ------------writes----------- -----IO------\n")); +- printf("%5s %6s %6s %7s %7s %6s %6s %7s %7s %6s %6s\n", ++ const char *header = ++ _("disk- ------------reads------------ ------------writes----------- -----IO------"); ++ const char *wide_header = ++ _("disk- -------------------reads------------------- -------------------writes------------------ ------IO-------"); ++ const char *timestamp_header = _(" -----timestamp-----"); ++ ++ const char format[] = ++ "%5s %6s %6s %7s %7s %6s %6s %7s %7s %6s %6s"; ++ const char wide_format[] = ++ "%5s %9s %9s %11s %11s %9s %9s %11s %11s %7s %7s"; ++ ++ printf(w_option ? wide_header : header); ++ ++ if (t_option) { ++ printf(timestamp_header); ++ } ++ ++ printf("\n"); ++ ++ printf(w_option ? wide_format : format, + " ", + /* Translation Hint: max 6 chars */ + _("total"), +@@ -479,25 +558,53 @@ static void diskheader(void) + _("cur"), + /* Translation Hint: max 6 chars */ + _("sec")); ++ ++ if (t_option) { ++ (void) time( &the_time ); ++ tm_ptr = localtime( &the_time ); ++ if (strftime(timebuf, sizeof(timebuf), "%Z", tm_ptr)) { ++ timebuf[strlen(timestamp_header) - 1] = '\0'; ++ } else { ++ timebuf[0] = '\0'; ++ } ++ printf(" %*s", (int)(strlen(timestamp_header) - 1), timebuf); ++ } ++ ++ printf("\n"); + } + + static void diskformat(void) + { ++ const char format[] = ++ "%-5s %6u %6u %7llu %7u %6u %6u %7llu %7u %6u %6u"; ++ const char wide_format[] = ++ "%-5s %9u %9u %11llu %11u %9u %9u %11llu %11u %7u %7u"; ++ + FILE *fDiskstat; + struct disk_stat *disks; + struct partition_stat *partitions; + unsigned long ndisks, i, j, k; +- const char format[] = "%-5s %6u %6u %7llu %7u %6u %6u %7llu %7u %6u %6u\n"; ++ struct tm *tm_ptr; ++ time_t the_time; ++ char timebuf[32]; ++ + + if ((fDiskstat = fopen("/proc/diskstats", "rb"))) { + fclose(fDiskstat); + ndisks = getdiskstat(&disks, &partitions); ++ ++ if (t_option) { ++ (void) time( &the_time ); ++ tm_ptr = localtime( &the_time ); ++ strftime(timebuf, sizeof(timebuf), "%Y-%m-%d %H:%M:%S", tm_ptr); ++ } ++ + if (!moreheaders) + diskheader(); + for (k = 0; k < ndisks; k++) { + if (moreheaders && ((k % height) == 0)) + diskheader(); +- printf(format, ++ printf(w_option ? wide_format : format, + disks[k].disk_name, + disks[k].reads, + disks[k].merged_reads, +@@ -510,31 +617,51 @@ static void diskformat(void) + disks[k].inprogress_IO ? disks[k].inprogress_IO / 1000 : 0, + disks[k].milli_spent_IO ? disks[k]. + milli_spent_IO / 1000 : 0); ++ ++ if (t_option) { ++ printf(" %s", timebuf); ++ } ++ ++ printf("\n"); + fflush(stdout); + } + free(disks); + free(partitions); ++ + for (j = 1; infinite_updates || j < num_updates; j++) { + sleep(sleep_time); + ndisks = getdiskstat(&disks, &partitions); +- for (i = 0; i < ndisks; i++, k++) { +- if (moreheaders && ((k % height) == 0)) +- diskheader(); +- printf(format, +- disks[i].disk_name, +- disks[i].reads, +- disks[i].merged_reads, +- disks[i].reads_sectors, +- disks[i].milli_reading, +- disks[i].writes, +- disks[i].merged_writes, +- disks[i].written_sectors, +- disks[i].milli_writing, +- disks[i].inprogress_IO ? disks[i].inprogress_IO / 1000 : 0, +- disks[i].milli_spent_IO ? disks[i]. +- milli_spent_IO / 1000 : 0); +- fflush(stdout); +- } ++ ++ if (t_option) { ++ (void) time( &the_time ); ++ tm_ptr = localtime( &the_time ); ++ strftime(timebuf, sizeof(timebuf), "%Y-%m-%d %H:%M:%S", tm_ptr); ++ } ++ ++ for (i = 0; i < ndisks; i++, k++) { ++ if (moreheaders && ((k % height) == 0)) ++ diskheader(); ++ printf(w_option ? wide_format : format, ++ disks[i].disk_name, ++ disks[i].reads, ++ disks[i].merged_reads, ++ disks[i].reads_sectors, ++ disks[i].milli_reading, ++ disks[i].writes, ++ disks[i].merged_writes, ++ disks[i].written_sectors, ++ disks[i].milli_writing, ++ disks[i].inprogress_IO ? disks[i].inprogress_IO / 1000 : 0, ++ disks[i].milli_spent_IO ? disks[i]. ++ milli_spent_IO / 1000 : 0); ++ ++ if (t_option) { ++ printf(" %s", timebuf); ++ } ++ ++ printf("\n"); ++ fflush(stdout); ++ } + free(disks); + free(partitions); + } +@@ -740,6 +867,7 @@ int main(int argc, char *argv[]) + {"partition", required_argument, NULL, 'p'}, + {"unit", required_argument, NULL, 'S'}, + {"wide", no_argument, NULL, 'w'}, ++ {"timestamp", no_argument, NULL, 't'}, + {"help", no_argument, NULL, 'h'}, + {"version", no_argument, NULL, 'V'}, + {NULL, 0, NULL, 0} +@@ -754,7 +882,7 @@ int main(int argc, char *argv[]) + atexit(close_stdout); + + while ((c = +- getopt_long(argc, argv, "afmnsdDp:S:whV", longopts, ++ getopt_long(argc, argv, "afmnsdDp:S:wthV", longopts, + NULL)) != EOF) + switch (c) { + case 'V': +@@ -820,6 +948,9 @@ int main(int argc, char *argv[]) + case 'w': + w_option = 1; + break; ++ case 't': ++ t_option = 1; ++ break; + default: + /* no other aguments defined yet. */ + usage(stderr); +-- +1.8.4.2 + diff --git a/watch-fd-leak.patch b/watch-fd-leak.patch new file mode 100644 index 0000000..ae59852 --- /dev/null +++ b/watch-fd-leak.patch @@ -0,0 +1,34 @@ +From 835b6294d18a6ad79ff56aaeb0038bc6d006384b Mon Sep 17 00:00:00 2001 +From: Josh Stone +Date: Tue, 4 Feb 2014 09:46:58 -0800 +Subject: [PATCH] watch: Don't leak extra fds to the child + +Once the write side of the pipe has been duped to stdout for the child, +the original pipefd is no longer needed, so it can be closed to avoid +leaking to the child. + +The leak can easily be seen with "watch ls -l /proc/self/fd", but I +found this due to "watch lvs" diagnosing itself: + + File descriptor 4 (pipe:[3163616]) leaked on lvs invocation. + +Signed-off-by: Josh Stone +--- + watch.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/watch.c b/watch.c +index 032dfb7..f0a3ec3 100644 +--- a/watch.c ++++ b/watch.c +@@ -387,6 +387,7 @@ static int run_command(char *restrict command, char **restrict command_argv) + if (dup2(pipefd[1], 1) < 0) { /* replace stdout with write side of pipe */ + xerr(3, _("dup2 failed")); + } ++ close(pipefd[1]); /* once duped, the write fd isn't needed */ + dup2(1, 2); /* stderr should default to stdout */ + + if (flags & WATCH_EXEC) { /* pass command to exec instead of system */ +-- +1.8.4.2 +