diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..02817f0
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+SOURCES/pcp-5.0.2.src.tar.gz
diff --git a/.pcp.metadata b/.pcp.metadata
new file mode 100644
index 0000000..017406d
--- /dev/null
+++ b/.pcp.metadata
@@ -0,0 +1 @@
+95c6975c1af0c910a0e26ad5677a40bd8cd52ed2 SOURCES/pcp-5.0.2.src.tar.gz
diff --git a/SOURCES/activemq-modules.patch b/SOURCES/activemq-modules.patch
new file mode 100644
index 0000000..f43068d
--- /dev/null
+++ b/SOURCES/activemq-modules.patch
@@ -0,0 +1,53 @@
+commit 4356ac909fa1cc30e5804d9ff6e4c9204977b091
+Author: Nathan Scott <nathans@redhat.com>
+Date:   Fri Jan 31 14:34:25 2020 +1100
+
+    pmdactivemq: module name and path resolution fixes for latest perl
+    
+    Picked up by test qa/760 with recent versions of perl.
+    
+    Resolves Red Hat BZ #1788881
+
+diff --git a/src/pmdas/activemq/GNUmakefile b/src/pmdas/activemq/GNUmakefile
+index 8289670ca..1ad330220 100644
+--- a/src/pmdas/activemq/GNUmakefile
++++ b/src/pmdas/activemq/GNUmakefile
+@@ -41,7 +41,9 @@ build-me: check_domain
+ install install_pcp: default
+ 	$(INSTALL) -m 755 -d $(PMDADIR)
+ 	$(INSTALL) -m 755 Install Remove $(PMDADIR)
+-	$(INSTALL) -m 644 pmda$(IAM).pl $(MODULES) $(PMDADIR)
++	$(INSTALL) -m 644 pmda$(IAM).pl $(PMDADIR)/pmda$(IAM).pl
++	$(INSTALL) -m 755 -d $(PMDADIR)/PCP
++	$(INSTALL) -m 644 $(MODULES) $(PMDADIR)/PCP
+ 	@$(INSTALL_MAN)
+ else
+ build-me:
+diff --git a/src/pmdas/activemq/pmdaactivemq.pl b/src/pmdas/activemq/pmdaactivemq.pl
+index 7f835aac5..4b5451688 100755
+--- a/src/pmdas/activemq/pmdaactivemq.pl
++++ b/src/pmdas/activemq/pmdaactivemq.pl
+@@ -49,16 +49,16 @@ my $jvm_garbage_collection_cluster = 5;
+ for my $file (pmda_config('PCP_PMDAS_DIR') . '/activemq/activemq.conf', 'activemq.conf') {
+     eval `cat $file` unless ! -f $file;
+ }
+-my $timesource = TimeSource->new;
+-my $cache = Cache->new($timesource, $cache_time);
++my $timesource = PCP::TimeSource->new;
++my $cache = PCP::Cache->new($timesource, $cache_time);
+ my $http_client = LWP::UserAgent->new;
+ $http_client->agent('pmdaactivemq');
+ $http_client->timeout($rest_timeout);
+-my $rest_client = RESTClient->new($http_client, $cache, $rest_hostname, $rest_port, $rest_username, $rest_password, $rest_realm);
+-my $activemq = ActiveMQ->new($rest_client);
+-my $jvm_memory = JVMMemory->new($rest_client);
+-my $jvm_memory_pool = JVMMemoryPool->new($rest_client);
+-my $jvm_garbage_collection = JVMGarbageCollection->new($rest_client);
++my $rest_client = PCP::RESTClient->new($http_client, $cache, $rest_hostname, $rest_port, $rest_username, $rest_password, $rest_realm);
++my $activemq = PCP::ActiveMQ->new($rest_client);
++my $jvm_memory = PCP::JVMMemory->new($rest_client);
++my $jvm_memory_pool = PCP::JVMMemoryPool->new($rest_client);
++my $jvm_garbage_collection = PCP::JVMGarbageCollection->new($rest_client);
+ 
+ my %queue_instances;
+ 
diff --git a/SOURCES/archive-discovery.patch b/SOURCES/archive-discovery.patch
new file mode 100644
index 0000000..cf7a3d3
--- /dev/null
+++ b/SOURCES/archive-discovery.patch
@@ -0,0 +1,3175 @@
+diff -Naurp pcp-5.0.2.orig/qa/1211.out pcp-5.0.2/qa/1211.out
+--- pcp-5.0.2.orig/qa/1211.out	2019-12-06 15:18:26.000000000 +1100
++++ pcp-5.0.2/qa/1211.out	2020-02-03 13:23:15.258762963 +1100
+@@ -144,6 +144,9 @@ kernel.uname.nodename
+ kernel.uname.release
+ kernel.uname.sysname
+ kernel.uname.version
++pmcd.pmlogger.archive
++pmcd.pmlogger.host
++pmcd.pmlogger.port
+ proc.fd.count
+ proc.id.egid
+ proc.id.egid_nm
+@@ -267,6 +270,7 @@ List all instance names ...
+ 030016 pmlogger -P -c config.default 20110930.17.20
+ 1 minute
+ 15 minute
++2950
+ 5 minute
+ cpu0
+ cpu1
+@@ -398,10 +402,10 @@ fecd5a4b4c6e1273eaa001287a6dd57b7bbd19f7
+ Values fetch for a single-valued query ...
+ 
+ d51624d12da45900bfee2fd73f1e23f3ccabb784
+-    [Mon Oct  3 09:10:22.959242000 2011] 172598244
+-    [Mon Oct  3 09:10:23.300460000 2011] 172598364
+-    [Mon Oct  3 09:10:23.802930000 2011] 172598481
+     [Mon Oct  3 09:10:24.305845000 2011] 172598559
++    [Mon Oct  3 09:10:23.802930000 2011] 172598481
++    [Mon Oct  3 09:10:23.300460000 2011] 172598364
++    [Mon Oct  3 09:10:22.959242000 2011] 172598244
+ 
+ Values fetch with a one-second interval ...
+ 
+@@ -420,15 +424,18 @@ d51624d12da45900bfee2fd73f1e23f3ccabb784
+ Values fetch for a multi-valued query ...
+ 
+ fecd5a4b4c6e1273eaa001287a6dd57b7bbd19f7
+-    [Mon Oct  3 09:10:23.300460000 2011] 0.000000e+00 59181b1de54ff2b383cfd1cdd8636f86c880b69b
+-    [Mon Oct  3 09:10:23.300460000 2011] 2.000000e-02 ab010c7d45145aa33c8f8fa681a68c9d4102ae19
+-    [Mon Oct  3 09:10:23.300460000 2011] 5.000000e-02 9d418095c9f971ff4fd44d6828ead27f9d021dc3
+-    [Mon Oct  3 09:10:23.802930000 2011] 0.000000e+00 59181b1de54ff2b383cfd1cdd8636f86c880b69b
+-    [Mon Oct  3 09:10:23.802930000 2011] 2.000000e-02 ab010c7d45145aa33c8f8fa681a68c9d4102ae19
+-    [Mon Oct  3 09:10:23.802930000 2011] 5.000000e-02 9d418095c9f971ff4fd44d6828ead27f9d021dc3
+     [Mon Oct  3 09:10:24.305845000 2011] 0.000000e+00 59181b1de54ff2b383cfd1cdd8636f86c880b69b
+     [Mon Oct  3 09:10:24.305845000 2011] 2.000000e-02 ab010c7d45145aa33c8f8fa681a68c9d4102ae19
+     [Mon Oct  3 09:10:24.305845000 2011] 5.000000e-02 9d418095c9f971ff4fd44d6828ead27f9d021dc3
++    [Mon Oct  3 09:10:23.802930000 2011] 0.000000e+00 59181b1de54ff2b383cfd1cdd8636f86c880b69b
++    [Mon Oct  3 09:10:23.802930000 2011] 2.000000e-02 ab010c7d45145aa33c8f8fa681a68c9d4102ae19
++    [Mon Oct  3 09:10:23.802930000 2011] 5.000000e-02 9d418095c9f971ff4fd44d6828ead27f9d021dc3
++    [Mon Oct  3 09:10:23.300460000 2011] 0.000000e+00 59181b1de54ff2b383cfd1cdd8636f86c880b69b
++    [Mon Oct  3 09:10:23.300460000 2011] 2.000000e-02 ab010c7d45145aa33c8f8fa681a68c9d4102ae19
++    [Mon Oct  3 09:10:23.300460000 2011] 5.000000e-02 9d418095c9f971ff4fd44d6828ead27f9d021dc3
++    [Mon Oct  3 09:10:22.959242000 2011] 0.000000e+00 59181b1de54ff2b383cfd1cdd8636f86c880b69b
++    [Mon Oct  3 09:10:22.959242000 2011] 2.000000e-02 ab010c7d45145aa33c8f8fa681a68c9d4102ae19
++    [Mon Oct  3 09:10:22.959242000 2011] 5.000000e-02 9d418095c9f971ff4fd44d6828ead27f9d021dc3
+ 
+ Multi-series lookups from a multi-series query ...
+ 2db1da4d276d81c42c578c2829e99188ae7cc898
+diff -Naurp pcp-5.0.2.orig/qa/1573 pcp-5.0.2/qa/1573
+--- pcp-5.0.2.orig/qa/1573	1970-01-01 10:00:00.000000000 +1000
++++ pcp-5.0.2/qa/1573	2020-02-03 13:36:17.288581801 +1100
+@@ -0,0 +1,103 @@
++#!/bin/sh
++# PCP QA Test No. 1573
++# Exercise libpcp_web memory leak without a redis-server.
++#
++# Copyright (c) 2020 Red Hat.
++#
++
++seq=`basename $0`
++echo "QA output created by $seq"
++
++# get standard environment, filters and checks
++. ./common.product
++. ./common.filter
++. ./common.check
++
++_check_series
++
++_cleanup()
++{
++    cd $here
++    if $need_restore
++    then
++	need_restore=false
++	_service pmlogger stop >/dev/null
++	$sudo rm -rf $PCP_LOG_DIR/pmlogger
++	$sudo mv $PCP_LOG_DIR/pmlogger.$seq $PCP_LOG_DIR/pmlogger
++	_restore_config $PCP_ETC_DIR/pcp/pmlogger
++	_service pcp restart 2>&1 | _filter_pcp_stop | _filter_pcp_start
++	_wait_for_pmcd
++	_wait_for_pmlogger
++	echo === restarting pmproxy
++	_restore_config $PCP_SYSCONF_DIR/pmproxy
++	_service pmproxy restart 2>&1 | _filter_pcp_start
++	_wait_for_pmproxy
++    fi
++    $sudo rm -rf $tmp $tmp.*
++}
++
++status=1	# failure is the default!
++need_restore=false
++$sudo rm -rf $tmp $tmp.* $seq.full
++trap "_cleanup; exit \$status" 0 1 2 3 15
++
++# real QA test starts here
++_save_config $PCP_SYSCONF_DIR/pmproxy
++need_restore=true
++
++# only want the primary logger running
++_save_config $PCP_ETC_DIR/pcp/pmlogger
++_restore_pmlogger_control
++
++#$sudo rm -f $PCP_SYSCONF_DIR/pmproxy/*
++echo "[pmproxy]" > $tmp.conf
++echo "pcp.enabled = true" >> $tmp.conf
++echo "http.enabled = true" >> $tmp.conf
++echo "redis.enabled = true" >> $tmp.conf
++echo "[discover]" >> $tmp.conf
++echo "enabled = true" >> $tmp.conf
++echo "[pmseries]" >> $tmp.conf
++echo "enabled = false" >> $tmp.conf
++$sudo cp $tmp.conf $PCP_SYSCONF_DIR/pmproxy/pmproxy.conf
++
++_service pmlogger stop >/dev/null
++
++# move aside existing logs so we can measure base memory footprint
++[ -d $PCP_LOG_DIR/pmlogger.$seq ] && $sudo mv $PCP_LOG_DIR/pmlogger.$seq $PCP_LOG_DIR/pmlogger.$seq.saved
++$sudo mv $PCP_LOG_DIR/pmlogger $PCP_LOG_DIR/pmlogger.$seq
++$sudo mkdir -p $PCP_LOG_DIR/pmlogger
++$sudo chmod 775 $PCP_LOG_DIR/pmlogger
++$sudo chown $PCP_USER:$PCP_USER $PCP_LOG_DIR/pmlogger
++
++_service pmproxy restart 2>&1 | _filter_pcp_stop | _filter_pcp_start
++_wait_for_pmproxy
++
++pmproxy_pid=`_get_pids_by_name -a pmproxy`
++[ -z "$pmproxy_pid" ] && echo === pmproxy not running && status=1 && exit 1
++echo === extract initial rss
++pmproxy_rss1=`pminfo -f proc.memory.rss |
++	$PCP_AWK_PROG '{ if ($2 == "['$pmproxy_pid'") { print $NF} }'`
++
++echo === restarting pmlogger # primary only
++_service pmlogger restart 2>&1 | _filter_pcp_start
++_wait_for_pmlogger
++
++echo === wait for pmproxy to process filesystem events
++pmsleep 4.2
++
++echo === extract updated rss
++pmproxy_rss2=`pminfo -f proc.memory.rss |
++	$PCP_AWK_PROG '{ if ($2 == "['$pmproxy_pid'") { print $NF} }'`
++
++echo === checking rss within tolerance
++_within_tolerance "rss" $pmproxy_rss1 $pmproxy_rss2 10%
++[ $pmproxy_rss2 -gt 10000 ] && echo "Unexpected pmproxy RSS: $pmproxy_rss2, was initially $pmproxy_rss1"
++
++echo "RSS1 for PID $pmproxy_pid is $pmproxy_rss1" >> $here/$seq.full
++echo "RSS2 for PID $pmproxy_pid is $pmproxy_rss2" >> $here/$seq.full
++cat $PCP_LOG_DIR/pmproxy/pmproxy.log >>$seq.full
++echo === see $seq.full for pmproxy rss and logs
++
++# success, all done
++status=0
++exit
+diff -Naurp pcp-5.0.2.orig/qa/1573.out pcp-5.0.2/qa/1573.out
+--- pcp-5.0.2.orig/qa/1573.out	1970-01-01 10:00:00.000000000 +1000
++++ pcp-5.0.2/qa/1573.out	2020-02-03 13:23:15.259762953 +1100
+@@ -0,0 +1,8 @@
++QA output created by 1573
++=== extract initial rss
++=== restarting pmlogger
++=== wait for pmproxy to process filesystem events
++=== extract updated rss
++=== checking rss within tolerance
++=== see 1573.full for pmproxy rss and logs
++=== restarting pmproxy
+diff -Naurp pcp-5.0.2.orig/qa/1600 pcp-5.0.2/qa/1600
+--- pcp-5.0.2.orig/qa/1600	2019-12-10 17:49:05.000000000 +1100
++++ pcp-5.0.2/qa/1600	2020-02-03 13:23:15.260762942 +1100
+@@ -82,7 +82,11 @@ _filter_values()
+ _filter_label_values()
+ {
+     sed \
++	-e "s/^domainname: \"${domainname}\"/domainname: \"DOMAIN\"/g" \
++	-e "s/^machineid: \"${machineid}\"/machineid: \"MACHINE\"/g" \
+ 	-e "s/^hostname: \"${hostname}\"/hostname: \"HOSTNAME\"/g" \
++	-e "s/^groupid: $groupid/groupid: GID/g" \
++	-e "s/^userid: $userid/userid: UID/g" \
+ 	-e "s/changed: false, true/changed: false/g" \
+ 	-e "/metric_label: null/d" \
+     #end
+diff -Naurp pcp-5.0.2.orig/qa/1600.out pcp-5.0.2/qa/1600.out
+--- pcp-5.0.2.orig/qa/1600.out	2019-12-10 10:46:20.000000000 +1100
++++ pcp-5.0.2/qa/1600.out	2020-02-03 13:23:15.260762942 +1100
+@@ -27,15 +27,15 @@ TIMESERIES
+ == verify metric labels
+ 
+ TIMESERIES
+-    inst [100 or "bin-100"] labels {"agent":"sample","hostname":"HOST","role":"testing"}
+-    inst [200 or "bin-200"] labels {"agent":"sample","hostname":"HOST","role":"testing"}
+-    inst [300 or "bin-300"] labels {"agent":"sample","hostname":"HOST","role":"testing"}
+-    inst [400 or "bin-400"] labels {"agent":"sample","hostname":"HOST","role":"testing"}
+-    inst [500 or "bin-500"] labels {"agent":"sample","hostname":"HOST","role":"testing"}
+-    inst [600 or "bin-600"] labels {"agent":"sample","hostname":"HOST","role":"testing"}
+-    inst [700 or "bin-700"] labels {"agent":"sample","hostname":"HOST","role":"testing"}
+-    inst [800 or "bin-800"] labels {"agent":"sample","hostname":"HOST","role":"testing"}
+-    inst [900 or "bin-900"] labels {"agent":"sample","hostname":"HOST","role":"testing"}
++    inst [100 or "bin-100"] labels {"agent":"sample","bin":100,"domainname":"DOMAIN","groupid":GID,"hostname":"HOST","latitude":-25.28496,"longitude":152.87886,"machineid":"MACHINE","role":"testing","userid":UID}
++    inst [200 or "bin-200"] labels {"agent":"sample","bin":200,"domainname":"DOMAIN","groupid":GID,"hostname":"HOST","latitude":-25.28496,"longitude":152.87886,"machineid":"MACHINE","role":"testing","userid":UID}
++    inst [300 or "bin-300"] labels {"agent":"sample","bin":300,"domainname":"DOMAIN","groupid":GID,"hostname":"HOST","latitude":-25.28496,"longitude":152.87886,"machineid":"MACHINE","role":"testing","userid":UID}
++    inst [400 or "bin-400"] labels {"agent":"sample","bin":400,"domainname":"DOMAIN","groupid":GID,"hostname":"HOST","latitude":-25.28496,"longitude":152.87886,"machineid":"MACHINE","role":"testing","userid":UID}
++    inst [500 or "bin-500"] labels {"agent":"sample","bin":500,"domainname":"DOMAIN","groupid":GID,"hostname":"HOST","latitude":-25.28496,"longitude":152.87886,"machineid":"MACHINE","role":"testing","userid":UID}
++    inst [600 or "bin-600"] labels {"agent":"sample","bin":600,"domainname":"DOMAIN","groupid":GID,"hostname":"HOST","latitude":-25.28496,"longitude":152.87886,"machineid":"MACHINE","role":"testing","userid":UID}
++    inst [700 or "bin-700"] labels {"agent":"sample","bin":700,"domainname":"DOMAIN","groupid":GID,"hostname":"HOST","latitude":-25.28496,"longitude":152.87886,"machineid":"MACHINE","role":"testing","userid":UID}
++    inst [800 or "bin-800"] labels {"agent":"sample","bin":800,"domainname":"DOMAIN","groupid":GID,"hostname":"HOST","latitude":-25.28496,"longitude":152.87886,"machineid":"MACHINE","role":"testing","userid":UID}
++    inst [900 or "bin-900"] labels {"agent":"sample","bin":900,"domainname":"DOMAIN","groupid":GID,"hostname":"HOST","latitude":-25.28496,"longitude":152.87886,"machineid":"MACHINE","role":"testing","userid":UID}
+ == verify metric values
+ 
+ TIMESERIES
+@@ -43,15 +43,24 @@ TIMESERIES
+     [TIMESTAMP] VALUE
+ == verify label names and values
+ agent: "mmv", "sample", "pmcd"
++bin: 100, 200, 300, 400, 500, 600, 700, 800, 900
+ changed: false
+ clan: "mcdonell"
+ cluster: "zero"
++domainname: "DOMAIN"
++groupid: GID
+ hostname: "HOSTNAME"
+ indom_label: 42.001
++latitude: -25.28496
++longitude: 152.87886
++machineid: "MACHINE"
+ measure: "speed"
+ model: "RGB"
++registry_label: "string"
+ role: "testing"
++transient: false, true
+ units: "metres per second"
+ unitsystem: "SI"
++userid: UID
+ == verify archive removal
+ == all done
+diff -Naurp pcp-5.0.2.orig/qa/1601.out pcp-5.0.2/qa/1601.out
+--- pcp-5.0.2.orig/qa/1601.out	2019-11-27 16:01:34.000000000 +1100
++++ pcp-5.0.2/qa/1601.out	2020-02-03 13:23:15.261762932 +1100
+@@ -131,7 +131,7 @@ Using series 01d8bc7fa75aaff98a08aa0b1c0
+     {
+         "series": "605fc77742cd0317597291329561ac4e50c0dd12",
+         "instance": "c3795d8b757506a2901c6b08b489ba56cae7f0d4",
+-        "timestamp": 1317633023300.460,
++        "timestamp": 1317633024305.845,
+         "value": "71661"
+     },
+     {
+@@ -147,7 +147,7 @@ Using series 01d8bc7fa75aaff98a08aa0b1c0
+         {
+             "series": "605fc77742cd0317597291329561ac4e50c0dd12",
+             "instance": "c3795d8b757506a2901c6b08b489ba56cae7f0d4",
+-            "timestamp": 1317633023300.460,
++            "timestamp": 1317633024305.845,
+             "value": "71661"
+         },
+         {
+@@ -163,7 +163,7 @@ Using series 01d8bc7fa75aaff98a08aa0b1c0
+     {
+         "series": "605fc77742cd0317597291329561ac4e50c0dd12",
+         "instance": "c3795d8b757506a2901c6b08b489ba56cae7f0d4",
+-        "timestamp": 1317633023300.460,
++        "timestamp": 1317633024305.845,
+         "value": "71661"
+     },
+     {
+@@ -179,7 +179,7 @@ Using series 01d8bc7fa75aaff98a08aa0b1c0
+         {
+             "series": "605fc77742cd0317597291329561ac4e50c0dd12",
+             "instance": "c3795d8b757506a2901c6b08b489ba56cae7f0d4",
+-            "timestamp": 1317633023300.460,
++            "timestamp": 1317633024305.845,
+             "value": "71661"
+         },
+         {
+diff -Naurp pcp-5.0.2.orig/qa/1661 pcp-5.0.2/qa/1661
+--- pcp-5.0.2.orig/qa/1661	2019-12-10 17:04:20.000000000 +1100
++++ pcp-5.0.2/qa/1661	2020-02-03 13:23:15.261762932 +1100
+@@ -41,8 +41,7 @@ _restore_pmlogger_control
+ echo;echo === restarting pmproxy service to ensure sane starting condition 
+ _service pmlogger stop 2>&1 | _filter_pcp_stop
+ _service pmproxy restart 2>&1 | _filter_pcp_stop | _filter_pcp_start
+-# give pmproxy a chance to startup
+-pmsleep 2; _wait_for_pmproxy
++_wait_for_pmproxy
+ 
+ pmproxy_pid=`_get_pids_by_name -a pmproxy`
+ [ -z "$pmproxy_pid" ] && echo === pmproxy not running && status=1 && exit 1
+diff -Naurp pcp-5.0.2.orig/qa/group pcp-5.0.2/qa/group
+--- pcp-5.0.2.orig/qa/group	2019-12-11 14:06:06.000000000 +1100
++++ pcp-5.0.2/qa/group	2020-02-03 13:23:15.261762932 +1100
+@@ -1688,6 +1688,7 @@ BAD
+ 1545 pcp2xml python pcp2xxx local
+ 1546 pmrep python local
+ 1547 pmrep python local
++1573 pmproxy libpcp_web pmlogger local
+ 1588 python pmiostat local
+ 1598 pmda.statsd local
+ 1599 pmda.statsd local
+diff -Naurp pcp-5.0.2.orig/src/include/pcp/libpcp.h pcp-5.0.2/src/include/pcp/libpcp.h
+--- pcp-5.0.2.orig/src/include/pcp/libpcp.h	2019-09-24 17:23:36.000000000 +1000
++++ pcp-5.0.2/src/include/pcp/libpcp.h	2020-02-03 13:23:15.261762932 +1100
+@@ -7,7 +7,7 @@
+  *	remain fixed across releases, and they may not work, or may
+  *	provide different semantics at some point in the future.
+  *
+- * Copyright (c) 2012-2019 Red Hat.
++ * Copyright (c) 2012-2020 Red Hat.
+  * Copyright (c) 2008-2009 Aconex.  All Rights Reserved.
+  * Copyright (c) 1995-2002 Silicon Graphics, Inc.  All Rights Reserved.
+  *
+@@ -846,6 +846,13 @@ PCP_CALL extern int __pmLogPutText(__pmA
+ PCP_CALL extern int __pmLogWriteLabel(__pmFILE *, const __pmLogLabel *);
+ PCP_CALL extern int __pmLogLoadLabel(__pmArchCtl *, const char *);
+ PCP_CALL extern int __pmLogLoadMeta(__pmArchCtl *);
++PCP_CALL extern int __pmLogAddDesc(__pmArchCtl *, const pmDesc *);
++PCP_CALL extern int __pmLogAddInDom(__pmArchCtl *, const pmTimespec *, const pmInResult *, int *, int);
++PCP_CALL extern int __pmLogAddPMNSNode(__pmArchCtl *, pmID, const char *);
++PCP_CALL extern int __pmLogAddLabelSets(__pmArchCtl *, const pmTimespec *, unsigned int, unsigned int, int, pmLabelSet *);
++PCP_CALL extern int __pmLogAddText(__pmArchCtl *, unsigned int, unsigned int, const char *);
++PCP_CALL extern int __pmLogAddVolume(__pmArchCtl *, unsigned int);
++
+ #define PMLOGREAD_NEXT		0
+ #define PMLOGREAD_TO_EOF	1
+ PCP_CALL extern int __pmLogRead(__pmArchCtl *, int, __pmFILE *, pmResult **, int);
+@@ -862,7 +869,9 @@ PCP_CALL extern int __pmLogLookupText(__
+ PCP_CALL extern int __pmLogNameInDom(__pmArchCtl *, pmInDom, pmTimeval *, int, char **);
+ PCP_CALL extern const char *__pmLogLocalSocketDefault(int, char *buf, size_t bufSize);
+ PCP_CALL extern const char *__pmLogLocalSocketUser(int, char *buf, size_t bufSize);
++PCP_CALL extern int __pmLogCompressedSuffix(const char *);
+ PCP_CALL extern char *__pmLogBaseName(char *);
++PCP_CALL extern char *__pmLogBaseNameVol(char *, int *);
+ PCP_DATA extern int __pmLogReads;
+ 
+ /* Convert opaque context handle to __pmContext pointer */
+diff -Naurp pcp-5.0.2.orig/src/libpcp/src/exports.master pcp-5.0.2/src/libpcp/src/exports.master
+--- pcp-5.0.2.orig/src/libpcp/src/exports.master	2019-10-02 14:40:30.000000000 +1000
++++ pcp-5.0.2/src/libpcp/src/exports.master	2020-02-03 13:23:15.262762921 +1100
+@@ -683,3 +683,15 @@ PCP_3.26 {
+   global:
+     __pmDupLabelSets;
+ } PCP_3.25;
++
++PCP_3.26_1 {
++  global:
++    __pmLogAddDesc;
++    __pmLogAddInDom;
++    __pmLogAddPMNSNode;
++    __pmLogAddLabelSets;
++    __pmLogAddText;
++    __pmLogAddVolume;
++    __pmLogCompressedSuffix;
++    __pmLogBaseNameVol;
++} PCP_3.26;
+diff -Naurp pcp-5.0.2.orig/src/libpcp/src/io.c pcp-5.0.2/src/libpcp/src/io.c
+--- pcp-5.0.2.orig/src/libpcp/src/io.c	2018-06-09 11:43:34.000000000 +1000
++++ pcp-5.0.2/src/libpcp/src/io.c	2020-02-03 13:23:15.262762921 +1100
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (c) 2017-2018 Red Hat.
++ * Copyright (c) 2017-2018,2020 Red Hat.
+  * 
+  * This library is free software; you can redistribute it and/or modify it
+  * under the terms of the GNU Lesser General Public License as published
+@@ -47,7 +47,7 @@ extern __pm_fops __pm_xz;
+ #endif
+ 
+ static const struct {
+-    const char	*suff;
++    const char	*suffix;
+     const int	appl;
+     __pm_fops   *handler;
+ } compress_ctl[] = {
+@@ -61,40 +61,43 @@ static const struct {
+ };
+ static const int ncompress = sizeof(compress_ctl) / sizeof(compress_ctl[0]);
+ 
++int
++__pmLogCompressedSuffix(const char *suffix)
++{
++    int		i;
++
++    for (i = 0; i < ncompress; i++)
++	if (strcmp(suffix, compress_ctl[i].suffix) == 0)
++	    return 1;
++    return 0;
++}
++
+ /*
+- * If name contains '.' and the suffix is "index", "meta" or a string of
+- * digits, all optionally followed by one of the compression suffixes,
+- * strip the suffix.
+- *
+- * Modifications are performed on the argument string in-place. If modifications
+- * are made, a pointer to the start of the modified string is returned.
+- * Otherwise, NULL is returned.
++ * Variant of __pmLogBaseName() - see below that also returns log
++ * the volume number if the file name is an archive log volume.
++ * If the vol argument is NULL it will be ignored.
+  */
+ char *
+-__pmLogBaseName(char *name)
++__pmLogBaseNameVol(char *name, int *vol)
+ {
+-    char *q;
+-    int   strip;
+-    int   i;
++    char	*q, *q2;
++    int		strip = 0;
+ 
+-    strip = 0;
++    if (vol)
++	*vol = -1;
+     if ((q = strrchr(name, '.')) != NULL) {
+-	for (i = 0; i < ncompress; i++) {
+-	    if (strcmp(q, compress_ctl[i].suff) == 0) {
+-		char	*q2;
+-		/*
+-		 * The name ends with one of the supported compressed file
+-		 * suffixes. Strip it before checking for other known suffixes.
+-		 */
+-		*q = '\0';
+-		if ((q2 = strrchr(name, '.')) == NULL) {
+-		    /* no . to the left of the suffix */
+-		    *q = '.';
+-		    goto done;
+-		}
+-		q = q2;
+-		break;
++	if (__pmLogCompressedSuffix(q)) {
++	    /*
++	     * The name ends with one of the supported compressed file
++	     * suffixes. Strip it before checking for other known suffixes.
++	     */
++	    *q = '\0';
++	    if ((q2 = strrchr(name, '.')) == NULL) {
++		/* no . to the left of the suffix */
++		*q = '.';
++		goto done;
+ 	    }
++	    q = q2;
+ 	}
+ 	if (strcmp(q, ".index") == 0) {
+ 	    strip = 1;
+@@ -109,16 +112,10 @@ __pmLogBaseName(char *name)
+ 	 */
+ 	if (q[1] != '\0') {
+ 	    char	*end;
+-	    /*
+-	     * Below we don't care about the value from strtol(),
+-	     * we're interested in updating the pointer "end".
+-	     * The messiness is thanks to gcc and glibc ... strtol()
+-	     * is marked __attribute__((warn_unused_result)) ...
+-	     * to avoid warnings on all platforms, assign to a
+-	     * dummy variable that is explicitly marked unused.
+-	     */
+-	    long	tmpl __attribute__((unused));
++	    long	tmpl;
+ 	    tmpl = strtol(q+1, &end, 10);
++	    if (vol)
++		*vol = tmpl;
+ 	    if (*end == '\0') strip = 1;
+ 	}
+     }
+@@ -131,6 +128,21 @@ done:
+     return NULL; /* not the name of an archive file. */
+ }
+ 
++/*
++ * If name contains '.' and the suffix is "index", "meta" or a string of
++ * digits, all optionally followed by one of the compression suffixes,
++ * strip the suffix.
++ *
++ * Modifications are performed on the argument string in-place. If modifications
++ * are made, a pointer to the start of the modified string is returned.
++ * Otherwise, NULL is returned.
++ */
++char *
++__pmLogBaseName(char *name)
++{
++    return __pmLogBaseNameVol(name, NULL);
++}
++
+ static int
+ popen_uncompress(const char *cmd, const char *arg, const char *fname, int fd)
+ {
+@@ -319,7 +331,7 @@ __pmCompressedFileIndex(char *fname, siz
+     char	tmpname[MAXPATHLEN];
+ 
+     for (i = 0; i < ncompress; i++) {
+-	suffix = compress_ctl[i].suff;
++	suffix = compress_ctl[i].suffix;
+ 	pmsprintf(tmpname, sizeof(tmpname), "%s%s", fname, suffix);
+ 	sts = access(tmpname, R_OK);
+ 	if (sts == 0 || (errno != ENOENT && errno != ENOTDIR)) {
+@@ -358,7 +370,7 @@ index_compress(char *fname, size_t flen)
+     suffix = strrchr(fname, '.');
+     if (suffix != NULL) {
+ 	for (i = 0; i < ncompress; i++) {
+-	    if (strcmp(suffix, compress_ctl[i].suff) == 0)
++	    if (strcmp(suffix, compress_ctl[i].suffix) == 0)
+ 		return i;
+ 	}
+     }
+@@ -731,7 +743,7 @@ compress_suffix_list(void)
+ 	const char	*q;
+ 
+ 	for (i = 0; i < ncompress; i++) {
+-	    q = compress_ctl[i].suff;
++	    q = compress_ctl[i].suffix;
+ 	    if (i > 0)
+ 		*p++ = ' ';
+ 	    while (*q) {
+diff -Naurp pcp-5.0.2.orig/src/libpcp/src/logmeta.c pcp-5.0.2/src/libpcp/src/logmeta.c
+--- pcp-5.0.2.orig/src/libpcp/src/logmeta.c	2018-09-14 10:22:56.000000000 +1000
++++ pcp-5.0.2/src/libpcp/src/logmeta.c	2020-02-03 13:23:15.262762921 +1100
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (c) 2013-2018 Red Hat.
++ * Copyright (c) 2013-2018, 2020 Red Hat.
+  * Copyright (c) 1995-2002 Silicon Graphics, Inc.  All Rights Reserved.
+  * 
+  * This library is free software; you can redistribute it and/or modify it
+@@ -490,7 +490,7 @@ check_dup_labels(const __pmArchCtl *acp)
+ }
+ 
+ static int
+-addtext(__pmArchCtl *acp, unsigned int ident, unsigned int type, char *buffer)
++addtext(__pmArchCtl *acp, unsigned int ident, unsigned int type, const char *buffer)
+ {
+     __pmLogCtl		*lcp = acp->ac_log;
+     __pmHashNode	*hp;
+@@ -553,6 +553,92 @@ PM_FAULT_POINT("libpcp/" __FILE__ ":15",
+     return sts;
+ }
+ 
++int
++__pmLogAddDesc(__pmArchCtl *acp, const pmDesc *newdp)
++{
++    __pmHashNode	*hp;
++    __pmLogCtl		*lcp = acp->ac_log;
++    pmDesc		*dp, *olddp;
++
++    if ((hp = __pmHashSearch((int)newdp->pmid, &lcp->l_hashpmid)) != NULL) {
++	/* PMID is already in the hash table - check for conflicts. */
++	olddp = (pmDesc *)hp->data;
++	if (newdp->type != olddp->type)
++	    return PM_ERR_LOGCHANGETYPE;
++	if (newdp->sem != olddp->sem)
++	    return PM_ERR_LOGCHANGESEM;
++	if (newdp->indom != olddp->indom)
++	    return PM_ERR_LOGCHANGEINDOM;
++	if (newdp->units.dimSpace != olddp->units.dimSpace ||
++	    newdp->units.dimTime != olddp->units.dimTime ||
++	    newdp->units.dimCount != olddp->units.dimCount ||
++	    newdp->units.scaleSpace != olddp->units.scaleSpace ||
++	    newdp->units.scaleTime != olddp->units.scaleTime ||
++	    newdp->units.scaleCount != olddp->units.scaleCount)
++	    return PM_ERR_LOGCHANGEUNITS;
++
++	/* PMID is already known and checks out - we're done here. */
++	return 0;
++    }
++
++    /* Add a copy of the descriptor into the PMID:desc hash table. */
++PM_FAULT_POINT("libpcp/" __FILE__ ":2", PM_FAULT_ALLOC);
++    if ((dp = (pmDesc *)malloc(sizeof(pmDesc))) == NULL)
++	return -oserror();
++    *dp = *newdp;
++
++    return __pmHashAdd((int)dp->pmid, (void *)dp, &lcp->l_hashpmid);
++}
++
++int
++__pmLogAddPMNSNode(__pmArchCtl *acp, pmID pmid, const char *name)
++{
++    __pmLogCtl		*lcp = acp->ac_log;
++    int			sts;
++
++    /*
++     * If we see a duplicate name with a different PMID, its a
++     * recoverable error.
++     * We wont be able to see all of the data in the log, but
++     * its better to provide access to some rather than none,
++     * esp. when only one or two metric IDs may be corrupted
++     * in this way (which we may not be interested in anyway).
++     */
++    sts = __pmAddPMNSNode(lcp->l_pmns, pmid, name);
++    if (sts == PM_ERR_PMID)
++	sts = 0;
++    return sts;
++}
++
++int
++__pmLogAddInDom(__pmArchCtl *acp, const pmTimespec *when, const pmInResult *in,
++		int *tbuf, int allinbuf)
++{
++    pmTimeval		tv;
++
++    tv.tv_sec = when->tv_sec;
++    tv.tv_usec = when->tv_nsec / 1000;
++    return addindom(acp->ac_log, in->indom, &tv,
++		    in->numinst, in->instlist, in->namelist, tbuf, allinbuf);
++}
++
++int
++__pmLogAddLabelSets(__pmArchCtl *acp, const pmTimespec *when, unsigned int type,
++		unsigned int ident, int nsets, pmLabelSet *labelsets)
++{
++    pmTimeval		tv;
++
++    tv.tv_sec = when->tv_sec;
++    tv.tv_usec = when->tv_nsec / 1000;
++    return addlabel(acp, type, ident, nsets, labelsets, &tv);
++}
++
++int
++__pmLogAddText(__pmArchCtl *acp, unsigned int ident, unsigned int type, const char *buffer)
++{
++    return addtext(acp, ident, type, buffer);
++}
++
+ /*
+  * Load _all_ of the hashed pmDesc and __pmLogInDom structures from the metadata
+  * log file -- used at the initialization (NewContext) of an archive.
+@@ -563,11 +649,8 @@ int
+ __pmLogLoadMeta(__pmArchCtl *acp)
+ {
+     __pmLogCtl		*lcp = acp->ac_log;
+-    __pmHashNode	*hp;
+     int			rlen;
+     int			check;
+-    pmDesc		*dp;
+-    pmDesc		*olddp;
+     int			sts = 0;
+     __pmLogHdr		h;
+     __pmFILE		*f = lcp->l_mdfp;
+@@ -615,13 +698,10 @@ __pmLogLoadMeta(__pmArchCtl *acp)
+ 	}
+ 	rlen = h.len - (int)sizeof(__pmLogHdr) - (int)sizeof(int);
+ 	if (h.type == TYPE_DESC) {
++	    pmDesc		desc;
++
+ 	    numpmid++;
+-PM_FAULT_POINT("libpcp/" __FILE__ ":2", PM_FAULT_ALLOC);
+-	    if ((dp = (pmDesc *)malloc(sizeof(pmDesc))) == NULL) {
+-		sts = -oserror();
+-		goto end;
+-	    }
+-	    if ((n = (int)__pmFread(dp, 1, sizeof(pmDesc), f)) != sizeof(pmDesc)) {
++	    if ((n = (int)__pmFread(&desc, 1, sizeof(pmDesc), f)) != sizeof(pmDesc)) {
+ 		if (pmDebugOptions.logmeta) {
+ 		    fprintf(stderr, "__pmLogLoadMeta: pmDesc read -> %d: expected: %d\n",
+ 			    n, (int)sizeof(pmDesc));
+@@ -632,67 +712,25 @@ PM_FAULT_POINT("libpcp/" __FILE__ ":2",
+ 		}
+ 		else
+ 		    sts = PM_ERR_LOGREC;
+-		free(dp);
+ 		goto end;
+ 	    }
+-	    else {
+-		/* swab desc */
+-		dp->type = ntohl(dp->type);
+-		dp->sem = ntohl(dp->sem);
+-		dp->indom = __ntohpmInDom(dp->indom);
+-		dp->units = __ntohpmUnits(dp->units);
+-		dp->pmid = __ntohpmID(dp->pmid);
+-	    }
+ 
+-	    /* Add it to the hash pmid hash table. */
+-	    if ((hp = __pmHashSearch((int)dp->pmid, &lcp->l_hashpmid)) != NULL) {
+-		/*
+-		 * This pmid is already in the hash table. Check for conflicts.
+-		 */
+-		olddp = (pmDesc *)hp->data;
+-		if (dp->type != olddp->type) {
+-		    sts = PM_ERR_LOGCHANGETYPE;
+-		    free(dp);
+-		    goto end;
+-		}
+-		if (dp->sem != olddp->sem) {
+-		    sts = PM_ERR_LOGCHANGESEM;
+-		    free(dp);
+-		    goto end;
+-		}
+-		if (dp->indom != olddp->indom) {
+-		    sts = PM_ERR_LOGCHANGEINDOM;
+-		    free(dp);
+-		    goto end;
+-		}
+-		if (dp->units.dimSpace != olddp->units.dimSpace ||
+-		    dp->units.dimTime != olddp->units.dimTime ||
+-		    dp->units.dimCount != olddp->units.dimCount ||
+-		    dp->units.scaleSpace != olddp->units.scaleSpace ||
+-		    dp->units.scaleTime != olddp->units.scaleTime ||
+-		    dp->units.scaleCount != olddp->units.scaleCount) {
+-		    sts = PM_ERR_LOGCHANGEUNITS;
+-		    free(dp);
+-		    goto end;
+-		}
+-                /*
+-                 * This pmid is already known, and matches.  We can free the newly
+-                 * read copy and use the one in the hash table. 
+-                 */
+-                free(dp);
+-                dp = olddp;
+-	    }
+-	    else if ((sts = __pmHashAdd((int)dp->pmid, (void *)dp, &lcp->l_hashpmid)) < 0) {
+-		free(dp);
++	    /* swab desc */
++	    desc.type = ntohl(desc.type);
++	    desc.sem = ntohl(desc.sem);
++	    desc.indom = __ntohpmInDom(desc.indom);
++	    desc.units = __ntohpmUnits(desc.units);
++	    desc.pmid = __ntohpmID(desc.pmid);
++
++	    if ((sts = __pmLogAddDesc(acp, &desc)) < 0)
+ 		goto end;
+-	    }
+ 
+ 	    /* read in the names & store in PMNS tree ... */
+ 	    if ((n = (int)__pmFread(&numnames, 1, sizeof(numnames), f)) != 
+ 		sizeof(numnames)) {
+ 		if (pmDebugOptions.logmeta) {
+-		    fprintf(stderr, "__pmLogLoadMeta: numnames read -> %d: expected: %d\n",
+-			    n, (int)sizeof(numnames));
++		    fprintf(stderr, "%s: numnames read -> %d: expected: %d\n",
++			    "__pmLogLoadMeta", n, (int)sizeof(numnames));
+ 		}
+ 		if (__pmFerror(f)) {
+ 		    __pmClearerr(f);
+@@ -711,8 +749,8 @@ PM_FAULT_POINT("libpcp/" __FILE__ ":2",
+ 		if ((n = (int)__pmFread(&len, 1, sizeof(len), f)) != 
+ 		    sizeof(len)) {
+ 		    if (pmDebugOptions.logmeta) {
+-			fprintf(stderr, "__pmLogLoadMeta: len name[%d] read -> %d: expected: %d\n",
+-				i, n, (int)sizeof(len));
++			fprintf(stderr, "%s: len name[%d] read -> %d: expected: %d\n",
++				"__pmLogLoadMeta", i, n, (int)sizeof(len));
+ 		    }
+ 		    if (__pmFerror(f)) {
+ 			__pmClearerr(f);
+@@ -729,8 +767,8 @@ PM_FAULT_POINT("libpcp/" __FILE__ ":2",
+ 
+ 		if ((n = (int)__pmFread(name, 1, len, f)) != len) {
+ 		    if (pmDebugOptions.logmeta) {
+-			fprintf(stderr, "__pmLogLoadMeta: name[%d] read -> %d: expected: %d\n",
+-				i, n, len);
++			fprintf(stderr, "%s: name[%d] read -> %d: expected: %d\n",
++				"__pmLogLoadMeta", i, n, len);
+ 		    }
+ 		    if (__pmFerror(f)) {
+ 			__pmClearerr(f);
+@@ -743,36 +781,23 @@ PM_FAULT_POINT("libpcp/" __FILE__ ":2",
+ 		name[len] = '\0';
+ 		if (pmDebugOptions.logmeta) {
+ 		    char	strbuf[20];
+-		    fprintf(stderr, "__pmLogLoadMeta: PMID: %s name: %s\n",
+-			    pmIDStr_r(dp->pmid, strbuf, sizeof(strbuf)), name);
++		    fprintf(stderr, "%s: PMID: %s name: %s\n",
++			    "__pmLogLoadMeta",
++			    pmIDStr_r(desc.pmid, strbuf, sizeof(strbuf)), name);
+ 		}
+-		/* Add the new PMNS node */
+-		if ((sts = __pmAddPMNSNode(lcp->l_pmns, dp->pmid, name)) < 0) {
+-		    /*
+-		     * If we see a duplicate name with a different PMID, its a
+-		     * recoverable error.
+-		     * We wont be able to see all of the data in the log, but
+-		     * its better to provide access to some rather than none,
+-		     * esp. when only one or two metric IDs may be corrupted
+-		     * in this way (which we may not be interested in anyway).
+-		     */
+-		    if (sts != PM_ERR_PMID)
+-			goto end;
+-		} 
++
++		/* Add the new PMNS node into this context */
++		if ((sts = __pmLogAddPMNSNode(acp, desc.pmid, name)) < 0)
++		    goto end;
+ 	    }/*for*/
+ 	}
+ 	else if (h.type == TYPE_INDOM) {
+-	    int			*tbuf;
+-	    pmInDom		indom;
+-	    pmTimeval		*when;
+-	    int			numinst;
+-	    int			*instlist;
+-	    char		**namelist;
++	    pmTimeval		*tv;
++	    pmTimespec		when;
++	    pmInResult		in;
+ 	    char		*namebase;
+-	    int			*stridx;
+-	    int			i;
+-	    int			k;
+-	    int			allinbuf = 0;
++	    int			*tbuf, *stridx;
++	    int			i, k, allinbuf = 0;
+ 
+ PM_FAULT_POINT("libpcp/" __FILE__ ":3", PM_FAULT_ALLOC);
+ 	    if ((tbuf = (int *)malloc(rlen)) == NULL) {
+@@ -781,8 +806,8 @@ PM_FAULT_POINT("libpcp/" __FILE__ ":3",
+ 	    }
+ 	    if ((n = (int)__pmFread(tbuf, 1, rlen, f)) != rlen) {
+ 		if (pmDebugOptions.logmeta) {
+-		    fprintf(stderr, "__pmLogLoadMeta: indom read -> %d: expected: %d\n",
+-			    n, rlen);
++		    fprintf(stderr, "%s: indom read -> %d: expected: %d\n",
++			    "__pmLogLoadMeta", n, rlen);
+ 		}
+ 		if (__pmFerror(f)) {
+ 		    __pmClearerr(f);
+@@ -795,44 +820,44 @@ PM_FAULT_POINT("libpcp/" __FILE__ ":3",
+ 	    }
+ 
+ 	    k = 0;
+-	    when = (pmTimeval *)&tbuf[k];
+-	    when->tv_sec = ntohl(when->tv_sec);
+-	    when->tv_usec = ntohl(when->tv_usec);
+-	    k += sizeof(*when)/sizeof(int);
+-	    indom = __ntohpmInDom((unsigned int)tbuf[k++]);
+-	    numinst = ntohl(tbuf[k++]);
+-	    if (numinst > 0) {
+-		instlist = &tbuf[k];
+-		k += numinst;
++	    tv = (pmTimeval *)&tbuf[k];
++	    when.tv_sec = ntohl(tv->tv_sec);
++	    when.tv_nsec = ntohl(tv->tv_usec) * 1000;
++	    k += sizeof(*tv)/sizeof(int);
++	    in.indom = __ntohpmInDom((unsigned int)tbuf[k++]);
++	    in.numinst = ntohl(tbuf[k++]);
++	    if (in.numinst > 0) {
++		in.instlist = &tbuf[k];
++		k += in.numinst;
+ 		stridx = &tbuf[k];
+ #if defined(HAVE_32BIT_PTR)
+-		namelist = (char **)stridx;
++		in.namelist = (char **)stridx;
+ 		allinbuf = 1; /* allocation is all in tbuf */
+ #else
+ 		allinbuf = 0; /* allocation for namelist + tbuf */
+ 		/* need to allocate to hold the pointers */
+ PM_FAULT_POINT("libpcp/" __FILE__ ":4", PM_FAULT_ALLOC);
+-		namelist = (char **)malloc(numinst*sizeof(char*));
+-		if (namelist == NULL) {
++		in.namelist = (char **)malloc(in.numinst * sizeof(char*));
++		if (in.namelist == NULL) {
+ 		    sts = -oserror();
+ 		    free(tbuf);
+ 		    goto end;
+ 		}
+ #endif
+-		k += numinst;
++		k += in.numinst;
+ 		namebase = (char *)&tbuf[k];
+-	        for (i = 0; i < numinst; i++) {
+-		    instlist[i] = ntohl(instlist[i]);
+-	            namelist[i] = &namebase[ntohl(stridx[i])];
++	        for (i = 0; i < in.numinst; i++) {
++		    in.instlist[i] = ntohl(in.instlist[i]);
++	            in.namelist[i] = &namebase[ntohl(stridx[i])];
+ 		}
+-		if ((sts = addindom(lcp, indom, when, numinst, instlist, namelist, tbuf, allinbuf)) < 0)
++		if ((sts = __pmLogAddInDom(acp, &when, &in, tbuf, allinbuf)) < 0)
+ 		    goto end;
+ 		/* If this indom was a duplicate, then we need to free tbuf and
+ 		   namelist, as appropriate. */
+ 		if (sts == PMLOGPUTINDOM_DUP) {
+ 		    free(tbuf);
+-		    if (namelist != NULL && !allinbuf)
+-			free(namelist);
++		    if (in.namelist != NULL && !allinbuf)
++			free(in.namelist);
+ 		}
+ 	    }
+ 	    else {
+@@ -860,8 +885,8 @@ PM_FAULT_POINT("libpcp/" __FILE__ ":11",
+ 	    }
+ 	    if ((n = (int)__pmFread(tbuf, 1, rlen, f)) != rlen) {
+ 		if (pmDebugOptions.logmeta) {
+-		    fprintf(stderr, "__pmLogLoadMeta: label read -> %d: expected: %d\n",
+-			    n, rlen);
++		    fprintf(stderr, "%s: label read -> %d: expected: %d\n",
++			    "__pmLogLoadMeta", n, rlen);
+ 		}
+ 		if (__pmFerror(f)) {
+ 		    __pmClearerr(f);
+@@ -908,7 +933,8 @@ PM_FAULT_POINT("libpcp/" __FILE__ ":11",
+ 
+ 		if (jsonlen < 0 || jsonlen > PM_MAXLABELJSONLEN) {
+ 		    if (pmDebugOptions.logmeta)
+-			fprintf(stderr, "__pmLogLoadMeta: corrupted json in labelset. jsonlen=%d\n", jsonlen);
++			fprintf(stderr, "%s: corrupted json in labelset. jsonlen=%d\n",
++					"__pmLogLoadMeta", jsonlen);
+ 		    sts = PM_ERR_LOGREC;
+ 		    free(labelsets);
+ 		    free(tbuf);
+@@ -935,7 +961,8 @@ PM_FAULT_POINT("libpcp/" __FILE__ ":11",
+ 		    if (nlabels > PM_MAXLABELS || k + nlabels * sizeof(pmLabel) > rlen) {
+ 			/* corrupt archive metadata detected. GH #475 */
+ 			if (pmDebugOptions.logmeta)
+-			    fprintf(stderr, "__pmLogLoadMeta: corrupted labelset. nlabels=%d\n", nlabels);
++			    fprintf(stderr, "%s: corrupted labelset. nlabels=%d\n",
++					    "__pmLogLoadMeta", nlabels);
+ 			sts = PM_ERR_LOGREC;
+ 			free(labelsets);
+ 			free(tbuf);
+@@ -975,8 +1002,8 @@ PM_FAULT_POINT("libpcp/" __FILE__ ":16",
+ 	    }
+ 	    if ((n = (int)__pmFread(tbuf, 1, rlen, f)) != rlen) {
+ 		if (pmDebugOptions.logmeta) {
+-		    fprintf(stderr, "__pmLogLoadMeta: text read -> %d: expected: %d\n",
+-			    n, rlen);
++		    fprintf(stderr, "%s: text read -> %d: expected: %d\n",
++				    "__pmLogLoadMeta", n, rlen);
+ 		}
+ 		if (__pmFerror(f)) {
+ 		    __pmClearerr(f);
+@@ -1005,8 +1032,8 @@ PM_FAULT_POINT("libpcp/" __FILE__ ":16",
+ 		ident = __ntohpmID(*((unsigned int *)&tbuf[k]));
+ 	    else {
+ 		if (pmDebugOptions.logmeta) {
+-		    fprintf(stderr, "__pmLogLoadMeta: bad text ident -> %x\n",
+-			    type);
++		    fprintf(stderr, "%s: bad text ident -> %x\n",
++				    "__pmLogLoadMeta", type);
+ 		}
+ 		free(tbuf);
+ 		continue;
+@@ -1024,8 +1051,9 @@ PM_FAULT_POINT("libpcp/" __FILE__ ":16",
+ 	check = ntohl(check);
+ 	if (n != sizeof(check) || h.len != check) {
+ 	    if (pmDebugOptions.logmeta) {
+-		fprintf(stderr, "__pmLogLoadMeta: trailer read -> %d or len=%d: expected %d @ offset=%d\n",
+-		    n, check, h.len, (int)(__pmFtell(f) - sizeof(check)));
++		fprintf(stderr, "%s: trailer read -> %d or len=%d: "
++				"expected %d @ offset=%d\n", "__pmLogLoadMeta",
++			n, check, h.len, (int)(__pmFtell(f) - sizeof(check)));
+ 	    }
+ 	    if (__pmFerror(f)) {
+ 		__pmClearerr(f);
+@@ -1046,7 +1074,7 @@ end:
+     if (sts == 0) {
+ 	if (numpmid == 0) {
+ 	    if (pmDebugOptions.logmeta) {
+-		fprintf(stderr, "__pmLogLoadMeta: no metrics found?\n");
++		fprintf(stderr, "%s: no metrics found?\n", "__pmLogLoadMeta");
+ 	    }
+ 	    sts = PM_ERR_LOGREC;
+ 	}
+diff -Naurp pcp-5.0.2.orig/src/libpcp/src/logutil.c pcp-5.0.2/src/libpcp/src/logutil.c
+--- pcp-5.0.2.orig/src/libpcp/src/logutil.c	2018-07-08 10:58:08.000000000 +1000
++++ pcp-5.0.2/src/libpcp/src/logutil.c	2020-02-03 13:23:15.263762911 +1100
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (c) 2012-2017 Red Hat.
++ * Copyright (c) 2012-2017,2020 Red Hat.
+  * Copyright (c) 1995-2002,2004 Silicon Graphics, Inc.  All Rights Reserved.
+  * 
+  * This library is free software; you can redistribute it and/or modify it
+@@ -764,6 +764,22 @@ __pmLogClose(__pmArchCtl *acp)
+ }
+ 
+ int
++__pmLogAddVolume(__pmArchCtl *acp, unsigned int vol)
++{
++    __pmLogCtl	*lcp = acp->ac_log;
++
++    if (lcp->l_minvol == -1) {
++	lcp->l_minvol = vol;
++	lcp->l_maxvol = vol;
++    } else if (vol < lcp->l_minvol) {
++	lcp->l_minvol = vol;
++    } else if (vol > lcp->l_maxvol) {
++	lcp->l_maxvol = vol;
++    }
++    return 0;
++}
++
++int
+ __pmLogLoadLabel(__pmArchCtl *acp, const char *name)
+ {
+     __pmLogCtl	*lcp = acp->ac_log;
+@@ -876,21 +892,14 @@ __pmLogLoadLabel(__pmArchCtl *acp, const
+ 		}
+ 	    }
+ 	    else {
+-		char	*q;
+-		int	vol;
+-		vol = (int)strtol(tp, &q, 10);
++		char		*q;
++		unsigned int	vol;
++
++		vol = (unsigned int)strtoul(tp, &q, 10);
+ 		if (*q == '\0') {
+ 		    exists = 1;
+-		    if (lcp->l_minvol == -1) {
+-			lcp->l_minvol = vol;
+-			lcp->l_maxvol = vol;
+-		    }
+-		    else {
+-			if (vol < lcp->l_minvol)
+-			    lcp->l_minvol = vol;
+-			if (vol > lcp->l_maxvol)
+-			    lcp->l_maxvol = vol;
+-		    }
++		    if ((sts = __pmLogAddVolume(acp, vol)) < 0)
++			goto cleanup;
+ 		}
+ 	    }
+ 	}
+@@ -2282,7 +2291,7 @@ __pmLogSetTime(__pmContext *ctxp)
+ 	int		match = 0;
+ 	int		vol;
+ 	int		numti = lcp->l_numti;
+-	__pmFILE		*f;
++	__pmFILE	*f;
+ 	__pmLogTI	*tip = lcp->l_ti;
+ 	double		t_lo;
+ 	struct stat	sbuf;
+diff -Naurp pcp-5.0.2.orig/src/libpcp_web/src/discover.c pcp-5.0.2/src/libpcp_web/src/discover.c
+--- pcp-5.0.2.orig/src/libpcp_web/src/discover.c	2019-12-10 17:04:20.000000000 +1100
++++ pcp-5.0.2/src/libpcp_web/src/discover.c	2020-02-03 13:36:11.958637560 +1100
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (c) 2018-2019 Red Hat.
++ * Copyright (c) 2018-2020 Red Hat.
+  *
+  * This library is free software; you can redistribute it and/or modify it
+  * under the terms of the GNU Lesser General Public License as published
+@@ -14,6 +14,8 @@
+ #include "discover.h"
+ #include "slots.h"
+ #include "util.h"
++#include <dirent.h>
++#include <sys/stat.h>
+ 
+ /* Decode various archive metafile records (desc, indom, labels, helptext) */
+ static int pmDiscoverDecodeMetaDesc(uint32_t *, int, pmDesc *, int *, char ***);
+@@ -24,11 +26,15 @@ static int pmDiscoverDecodeMetaLabelSet(
+ /* array of registered callbacks, see pmDiscoverSetup() */
+ static int discoverCallBackTableSize;
+ static pmDiscoverCallBacks **discoverCallBackTable;
++static char *pmDiscoverFlagsStr(pmDiscover *);
+ 
+ /* internal hash table of discovered paths */
+-#define PM_DISCOVER_HASHTAB_SIZE 64
++#define PM_DISCOVER_HASHTAB_SIZE 16
+ static pmDiscover *discover_hashtable[PM_DISCOVER_HASHTAB_SIZE];
+ 
++/* pmlogger_daily log-roll lock count */
++static int lockcnt = 0;
++
+ /* FNV string hash algorithm. Return unsigned in range 0 .. limit-1 */
+ static unsigned int
+ strhash(const char *s, unsigned int limit)
+@@ -43,18 +49,38 @@ strhash(const char *s, unsigned int limi
+     return h % limit;
+ }
+ 
++/* ctime string - note static buf is returned */
++static char *
++stamp(void)
++{
++    time_t now = time(NULL);
++    char *p, *c = ctime(&now);
++
++    if ((p = strrchr(c, '\n')) != NULL)
++    	*p = '\0';
++    return c;
++}
++
+ /*
+- * Lookup or Add a discovered file path (directory or PCP archive file)
++ * Lookup or Add a discovered file path (directory or PCP archive file).
++ * Note: the fullpath suffix (.meta, .[0-9]+) should already be stripped.
+  * Return path table entry (new or existing).
+  */
+ static pmDiscover *
+-pmDiscoverLookupAdd(const char *path, pmDiscoverModule *module, void *arg)
++pmDiscoverLookupAdd(const char *fullpath, pmDiscoverModule *module, void *arg)
+ {
+     pmDiscover		*p, *h;
+-    unsigned int	k = strhash(path, PM_DISCOVER_HASHTAB_SIZE);
++    unsigned int	k;
++    sds			name;
++
++    name = sdsnew(fullpath);
++    k = strhash(name, PM_DISCOVER_HASHTAB_SIZE);
++
++    if (pmDebugOptions.discovery)
++	fprintf(stderr, "pmDiscoverLookupAdd: name=%s\n", name);
+ 
+     for (p = NULL, h = discover_hashtable[k]; h != NULL; p = h, h = h->next) {
+-    	if (strcmp(h->context.name, path) == 0)
++    	if (sdscmp(h->context.name, name) == 0)
+ 	    break;
+     }
+ 
+@@ -65,14 +91,24 @@ pmDiscoverLookupAdd(const char *path, pm
+ 	h->ctx = -1; /* no PMAPI context initially */
+ 	h->flags = PM_DISCOVER_FLAGS_NEW;
+ 	h->context.type = PM_CONTEXT_ARCHIVE;
+-	h->context.name = sdsnew(path);
++	h->context.name = name;
+ 	h->module = module;
+ 	h->data = arg;
+ 	if (p == NULL)
+ 	    discover_hashtable[k] = h;
+ 	else
+ 	    p->next = h;
++	if (pmDebugOptions.discovery)
++	    fprintf(stderr, "pmDiscoverLookupAdd: --> new entry %s\n", name);
++
++    }
++    else {
++	/* already in hash table, so free the buffer */
++	if (pmDebugOptions.discovery)
++	    fprintf(stderr, "pmDiscoverLookupAdd: --> existing entry %s\n", name);
++    	sdsfree(name);
+     }
++
+     return h;
+ }
+ 
+@@ -82,12 +118,6 @@ pmDiscoverLookup(const char *path)
+     return pmDiscoverLookupAdd(path, NULL, NULL);
+ }
+ 
+-static pmDiscover *
+-pmDiscoverAdd(const char *path, pmDiscoverModule *module, void *arg)
+-{
+-    return pmDiscoverLookupAdd(path, module, arg);
+-}
+-
+ static void
+ pmDiscoverFree(pmDiscover *p)
+ {
+@@ -101,39 +131,42 @@ pmDiscoverFree(pmDiscover *p)
+ 	sdsfree(p->context.source);
+     if (p->context.labelset)
+ 	pmFreeLabelSets(p->context.labelset, 1);
++    if (p->event_handle) {
++	uv_fs_event_stop(p->event_handle);
++	free(p->event_handle);
++	p->event_handle = NULL;
++    }
++
+     memset(p, 0, sizeof(*p));
+     free(p);
+ }
+ 
+ /*
+- * Delete tracking of a previously discovered path. Frees resources and
+- * destroy PCP context (if any).
++ * Traverse and invoke callback for all paths matching any bit
++ * in the flags bitmap. Callback can be NULL to just get a count.
++ * Return count of matching paths, may be 0.
+  */
+-static void
+-pmDiscoverDelete(sds path)
++static int
++pmDiscoverTraverse(unsigned int flags, void (*callback)(pmDiscover *))
+ {
+-    pmDiscover		*p, *h;
+-    unsigned int	k = strhash(path, PM_DISCOVER_HASHTAB_SIZE);
++    int			count = 0, i;
++    pmDiscover		*p;
+ 
+-    for (p = NULL, h = discover_hashtable[k]; h != NULL; p = h, h = h->next) {
+-    	if (sdscmp(h->context.name, path) == 0) {
+-	    if (p == NULL)
+-	    	discover_hashtable[k] = NULL;
+-	    else
+-	    	p->next = h->next;
+-	    pmDiscoverFree(h);
+-	    break;
++    for (i = 0; i < PM_DISCOVER_HASHTAB_SIZE; i++) {
++    	for (p = discover_hashtable[i]; p; p = p->next) {
++	    if (p->flags & flags) {
++		if (callback)
++		    callback(p);
++		count++;
++	    }
+ 	}
+     }
++    return count;
+ }
+ 
+-/*
+- * Traverse and invoke callback for all paths matching any bit
+- * in the flags bitmap. Callback can be NULL to just get a count.
+- * Return count of matching paths, may be 0.
+- */
++/* as above, but with an extra (void *)arg passed to the cb */
+ static int
+-pmDiscoverTraverse(unsigned int flags, void (*callback)(pmDiscover *))
++pmDiscoverTraverseArg(unsigned int flags, void (*callback)(pmDiscover *, void *), void *arg)
+ {
+     int			count = 0, i;
+     pmDiscover		*p;
+@@ -142,7 +175,7 @@ pmDiscoverTraverse(unsigned int flags, v
+     	for (p = discover_hashtable[i]; p; p = p->next) {
+ 	    if (p->flags & flags) {
+ 		if (callback)
+-		    callback(p);
++		    callback(p, arg);
+ 		count++;
+ 	    }
+ 	}
+@@ -150,6 +183,7 @@ pmDiscoverTraverse(unsigned int flags, v
+     return count;
+ }
+ 
++
+ /*
+  * Traverse and purge deleted entries
+  * Return count of purged entries.
+@@ -173,6 +207,9 @@ pmDiscoverPurgeDeleted(void)
+ 		    prev->next = next;
+ 		else
+ 		    discover_hashtable[i] = next;
++		if (pmDebugOptions.discovery)
++		    fprintf(stderr, "pmDiscoverPurgeDeleted: deleted %s %s\n",
++		    	p->context.name, pmDiscoverFlagsStr(p));
+ 		pmDiscoverFree(p);
+ 		count++;
+ 	    }
+@@ -180,14 +217,32 @@ pmDiscoverPurgeDeleted(void)
+ 	}
+     }
+ 
+-    if (pmDebugOptions.discovery)
+-	fprintf(stderr, "%s: purged %d entries\n",
+-			"pmDiscoverPurgeDeleted", count);
+-
+     return count;
+ }
+ 
+ /*
++ * if string ends with given suffix then return pointer
++ * to start of suffix in string, else NULL
++ */
++static char *
++strsuffix(char *s, const char *suffix)
++{
++    int slen, suflen;
++    char *ret = NULL;
++
++    if (s && suffix) {
++    	slen = strlen(s);
++	suflen = strlen(suffix);
++	if (slen >= suflen) {
++	    ret = s + (slen - suflen);
++	    if (strncmp(ret, suffix, suflen) != 0)
++	    	ret = NULL;
++	}
++    }
++    return ret;
++}
++
++/*
+  * Discover dirs and archives - add new entries or refresh existing.
+  * Call this for each top-level directory. Discovered paths are not
+  * automatically monitored. After discovery, need to traverse and
+@@ -196,44 +251,88 @@ pmDiscoverPurgeDeleted(void)
+ static int
+ pmDiscoverArchives(const char *dir, pmDiscoverModule *module, void *arg)
+ {
+-    uv_fs_t		sreq, req;
+-    uv_dirent_t		dent;
+-    uv_stat_t		*s;
++    DIR			*dirp;
++    struct dirent	*dent;
++    struct stat		*s;
++    struct stat		statbuf;
+     pmDiscover		*a;
++    char		*suffix;
+     char		path[MAXNAMELEN];
+-    char		basepath[MAXNAMELEN];
+     int			sep = pmPathSeparator();
++    int			vol;
++
++    /*
++     * note: pmDiscoverLookupAdd sets PM_DISCOVER_FLAGS_NEW
++     * if this is a newly discovered archive or directory
++     */
++    a = pmDiscoverLookupAdd(dir, module, arg);
++    a->flags |= PM_DISCOVER_FLAGS_DIRECTORY;
+ 
+-    if (uv_fs_scandir(NULL, &req, dir, 0, NULL) < 0)
++    if ((dirp = opendir(dir)) == NULL) {
++	if (pmDebugOptions.discovery)
++	    fprintf(stderr, "pmDiscoverArchives: opendir %s failed %s: err %d\n", dir, path, errno);
+ 	return -ESRCH;
++    }
+ 
+-    a = pmDiscoverAdd(dir, module, arg);
+-    a->flags |= PM_DISCOVER_FLAGS_DIRECTORY;
++    while ((dent = readdir(dirp)) != NULL) {
++	if (dent->d_name[0] == '.')
++	    continue;
++	pmsprintf(path, sizeof(path), "%s%c%s", dir, sep, dent->d_name);
++
++	if (pmDebugOptions.discovery)
++	    fprintf(stderr, "pmDiscoverArchives: readdir found %s\n", path);
+ 
+-    while (uv_fs_scandir_next(&req, &dent) != UV_EOF) {
+-	pmsprintf(path, sizeof(path), "%s%c%s", dir, sep, dent.name);
+-	if (uv_fs_stat(NULL, &sreq, path, NULL) < 0)
++	if (stat(path, &statbuf) < 0) {
++	    if (pmDebugOptions.discovery)
++		fprintf(stderr, "pmDiscoverArchives: stat failed %s, err %d\n", path, errno);
+ 	    continue;
+-	s = &sreq.statbuf;
+-	strncpy(basepath, path, sizeof(basepath)); /* __pmLogBaseName modifies it's argument */
+-	if (S_ISREG(s->st_mode) && __pmLogBaseName(basepath) != NULL) {
+-	    /*
+-	     * An archive file (index, meta or data vol). If compressed, then
+-	     * it is read-only and we don't have to monitor it for growth.
+-	     */
+-	    a = pmDiscoverAdd(path, module, arg);
+-	    a->flags &= ~PM_DISCOVER_FLAGS_DELETED;
++	}
+ 
+-	    if (strstr(path, ".meta"))
+-	    	a->flags |= PM_DISCOVER_FLAGS_META;
+-	    else if (strstr(path, ".index"))
+-	    	a->flags |= PM_DISCOVER_FLAGS_INDEX;
+-	    else
+-	    	a->flags |= PM_DISCOVER_FLAGS_DATAVOL;
+-
+-	    /* compare to libpcp io.c for suffix list */
+-	    if (strstr(path, ".xz") || strstr(path, ".gz"))
+-	    	a->flags |= PM_DISCOVER_FLAGS_COMPRESSED;
++	s = &statbuf;
++	if (S_ISREG(s->st_mode)) {
++	    if ((suffix = strsuffix(path, ".meta")) != NULL) {
++		/*
++		 * An uncompressed PCP archive meta file. Track the meta
++		 * file - the matching logvol filename varies because logvols
++		 * are periodically rolled by pmlogger. Importantly, process all
++		 * available metadata to EOF before processing any logvol data.
++		 */
++		*suffix = '\0'; /* strip suffix from path giving archive name */
++		a = pmDiscoverLookupAdd(path, module, arg);
++
++		/*
++		 * note: pmDiscoverLookupAdd sets PM_DISCOVER_FLAGS_NEW
++		 * if this is a newly discovered archive, otherwise we're
++		 * already tracking this archive.
++		 */
++		a->flags |= PM_DISCOVER_FLAGS_META;
++	    }
++	    else if ((suffix = __pmLogBaseNameVol(path, &vol)) != NULL && vol >= 0) {
++		/*
++		 * An archive logvol. This logvol may have been created since
++		 * the context was first opened. Update the context maxvol
++		 * to be sure pmFetchArchive can switch to it in due course.
++		 */
++		if ((a = pmDiscoverLookup(path)) != NULL) {
++		    a->flags |= PM_DISCOVER_FLAGS_DATAVOL;
++		    /* ensure archive context knows about this volume */
++		    if (pmDebugOptions.discovery)
++			fprintf(stderr, "pmDiscoverArchives: found logvol %s %s vol=%d\n",
++			    a->context.name, pmDiscoverFlagsStr(a), vol);
++		    if (a->ctx >= 0 && vol >= 0) {
++			__pmContext *ctxp = __pmHandleToPtr(a->ctx);
++			__pmArchCtl *acp = ctxp->c_archctl;
++
++		    	__pmLogAddVolume(acp, vol);
++			PM_UNLOCK(ctxp->c_lock);
++		    }
++		    if (pmDebugOptions.discovery)
++			fprintf(stderr, "pmDiscoverArchives: added logvol %s %s vol=%d\n",
++			    a->context.name, pmDiscoverFlagsStr(a), vol);
++		}
++	    } else if (pmDebugOptions.discovery) {
++		fprintf(stderr, "pmDiscoverArchives: ignored regular file %s\n", path);
++	    }
+ 	}
+ 	else if (S_ISDIR(s->st_mode)) {
+ 	    /*
+@@ -241,29 +340,117 @@ pmDiscoverArchives(const char *dir, pmDi
+ 	     */
+ 	    pmDiscoverArchives(path, module, arg);
+ 	}
+-	uv_fs_req_cleanup(&sreq);
+     }
+-    uv_fs_req_cleanup(&req);
++    if (dirp)
++	closedir(dirp);
+ 
+     /* success */
+     return 0;
+ }
+ 
++/*
++ * Return 1 if monitored path has been deleted.
++ * For archives, we only check the meta file because
++ * a logvol can be deleted (e.g. via compression when
++ * the logvol is rolled to a new volume) without
++ * actually deleting the archive.
++ */
++static int
++is_deleted(pmDiscover *p, struct stat *sbuf)
++{
++    int			ret = 0;
++
++    if (p->flags & PM_DISCOVER_FLAGS_DIRECTORY) {
++	if (stat(p->context.name, sbuf) < 0)
++	    ret = 1; /* directory has been deleted */
++    }
++
++    if (p->flags & (PM_DISCOVER_FLAGS_META|PM_DISCOVER_FLAGS_DATAVOL)) {
++    	sds meta = sdsnew(p->context.name);
++	meta = sdscat(meta, ".meta");
++	if (stat(meta, sbuf) < 0) {
++	    /*
++	     * Archive metadata file has been deleted (or compressed)
++	     * hence consider the archive to be deleted because there
++	     * is no more data to logtail.
++	     */
++	    ret = 1;
++	}
++	sdsfree(meta);
++    }
++
++    if (pmDebugOptions.discovery) {
++	fprintf(stderr, "is_deleted: checking %s (%s) -> %s\n",
++		p->context.name, pmDiscoverFlagsStr(p), ret ? "DELETED" : "no");
++    }
++
++    return ret;
++}
++
++static void
++logdir_is_locked_callBack(pmDiscover *p, void *arg)
++{
++    int			*cntp = (int *)arg;
++    char		sep = pmPathSeparator();
++    char		path[MAXNAMELEN];
++
++    pmsprintf(path, sizeof(path), "%s%c%s", p->context.name, sep, "lock");
++    if (access(path, F_OK) == 0)
++    	(*cntp)++;
++}
++
++static void
++check_deleted(pmDiscover *p)
++{
++    struct stat sbuf;
++    if (!(p->flags & PM_DISCOVER_FLAGS_DELETED) && is_deleted(p, &sbuf))
++    	p->flags |= PM_DISCOVER_FLAGS_DELETED;
++}
++
+ static void
+ fs_change_callBack(uv_fs_event_t *handle, const char *filename, int events, int status)
+ {
+     char		buffer[MAXNAMELEN];
+     size_t		bytes = sizeof(buffer) - 1;
+     pmDiscover		*p;
+-    uv_fs_t		sreq;
++    char		*s;
+     sds			path;
+-    int			path_changed = 0;
++    int			count = 0;
++    struct stat		statbuf;
++
++    /*
++     * check if logs are currently being rolled by pmlogger_daily et al
++     * in any of the directories we are tracking. For mutex, the log control
++     * scripts use a 'lock' file in each directory as it is processed.
++     */
++    pmDiscoverTraverseArg(PM_DISCOVER_FLAGS_DIRECTORY,
++    	logdir_is_locked_callBack, (void *)&count);
++
++    if (lockcnt == 0 && count > 0) {
++	/* log-rolling has started */
++    	fprintf(stderr, "%s discovery callback ignored: log-rolling is now in progress\n", stamp());
++	lockcnt = count;
++	return;
++    }
++
++    if (lockcnt > 0 && count > 0) {
++	/* log-rolling is still in progress */
++	lockcnt = count;
++	return;
++    }
++
++    if (lockcnt > 0 && count == 0) {
++    	/* log-rolling is finished: check what got deleted, and then purge */
++    	fprintf(stderr, "%s discovery callback: finished log-rolling\n", stamp());
++	pmDiscoverTraverse(PM_DISCOVER_FLAGS_META|PM_DISCOVER_FLAGS_DATAVOL, check_deleted);
++    }
++    lockcnt = count;
+ 
+     uv_fs_event_getpath(handle, buffer, &bytes);
+     path = sdsnewlen(buffer, bytes);
+ 
+     if (pmDebugOptions.discovery) {
+-	fprintf(stderr, "%s: event on %s -", "fs_change_callBack", path);
++	fprintf(stderr, "fs_change_callBack: event on %s -", path);
+ 	if (events & UV_RENAME)
+ 	    fprintf(stderr, " renamed");
+ 	if (events & UV_CHANGE)
+@@ -271,38 +458,40 @@ fs_change_callBack(uv_fs_event_t *handle
+ 	fputc('\n', stderr);
+     }
+ 
++    	
+     /*
+-     * Lookup the path, stat and update it's flags accordingly. If the
+-     * path has been deleted, stop it's event monitor and free the req buffer.
+-     * Then call the pmDiscovery callback.
++     * Strip ".meta" suffix (if any) and lookup the path. stat and update it's
++     * flags accordingly. If the path has been deleted, stop it's event monitor
++     * and free the req buffer, else call the pmDiscovery callback.
+      */
+-    if ((p = pmDiscoverLookup(path)) == NULL) {
++    if ((s = strsuffix(path, ".meta")) != NULL)
++	*s = '\0';
++
++    p = pmDiscoverLookup(path);
++    if (p && pmDebugOptions.discovery) {
++	fprintf(stderr, "fs_change_callBack: ---> found entry %s (%s)\n",
++		p->context.name, pmDiscoverFlagsStr(p));
++    }
++
++    if (p == NULL) {
+ 	if (pmDebugOptions.discovery)
+-	    fprintf(stderr, "%s: filename %s lookup failed\n",
+-		    "fs_change_callBack", filename);
++	    fprintf(stderr, "fs_change_callBack: %s lookup failed\n", filename);
+     }
+-    else if (uv_fs_stat(NULL, &sreq, p->context.name, NULL) < 0) {
+-    	p->flags |= PM_DISCOVER_FLAGS_DELETED;
+-	if (p->event_handle) {
+-	    uv_fs_event_stop(p->event_handle);
+-	    free(p->event_handle);
+-	    p->event_handle = NULL;
+-	}
++    else if (is_deleted(p, &statbuf)) {
+ 	/* path has been deleted. statbuf is invalid */
++    	p->flags |= PM_DISCOVER_FLAGS_DELETED;
+ 	memset(&p->statbuf, 0, sizeof(p->statbuf));
+-	path_changed = 1;
+-    }
+-    else {
+-	/* avoid spurious events. only call the callBack if it really changed */
+-	if (p->statbuf.st_mtim.tv_sec != sreq.statbuf.st_mtim.tv_sec ||
+-	    p->statbuf.st_mtim.tv_nsec != sreq.statbuf.st_mtim.tv_nsec)
+-	    path_changed = 1;
+-	p->statbuf = sreq.statbuf; /* struct copy */
+-	uv_fs_req_cleanup(&sreq);
++	if (pmDebugOptions.discovery)
++	    fprintf(stderr, "fs_change_callBack: %s (%s) has been deleted",
++	    	p->context.name, pmDiscoverFlagsStr(p));
+     }
+ 
+-    if (p && p->changed && path_changed && !(p->flags & PM_DISCOVER_FLAGS_DELETED))
+-	p->changed(p);
++    /*
++     * Something in the directory changed - new or deleted archive, or
++     * a tracked archive meta data file or logvolume grew
++     */
++    if (p)
++	p->changed(p); /* returns immediately if PM_DISCOVER_FLAGS_DELETED */
+ 
+     sdsfree(path);
+ }
+@@ -316,9 +505,14 @@ pmDiscoverMonitor(sds path, void (*callb
+ {
+     discoverModuleData	*data;
+     pmDiscover		*p;
++    sds			eventfilename;
+ 
+-    if ((p = pmDiscoverLookup(path)) == NULL)
++    if ((p = pmDiscoverLookup(path)) == NULL) {
++	if (pmDebugOptions.discovery) {
++	    fprintf(stderr, "pmDiscoverMonitor: lookup failed for %s\n", path);
++	}
+ 	return -ESRCH;
++    }
+     data = getDiscoverModuleData(p->module);
+ 
+     /* save the discovery callback to be invoked */
+@@ -330,9 +524,29 @@ pmDiscoverMonitor(sds path, void (*callb
+ 	 * Start monitoring, using given uv loop. Up to the caller to create
+ 	 * a PCP PMAPI context and to fetch/logtail in the changed callback.
+ 	 */
++	eventfilename = sdsnew(p->context.name);
+ 	uv_fs_event_init(data->events, p->event_handle);
+-	uv_fs_event_start(p->event_handle, fs_change_callBack, p->context.name,
++
++	if (p->flags & PM_DISCOVER_FLAGS_DIRECTORY) {
++	    uv_fs_event_start(p->event_handle, fs_change_callBack, eventfilename,
++			    UV_FS_EVENT_WATCH_ENTRY);
++	}
++	else {
++	    /*
++	     * Monitor an archive file. This tracks the archive meta file
++	     * but the change callback processes both meta and logvol on
++	     * every callback (meta before logvol).
++	     */
++	    eventfilename = sdscat(eventfilename, ".meta");
++	    uv_fs_event_start(p->event_handle, fs_change_callBack, eventfilename,
+ 			UV_FS_EVENT_WATCH_ENTRY);
++	}
++
++	if (pmDebugOptions.discovery) {
++	    fprintf(stderr, "pmDiscoverMonitor: added event for %s (%s)\n",
++	    	eventfilename, pmDiscoverFlagsStr(p));
++	}
++	sdsfree(eventfilename);
+     }
+ 
+     return 0;
+@@ -411,41 +625,23 @@ static void changed_callback(pmDiscover
+ static void
+ created_callback(pmDiscover *p)
+ {
++    if (p->flags & (PM_DISCOVER_FLAGS_COMPRESSED|PM_DISCOVER_FLAGS_INDEX))
++    	return; /* compressed archives don't grow and we ignore archive index files */
++
+     if (pmDebugOptions.discovery)
+ 	fprintf(stderr, "CREATED %s, %s\n", p->context.name, pmDiscoverFlagsStr(p));
+ 
+-    p->flags &= ~PM_DISCOVER_FLAGS_NEW;
+-
+-    if (p->flags & PM_DISCOVER_FLAGS_COMPRESSED)
+-    	return; /* compressed archives don't grow */
+-
+     if (p->flags & PM_DISCOVER_FLAGS_DIRECTORY) {
+ 	if (pmDebugOptions.discovery)
+ 	    fprintf(stderr, "MONITOR directory %s\n", p->context.name);
+ 	pmDiscoverMonitor(p->context.name, changed_callback);
+     }
+-
+-    if (p->flags & PM_DISCOVER_FLAGS_DATAVOL) {
++    else if (p->flags & (PM_DISCOVER_FLAGS_META|PM_DISCOVER_FLAGS_DATAVOL)) {
+ 	if (pmDebugOptions.discovery)
+-	    fprintf(stderr, "MONITOR logvol %s\n", p->context.name);
++	    fprintf(stderr, "MONITOR archive %s\n", p->context.name);
+ 	pmDiscoverMonitor(p->context.name, changed_callback);
+     }
+-
+-    if (p->flags & PM_DISCOVER_FLAGS_META) {
+-	if (pmDebugOptions.discovery)
+-	    fprintf(stderr, "MONITOR metadata %s\n", p->context.name);
+-	pmDiscoverMonitor(p->context.name, changed_callback);
+-    }
+-}
+-
+-static void
+-deleted_callback(pmDiscover *p)
+-{
+-    if (pmDebugOptions.discovery)
+-	fprintf(stderr, "DELETED %s (%s)\n", p->context.name,
+-			pmDiscoverFlagsStr(p));
+-    pmDiscoverDelete(p->context.name);
+-    /* p is now no longer valid */
++    p->flags &= ~PM_DISCOVER_FLAGS_NEW;
+ }
+ 
+ static void
+@@ -509,37 +705,84 @@ static void
+ pmDiscoverInvokeMetricCallBacks(pmDiscover *p, pmTimespec *ts, pmDesc *desc,
+ 		int numnames, char **names)
+ {
++    discoverModuleData	*data = getDiscoverModuleData(p->module);
+     pmDiscoverCallBacks	*callbacks;
+     pmDiscoverEvent	event;
+     char		buf[32];
+-    int			i;
++    int			i, sts;
+ 
+     if (pmDebugOptions.discovery) {
+ 	fprintf(stderr, "%s[%s]: %s name%s", "pmDiscoverInvokeMetricCallBacks",
+ 			timespec_str(ts, buf, sizeof(buf)),
+ 			p->context.source, numnames > 0 ? " " : "(none)\n");
+ 	for (i = 0; i < numnames; i++)
+-	    printf("\"%s\"%s", names[i], i < numnames - 1 ? ", " : "\n");
++	    fprintf(stderr, "[%u/%u] \"%s\"%s", i+1, numnames, names[i],
++			    i < numnames - 1 ? ", " : "\n");
+ 	pmPrintDesc(stderr, desc);
+ 	if (pmDebugOptions.labels)
+ 	    fprintf(stderr, "context labels %s\n", p->context.labelset->json);
+     }
+ 
++    if (data->pmids) {
++	if (dictFind(data->pmids, &desc->pmid) != NULL)
++	    goto out;	/* metric contains an already excluded PMID */
++	for (i = 0; i < numnames; i++) {
++	    if (regexec(&data->exclude_names, names[i], 0, NULL, 0) == 0)
++		break;
++	}
++	if (i != numnames) {
++	    if (pmDebugOptions.discovery)
++		fprintf(stderr, "%s: excluding metric %s\n",
++				"pmDiscoverInvokeMetricCallBacks", names[i]);
++	    /* add this pmid to the exclusion list and return early */
++	    dictAdd(data->pmids, &desc->pmid, NULL);
++	    goto out;
++	}
++    }
++    if (data->indoms) {
++	if (dictFind(data->indoms, &desc->indom) != NULL)
++	    goto out;	/* metric contains an already excluded InDom */
++    }
++
++    if (p->ctx >= 0 && p->context.type == PM_CONTEXT_ARCHIVE) {
++	__pmContext	*ctxp = __pmHandleToPtr(p->ctx);
++	__pmArchCtl	*acp = ctxp->c_archctl;
++	char		idstr[32];
++
++	if ((sts = __pmLogAddDesc(acp, desc)) < 0)
++	    fprintf(stderr, "%s: failed to add metric descriptor for %s\n",
++			    "pmDiscoverInvokeMetricCallBacks",
++			    pmIDStr_r(desc->pmid, idstr, sizeof(idstr)));
++	for (i = 0; i < numnames; i++) {
++	    if ((sts = __pmLogAddPMNSNode(acp, desc->pmid, names[i])) < 0)
++		fprintf(stderr, "%s: failed to add metric name %s for %s\n",
++				"pmDiscoverInvokeMetricCallBacks", names[i],
++				pmIDStr_r(desc->pmid, idstr, sizeof(idstr)));
++	}
++	PM_UNLOCK(ctxp->c_lock);
++    }
++
+     discover_event_init(p, ts, &event);
+     for (i = 0; i < discoverCallBackTableSize; i++) {
+ 	if ((callbacks = discoverCallBackTable[i]) &&
+ 	    callbacks->on_metric != NULL)
+ 	    callbacks->on_metric(&event, desc, numnames, names, p->data);
+     }
++
++out:
++    for (i = 0; i < numnames; i++)
++	free(names[i]);
++    free(names);
+ }
+ 
+ static void
+ pmDiscoverInvokeInDomCallBacks(pmDiscover *p, pmTimespec *ts, pmInResult *in)
+ {
++    discoverModuleData	*data = getDiscoverModuleData(p->module);
+     pmDiscoverCallBacks	*callbacks;
+     pmDiscoverEvent	event;
+     char		buf[32], inbuf[32];
+-    int			i;
++    int			i, sts = PMLOGPUTINDOM_DUP; /* free after callbacks */
+ 
+     if (pmDebugOptions.discovery) {
+ 	fprintf(stderr, "%s[%s]: %s numinst %d indom %s\n",
+@@ -551,22 +794,48 @@ pmDiscoverInvokeInDomCallBacks(pmDiscove
+ 	    fprintf(stderr, "context labels %s\n", p->context.labelset->json);
+     }
+ 
++    if (data->indoms) {
++	if (dictFind(data->indoms, &in->indom) != NULL)
++	    goto out;	/* excluded InDom */
++    }
++
++    if (p->ctx >= 0 && p->context.type == PM_CONTEXT_ARCHIVE) {
++	__pmContext	*ctxp = __pmHandleToPtr(p->ctx);
++	__pmArchCtl	*acp = ctxp->c_archctl;
++	char		errmsg[PM_MAXERRMSGLEN];
++
++	if ((sts = __pmLogAddInDom(acp, ts, in, NULL, 0)) < 0)
++	    fprintf(stderr, "%s: failed to add indom for %s: %s\n",
++			"pmDiscoverInvokeInDomCallBacks", pmIDStr(in->indom),
++			pmErrStr_r(sts, errmsg, sizeof(errmsg)));
++	PM_UNLOCK(ctxp->c_lock);
++    }
++
+     discover_event_init(p, ts, &event);
+     for (i = 0; i < discoverCallBackTableSize; i++) {
+ 	if ((callbacks = discoverCallBackTable[i]) &&
+ 	    callbacks->on_indom != NULL)
+ 	    callbacks->on_indom(&event, in, p->data);
+     }
++
++out:
++    if (sts == PMLOGPUTINDOM_DUP) {
++	for (i = 0; i < in->numinst; i++)
++	    free(in->namelist[i]);
++	free(in->namelist);
++	free(in->instlist);
++    }
+ }
+ 
+ static void
+ pmDiscoverInvokeLabelsCallBacks(pmDiscover *p, pmTimespec *ts,
+ 		int ident, int type, pmLabelSet *sets, int nsets)
+ {
++    discoverModuleData	*data = getDiscoverModuleData(p->module);
+     pmDiscoverCallBacks	*callbacks;
+     pmDiscoverEvent	event;
+     char		buf[32], idbuf[64];
+-    int			i;
++    int			i, sts = -EAGAIN; /* free labelsets after callbacks */
+ 
+     if (pmDebugOptions.discovery) {
+ 	__pmLabelIdentString(ident, type, idbuf, sizeof(idbuf));
+@@ -579,22 +848,48 @@ pmDiscoverInvokeLabelsCallBacks(pmDiscov
+ 	    fprintf(stderr, "context labels %s\n", p->context.labelset->json);
+     }
+ 
++    if ((type & PM_LABEL_ITEM) && data->pmids) {
++	if (dictFind(data->pmids, &ident) != NULL)
++	    goto out;	/* text from an already excluded InDom */
++    }
++    if ((type & (PM_LABEL_INDOM|PM_LABEL_INSTANCES)) && data->indoms) {
++	if (dictFind(data->indoms, &ident) != NULL)
++	    goto out;	/* text from an already excluded InDom */
++    }
++
++    if (p->ctx >= 0 && p->context.type == PM_CONTEXT_ARCHIVE) {
++	__pmContext	*ctxp = __pmHandleToPtr(p->ctx);
++	__pmArchCtl	*acp = ctxp->c_archctl;
++	char		errmsg[PM_MAXERRMSGLEN];
++
++	if ((sts = __pmLogAddLabelSets(acp, ts, type, ident, nsets, sets)) < 0)
++	    fprintf(stderr, "%s: failed to add log labelset: %s\n",
++			"pmDiscoverInvokeLabelsCallBacks",
++			pmErrStr_r(sts, errmsg, sizeof(errmsg)));
++	PM_UNLOCK(ctxp->c_lock);
++    }
++
+     discover_event_init(p, ts, &event);
+     for (i = 0; i < discoverCallBackTableSize; i++) {
+ 	if ((callbacks = discoverCallBackTable[i]) &&
+ 	    callbacks->on_labels != NULL)
+ 	    callbacks->on_labels(&event, ident, type, sets, nsets, p->data);
+     }
++
++out:
++    if (sts < 0)
++	pmFreeLabelSets(sets, nsets);
+ }
+ 
+ static void
+ pmDiscoverInvokeTextCallBacks(pmDiscover *p, pmTimespec *ts,
+ 		int ident, int type, char *text)
+ {
++    discoverModuleData	*data = getDiscoverModuleData(p->module);
+     pmDiscoverCallBacks	*callbacks;
+     pmDiscoverEvent	event;
+     char		buf[32];
+-    int			i;
++    int			i, sts;
+ 
+     if (pmDebugOptions.discovery) {
+ 	fprintf(stderr, "%s[%s]: %s ", "pmDiscoverInvokeTextCallBacks",
+@@ -612,12 +907,36 @@ pmDiscoverInvokeTextCallBacks(pmDiscover
+ 	    fprintf(stderr, "context labels %s\n", p->context.labelset->json);
+     }
+ 
++    if ((type & PM_TEXT_PMID) && data->pmids) {
++	if (dictFind(data->pmids, &ident) != NULL)
++	    goto out;	/* text from an already excluded InDom */
++    }
++    if ((type & PM_TEXT_INDOM) && data->indoms) {
++	if (dictFind(data->indoms, &ident) != NULL)
++	    goto out;	/* text from an already excluded InDom */
++    }
++
++    if (p->ctx >= 0 && p->context.type == PM_CONTEXT_ARCHIVE) {
++	__pmContext	*ctxp = __pmHandleToPtr(p->ctx);
++	__pmArchCtl	*acp = ctxp->c_archctl;
++	char		errmsg[PM_MAXERRMSGLEN];
++
++	if ((sts = __pmLogAddText(acp, ident, type, text)) < 0)
++	    fprintf(stderr, "%s: failed to add %u text for %u: %s\n",
++	               "pmDiscoverInvokeTextCallBacks", type, ident,
++			pmErrStr_r(sts, errmsg, sizeof(errmsg)));
++	PM_UNLOCK(ctxp->c_lock);
++    }
++
+     discover_event_init(p, ts, &event);
+     for (i = 0; i < discoverCallBackTableSize; i++) {
+ 	if ((callbacks = discoverCallBackTable[i]) &&
+ 	    callbacks->on_text != NULL)
+ 	    callbacks->on_text(&event, ident, type, text, p->data);
+     }
++
++out:
++    free(text);
+ }
+ 
+ static void
+@@ -645,8 +964,8 @@ pmDiscoverNewSource(pmDiscover *p, int c
+     p->context.labelset = labelset;
+ 
+     /* use timestamp from file creation as starting time */
+-    timestamp.tv_sec = p->statbuf.st_birthtim.tv_sec;
+-    timestamp.tv_nsec = p->statbuf.st_birthtim.tv_nsec;
++    timestamp.tv_sec = p->statbuf.st_ctim.tv_sec;
++    timestamp.tv_nsec = p->statbuf.st_ctim.tv_nsec;
+ 
+     /* inform utilities that a source has been discovered */
+     pmDiscoverInvokeSourceCallBacks(p, &timestamp);
+@@ -664,7 +983,7 @@ process_metadata(pmDiscover *p)
+     pmDesc		desc;
+     off_t		off;
+     char		*buffer;
+-    int			e, i, nb, len, nsets;
++    int			e, nb, len, nsets;
+     int			type, id; /* pmID or pmInDom */
+     int			nnames;
+     char		**names;
+@@ -674,6 +993,8 @@ process_metadata(pmDiscover *p)
+     __pmLogHdr		hdr;
+     sds			msg, source;
+     static uint32_t	*buf = NULL;
++    int			deleted;
++    struct stat		sbuf;
+     static int		buflen = 0;
+ 
+     /*
+@@ -683,14 +1004,17 @@ process_metadata(pmDiscover *p)
+      */
+     p->flags |= PM_DISCOVER_FLAGS_META_IN_PROGRESS;
+     if (pmDebugOptions.discovery)
+-	fprintf(stderr, "%s: in progress, flags=%s\n",
+-			"process_metadata", pmDiscoverFlagsStr(p));
++	fprintf(stderr, "process_metadata: %s in progress %s\n",
++		p->context.name, pmDiscoverFlagsStr(p));
+     for (;;) {
+ 	off = lseek(p->fd, 0, SEEK_CUR);
+ 	nb = read(p->fd, &hdr, sizeof(__pmLogHdr));
+ 
+-	if (nb <= 0) {
+-	    /* we're at EOF or an error. But may still be part way through a record */
++	deleted = is_deleted(p, &sbuf);
++	if (nb <= 0 || deleted) {
++	    /* we're at EOF or an error, or deleted. But may still be part way through a record */
++	    if (deleted)
++	    	p->flags |= PM_DISCOVER_FLAGS_DELETED;
+ 	    break;
+ 	}
+ 
+@@ -750,10 +1074,6 @@ process_metadata(pmDiscover *p)
+ 	    ts.tv_sec = p->statbuf.st_mtim.tv_sec;
+ 	    ts.tv_nsec = p->statbuf.st_mtim.tv_nsec;
+ 	    pmDiscoverInvokeMetricCallBacks(p, &ts, &desc, nnames, names);
+-	    for (i = 0; i < nnames; i++)
+-		free(names[i]);
+-	    if (names)
+-		free(names);
+ 	    break;
+ 
+ 	case TYPE_INDOM:
+@@ -765,12 +1085,6 @@ process_metadata(pmDiscover *p)
+ 		break;
+ 	    }
+ 	    pmDiscoverInvokeInDomCallBacks(p, &ts, &inresult);
+-	    if (inresult.numinst > 0) {
+-		for (i = 0; i < inresult.numinst; i++)
+-		    free(inresult.namelist[i]);
+-		free(inresult.namelist);
+-		free(inresult.instlist);
+-	    }
+ 	    break;
+ 
+ 	case TYPE_LABEL:
+@@ -795,13 +1109,13 @@ process_metadata(pmDiscover *p)
+ 		} else {
+ 		    sdsfree(p->context.source);
+ 		    p->context.source = source;
+-		    p->context.labelset = labelset;
++		    if (p->context.labelset)
++			pmFreeLabelSets(p->context.labelset, 1);
++		    p->context.labelset = __pmDupLabelSets(labelset, 1);
+ 		    pmDiscoverInvokeSourceCallBacks(p, &ts);
+ 		}
+ 	    }
+ 	    pmDiscoverInvokeLabelsCallBacks(p, &ts, id, type, labelset, nsets);
+-	    if (labelset != p->context.labelset)
+-		pmFreeLabelSets(labelset, nsets);
+ 	    break;
+ 
+ 	case TYPE_TEXT:
+@@ -819,8 +1133,6 @@ process_metadata(pmDiscover *p)
+ 	    ts.tv_sec = p->statbuf.st_mtim.tv_sec;
+ 	    ts.tv_nsec = p->statbuf.st_mtim.tv_nsec;
+ 	    pmDiscoverInvokeTextCallBacks(p, &ts, id, type, buffer);
+-	    if (buffer)
+-		free(buffer);
+ 	    break;
+ 
+ 	default:
+@@ -833,38 +1145,89 @@ process_metadata(pmDiscover *p)
+     }
+ 
+     if (partial == 0)
+-	/* flag that all available metadata has been now been read */
++	/* flag that all available metadata has now been read */
+ 	p->flags &= ~PM_DISCOVER_FLAGS_META_IN_PROGRESS;
+ 
+     if (pmDebugOptions.discovery)
+-	fprintf(stderr, "%s : completed, partial=%d flags=%s\n",
+-			"process_metadata", partial, pmDiscoverFlagsStr(p));
++	fprintf(stderr, "%s: completed, partial=%d %s %s\n",
++			"process_metadata", partial, p->context.name, pmDiscoverFlagsStr(p));
+ }
+ 
+ /*
+- * fetch metric values to EOF and call all registered callbacks
++ * Fetch metric values to EOF and call all registered callbacks.
++ * Always process metadata thru to EOF before any logvol data.
+  */
+ static void
+-process_logvol_callback(pmDiscover *p)
++process_logvol(pmDiscover *p)
+ {
++    int			sts;
+     pmResult		*r;
+     pmTimespec		ts;
++    int			oldcurvol;
++    __pmContext		*ctxp;
++    __pmArchCtl		*acp;
++
++    for (;;) {
++	pmUseContext(p->ctx);
++	ctxp = __pmHandleToPtr(p->ctx);
++	acp = ctxp->c_archctl;
++	oldcurvol = acp->ac_curvol;
++	PM_UNLOCK(ctxp->c_lock);
++
++	if ((sts = pmFetchArchive(&r)) < 0) {
++	    /* err handling to skip to the next vol */
++	    ctxp = __pmHandleToPtr(p->ctx);
++	    acp = ctxp->c_archctl;
++	    if (oldcurvol < acp->ac_curvol) {
++	    	__pmLogChangeVol(acp, acp->ac_curvol);
++		acp->ac_offset = 0; /* __pmLogFetch will fix it up */
++	    }
++	    PM_UNLOCK(ctxp->c_lock);
++
++	    if (sts == PM_ERR_EOL) {
++		if (pmDebugOptions.discovery)
++		    fprintf(stderr, "process_logvol: %s end of archive reached\n",
++		    	p->context.name);
++
++		/* succesfully processed to current end of log */
++		break;
++	    } else {
++		/* 
++		 * This log vol was probably deleted (likely compressed)
++		 * under our feet. Try and skip to the next volume.
++		 * We hold the context lock during error recovery here.
++		 */
++		if (pmDebugOptions.discovery)
++		    fprintf(stderr, "process_logvol: %s fetch failed:%s\n",
++			p->context.name, pmErrStr(sts));
++	    }
+ 
+-    pmUseContext(p->ctx);
+-    while (pmFetchArchive(&r) == 0) {
++	    /* we are done - return and wait for another callback */
++	    break;
++	}
++
++	/*
++	 * Fetch succeeded - call the values callback and continue
++	 */
+ 	if (pmDebugOptions.discovery) {
+ 	    char		tbuf[64], bufs[64];
+ 
+-	    fprintf(stderr, "FETCHED @%s [%s] %d metrics\n",
+-		    timeval_str(&r->timestamp, tbuf, sizeof(tbuf)),
++	    fprintf(stderr, "process_logvol: %s FETCHED @%s [%s] %d metrics\n",
++		    p->context.name, timeval_str(&r->timestamp, tbuf, sizeof(tbuf)),
+ 		    timeval_stream_str(&r->timestamp, bufs, sizeof(bufs)),
+ 		    r->numpmid);
+ 	}
++
++	/*
++	 * TODO: persistently save current timestamp, so after being restarted,
++	 * pmproxy can resume where it left off for each archive.
++	 */
+ 	ts.tv_sec = r->timestamp.tv_sec;
+ 	ts.tv_nsec = r->timestamp.tv_usec * 1000;
+ 	pmDiscoverInvokeValuesCallBack(p, &ts, r);
+ 	pmFreeResult(r);
+     }
++
+     /* datavol is now up-to-date and at EOF */
+     p->flags &= ~PM_DISCOVER_FLAGS_DATAVOL_READY;
+ }
+@@ -874,12 +1237,13 @@ pmDiscoverInvokeCallBacks(pmDiscover *p)
+ {
+     int			sts;
+     sds			msg;
++    sds			metaname;
+ 
+     if (p->ctx < 0) {
+ 	/*
+ 	 * once off initialization on the first event
+ 	 */
+-	if (p->flags & PM_DISCOVER_FLAGS_DATAVOL) {
++	if (p->flags & (PM_DISCOVER_FLAGS_DATAVOL | PM_DISCOVER_FLAGS_META)) {
+ 	    struct timeval	tvp;
+ 
+ 	    /* create the PMAPI context (once off) */
+@@ -898,28 +1262,25 @@ pmDiscoverInvokeCallBacks(pmDiscover *p)
+ 		p->ctx = -1;
+ 		return;
+ 	    }
++	    /* seek to end of archive for logvol data - see TODO in process_logvol() */
+ 	    pmSetMode(PM_MODE_FORW, &tvp, 1);
+-	    /* note: we do not scan pre-existing logvol data. */
+-	}
+-	else if (p->flags & PM_DISCOVER_FLAGS_META) {
+-	    if ((sts = pmNewContext(p->context.type, p->context.name)) < 0) {
+-		infofmt(msg, "pmNewContext failed for %s: %s\n",
+-				p->context.name, pmErrStr(sts));
+-		moduleinfo(p->module, PMLOG_ERROR, msg, p->data);
+-		return;
+-	    }
+-	    pmDiscoverNewSource(p, sts);
+ 
+-	    /* for archive meta files, p->fd is the direct file descriptor */
+-	    if ((p->fd = open(p->context.name, O_RDONLY)) < 0) {
+-		infofmt(msg, "open failed for %s: %s\n", p->context.name,
+-				osstrerror());
++	    /*
++	     * For archive meta files, p->fd is the direct file descriptor
++	     * and we pre-scan existing metadata. Note: we do NOT scan
++	     * pre-existing logvol data (see pmSetMode above)
++	     */
++	    metaname = sdsnew(p->context.name);
++	    metaname = sdscat(metaname, ".meta");
++	    if ((p->fd = open(metaname, O_RDONLY)) < 0) {
++		infofmt(msg, "open failed for %s: %s\n", metaname, osstrerror());
+ 		moduleinfo(p->module, PMLOG_ERROR, msg, p->data);
++		sdsfree(metaname);
+ 		return;
+ 	    }
+-
+-	    /* process all existing metadata */
++	    /* pre-process all existing metadata */
+ 	    process_metadata(p);
++	    sdsfree(metaname);
+ 	}
+     }
+ 
+@@ -943,15 +1304,61 @@ pmDiscoverInvokeCallBacks(pmDiscover *p)
+     }
+ 
+     if (p->flags & PM_DISCOVER_FLAGS_META) {
+-	/* process metadata */
++	/* process new metadata, if any */
+ 	process_metadata(p);
+     }
+ 
+-    /* process any unprocessed datavol callbacks */
+-    pmDiscoverTraverse(PM_DISCOVER_FLAGS_DATAVOL_READY, process_logvol_callback);
++    if ((p->flags & PM_DISCOVER_FLAGS_META_IN_PROGRESS) == 0) {
++	/* no metdata read in progress, so process new datavol data, if any */
++	process_logvol(p);
++    }
++}
++
++static void
++print_callback(pmDiscover *p)
++{
++    if (p->flags & PM_DISCOVER_FLAGS_DIRECTORY) {
++	fprintf(stderr, "    DIRECTORY %s %s\n",
++	    p->context.name, pmDiscoverFlagsStr(p));
++    }
++    else {
++	__pmContext *ctxp;
++	__pmArchCtl *acp;
+ 
+-    /* finally, purge deleted entries, if any */
+-    pmDiscoverPurgeDeleted();
++	if (p->ctx >= 0 && (ctxp = __pmHandleToPtr(p->ctx)) != NULL) {
++	    acp = ctxp->c_archctl;
++	    fprintf(stderr, "    ARCHIVE %s fd=%d ctx=%d maxvol=%d ac_curvol=%d ac_offset=%ld %s\n",
++		p->context.name, p->fd, p->ctx, acp->ac_log->l_maxvol, acp->ac_curvol,
++		acp->ac_offset, pmDiscoverFlagsStr(p));
++	    PM_UNLOCK(ctxp->c_lock);
++	} else {
++	    /* no context yet - probably PM_DISCOVER_FLAGS_NEW */
++	    fprintf(stderr, "    ARCHIVE %s fd=%d ctx=%d %s\n",
++		p->context.name, p->fd, p->ctx, pmDiscoverFlagsStr(p));
++	}
++    }
++}
++
++/*
++ * p is a tracked archive and arg is a directory path.
++ * If p is in the directory, call it's callbacks to
++ * process metadata and logvol data. This allows better
++ * scalability because we only process archives in the
++ * directories that have changed.
++ */
++static void
++directory_changed_cb(pmDiscover *p, void *arg)
++{
++    char *dirpath = (char *)arg;
++    int dlen = strlen(dirpath);
++
++    if (strncmp(p->context.name, dirpath, dlen) == 0) {
++    	/* this archive is in this directory - process it's metadata and logvols */
++	if (pmDebugOptions.discovery)
++	    fprintf(stderr, "directory_changed_cb: archive %s is in dir %s\n",
++		p->context.name, dirpath);
++	pmDiscoverInvokeCallBacks(p);
++    }
+ }
+ 
+ static void
+@@ -962,27 +1369,46 @@ changed_callback(pmDiscover *p)
+ 			pmDiscoverFlagsStr(p));
+ 
+     if (p->flags & PM_DISCOVER_FLAGS_DELETED) {
+-	/* path or directory has been deleted - remove from hash table */
+-	deleted_callback(p);
+-    }
+-    else if (p->flags & PM_DISCOVER_FLAGS_DIRECTORY) {
+ 	/*
+-	 * A changed directory path means a new archive or subdirectory
+-	 * has been created - traverse and update the hash table.
++	 * Path has been deleted. Do nothing for now. Will be purged
++	 * in due course by pmDiscoverPurgeDeleted.
+ 	 */
+-	pmDiscoverArchives(p->context.name, p->module, p->data);
+-	pmDiscoverTraverse(PM_DISCOVER_FLAGS_NEW, created_callback);
++	return;
++	
+     }
+-    else if (p->flags & PM_DISCOVER_FLAGS_COMPRESSED) {
++
++    if (p->flags & PM_DISCOVER_FLAGS_COMPRESSED) {
+     	/* we do not monitor compressed files - do nothing */
+-	; /**/
++	return;
+     }
+-    else if (p->flags & (PM_DISCOVER_FLAGS_DATAVOL|PM_DISCOVER_FLAGS_META)) {
+-    	/*
+-	 * We only monitor uncompressed logvol and metadata paths. Fetch new data
+-	 * (metadata or logvol) and call the registered callbacks.
++
++    if (p->flags & PM_DISCOVER_FLAGS_DIRECTORY) {
++	/*
++	 * A changed directory path means a new archive or subdirectory may have
++	 * been created or deleted - traverse and update the hash table.
+ 	 */
+-	pmDiscoverInvokeCallBacks(p);
++	if (pmDebugOptions.discovery) {
++	    fprintf(stderr, "%s DIRECTORY CHANGED %s (%s)\n",
++	    	stamp(), p->context.name, pmDiscoverFlagsStr(p));
++	}
++	pmDiscoverArchives(p->context.name, p->module, p->data);
++	pmDiscoverTraverse(PM_DISCOVER_FLAGS_NEW, created_callback);
++
++	/*
++	 * Walk directory and invoke callbacks for tracked archives in this
++	 * directory that have changed
++	 */
++	pmDiscoverTraverseArg(PM_DISCOVER_FLAGS_DATAVOL|PM_DISCOVER_FLAGS_META,
++	    directory_changed_cb, (void *)p->context.name);
++
++	/* finally, purge deleted entries (globally), if any */
++	pmDiscoverPurgeDeleted();
++    }
++
++    if (pmDebugOptions.discovery) {
++	fprintf(stderr, "%s -- tracking status\n", stamp());
++	pmDiscoverTraverse(PM_DISCOVER_FLAGS_ALL, print_callback);
++	fprintf(stderr, "--\n");
+     }
+ }
+ 
+@@ -995,18 +1421,9 @@ dir_callback(pmDiscover *p)
+ static void
+ archive_callback(pmDiscover *p)
+ {
+-    if (p->flags & PM_DISCOVER_FLAGS_COMPRESSED)
+-    	return; /* compressed archives don't grow */
+-
+-    if (p->flags & PM_DISCOVER_FLAGS_DATAVOL) {
+-	if (pmDebugOptions.discovery)
+-	    fprintf(stderr, "DISCOVERED ARCHIVE LOGVOL %s\n", p->context.name);
+-	pmDiscoverMonitor(p->context.name, changed_callback);
+-    }
+-
+     if (p->flags & PM_DISCOVER_FLAGS_META) {
+ 	if (pmDebugOptions.discovery)
+-	    fprintf(stderr, "DISCOVERED ARCHIVE METADATA %s\n", p->context.name);
++	    fprintf(stderr, "DISCOVERED ARCHIVE %s\n", p->context.name);
+ 	pmDiscoverMonitor(p->context.name, changed_callback);
+     }
+ }
+@@ -1048,9 +1465,9 @@ pmDiscoverRegister(const char *dir, pmDi
+     }
+ 
+     if (pmDebugOptions.discovery) {
+-	fprintf(stderr, "Now managing %d directories and %d archive files\n",
++	fprintf(stderr, "Now tracking %d directories and %d archives\n",
+ 	    pmDiscoverTraverse(PM_DISCOVER_FLAGS_DIRECTORY, NULL),
+-	    pmDiscoverTraverse(PM_DISCOVER_FLAGS_DATAVOL, NULL));
++	    pmDiscoverTraverse(PM_DISCOVER_FLAGS_DATAVOL|PM_DISCOVER_FLAGS_META, NULL));
+     }
+ 
+     /* monitor the directories */
+diff -Naurp pcp-5.0.2.orig/src/libpcp_web/src/discover.h pcp-5.0.2/src/libpcp_web/src/discover.h
+--- pcp-5.0.2.orig/src/libpcp_web/src/discover.h	2019-12-10 17:04:20.000000000 +1100
++++ pcp-5.0.2/src/libpcp_web/src/discover.h	2020-02-03 13:36:09.904659047 +1100
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (c) 2018-2019 Red Hat.
++ * Copyright (c) 2018-2020 Red Hat.
+  *
+  * This library is free software; you can redistribute it and/or modify it
+  * under the terms of the GNU Lesser General Public License as published
+@@ -18,7 +18,9 @@
+ #include "libpcp.h"
+ #include "mmv_stats.h"
+ #include "slots.h"
+-
++#ifdef HAVE_REGEX_H
++#include <regex.h>
++#endif
+ #ifdef HAVE_LIBUV
+ #include <uv.h>
+ #else
+@@ -84,8 +86,8 @@ typedef struct pmDiscover {
+     int				fd;		/* meta file descriptor */
+ #ifdef HAVE_LIBUV
+     uv_fs_event_t		*event_handle;	/* uv fs_notify event handle */ 
+-    uv_stat_t			statbuf;	/* stat buffer from event CB */
+ #endif
++    struct stat			statbuf;	/* stat buffer */
+     void			*baton;		/* private internal lib data */
+     void			*data;		/* opaque user data pointer */
+ } pmDiscover;
+@@ -115,6 +117,10 @@ typedef struct discoverModuleData {
+     struct dict			*config;	/* configuration dict */
+     uv_loop_t			*events;	/* event library loop */
+     redisSlots			*slots;		/* server slots data */
++    regex_t			exclude_names;	/* metric names to exclude */
++    struct dict			*pmids;		/* dict of excluded PMIDs */
++    unsigned int		exclude_indoms;	/* exclude instance domains */
++    struct dict			*indoms;	/* dict of excluded InDoms */
+     void			*data;		/* user-supplied pointer */
+ } discoverModuleData;
+ 
+diff -Naurp pcp-5.0.2.orig/src/libpcp_web/src/exports pcp-5.0.2/src/libpcp_web/src/exports
+--- pcp-5.0.2.orig/src/libpcp_web/src/exports	2019-11-26 16:29:58.000000000 +1100
++++ pcp-5.0.2/src/libpcp_web/src/exports	2020-02-03 13:23:15.264762900 +1100
+@@ -178,3 +178,8 @@ PCP_WEB_1.11 {
+   global:
+     pmSeriesLabelValues;
+ } PCP_WEB_1.10;
++
++PCP_WEB_1.12 {
++  global:
++    SDS_NOINIT;
++} PCP_WEB_1.11;
+diff -Naurp pcp-5.0.2.orig/src/libpcp_web/src/load.c pcp-5.0.2/src/libpcp_web/src/load.c
+--- pcp-5.0.2.orig/src/libpcp_web/src/load.c	2019-12-11 14:01:53.000000000 +1100
++++ pcp-5.0.2/src/libpcp_web/src/load.c	2020-02-03 13:36:03.947721365 +1100
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (c) 2017-2019 Red Hat.
++ * Copyright (c) 2017-2020 Red Hat.
+  *
+  * This library is free software; you can redistribute it and/or modify it
+  * under the terms of the GNU Lesser General Public License as published
+@@ -112,22 +112,41 @@ load_prepare_metric(const char *name, vo
+  * Iterate over an instance domain and extract names and labels
+  * for each instance.
+  */
+-static unsigned int
+-get_instance_metadata(seriesLoadBaton *baton, pmInDom indom)
++static void
++get_instance_metadata(seriesLoadBaton *baton, pmInDom indom, int force_refresh)
+ {
+     context_t		*cp = &baton->pmapi.context;
+-    unsigned int	count = 0;
+     domain_t		*dp;
+     indom_t		*ip;
+ 
+     if (indom != PM_INDOM_NULL) {
+ 	if ((dp = pmwebapi_add_domain(cp, pmInDom_domain(indom))))
+ 	    pmwebapi_add_domain_labels(cp, dp);
+-	if ((ip = pmwebapi_add_indom(cp, dp, indom)) &&
+-	    (count = pmwebapi_add_indom_instances(cp, ip)) > 0)
+-	    pmwebapi_add_instances_labels(cp, ip);
++	if ((ip = pmwebapi_add_indom(cp, dp, indom)) != NULL) {
++	    if (force_refresh)
++		ip->updated = 1;
++	    if (ip->updated) {
++		pmwebapi_add_indom_instances(cp, ip);
++		pmwebapi_add_instances_labels(cp, ip);
++	    }
++	}
+     }
+-    return count;
++}
++
++static void
++get_metric_metadata(seriesLoadBaton *baton, metric_t *metric)
++{
++    context_t		*context = &baton->pmapi.context;
++
++    if (metric->cluster) {
++	if (metric->cluster->domain)
++	    pmwebapi_add_domain_labels(context, metric->cluster->domain);
++	pmwebapi_add_cluster_labels(context, metric->cluster);
++    }
++    if (metric->indom)
++	pmwebapi_add_instances_labels(context, metric->indom);
++    pmwebapi_add_item_labels(context, metric);
++    pmwebapi_metric_hash(metric);
+ }
+ 
+ static metric_t *
+@@ -140,18 +159,25 @@ new_metric(seriesLoadBaton *baton, pmVal
+     char		**nameall = NULL;
+     int			count, sts, i;
+ 
+-    if ((sts = pmLookupDesc(vsp->pmid, &desc)) < 0) {
++    if ((sts = pmUseContext(context->context)) < 0) {
++	fprintf(stderr, "%s: failed to use context for PMID %s: %s\n",
++		"new_metric",
++		pmIDStr_r(vsp->pmid, idbuf, sizeof(idbuf)),
++		pmErrStr_r(sts, errmsg, sizeof(errmsg)));
++    } else if ((sts = pmLookupDesc(vsp->pmid, &desc)) < 0) {
+ 	if (sts == PM_ERR_IPC)
+ 	    context->setup = 0;
+ 	if (pmDebugOptions.series)
+-	    fprintf(stderr, "failed to lookup metric %s descriptor: %s",
++	    fprintf(stderr, "%s: failed to lookup metric %s descriptor: %s\n",
++		"new_metric",
+ 		pmIDStr_r(vsp->pmid, idbuf, sizeof(idbuf)),
+ 		pmErrStr_r(sts, errmsg, sizeof(errmsg)));
+     } else if ((sts = count = pmNameAll(vsp->pmid, &nameall)) < 0) {
+ 	if (sts == PM_ERR_IPC)
+ 	    context->setup = 0;
+ 	if (pmDebugOptions.series)
+-	    fprintf(stderr, "failed to lookup metric %s names: %s",
++	    fprintf(stderr, "%s: failed to lookup metric %s names: %s\n",
++		"new_metric",
+ 		pmIDStr_r(vsp->pmid, idbuf, sizeof(idbuf)),
+ 		pmErrStr_r(sts, errmsg, sizeof(errmsg)));
+     }
+@@ -160,18 +186,10 @@ new_metric(seriesLoadBaton *baton, pmVal
+ 
+     if ((metric = pmwebapi_new_metric(context, NULL, &desc, count, nameall)) == NULL)
+ 	return NULL;
+-    if (metric->cluster) {
+-	if (metric->cluster->domain)
+-	    pmwebapi_add_domain_labels(context, metric->cluster->domain);
+-	pmwebapi_add_cluster_labels(context, metric->cluster);
+-    }
+-    if (metric->indom)
+-	pmwebapi_add_instances_labels(context, metric->indom);
+-    pmwebapi_add_item_labels(context, metric);
+-    pmwebapi_metric_hash(metric);
++    get_metric_metadata(baton, metric);
+ 
+     if (pmDebugOptions.series) {
+-	fprintf(stderr, "new_metric [%s] names:",
++	fprintf(stderr, "%s [%s] names:\n", "new_metric",
+ 		pmIDStr_r(vsp->pmid, idbuf, sizeof(idbuf)));
+ 	for (i = 0; i < count; i++) {
+ 	    pmwebapi_hash_str(metric->names[i].hash, idbuf, sizeof(idbuf));
+@@ -409,7 +427,7 @@ pmwebapi_add_valueset(metric_t *metric,
+ }
+ 
+ static void
+-series_cache_update(seriesLoadBaton *baton)
++series_cache_update(seriesLoadBaton *baton, struct dict *exclude)
+ {
+     seriesGetContext	*context = &baton->pmapi;
+     context_t		*cp = &context->context;
+@@ -418,7 +436,7 @@ series_cache_update(seriesLoadBaton *bat
+     metric_t		*metric = NULL;
+     char		ts[64];
+     sds			timestamp;
+-    int			i, write_meta, write_data;
++    int			i, write_meta, write_inst, write_data;
+ 
+     timestamp = sdsnew(timeval_stream_str(&result->timestamp, ts, sizeof(ts)));
+     write_data = (!(baton->flags & PM_SERIES_FLAG_METADATA));
+@@ -441,6 +459,12 @@ series_cache_update(seriesLoadBaton *bat
+ 	    dictFetchValue(baton->wanted, &vsp->pmid) == NULL)
+ 	    continue;
+ 
++	/* check if metric to be skipped (optional metric exclusion) */
++	if (exclude && (dictFind(exclude, &vsp->pmid)) != NULL)
++	    continue;
++
++	write_meta = write_inst = 0;
++
+ 	/* check if pmid already in hash list */
+ 	if ((metric = dictFetchValue(cp->pmids, &vsp->pmid)) == NULL) {
+ 	    /* create a new metric, and add it to load context */
+@@ -448,21 +472,22 @@ series_cache_update(seriesLoadBaton *bat
+ 		continue;
+ 	    write_meta = 1;
+ 	} else {	/* pmid already observed */
+-	    write_meta = 0;
++	    if ((write_meta = metric->cached) == 0)
++		get_metric_metadata(baton, metric);
+ 	}
+ 
+ 	/* iterate through result instances and ensure metric_t is complete */
+ 	if (metric->error == 0 && vsp->numval < 0)
+ 	    write_meta = 1;
+ 	if (pmwebapi_add_valueset(metric, vsp) != 0)
+-	    write_meta = 1;
++	    write_meta = write_inst = 1;
+ 
+ 	/* record the error code in the cache */
+ 	metric->error = (vsp->numval < 0) ? vsp->numval : 0;
+ 
+ 	/* make PMAPI calls to cache metadata */
+-	if (write_meta && get_instance_metadata(baton, metric->desc.indom) != 0)
+-	    continue;
++	if (write_meta)
++	    get_instance_metadata(baton, metric->desc.indom, write_inst);
+ 
+ 	/* initiate writes to backend caching servers (Redis) */
+ 	server_cache_metric(baton, metric, timestamp, write_meta, write_data);
+@@ -549,7 +574,7 @@ server_cache_window(void *arg)
+ 	    (finish->tv_sec == result->timestamp.tv_sec &&
+ 	     finish->tv_usec >= result->timestamp.tv_usec)) {
+ 	    context->done = server_cache_update_done;
+-	    series_cache_update(baton);
++	    series_cache_update(baton, NULL);
+ 	}
+ 	else {
+ 	    if (pmDebugOptions.series)
+@@ -1023,7 +1048,7 @@ pmSeriesDiscoverSource(pmDiscoverEvent *
+     sds			msg;
+     int			i;
+ 
+-    if (data == NULL || data->slots == NULL)
++    if (data == NULL || data->slots == NULL || data->slots->setup == 0)
+ 	return;
+ 
+     baton = (seriesLoadBaton *)calloc(1, sizeof(seriesLoadBaton));
+@@ -1032,22 +1057,31 @@ pmSeriesDiscoverSource(pmDiscoverEvent *
+ 	moduleinfo(module, PMLOG_ERROR, msg, arg);
+ 	return;
+     }
++    if ((set = pmwebapi_labelsetdup(p->context.labelset)) == NULL) {
++	infofmt(msg, "%s: out of memory for labels", "pmSeriesDiscoverSource");
++	moduleinfo(module, PMLOG_ERROR, msg, arg);
++	free(baton);
++	return;
++    }
++
+     initSeriesLoadBaton(baton, module, 0 /*flags*/,
+ 			module->on_info, series_discover_done,
+ 			data->slots, arg);
+     initSeriesGetContext(&baton->pmapi, baton);
+     p->baton = baton;
+ 
++    cp = &baton->pmapi.context;
++
+     if (pmDebugOptions.discovery)
+-	fprintf(stderr, "%s: new source %s context=%d\n",
+-			"pmSeriesDiscoverSource", p->context.name, p->ctx);
++	fprintf(stderr, "%s: new source %s context=%p ctxid=%d\n",
++			"pmSeriesDiscoverSource", p->context.name, cp, p->ctx);
+ 
+-    cp = &baton->pmapi.context;
+     cp->context = p->ctx;
+     cp->type = p->context.type;
+     cp->name.sds = sdsdup(p->context.name);
+-    cp->host = p->context.hostname;
+-    cp->labelset = set = p->context.labelset;
++    cp->host = sdsdup(p->context.hostname);
++    cp->labelset = set;
++
+     pmwebapi_source_hash(cp->name.hash, set->json, set->jsonlen);
+     pmwebapi_setup_context(cp);
+     set_source_origin(cp);
+@@ -1095,21 +1129,22 @@ pmSeriesDiscoverLabels(pmDiscoverEvent *
+     sds			msg;
+     int			i, id;
+ 
++    if (baton == NULL || baton->slots == NULL || baton->slots->setup == 0)
++	return;
++
+     switch (type) {
+     case PM_LABEL_CONTEXT:
+ 	if (pmDebugOptions.discovery)
+ 	    fprintf(stderr, "%s: context\n", "pmSeriesDiscoverLabels");
+ 
+ 	if ((labels = pmwebapi_labelsetdup(sets)) != NULL) {
+-#if 0 /* PCP GH#800 do not free this labelset - it's owned by the discover code */
+ 	    if (cp->labelset)
+ 		pmFreeLabelSets(cp->labelset, 1);
+-#endif
+ 	    cp->labelset = labels;
+ 	    pmwebapi_locate_context(cp);
+ 	    cp->updated = 1;
+ 	} else {
+-	    infofmt(msg, "failed to duplicate label set");
++	    infofmt(msg, "failed to duplicate %s label set", "context");
+ 	    moduleinfo(event->module, PMLOG_ERROR, msg, arg);
+ 	}
+ 	break;
+@@ -1125,8 +1160,8 @@ pmSeriesDiscoverLabels(pmDiscoverEvent *
+ 		pmFreeLabelSets(domain->labelset, 1);
+ 	    domain->labelset = labels;
+ 	    domain->updated = 1;
+-	} else {
+-	    infofmt(msg, "failed to duplicate label set");
++	} else if (domain) {
++	    infofmt(msg, "failed to duplicate %s label set", "domain");
+ 	    moduleinfo(event->module, PMLOG_ERROR, msg, arg);
+ 	}
+ 	break;
+@@ -1142,8 +1177,8 @@ pmSeriesDiscoverLabels(pmDiscoverEvent *
+ 		pmFreeLabelSets(cluster->labelset, 1);
+ 	    cluster->labelset = labels;
+ 	    cluster->updated = 1;
+-	} else {
+-	    infofmt(msg, "failed to duplicate label set");
++	} else if (cluster) {
++	    infofmt(msg, "failed to duplicate %s label set", "cluster");
+ 	    moduleinfo(event->module, PMLOG_ERROR, msg, arg);
+ 	}
+ 	break;
+@@ -1159,8 +1194,8 @@ pmSeriesDiscoverLabels(pmDiscoverEvent *
+ 		pmFreeLabelSets(metric->labelset, 1);
+ 	    metric->labelset = labels;
+ 	    metric->updated = 1;
+-	} else {
+-	    infofmt(msg, "failed to duplicate label set");
++	} else if (metric) {
++	    infofmt(msg, "failed to duplicate %s label set", "item");
+ 	    moduleinfo(event->module, PMLOG_ERROR, msg, arg);
+ 	}
+ 	break;
+@@ -1177,8 +1212,8 @@ pmSeriesDiscoverLabels(pmDiscoverEvent *
+ 		pmFreeLabelSets(indom->labelset, 1);
+ 		    indom->labelset = labels;
+ 	    indom->updated = 1;
+-	} else {
+-	    infofmt(msg, "failed to duplicate label set");
++	} else if (indom) {
++	    infofmt(msg, "failed to duplicate %s label set", "indom");
+ 	    moduleinfo(event->module, PMLOG_ERROR, msg, arg);
+ 	}
+ 	break;
+@@ -1196,7 +1231,7 @@ pmSeriesDiscoverLabels(pmDiscoverEvent *
+ 	    if ((instance = dictFetchValue(indom->insts, &id)) == NULL)
+ 		continue;
+ 	    if ((labels = pmwebapi_labelsetdup(&sets[i])) == NULL) {
+-		infofmt(msg, "failed to dup %s instance labels: %s",
++		infofmt(msg, "failed to dup indom %s instance label set: %s",
+ 			pmInDomStr_r(indom->indom, idbuf, sizeof(idbuf)),
+ 			pmErrStr_r(-ENOMEM, errmsg, sizeof(errmsg)));
+ 		moduleinfo(event->module, PMLOG_ERROR, msg, arg);
+@@ -1229,10 +1264,13 @@ pmSeriesDiscoverMetric(pmDiscoverEvent *
+ 
+     if (pmDebugOptions.discovery) {
+ 	for (i = 0; i < numnames; i++)
+-	    fprintf(stderr, "pmSeriesDiscoverMetric: [%d/%d] %s - %s\n",
++	    fprintf(stderr, "%s: [%d/%d] %s - %s\n", "pmSeriesDiscoverMetric",
+ 			i + 1, numnames, pmIDStr(desc->pmid), names[i]);
+     }
+ 
++    if (baton == NULL || baton->slots == NULL || baton->slots->setup == 0)
++	return;
++
+     if ((metric = pmwebapi_add_metric(&baton->pmapi.context,
+ 				NULL, desc, numnames, names)) == NULL) {
+ 	infofmt(msg, "%s: failed metric discovery", "pmSeriesDiscoverMetric");
+@@ -1244,18 +1282,23 @@ pmSeriesDiscoverMetric(pmDiscoverEvent *
+ void
+ pmSeriesDiscoverValues(pmDiscoverEvent *event, pmResult *result, void *arg)
+ {
++    pmDiscoverModule	*module = event->module;
+     pmDiscover		*p = (pmDiscover *)event->data;
+     seriesLoadBaton	*baton = p->baton;
+     seriesGetContext	*context = &baton->pmapi;
++    discoverModuleData	*data = getDiscoverModuleData(module);
+ 
+     if (pmDebugOptions.discovery)
+ 	fprintf(stderr, "%s: result numpmids=%d\n", "pmSeriesDiscoverValues", result->numpmid);
+ 
++    if (baton == NULL || baton->slots == NULL || baton->slots->setup == 0)
++	return;
++
+     seriesBatonReference(context, "pmSeriesDiscoverValues");
+     baton->arg = arg;
+     context->result = result;
+ 
+-    series_cache_update(baton);
++    series_cache_update(baton, data->pmids);
+ }
+ 
+ void
+@@ -1271,7 +1314,10 @@ pmSeriesDiscoverInDom(pmDiscoverEvent *e
+     int			i;
+ 
+     if (pmDebugOptions.discovery)
+-	fprintf(stderr, "pmSeriesDiscoverInDom: %s\n", pmInDomStr(id));
++	fprintf(stderr, "%s: %s\n", "pmSeriesDiscoverInDom", pmInDomStr(id));
++
++    if (baton == NULL || baton->slots == NULL || baton->slots->setup == 0)
++	return;
+ 
+     if ((domain = pmwebapi_add_domain(context, pmInDom_domain(id))) == NULL) {
+ 	infofmt(msg, "%s: failed indom discovery (domain %u)",
+@@ -1303,11 +1349,10 @@ pmSeriesDiscoverText(pmDiscoverEvent *ev
+     pmDiscover		*p = (pmDiscover *)event->data;
+     seriesLoadBaton	*baton = p->baton;
+ 
+-    (void)baton;
+-    (void)ident;
+-    (void)type;
+-    (void)text;
+-    (void)arg;
++    if (pmDebugOptions.discovery)
++	fprintf(stderr, "%s: ident=%u type=%u arg=%p\n",
++			"pmSeriesDiscoverText", ident, type, arg);
+ 
+-    /* for Redis, help text will need special handling (RediSearch) */
++    if (baton == NULL || baton->slots == NULL || baton->slots->setup == 0)
++	return;
+ }
+diff -Naurp pcp-5.0.2.orig/src/libpcp_web/src/query.c pcp-5.0.2/src/libpcp_web/src/query.c
+--- pcp-5.0.2.orig/src/libpcp_web/src/query.c	2019-12-05 17:29:43.000000000 +1100
++++ pcp-5.0.2/src/libpcp_web/src/query.c	2020-02-03 13:23:15.265762890 +1100
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (c) 2017-2019 Red Hat.
++ * Copyright (c) 2017-2020 Red Hat.
+  *
+  * This library is free software; you can redistribute it and/or modify it
+  * under the terms of the GNU Lesser General Public License as published
+@@ -1243,24 +1243,43 @@ series_prepare_time_reply(
+     series_query_end_phase(baton);
+ }
+ 
++unsigned int
++series_value_count_only(timing_t *tp)
++{
++    if (tp->window.range || tp->window.delta ||
++	tp->window.start || tp->window.end)
++	return 0;
++    return tp->count;
++}
++
+ static void
+ series_prepare_time(seriesQueryBaton *baton, series_set_t *result)
+ {
+     timing_t		*tp = &baton->u.query.timing;
+     unsigned char	*series = result->series;
+     seriesGetSID	*sid;
+-    char		buffer[64];
++    char		buffer[64], revbuf[64];
+     sds			start, end, key, cmd;
+-    unsigned int	i;
++    unsigned int	i, revlen = 0, reverse = 0;
++
++    /* if only 'count' is requested, work back from most recent value */
++    if ((reverse = series_value_count_only(tp)) != 0) {
++	revlen = pmsprintf(revbuf, sizeof(revbuf), "%u", reverse);
++	start = sdsnew("+");
++    } else {
++	start = sdsnew(timeval_stream_str(&tp->start, buffer, sizeof(buffer)));
++    }
+ 
+-    start = sdsnew(timeval_stream_str(&tp->start, buffer, sizeof(buffer)));
+     if (pmDebugOptions.series)
+ 	fprintf(stderr, "START: %s\n", start);
+ 
+-    if (tp->end.tv_sec)
++    if (reverse)
++	end = sdsnew("-");
++    else if (tp->end.tv_sec)
+ 	end = sdsnew(timeval_stream_str(&tp->end, buffer, sizeof(buffer)));
+     else
+ 	end = sdsnew("+");	/* "+" means "no end" - to the most recent */
++
+     if (pmDebugOptions.series)
+ 	fprintf(stderr, "END: %s\n", end);
+ 
+@@ -1277,12 +1296,21 @@ series_prepare_time(seriesQueryBaton *ba
+ 
+ 	key = sdscatfmt(sdsempty(), "pcp:values:series:%S", sid->name);
+ 
+-	/* XRANGE key t1 t2 */
+-	cmd = redis_command(4);
+-	cmd = redis_param_str(cmd, XRANGE, XRANGE_LEN);
++	/* X[REV]RANGE key t1 t2 [count N] */
++	if (reverse) {
++	    cmd = redis_command(6);
++	    cmd = redis_param_str(cmd, XREVRANGE, XREVRANGE_LEN);
++	} else {
++	    cmd = redis_command(4);
++	    cmd = redis_param_str(cmd, XRANGE, XRANGE_LEN);
++	}
+ 	cmd = redis_param_sds(cmd, key);
+ 	cmd = redis_param_sds(cmd, start);
+ 	cmd = redis_param_sds(cmd, end);
++	if (reverse) {
++	    cmd = redis_param_str(cmd, "COUNT", sizeof("COUNT")-1);
++	    cmd = redis_param_str(cmd, revbuf, revlen);
++	}
+ 	redisSlotsRequest(baton->slots, XRANGE, key, cmd,
+ 				series_prepare_time_reply, sid);
+     }
+diff -Naurp pcp-5.0.2.orig/src/libpcp_web/src/schema.c pcp-5.0.2/src/libpcp_web/src/schema.c
+--- pcp-5.0.2.orig/src/libpcp_web/src/schema.c	2019-11-18 19:35:11.000000000 +1100
++++ pcp-5.0.2/src/libpcp_web/src/schema.c	2020-02-03 13:36:03.948721355 +1100
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (c) 2017-2019 Red Hat.
++ * Copyright (c) 2017-2020 Red Hat.
+  *
+  * This library is free software; you can redistribute it and/or modify it
+  * under the terms of the GNU Lesser General Public License as published
+@@ -819,7 +819,7 @@ redis_series_metric(redisSlots *slots, m
+      */
+ 
+     /* ensure all metric name strings are mapped */
+-    for (i = 0; i < metric->numnames; i++) {
++    for (i = 0; metric->cached == 0 && i < metric->numnames; i++) {
+ 	assert(metric->names[i].sds != NULL);
+ 	seriesBatonReference(baton, "redis_series_metric");
+ 	redisGetMap(slots,
+@@ -830,7 +830,8 @@ redis_series_metric(redisSlots *slots, m
+ 
+     /* ensure all metric or instance label strings are mapped */
+     if (metric->desc.indom == PM_INDOM_NULL || metric->u.vlist == NULL) {
+-	series_metric_label_mapping(metric, baton);
++	if (metric->cached == 0)
++	    series_metric_label_mapping(metric, baton);
+     } else {
+ 	for (i = 0; i < metric->u.vlist->listcount; i++) {
+ 	    value = &metric->u.vlist->value[i];
+@@ -847,7 +848,8 @@ redis_series_metric(redisSlots *slots, m
+ 			series_name_mapping_callback,
+ 			baton->info, baton->userdata, baton);
+ 
+-	    series_instance_label_mapping(metric, instance, baton);
++	    if (instance->cached == 0)
++		series_instance_label_mapping(metric, instance, baton);
+ 	}
+     }
+ 
+@@ -941,6 +943,9 @@ redis_series_metadata(context_t *context
+     sds				cmd, key;
+     int				i;
+ 
++    if (metric->cached)
++	goto check_instances;
++
+     indom = pmwebapi_indom_str(metric, ibuf, sizeof(ibuf));
+     pmid = pmwebapi_pmid_str(metric, pbuf, sizeof(pbuf));
+     sem = pmwebapi_semantics_str(metric, sbuf, sizeof(sbuf));
+@@ -1000,16 +1005,24 @@ redis_series_metadata(context_t *context
+ 	cmd = redis_param_sha(cmd, metric->names[i].hash);
+     redisSlotsRequest(slots, SADD, key, cmd, redis_series_source_callback, arg);
+ 
++check_instances:
+     if (metric->desc.indom == PM_INDOM_NULL || metric->u.vlist == NULL) {
+-	redis_series_labelset(slots, metric, NULL, baton);
++	if (metric->cached == 0) {
++	    redis_series_labelset(slots, metric, NULL, baton);
++	    metric->cached = 1;
++	}
+     } else {
+ 	for (i = 0; i < metric->u.vlist->listcount; i++) {
+ 	    value = &metric->u.vlist->value[i];
+ 	    if ((instance = dictFetchValue(metric->indom->insts, &value->inst)) == NULL)
+ 		continue;
+-	    redis_series_instance(slots, metric, instance, baton);
+-	    redis_series_labelset(slots, metric, instance, baton);
++	    if (instance->cached == 0 || metric->cached == 0) {
++		redis_series_instance(slots, metric, instance, baton);
++		redis_series_labelset(slots, metric, instance, baton);
++	    }
++	    instance->cached = 1;
+ 	}
++	metric->cached = 1;
+     }
+ }
+ 
+@@ -1210,7 +1223,6 @@ redis_series_stream(redisSlots *slots, s
+ 
+     redisSlotsRequest(slots, XADD, key, cmd, redis_series_stream_callback, baton);
+ 
+-
+     key = sdscatfmt(sdsempty(), "pcp:values:series:%s", hash);
+     cmd = redis_command(3);	/* EXPIRE key timer */
+     cmd = redis_param_str(cmd, EXPIRE, EXPIRE_LEN);
+@@ -1228,9 +1240,6 @@ redis_series_streamed(sds stamp, metric_
+     char			hashbuf[42];
+     int				i;
+ 
+-    if (metric->updated == 0)
+-	return;
+-
+     for (i = 0; i < metric->numnames; i++) {
+ 	pmwebapi_hash_str(metric->names[i].hash, hashbuf, sizeof(hashbuf));
+ 	redis_series_stream(slots, stamp, metric, hashbuf, arg);
+@@ -1545,7 +1554,10 @@ redis_load_slots_callback(
+     redisSlots		*slots = baton->slots;
+ 
+     seriesBatonCheckMagic(baton, MAGIC_SLOTS, "redis_load_slots_callback");
++
++    slots->setup = 1;	/* we've received initial response from Redis */
+     slots->refresh = 0;	/* we're processing CLUSTER SLOTS command now */
++
+     /* no cluster redirection checking is needed for this callback */
+     sdsfree(cmd);
+ 
+@@ -1832,12 +1844,47 @@ pmDiscoverSetup(pmDiscoverModule *module
+     const char		fallback[] = "/var/log/pcp";
+     const char		*paths[] = { "pmlogger", "pmmgr" };
+     const char		*logdir = pmGetOptionalConfig("PCP_LOG_DIR");
++    struct dict		*config;
++    unsigned int	domain, serial;
++    pmInDom		indom;
+     char		path[MAXPATHLEN];
+     char		sep = pmPathSeparator();
+-    int			i, sts, count = 0;
++    sds			option, *ids;
++    int			i, sts, nids, count = 0;
+ 
+     if (data == NULL)
+ 	return -ENOMEM;
++    config = data->config;
++
++    /* double-check that we are supposed to be in here */
++    if ((option = pmIniFileLookup(config, "discover", "enabled"))) {
++	if (strcasecmp(option, "false") == 0)
++	    return 0;
++    }
++
++    /* prepare for optional metric and indom exclusion */
++    if ((option = pmIniFileLookup(config, "discover", "exclude.metrics"))) {
++	if ((data->pmids = dictCreate(&intKeyDictCallBacks, NULL)) == NULL)
++	    return -ENOMEM;
++	/* parse regular expression string for matching on metric names */
++	regcomp(&data->exclude_names, option, REG_EXTENDED|REG_NOSUB);
++    }
++    if ((option = pmIniFileLookup(config, "discover", "exclude.indoms"))) {
++	if ((data->indoms = dictCreate(&intKeyDictCallBacks, NULL)) == NULL)
++	    return -ENOMEM;
++	/* parse comma-separated indoms in 'option', convert to pmInDom */
++	if ((ids = sdssplitlen(option, sdslen(option), ",", 1, &nids))) {
++	    data->exclude_indoms = nids;
++	    for (i = 0; i < nids; i++) {
++		if (sscanf(ids[i], "%u.%u", &domain, &serial) == 2) {
++		    indom = pmInDom_build(domain, serial);
++		    dictAdd(data->indoms, &indom, NULL);
++		}
++		sdsfree(ids[i]);
++	    }
++	    free(ids);
++	}
++    }
+ 
+     /* create global EVAL hashes and string map caches */
+     redisGlobalsInit(data->config);
+diff -Naurp pcp-5.0.2.orig/src/libpcp_web/src/schema.h pcp-5.0.2/src/libpcp_web/src/schema.h
+--- pcp-5.0.2.orig/src/libpcp_web/src/schema.h	2019-10-11 17:16:29.000000000 +1100
++++ pcp-5.0.2/src/libpcp_web/src/schema.h	2020-02-03 13:23:15.266762879 +1100
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (c) 2017-2018 Red Hat.
++ * Copyright (c) 2017-2020 Red Hat.
+  * 
+  * This library is free software; you can redistribute it and/or modify it
+  * under the terms of the GNU Lesser General Public License as published
+@@ -51,6 +51,10 @@
+ #define HSET_LEN	(sizeof(HSET)-1)
+ #define HVALS		"HVALS"
+ #define HVALS_LEN	(sizeof(HVALS)-1)
++#define INFO		"INFO"
++#define INFO_LEN	(sizeof(INFO)-1)
++#define PING		"PING"
++#define PING_LEN	(sizeof(PING)-1)
+ #define PUBLISH		"PUBLISH"
+ #define PUBLISH_LEN	(sizeof(PUBLISH)-1)
+ #define SADD		"SADD"
+@@ -63,6 +67,8 @@
+ #define XADD_LEN	(sizeof(XADD)-1)
+ #define XRANGE		"XRANGE"
+ #define XRANGE_LEN	(sizeof(XRANGE)-1)
++#define XREVRANGE	"XREVRANGE"
++#define XREVRANGE_LEN	(sizeof(XREVRANGE)-1)
+ 
+ /* create a Redis protocol command (e.g. XADD, SMEMBER) */
+ static inline sds
+diff -Naurp pcp-5.0.2.orig/src/libpcp_web/src/slots.c pcp-5.0.2/src/libpcp_web/src/slots.c
+--- pcp-5.0.2.orig/src/libpcp_web/src/slots.c	2019-10-11 17:16:29.000000000 +1100
++++ pcp-5.0.2/src/libpcp_web/src/slots.c	2020-02-03 13:23:15.266762879 +1100
+@@ -356,6 +356,21 @@ redisSlotsRequest(redisSlots *slots, con
+ 
+     if (UNLIKELY(pmDebugOptions.desperate))
+ 	fputs(cmd, stderr);
++    if (UNLIKELY(!key && !slots->setup)) {
++	/*
++	 * First request must be CLUSTER, PING, or similar - must
++	 * not allow regular requests until these have completed.
++	 * This is because the low layers accumulate async requests
++	 * until connection establishment, which might not happen.
++	 * Over time this becomes a memory leak - if we do not ever
++	 * establish an initial connection).
++	 */
++	if (strcmp(topic, CLUSTER) != 0 &&
++	    strcmp(topic, PING) != 0 && strcmp(topic, INFO) != 0) {
++	    sdsfree(cmd);
++	    return -ENOTCONN;
++	}
++    }
+ 
+     sts = redisAsyncFormattedCommand(context, callback, cmd, arg);
+     if (key)
+diff -Naurp pcp-5.0.2.orig/src/libpcp_web/src/slots.h pcp-5.0.2/src/libpcp_web/src/slots.h
+--- pcp-5.0.2.orig/src/libpcp_web/src/slots.h	2019-04-08 09:11:00.000000000 +1000
++++ pcp-5.0.2/src/libpcp_web/src/slots.h	2020-02-03 13:23:15.266762879 +1100
+@@ -44,10 +44,11 @@ typedef struct redisSlotRange {
+ typedef struct redisSlots {
+     unsigned int	counter;
+     unsigned int	nslots;
++    unsigned int	setup;		/* slots info all successfully setup */
++    unsigned int	refresh;	/* do slot refresh whenever possible */
+     redisSlotRange	*slots;		/* all instances; e.g. CLUSTER SLOTS */
+     redisMap		*keymap;	/* map command names to key position */
+     dict		*contexts;	/* async contexts access by hostspec */
+-    unsigned int	refresh;	/* do slot refresh whenever possible */
+     void		*events;
+ } redisSlots;
+ 
+diff -Naurp pcp-5.0.2.orig/src/libpcp_web/src/util.c pcp-5.0.2/src/libpcp_web/src/util.c
+--- pcp-5.0.2.orig/src/libpcp_web/src/util.c	2019-12-10 17:39:49.000000000 +1100
++++ pcp-5.0.2/src/libpcp_web/src/util.c	2020-02-03 13:23:15.266762879 +1100
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (c) 2017-2019 Red Hat.
++ * Copyright (c) 2017-2020 Red Hat.
+  *
+  * This library is free software; you can redistribute it and/or modify it
+  * under the terms of the GNU Lesser General Public License as published
+@@ -535,6 +535,8 @@ pmwebapi_metric_hash(metric_t *metric)
+ 	sdsclear(identifier);
+     }
+     sdsfree(identifier);
++
++    metric->cached = 0;
+ }
+ 
+ void
+@@ -574,6 +576,8 @@ pmwebapi_instance_hash(indom_t *ip, inst
+     SHA1Update(&shactx, (unsigned char *)identifier, sdslen(identifier));
+     SHA1Final(instance->name.hash, &shactx);
+     sdsfree(identifier);
++
++    instance->cached = 0;
+ }
+ 
+ sds
+@@ -1046,7 +1050,6 @@ pmwebapi_add_instance(struct indom *indo
+ 	    instance->name.sds = sdscatlen(instance->name.sds, name, length);
+ 	    pmwebapi_string_hash(instance->name.id, name, length);
+ 	    pmwebapi_instance_hash(indom, instance);
+-	    instance->cached = 0;
+ 	}
+ 	return instance;
+     }
+@@ -1202,12 +1205,14 @@ struct metric *
+ pmwebapi_add_metric(context_t *cp, const sds base, pmDesc *desc, int numnames, char **names)
+ {
+     struct metric	*metric;
+-    sds			name = sdsempty();
++    sds			name;
+     int			i;
+ 
+     /* search for a match on any of the given names */
+     if (base && (metric = dictFetchValue(cp->metrics, base)) != NULL)
+ 	return metric;
++
++    name = sdsempty();
+     for (i = 0; i < numnames; i++) {
+ 	sdsclear(name);
+ 	name = sdscat(name, names[i]);
+@@ -1217,6 +1222,7 @@ pmwebapi_add_metric(context_t *cp, const
+ 	}
+     }
+     sdsfree(name);
++
+     return pmwebapi_new_metric(cp, base, desc, numnames, names);
+ }
+ 
+@@ -1230,21 +1236,24 @@ pmwebapi_new_pmid(context_t *cp, const s
+     int			sts, numnames;
+ 
+     if ((sts = pmUseContext(cp->context)) < 0) {
+-	fprintf(stderr, "failed to use context for PMID %s: %s",
++	fprintf(stderr, "%s: failed to use context for PMID %s: %s\n",
++		"pmwebapi_new_pmid",
+ 		pmIDStr_r(pmid, buffer, sizeof(buffer)),
+ 		pmErrStr_r(sts, errmsg, sizeof(errmsg)));
+     } else if ((sts = pmLookupDesc(pmid, &desc)) < 0) {
+ 	if (sts == PM_ERR_IPC)
+ 	    cp->setup = 0;
+ 	if (pmDebugOptions.series)
+-	    fprintf(stderr, "failed to lookup metric %s descriptor: %s",
++	    fprintf(stderr, "%s: failed to lookup metric %s descriptor: %s\n",
++		    "pmwebapi_new_pmid",
+ 		    pmIDStr_r(pmid, buffer, sizeof(buffer)),
+ 		    pmErrStr_r(sts, errmsg, sizeof(errmsg)));
+     } else if ((numnames = sts = pmNameAll(pmid, &names)) < 0) {
+ 	if (sts == PM_ERR_IPC)
+ 	    cp->setup = 0;
+ 	if (pmDebugOptions.series)
+-	    fprintf(stderr, "failed to lookup metric %s names: %s",
++	    fprintf(stderr, "%s: failed to lookup metric %s names: %s\n",
++		    "pmwebapi_new_pmid",
+ 		    pmIDStr_r(pmid, buffer, sizeof(buffer)),
+ 		    pmErrStr_r(sts, errmsg, sizeof(errmsg)));
+     } else {
+diff -Naurp pcp-5.0.2.orig/src/pmproxy/pmproxy.conf pcp-5.0.2/src/pmproxy/pmproxy.conf
+--- pcp-5.0.2.orig/src/pmproxy/pmproxy.conf	2019-08-09 15:50:17.000000000 +1000
++++ pcp-5.0.2/src/pmproxy/pmproxy.conf	2020-02-03 13:36:03.948721355 +1100
+@@ -43,6 +43,11 @@ secure.enabled = true
+ # propogate archives from pmlogger(1) into Redis querying
+ enabled = true
+ 
++# metrics name regex to skip during discovery (eg due to high volume)
++exclude.metrics = proc.*
++
++# comma-separated list of instance domains to skip during discovery
++exclude.indoms = 3.9,79.7
+ 
+ #####################################################################
+ ## settings for fast, scalable time series quering via Redis
+diff -Naurp pcp-5.0.2.orig/src/pmproxy/src/redis.c pcp-5.0.2/src/pmproxy/src/redis.c
+--- pcp-5.0.2.orig/src/pmproxy/src/redis.c	2019-12-02 16:39:33.000000000 +1100
++++ pcp-5.0.2/src/pmproxy/src/redis.c	2020-02-03 13:36:13.585620539 +1100
+@@ -145,11 +145,11 @@ setup_redis_module(struct proxy *proxy)
+ 	proxy->slots = redisSlotsConnect(proxy->config,
+ 			flags, proxylog, on_redis_connected,
+ 			proxy, proxy->events, proxy);
+-	if (archive_discovery)
++	if (archive_discovery && series_queries)
+ 	    pmDiscoverSetSlots(&redis_discover.module, proxy->slots);
+     }
+ 
+-    if (archive_discovery) {
++    if (archive_discovery && series_queries) {
+ 	pmDiscoverSetEventLoop(&redis_discover.module, proxy->events);
+ 	pmDiscoverSetConfiguration(&redis_discover.module, proxy->config);
+ 	pmDiscoverSetMetricRegistry(&redis_discover.module, metric_registry);
diff --git a/SOURCES/multilib-pcp-devel.patch b/SOURCES/multilib-pcp-devel.patch
new file mode 100644
index 0000000..74bfaf3
--- /dev/null
+++ b/SOURCES/multilib-pcp-devel.patch
@@ -0,0 +1,22 @@
+commit 43cc36abff0fbaa5b5b434ca17b4b74f45dad98a
+Author: Nathan Scott <nathans@redhat.com>
+Date:   Thu Jan 9 16:01:18 2020 +1100
+
+    build: ensure generated demo Makefile matches on 32/64 Linux
+    
+    This corrects a multilib issue with the pcp-devel RPMs.
+    Resolves Red Hat bugzilla #1788119
+
+diff --git a/src/pmdas/trace/GNUmakefile b/src/pmdas/trace/GNUmakefile
+index b7087d017..b5e0589ad 100644
+--- a/src/pmdas/trace/GNUmakefile
++++ b/src/pmdas/trace/GNUmakefile
+@@ -101,7 +101,7 @@ MY_INC_DIR	= -I$(PCP_INC_DIR)/..
+ else
+ MY_INC_DIR	=
+ endif
+-ifneq "$(PCP_LIB_DIR)" "/usr/lib"
++ifeq "$(findstring $(PCP_LIB_DIR), /usr/lib /usr/lib64)" ""
+ # for ld add -L<run-time-lib-dir> and include -rpath when
+ # $(PCP_LIB_DIR) may not be on the default ld search path.
+ #
diff --git a/SOURCES/s390x-interrupts.patch b/SOURCES/s390x-interrupts.patch
new file mode 100644
index 0000000..6a1bb59
--- /dev/null
+++ b/SOURCES/s390x-interrupts.patch
@@ -0,0 +1,108 @@
+commit 04be64dc8a08203decc6fe206700dcb1f06c8d79
+Author: Nathan Scott <nathans@redhat.com>
+Date:   Mon Feb 24 17:28:48 2020 +1100
+
+    pmdalinux: fix interrupts file parser for s390x /proc/interrupts layout
+    
+    The s390x interrupts file produced by the kernel was causing a failure
+    in pmdalinux because the code expected first numeric interrupt lines &
+    then named (text) lines, whereas on this platform they're intermixed.
+    
+    Add a sample interrupts file from these kernels for qa/886 to test.
+    
+    Resolves Red Hat BZ #1798058
+
+diff --git a/qa/886.out.bz2 b/qa/886.out.bz2
+index 59bfae0e2..8db30e566 100644
+Binary files a/qa/886.out.bz2 and b/qa/886.out.bz2 differ
+diff --git a/qa/linux/interrupts-16cpu-s390x b/qa/linux/interrupts-16cpu-s390x
+new file mode 100644
+index 000000000..574dec6b0
+--- /dev/null
++++ b/qa/linux/interrupts-16cpu-s390x
+@@ -0,0 +1,59 @@
++           CPU0       CPU1       CPU2       CPU3       CPU4       CPU5       CPU6       CPU7       CPU8       CPU9       CPU10      CPU11      CPU12      CPU13      CPU14      CPU15      
++EXT:      30368       5872      22695      18176      19463       5347      21306      15838      21533       6333      32165       7468      23182       5010      28665       6909 
++I/O:        675        559        764        682        764        631        646        645        822        909        464        463        645        653        574        377 
++AIO:         39         32        101        122         58         67         87         65        156        145         33         50         64         51         48         34 
++  3:          6          4         43         44         13         22         37         26         64         55         11         29         20         15         10          7   PCI-MSI  mlx5_async@pci:0002:00:00.0
++  4:          0          0          0          1          0          0          0          0          0          0          0          0          0          0          0          0   PCI-MSI  mlx5_comp0@pci:0002:00:00.0
++  5:          0          0          0          0          0          0          0          0          0          0          0          1          0          0          0          0   PCI-MSI  mlx5_comp1@pci:0002:00:00.0
++  6:          0          0          0          0          0          0          0          0          0          0          0          0          1          0          0          0   PCI-MSI  mlx5_comp2@pci:0002:00:00.0
++  7:          0          0          0          0          0          1          0          0          0          0          0          0          0          0          0          0   PCI-MSI  mlx5_comp3@pci:0002:00:00.0
++  8:          0          0          0          0          0          0          0          0          0          1          0          0          0          0          0          0   PCI-MSI  mlx5_comp4@pci:0002:00:00.0
++  9:          0          0          0          0          0          0          0          0          0          0          0          0          0          1          0          0   PCI-MSI  mlx5_comp5@pci:0002:00:00.0
++ 10:          0          0          0          0          0          0          0          0          0          0          0          0          0          1          0          0   PCI-MSI  mlx5_comp6@pci:0002:00:00.0
++ 11:          0          0          1          0          0          0          0          0          0          0          0          0          0          0          0          0   PCI-MSI  mlx5_comp7@pci:0002:00:00.0
++ 12:          0          0          0          0          0          0          0          0          0          0          1          0          0          0          0          0   PCI-MSI  mlx5_comp8@pci:0002:00:00.0
++ 13:         15         11         39         49         24         25         18         13         64         64          3         12         27         13         22          7   PCI-MSI  mlx5_async@pci:0003:00:00.0
++ 14:          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          1   PCI-MSI  mlx5_comp0@pci:0003:00:00.0
++ 15:          0          0          0          1          0          0          0          0          0          0          0          0          0          0          0          0   PCI-MSI  mlx5_comp1@pci:0003:00:00.0
++ 16:          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          1   PCI-MSI  mlx5_comp2@pci:0003:00:00.0
++ 17:          0          0          0          0          0          0          0          0          0          0          0          0          0          0          1          0   PCI-MSI  mlx5_comp3@pci:0003:00:00.0
++ 18:          0          0          0          0          0          0          1          0          0          0          0          0          0          0          0          0   PCI-MSI  mlx5_comp4@pci:0003:00:00.0
++ 19:          0          0          0          0          0          0          0          0          0          0          0          0          1          0          0          0   PCI-MSI  mlx5_comp5@pci:0003:00:00.0
++ 20:          0          0          0          0          1          0          0          0          0          0          0          0          0          0          0          0   PCI-MSI  mlx5_comp6@pci:0003:00:00.0
++ 21:          0          0          0          0          0          0          0          0          0          0          0          1          0          0          0          0   PCI-MSI  mlx5_comp7@pci:0003:00:00.0
++ 22:          0          0          0          0          0          0          0          0          0          0          0          0          0          1          0          0   PCI-MSI  mlx5_comp8@pci:0003:00:00.0
++ 23:          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   PCI-MSI  0000:00:00.0
++ 24:          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   PCI-MSI  0001:00:00.0
++CLK:       2876       2246       9129      14527       2478       1653       2830       3374       8696       1867      12976       3002       2341       1935       3066       3063   [EXT] Clock Comparator
++EXC:      27474       3626      13527       3649      16970       3694      18487      12464      12834       4466      19188       4466      20848       3077      25599       3846   [EXT] External Call
++EMS:          0          0          0          1          0          0          0          0          0          0          0          0          0          0          0          0   [EXT] Emergency Signal
++TMR:          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   [EXT] CPU Timer
++TAL:          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   [EXT] Timing Alert
++PFL:          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   [EXT] Pseudo Page Fault
++DSD:          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   [EXT] DASD Diag
++VRT:          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   [EXT] Virtio
++SCP:         18          0         39          0         15          0          5          0          3          0          1          0          0          0          0          0   [EXT] Service Call
++IUC:          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   [EXT] IUCV
++CMS:          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   [EXT] CPU-Measurement: Sampling
++CMC:          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   [EXT] CPU-Measurement: Counter
++FTP:          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   [EXT] HMC FTP Service
++CIO:         62         57         80         90        101         81         91         81         93        112         59         46         70         97         46         37   [I/O] Common I/O Layer Interrupt
++DAS:        613        502        684        592        663        550        555        564        729        797        405        417        575        556        528        340   [I/O] DASD
++C15:          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   [I/O] 3215
++C70:          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   [I/O] 3270
++TAP:          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   [I/O] Tape
++VMR:          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   [I/O] Unit Record Devices
++LCS:          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   [I/O] LCS
++CTC:          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   [I/O] CTC
++ADM:          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   [I/O] EADM Subchannel
++CSC:          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   [I/O] CHSC Subchannel
++VIR:          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   [I/O] Virtual I/O Devices
++QAI:         18         17         18         27         20         20         31         26         28         25         18          7         15         20         15         18   [AIO] QDIO Adapter Interrupt
++APB:          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   [AIO] AP Bus
++PCF:         21         15         83         95         38         48         56         39        128        120         15         43         49         31         33         16   [AIO] PCI Floating Interrupt
++PCD:          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   [AIO] PCI Directed Interrupt
++MSI:         21         15         83         95         38         48         56         39        128        120         15         43         49         31         33         16   [AIO] MSI Interrupt
++VAI:          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   [AIO] Virtual I/O Devices AI
++GAL:          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   [AIO] GIB Alert
++NMI:          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0          0   [NMI] Machine Check
++RST:          0          1          1          1          1          1          1          1          1          1          1          1          1          1          1          1   [CPU] CPU Restart
+diff --git a/src/pmdas/linux/interrupts.c b/src/pmdas/linux/interrupts.c
+index f8a4d9b1b..f57af9e43 100644
+--- a/src/pmdas/linux/interrupts.c
++++ b/src/pmdas/linux/interrupts.c
+@@ -456,7 +456,9 @@ refresh_interrupt_values(void)
+     while (fgets(iobuf, iobufsz, fp) != NULL) {
+ 	iobuf[iobufsz - 1] = '\0';
+ 	/* next we parse each interrupt line row (starting with a digit) */
+-	sts = extract_interrupt_lines(iobuf, ncolumns, i++);
++	sts = extract_interrupt_lines(iobuf, ncolumns, i);
++	if (sts > 0)
++	    i++;
+ 	if (sts > 1)
+ 	    resized++;
+ 	if (sts)
+@@ -466,7 +468,9 @@ refresh_interrupt_values(void)
+ 	if (extract_interrupt_misses(iobuf))
+ 	    continue;
+ 	/* parse other per-CPU interrupt counter rows (starts non-digit) */
+-	sts = extract_interrupt_other(iobuf, ncolumns, j++);
++	sts = extract_interrupt_other(iobuf, ncolumns, j);
++	if (sts > 0)
++	    j++;
+ 	if (sts > 1)
+ 	    resized++;
+ 	if (!sts)
diff --git a/SPECS/pcp.spec b/SPECS/pcp.spec
new file mode 100644
index 0000000..e2c345d
--- /dev/null
+++ b/SPECS/pcp.spec
@@ -0,0 +1,3672 @@
+Name:    pcp
+Version: 5.0.2
+Release: 5%{?dist}
+Summary: System-level performance monitoring and performance management
+License: GPLv2+ and LGPLv2+ and CC-BY
+URL:     https://pcp.io
+
+%global  bintray https://bintray.com/artifact/download
+Source0: %{bintray}/pcp/source/pcp-%{version}.src.tar.gz
+
+# RHBZ 1788119
+Patch1:  multilib-pcp-devel.patch
+# RHBZ 1785560
+Patch2:  archive-discovery.patch
+# RHBZ 1788881
+Patch3:  activemq-modules.patch
+# RHBZ 1798058
+Patch4:  s390x-interrupts.patch
+
+%if 0%{?fedora} >= 26 || 0%{?rhel} > 7
+%global __python2 python2
+%else
+%global __python2 python
+%endif
+
+%if 0%{?fedora} || 0%{?rhel} > 5
+%global disable_selinux 0
+%else
+%global disable_selinux 1
+%endif
+
+%global disable_snmp 0
+
+# No libpfm devel packages for s390, armv7hl nor for some rhels, disable
+%ifarch s390 s390x armv7hl
+%global disable_perfevent 1
+%else
+%if 0%{?fedora} >= 20 || 0%{?rhel} > 6
+%global disable_perfevent 0
+%else
+%global disable_perfevent 1
+%endif
+%endif
+
+# libvarlink and pmdapodman
+%if 0%{?fedora} >= 28 || 0%{?rhel} > 7
+%global disable_podman 0
+%else
+%global disable_podman 1
+%endif
+
+# libchan, libhdr_histogram and pmdastatsd
+%if 0%{?fedora} >= 29 || 0%{?rhel} > 8
+%global disable_statsd 0
+%else
+%global disable_statsd 1
+%endif
+
+%if 0%{?fedora} >= 30 || 0%{?rhel} > 7
+%global _with_python2 --with-python=no
+%global disable_python2 1
+%else
+%global disable_python2 0
+%endif
+
+# Default for epel5 is python24, so use the (optional) python26 packages
+%if 0%{?rhel} == 5
+%global default_python 26
+%endif
+# No python3 development environment before el8
+%if 0%{?rhel} == 0 || 0%{?rhel} > 7
+%global disable_python3 0
+# Do we wish to mandate python3 use in pcp?  (f22+ and el8+)
+%if 0%{?fedora} >= 22 || 0%{?rhel} > 7
+%global default_python 3
+%endif
+%else
+%global disable_python3 1
+%endif
+
+%if 0%{?fedora} >= 24 || 0%{?rhel} > 7
+%global perl_interpreter perl-interpreter
+%else
+%global perl_interpreter perl
+%endif
+
+# support for pmdabcc, check bcc.spec for supported architectures of bcc
+%if 0%{?fedora} >= 25 || 0%{?rhel} > 6
+%ifarch x86_64 %{power64} aarch64 s390x
+%global disable_bcc 0
+%else
+%global disable_bcc 1
+%endif
+%else
+%global disable_bcc 1
+%endif
+
+# support for pmdabpftrace, check bpftrace.spec for supported architectures of bpftrace
+%if 0%{?fedora} >= 30 || 0%{?rhel} > 7
+%ifarch x86_64 %{power64} aarch64 s390x
+%global disable_bpftrace 0
+%else
+%global disable_bpftrace 1
+%endif
+%else
+%global disable_bpftrace 1
+%endif
+
+# support for pmdajson
+%if 0%{?rhel} == 0 || 0%{?rhel} > 6
+%if !%{disable_python2} || !%{disable_python3}
+%global disable_json 0
+%else
+%global disable_json 1
+%endif
+%else
+%global disable_json 1
+%endif
+
+# No mssql ODBC driver on non-x86 platforms
+%ifarch x86_64
+%if !%{disable_python2} || !%{disable_python3}
+%global disable_mssql 0
+%else
+%global disable_mssql 1
+%endif
+%else
+%global disable_mssql 1
+%endif
+
+# support for pmdanutcracker (perl deps missing on rhel)
+%if 0%{?rhel} == 0
+%global disable_nutcracker 0
+%else
+%global disable_nutcracker 1
+%endif
+
+# support for pmdarpm
+%if 0%{?rhel} == 0 || 0%{?rhel} > 5
+%global disable_rpm 0
+%else
+%global disable_rpm 1
+%endif
+
+# Qt development and runtime environment missing components before el6
+%if 0%{?rhel} == 0 || 0%{?rhel} > 5
+%global disable_qt 0
+%if 0%{?fedora} != 0 || 0%{?rhel} > 7
+%global default_qt 5
+%endif
+%else
+%global disable_qt 1
+%endif
+
+# systemd services and pmdasystemd
+%if 0%{?fedora} >= 19 || 0%{?rhel} >= 7
+%global disable_systemd 0
+%else
+%global disable_systemd 1
+%endif
+
+# static probes, missing before el6 and on some architectures
+%if 0%{?rhel} == 0 || 0%{?rhel} > 5
+%global disable_sdt 0
+%else
+%ifnarch ppc ppc64
+%global disable_sdt 0
+%else
+%global disable_sdt 1
+%endif
+%endif
+
+# libuv async event library
+%if 0%{?fedora} >= 28 || 0%{?rhel} > 7
+%global disable_libuv 0
+%else
+%global disable_libuv 1
+%endif
+
+%global disable_openssl 0
+
+# rpm producing "noarch" packages
+%if 0%{?rhel} == 0 || 0%{?rhel} > 5
+%global disable_noarch 0
+%else
+%global disable_noarch 1
+%endif
+
+%if 0%{?fedora} >= 24
+%global disable_xlsx 0
+%else
+%global disable_xlsx 1
+%endif
+
+# prevent conflicting binary and man page install for pcp(1)
+Conflicts: librapi < 0.16
+
+# KVM PMDA moved into pcp (no longer using Perl, default on)
+Obsoletes: pcp-pmda-kvm < 4.1.1
+Provides: pcp-pmda-kvm
+
+# PCP REST APIs are now provided by pmproxy
+Obsoletes: pcp-webapi-debuginfo < 5.0.0
+Obsoletes: pcp-webapi < 5.0.0
+Provides: pcp-webapi
+
+# https://fedoraproject.org/wiki/Packaging "C and C++"
+BuildRequires: gcc gcc-c++
+BuildRequires: procps autoconf bison flex
+BuildRequires: nss-devel
+BuildRequires: rpm-devel
+BuildRequires: avahi-devel
+BuildRequires: xz-devel
+BuildRequires: zlib-devel
+%if !%{disable_python2}
+%if 0%{?default_python} != 3
+BuildRequires: python%{?default_python}-devel
+%else
+BuildRequires: %{__python2}-devel
+%endif
+%endif
+%if !%{disable_python3}
+BuildRequires: python3-devel
+%endif
+BuildRequires: ncurses-devel
+BuildRequires: readline-devel
+BuildRequires: cyrus-sasl-devel
+%if !%{disable_podman}
+BuildRequires: libvarlink-devel
+%endif
+%if !%{disable_statsd}
+BuildRequires: ragel chan-devel HdrHistogram_c-devel
+%endif
+%if !%{disable_perfevent}
+BuildRequires: libpfm-devel >= 4
+%endif
+%if !%{disable_sdt}
+BuildRequires: systemtap-sdt-devel
+%endif
+%if !%{disable_libuv}
+BuildRequires: libuv-devel >= 1.0
+%endif
+%if !%{disable_openssl}
+BuildRequires: openssl-devel >= 1.1.1
+%endif
+%if 0%{?rhel} == 0 || 0%{?rhel} > 7
+BuildRequires: perl-generators
+%endif
+BuildRequires: perl-devel perl(strict)
+BuildRequires: perl(ExtUtils::MakeMaker) perl(LWP::UserAgent) perl(JSON)
+BuildRequires: perl(LWP::UserAgent) perl(Time::HiRes) perl(Digest::MD5)
+BuildRequires: man hostname
+%if !%{disable_systemd}
+BuildRequires: systemd-devel
+%endif
+%if !%{disable_qt}
+BuildRequires: desktop-file-utils
+%if 0%{?default_qt} != 5
+BuildRequires: qt4-devel >= 4.4
+%else
+BuildRequires: qt5-qtbase-devel
+BuildRequires: qt5-qtsvg-devel
+%endif
+%endif
+
+Requires: bash xz gawk sed grep findutils which hostname
+Requires: pcp-libs = %{version}-%{release}
+%if !%{disable_selinux}
+Requires: pcp-selinux = %{version}-%{release}
+%endif
+
+# Some older releases did not update or replace pcp-gui-debuginfo properly
+%if 0%{?fedora} < 27 && 0%{?rhel} <= 7 && "%{_vendor}" == "redhat"
+Obsoletes: pcp-gui-debuginfo < 4.1.1
+%endif
+
+Obsoletes: pcp-compat < 4.2.0
+Obsoletes: pcp-monitor < 4.2.0
+Obsoletes: pcp-collector < 4.2.0
+Obsoletes: pcp-pmda-nvidia < 3.10.5
+
+Requires: pcp-libs = %{version}-%{release}
+
+%global _confdir	%{_sysconfdir}/pcp
+%global _logsdir	%{_localstatedir}/log/pcp
+%global _pmnsdir	%{_localstatedir}/lib/pcp/pmns
+%global _tempsdir	%{_localstatedir}/lib/pcp/tmp
+%global _pmdasdir	%{_localstatedir}/lib/pcp/pmdas
+%global _testsdir	%{_localstatedir}/lib/pcp/testsuite
+%global _selinuxdir	%{_localstatedir}/lib/pcp/selinux
+%global _logconfdir	%{_localstatedir}/lib/pcp/config/pmlogconf
+%global _ieconfdir	%{_localstatedir}/lib/pcp/config/pmieconf
+%global _tapsetdir	%{_datadir}/systemtap/tapset
+%global _bashcompdir	%{_datadir}/bash-completion/completions
+%global _pixmapdir	%{_datadir}/pcp-gui/pixmaps
+%global _hicolordir	%{_datadir}/icons/hicolor
+%global _booksdir	%{_datadir}/doc/pcp-doc
+
+%if 0%{?fedora} >= 20 || 0%{?rhel} >= 8
+%global _with_doc --with-docdir=%{_docdir}/%{name}
+%endif
+
+%if 0%{?fedora} >= 29 || 0%{?rhel} >= 8
+%global _with_dstat --with-dstat-symlink=yes
+%global disable_dstat 0
+%else
+%global _with_dstat --with-dstat-symlink=no
+%global disable_dstat 1
+%endif
+
+%if !%{disable_systemd}
+%global _initddir %{_datadir}/pcp/lib
+%else
+%global _initddir %{_sysconfdir}/rc.d/init.d
+%global _with_initd --with-rcdir=%{_initddir}
+%endif
+
+# we never want Infiniband on s390 and armv7hl platforms
+%ifarch s390 s390x armv7hl
+%global disable_infiniband 1
+%else
+# we never want Infiniband on RHEL5 or earlier
+%if 0%{?rhel} != 0 && 0%{?rhel} < 6
+%global disable_infiniband 1
+%else
+%global disable_infiniband 0
+%endif
+%endif
+
+%if !%{disable_infiniband}
+%global _with_ib --with-infiniband=yes
+%endif
+
+%if %{disable_perfevent}
+%global _with_perfevent --with-perfevent=no
+%else
+%global _with_perfevent --with-perfevent=yes
+%endif
+
+%if %{disable_podman}
+%global _with_podman --with-podman=no
+%else
+%global _with_podman --with-podman=yes
+%endif
+
+%if %{disable_statsd}
+%global _with_statsd --with-statsd=no
+%else
+%global _with_statsd --with-statsd=yes
+%endif
+
+%if %{disable_bcc}
+%global _with_bcc --with-pmdabcc=no
+%else
+%global _with_bcc --with-pmdabcc=yes
+%endif
+
+%if %{disable_bpftrace}
+%global _with_bpftrace --with-pmdabpftrace=no
+%else
+%global _with_bpftrace --with-pmdabpftrace=yes
+%endif
+
+%if %{disable_json}
+%global _with_json --with-pmdajson=no
+%else
+%global _with_json --with-pmdajson=yes
+%endif
+
+%if %{disable_nutcracker}
+%global _with_nutcracker --with-pmdanutcracker=no
+%else
+%global _with_nutcracker --with-pmdanutcracker=yes
+%endif
+
+%if %{disable_snmp}
+%global _with_snmp --with-pmdasnmp=no
+%else
+%global _with_snmp --with-pmdasnmp=yes
+%endif
+
+%global pmda_remove() %{expand:
+if [ %1 -eq 0 ]
+then
+    PCP_PMDAS_DIR=%{_pmdasdir}
+    PCP_PMCDCONF_PATH=%{_confdir}/pmcd/pmcd.conf
+    if [ -f "$PCP_PMCDCONF_PATH" -a -f "$PCP_PMDAS_DIR/%2/domain.h" ]
+    then
+	(cd "$PCP_PMDAS_DIR/%2/" && ./Remove >/dev/null 2>&1)
+    fi
+fi
+}
+
+%global selinux_handle_policy() %{expand:
+if [ %1 -ge 1 ]
+then
+    %{_libexecdir}/pcp/bin/selinux-setup %{_selinuxdir} install %2
+elif [ %1 -eq 0 ]
+then
+    %{_libexecdir}/pcp/bin/selinux-setup %{_selinuxdir} remove %2
+fi
+}
+
+%description
+Performance Co-Pilot (PCP) provides a framework and services to support
+system-level performance monitoring and performance management.
+
+The PCP open source release provides a unifying abstraction for all of
+the interesting performance data in a system, and allows client
+applications to easily retrieve and process any subset of that data.
+
+#
+# pcp-conf
+#
+%package conf
+License: LGPLv2+
+Summary: Performance Co-Pilot run-time configuration
+URL: https://pcp.io
+
+# http://fedoraproject.org/wiki/Packaging:Conflicts "Splitting Packages"
+Conflicts: pcp-libs < 3.9
+
+%description conf
+Performance Co-Pilot (PCP) run-time configuration
+
+#
+# pcp-libs
+#
+%package libs
+License: LGPLv2+
+Summary: Performance Co-Pilot run-time libraries
+URL: https://pcp.io
+Requires: pcp-conf = %{version}-%{release}
+
+%description libs
+Performance Co-Pilot (PCP) run-time libraries
+
+#
+# pcp-libs-devel
+#
+%package libs-devel
+License: GPLv2+ and LGPLv2+
+Summary: Performance Co-Pilot (PCP) development headers
+URL: https://pcp.io
+Requires: pcp = %{version}-%{release} pcp-libs = %{version}-%{release}
+
+%description libs-devel
+Performance Co-Pilot (PCP) headers for development.
+
+#
+# pcp-devel
+#
+%package devel
+License: GPLv2+ and LGPLv2+
+Summary: Performance Co-Pilot (PCP) development tools and documentation
+URL: https://pcp.io
+Requires: pcp = %{version}-%{release}
+Requires: pcp-libs = %{version}-%{release}
+Requires: pcp-libs-devel = %{version}-%{release}
+
+%description devel
+Performance Co-Pilot (PCP) documentation and tools for development.
+
+#
+# pcp-testsuite
+#
+%package testsuite
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) test suite
+URL: https://pcp.io
+Requires: pcp = %{version}-%{release}
+Requires: pcp-libs = %{version}-%{release}
+Requires: pcp-libs-devel = %{version}-%{release}
+Requires: pcp-devel = %{version}-%{release}
+Obsoletes: pcp-gui-testsuite < 3.9.5
+# The following are inherited from pcp-collector and pcp-monitor,
+# both of which are now obsoleted by the base pcp package
+Requires: pcp-pmda-activemq pcp-pmda-bonding pcp-pmda-dbping pcp-pmda-ds389 pcp-pmda-ds389log
+Requires: pcp-pmda-elasticsearch pcp-pmda-gpfs pcp-pmda-gpsd pcp-pmda-lustre
+Requires: pcp-pmda-memcache pcp-pmda-mysql pcp-pmda-named pcp-pmda-netfilter pcp-pmda-news
+Requires: pcp-pmda-nginx pcp-pmda-nfsclient pcp-pmda-pdns pcp-pmda-postfix pcp-pmda-postgresql pcp-pmda-oracle
+Requires: pcp-pmda-samba pcp-pmda-slurm pcp-pmda-vmware pcp-pmda-zimbra
+Requires: pcp-pmda-dm pcp-pmda-apache
+Requires: pcp-pmda-bash pcp-pmda-cisco pcp-pmda-gfs2 pcp-pmda-mailq pcp-pmda-mounts
+Requires: pcp-pmda-nvidia-gpu pcp-pmda-roomtemp pcp-pmda-sendmail pcp-pmda-shping pcp-pmda-smart
+Requires: pcp-pmda-lustrecomm pcp-pmda-logger pcp-pmda-docker pcp-pmda-bind2
+%if !%{disable_podman}
+Requires: pcp-pmda-podman
+%endif
+%if !%{disable_statsd}
+Requires: pcp-pmda-statsd
+%endif
+%if !%{disable_nutcracker}
+Requires: pcp-pmda-nutcracker
+%endif
+%if !%{disable_bcc}
+Requires: pcp-pmda-bcc
+%endif
+%if !%{disable_bpftrace}
+Requires: pcp-pmda-bpftrace
+%endif
+%if !%{disable_python2} || !%{disable_python3}
+Requires: pcp-pmda-gluster pcp-pmda-zswap pcp-pmda-unbound pcp-pmda-mic
+Requires: pcp-pmda-libvirt pcp-pmda-lio pcp-pmda-openmetrics pcp-pmda-haproxy
+Requires: pcp-pmda-lmsensors pcp-pmda-netcheck
+%endif
+%if !%{disable_mssql}
+Requires: pcp-pmda-mssql
+%endif
+%if !%{disable_snmp}
+Requires: pcp-pmda-snmp
+%endif
+%if !%{disable_json}
+Requires: pcp-pmda-json
+%endif
+%if !%{disable_rpm}
+Requires: pcp-pmda-rpm
+%endif
+Requires: pcp-pmda-summary pcp-pmda-trace pcp-pmda-weblog
+%if !%{disable_python2} || !%{disable_python3}
+Requires: pcp-system-tools
+%endif
+%if !%{disable_qt}
+Requires: pcp-gui
+%endif
+Requires: bc gcc gzip bzip2
+Requires: redhat-rpm-config
+
+%description testsuite
+Quality assurance test suite for Performance Co-Pilot (PCP).
+# end testsuite
+
+#
+# pcp-manager
+#
+%package manager
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) manager daemon
+URL: https://pcp.io
+Requires: pcp = %{version}-%{release} pcp-libs = %{version}-%{release}
+
+%description manager
+An optional daemon (pmmgr) that manages a collection of pmlogger and
+pmie daemons, for a set of discovered local and remote hosts running
+the performance metrics collection daemon (pmcd).  It ensures these
+daemons are running when appropriate, and manages their log rotation
+needs.  It is an alternative to the cron-based pmlogger/pmie service
+scripts.
+
+#
+# perl-PCP-PMDA. This is the PCP agent perl binding.
+#
+%package -n perl-PCP-PMDA
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) Perl bindings and documentation
+URL: https://pcp.io
+Requires: pcp-libs = %{version}-%{release}
+Requires: %{perl_interpreter}
+
+%description -n perl-PCP-PMDA
+The PCP::PMDA Perl module contains the language bindings for
+building Performance Metric Domain Agents (PMDAs) using Perl.
+Each PMDA exports performance data for one specific domain, for
+example the operating system kernel, Cisco routers, a database,
+an application, etc.
+
+#
+# perl-PCP-MMV
+#
+%package -n perl-PCP-MMV
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) Perl bindings for PCP Memory Mapped Values
+URL: https://pcp.io
+Requires: pcp-libs = %{version}-%{release}
+Requires: %{perl_interpreter}
+
+%description -n perl-PCP-MMV
+The PCP::MMV module contains the Perl language bindings for
+building scripts instrumented with the Performance Co-Pilot
+(PCP) Memory Mapped Value (MMV) mechanism.
+This mechanism allows arbitrary values to be exported from an
+instrumented script into the PCP infrastructure for monitoring
+and analysis with pmchart, pmie, pmlogger and other PCP tools.
+
+#
+# perl-PCP-LogImport
+#
+%package -n perl-PCP-LogImport
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) Perl bindings for importing external data into PCP archives
+URL: https://pcp.io
+Requires: pcp-libs = %{version}-%{release}
+Requires: %{perl_interpreter}
+
+%description -n perl-PCP-LogImport
+The PCP::LogImport module contains the Perl language bindings for
+importing data in various 3rd party formats into PCP archives so
+they can be replayed with standard PCP monitoring tools.
+
+#
+# perl-PCP-LogSummary
+#
+%package -n perl-PCP-LogSummary
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) Perl bindings for post-processing output of pmlogsummary
+URL: https://pcp.io
+Requires: pcp-libs = %{version}-%{release}
+Requires: %{perl_interpreter}
+
+%description -n perl-PCP-LogSummary
+The PCP::LogSummary module provides a Perl module for using the
+statistical summary data produced by the Performance Co-Pilot
+pmlogsummary utility.  This utility produces various averages,
+minima, maxima, and other calculations based on the performance
+data stored in a PCP archive.  The Perl interface is ideal for
+exporting this data into third-party tools (e.g. spreadsheets).
+
+#
+# pcp-import-sar2pcp
+#
+%package import-sar2pcp
+License: LGPLv2+
+Summary: Performance Co-Pilot tools for importing sar data into PCP archive logs
+URL: https://pcp.io
+Requires: pcp-libs = %{version}-%{release}
+Requires: perl-PCP-LogImport = %{version}-%{release}
+Requires: perl(XML::TokeParser)
+
+%description import-sar2pcp
+Performance Co-Pilot (PCP) front-end tools for importing sar data
+into standard PCP archive logs for replay with any PCP monitoring tool.
+
+#
+# pcp-import-iostat2pcp
+#
+%package import-iostat2pcp
+License: LGPLv2+
+Summary: Performance Co-Pilot tools for importing iostat data into PCP archive logs
+URL: https://pcp.io
+Requires: pcp-libs = %{version}-%{release}
+Requires: perl-PCP-LogImport = %{version}-%{release}
+
+%description import-iostat2pcp
+Performance Co-Pilot (PCP) front-end tools for importing iostat data
+into standard PCP archive logs for replay with any PCP monitoring tool.
+
+#
+# pcp-import-mrtg2pcp
+#
+%package import-mrtg2pcp
+License: LGPLv2+
+Summary: Performance Co-Pilot tools for importing MTRG data into PCP archive logs
+URL: https://pcp.io
+Requires: pcp-libs = %{version}-%{release}
+Requires: perl-PCP-LogImport = %{version}-%{release}
+
+%description import-mrtg2pcp
+Performance Co-Pilot (PCP) front-end tools for importing MTRG data
+into standard PCP archive logs for replay with any PCP monitoring tool.
+
+#
+# pcp-import-ganglia2pcp
+#
+%package import-ganglia2pcp
+License: LGPLv2+
+Summary: Performance Co-Pilot tools for importing ganglia data into PCP archive logs
+URL: https://pcp.io
+Requires: pcp-libs = %{version}-%{release}
+Requires: perl-PCP-LogImport = %{version}-%{release}
+
+%description import-ganglia2pcp
+Performance Co-Pilot (PCP) front-end tools for importing ganglia data
+into standard PCP archive logs for replay with any PCP monitoring tool.
+
+#
+# pcp-import-collectl2pcp
+#
+%package import-collectl2pcp
+License: LGPLv2+
+Summary: Performance Co-Pilot tools for importing collectl log files into PCP archive logs
+URL: https://pcp.io
+Requires: pcp-libs = %{version}-%{release}
+
+%description import-collectl2pcp
+Performance Co-Pilot (PCP) front-end tools for importing collectl data
+into standard PCP archive logs for replay with any PCP monitoring tool.
+
+#
+# pcp-export-zabbix-agent
+#
+%package export-zabbix-agent
+License: GPLv2+
+Summary: Module for exporting PCP metrics to Zabbix agent
+URL: https://pcp.io
+Requires: pcp-libs = %{version}-%{release}
+
+%description export-zabbix-agent
+Performance Co-Pilot (PCP) module for exporting metrics from PCP to
+Zabbix via the Zabbix agent - see zbxpcp(3) for further details.
+
+%if !%{disable_python2} || !%{disable_python3}
+#
+# pcp-export-pcp2elasticsearch
+#
+%package export-pcp2elasticsearch
+License: GPLv2+
+Summary: Performance Co-Pilot tools for exporting PCP metrics to ElasticSearch
+URL: https://pcp.io
+Requires: pcp-libs >= %{version}-%{release}
+%if !%{disable_python3}
+Requires: python3-pcp = %{version}-%{release}
+Requires: python3-requests
+BuildRequires: python3-requests
+%else
+Requires: %{__python2}-pcp = %{version}-%{release}
+Requires: %{__python2}-requests
+BuildRequires: %{__python2}-requests
+%endif
+
+%description export-pcp2elasticsearch
+Performance Co-Pilot (PCP) front-end tools for exporting metric values
+to Elasticsearch - a distributed, RESTful search and analytics engine.
+See https://www.elastic.co/community for further details.
+
+#
+# pcp-export-pcp2graphite
+#
+%package export-pcp2graphite
+License: GPLv2+
+Summary: Performance Co-Pilot tools for exporting PCP metrics to Graphite
+URL: https://pcp.io
+Requires: pcp-libs >= %{version}-%{release}
+%if !%{disable_python3}
+Requires: python3-pcp = %{version}-%{release}
+%else
+Requires: %{__python2}-pcp = %{version}-%{release}
+%endif
+
+%description export-pcp2graphite
+Performance Co-Pilot (PCP) front-end tools for exporting metric values
+to graphite (http://graphite.readthedocs.org).
+
+# pcp-export-pcp2influxdb
+#
+%package export-pcp2influxdb
+License: GPLv2+
+Summary: Performance Co-Pilot tools for exporting PCP metrics to InfluxDB
+URL: https://pcp.io
+Requires: pcp-libs >= %{version}-%{release}
+%if !%{disable_python3}
+Requires: python3-pcp = %{version}-%{release}
+Requires: python3-requests
+%else
+Requires: %{__python2}-pcp = %{version}-%{release}
+Requires: %{__python2}-requests
+%endif
+
+%description export-pcp2influxdb
+Performance Co-Pilot (PCP) front-end tools for exporting metric values
+to InfluxDB (https://influxdata.com/time-series-platform/influxdb).
+
+#
+# pcp-export-pcp2json
+#
+%package export-pcp2json
+License: GPLv2+
+Summary: Performance Co-Pilot tools for exporting PCP metrics in JSON format
+URL: https://pcp.io
+Requires: pcp-libs >= %{version}-%{release}
+%if !%{disable_python3}
+Requires: python3-pcp = %{version}-%{release}
+%else
+Requires: %{__python2}-pcp = %{version}-%{release}
+%endif
+
+%description export-pcp2json
+Performance Co-Pilot (PCP) front-end tools for exporting metric values
+in JSON format.
+
+#
+# pcp-export-pcp2spark
+#
+%package export-pcp2spark
+License: GPLv2+
+Summary: Performance Co-Pilot tools for exporting PCP metrics to Apache Spark
+URL: https://pcp.io
+Requires: pcp-libs >= %{version}-%{release}
+%if !%{disable_python3}
+Requires: python3-pcp = %{version}-%{release}
+%else
+Requires: %{__python2}-pcp = %{version}-%{release}
+%endif
+
+%description export-pcp2spark
+Performance Co-Pilot (PCP) front-end tools for exporting metric values
+in JSON format to Apache Spark. See https://spark.apache.org/ for
+further details on Apache Spark.
+
+#
+# pcp-export-pcp2xlsx
+#
+%if !%{disable_xlsx}
+%package export-pcp2xlsx
+License: GPLv2+
+Summary: Performance Co-Pilot tools for exporting PCP metrics to Excel
+URL: https://pcp.io
+Requires: pcp-libs >= %{version}-%{release}
+%if !%{disable_python3}
+Requires: python3-pcp = %{version}-%{release}
+Requires: python3-openpyxl
+BuildRequires: python3-openpyxl
+%else
+Requires: %{__python2}-pcp = %{version}-%{release}
+Requires: %{__python2}-openpyxl
+BuildRequires: %{__python2}-openpyxl
+%endif
+
+%description export-pcp2xlsx
+Performance Co-Pilot (PCP) front-end tools for exporting metric values
+in Excel spreadsheet format.
+%endif
+#
+# pcp-export-pcp2xml
+#
+%package export-pcp2xml
+License: GPLv2+
+Summary: Performance Co-Pilot tools for exporting PCP metrics in XML format
+URL: https://pcp.io
+Requires: pcp-libs >= %{version}-%{release}
+%if !%{disable_python3}
+Requires: python3-pcp = %{version}-%{release}
+%else
+Requires: %{__python2}-pcp = %{version}-%{release}
+%endif
+
+%description export-pcp2xml
+Performance Co-Pilot (PCP) front-end tools for exporting metric values
+in XML format.
+
+#
+# pcp-export-pcp2zabbix
+#
+%package export-pcp2zabbix
+License: GPLv2+
+Summary: Performance Co-Pilot tools for exporting PCP metrics to Zabbix
+URL: https://pcp.io
+Requires: pcp-libs >= %{version}-%{release}
+%if !%{disable_python3}
+Requires: python3-pcp = %{version}-%{release}
+%else
+Requires: %{__python2}-pcp = %{version}-%{release}
+%endif
+
+%description export-pcp2zabbix
+Performance Co-Pilot (PCP) front-end tools for exporting metric values
+to the Zabbix (https://www.zabbix.org/) monitoring software.
+%endif
+
+%if !%{disable_podman}
+#
+# pcp-pmda-podman
+#
+%package pmda-podman
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics for podman containers
+URL: https://pcp.io
+Requires: pcp = %{version}-%{release} pcp-libs = %{version}-%{release}
+Requires: libvarlink
+BuildRequires: libvarlink-devel
+
+%description pmda-podman
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+collecting podman container and pod statistics through libvarlink.
+%endif
+
+%if !%{disable_statsd}
+#
+# pcp-pmda-statsd
+#
+%package pmda-statsd
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics from statsd
+URL: https://pcp.io
+Requires: pcp = %{version}-%{release} pcp-libs = %{version}-%{release}
+Requires: chan HdrHistogram_c
+
+%description pmda-statsd
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+collecting statistics from the statsd daemon.
+%endif
+
+%if !%{disable_perfevent}
+#
+# pcp-pmda-perfevent
+#
+%package pmda-perfevent
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics for hardware counters
+URL: https://pcp.io
+Requires: pcp = %{version}-%{release} pcp-libs = %{version}-%{release}
+Requires: libpfm >= 4
+BuildRequires: libpfm-devel >= 4
+Obsoletes: pcp-pmda-papi < 5.0.0
+Obsoletes: pcp-pmda-papi-debuginfo < 5.0.0
+
+%description pmda-perfevent
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+collecting hardware counters statistics through libpfm.
+%endif
+
+%if !%{disable_infiniband}
+#
+# pcp-pmda-infiniband
+#
+%package pmda-infiniband
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics for Infiniband HCAs and switches
+URL: https://pcp.io
+Requires: pcp = %{version}-%{release} pcp-libs = %{version}-%{release}
+Requires: libibmad >= 1.3.7 libibumad >= 1.3.7
+BuildRequires: libibmad-devel >= 1.3.7 libibumad-devel >= 1.3.7
+
+%description pmda-infiniband
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+collecting Infiniband statistics.  By default, it monitors the local HCAs
+but can also be configured to monitor remote GUIDs such as IB switches.
+%endif
+
+#
+# pcp-pmda-activemq
+#
+%package pmda-activemq
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics for ActiveMQ
+URL: https://pcp.io
+Requires: perl-PCP-PMDA = %{version}-%{release}
+Requires: perl(LWP::UserAgent)
+
+%description pmda-activemq
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+collecting metrics about the ActiveMQ message broker.
+#end pcp-pmda-activemq
+
+#
+# pcp-pmda-bind2
+#
+%package pmda-bind2
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics for BIND servers
+URL: https://pcp.io
+Requires: perl-PCP-PMDA = %{version}-%{release}
+Requires: perl(LWP::UserAgent)
+Requires: perl(XML::LibXML)
+Requires: perl(File::Slurp)
+
+%description pmda-bind2
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+collecting metrics from BIND (Berkeley Internet Name Domain).
+#end pcp-pmda-bind2
+
+#
+# pcp-pmda-redis
+#
+%package pmda-redis
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics for Redis
+URL: https://pcp.io
+Requires: perl-PCP-PMDA = %{version}-%{release}
+
+%description pmda-redis
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+collecting metrics from Redis servers (redis.io).
+#end pcp-pmda-redis
+
+%if !%{disable_nutcracker}
+#
+# pcp-pmda-nutcracker
+#
+%package pmda-nutcracker
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics for NutCracker (TwemCache)
+URL: https://pcp.io
+Requires: perl-PCP-PMDA = %{version}-%{release}
+Requires: perl(YAML::XS::LibYAML)
+Requires: perl(JSON)
+
+%description pmda-nutcracker
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+collecting metrics from NutCracker (TwemCache).
+#end pcp-pmda-nutcracker
+%endif
+
+#
+# pcp-pmda-bonding
+#
+%package pmda-bonding
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics for Bonded network interfaces
+URL: https://pcp.io
+Requires: perl-PCP-PMDA = %{version}-%{release}
+
+%description pmda-bonding
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+collecting metrics about bonded network interfaces.
+#end pcp-pmda-bonding
+
+#
+# pcp-pmda-dbping
+#
+%package pmda-dbping
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics for Database response times and Availablility
+URL: https://pcp.io
+Requires: perl-PCP-PMDA = %{version}-%{release}
+
+%description pmda-dbping
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+collecting metrics about the Database response times and Availablility.
+#end pcp-pmda-dbping
+
+#
+# pcp-pmda-ds389
+#
+%package pmda-ds389
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics for 389 Directory Servers
+URL: https://pcp.io
+Requires: perl-PCP-PMDA = %{version}-%{release}
+%if 0%{?rhel} <= 7
+Requires: perl-LDAP
+%endif
+
+%description pmda-ds389
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+collecting metrics about a 389 Directory Server.
+#end pcp-pmda-ds389
+
+#
+# pcp-pmda-ds389log
+#
+%package pmda-ds389log
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics for 389 Directory Server Loggers
+URL: https://pcp.io
+Requires: perl-PCP-PMDA = %{version}-%{release}
+Requires: perl-Date-Manip
+
+%description pmda-ds389log
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+collecting metrics from a 389 Directory Server log.
+#end pcp-pmda-ds389log
+
+
+#
+# pcp-pmda-gpfs
+#
+%package pmda-gpfs
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics for GPFS Filesystem
+URL: https://pcp.io
+Requires: perl-PCP-PMDA = %{version}-%{release}
+
+%description pmda-gpfs
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+collecting metrics about the GPFS filesystem.
+#end pcp-pmda-gpfs
+
+#
+# pcp-pmda-gpsd
+#
+%package pmda-gpsd
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics for a GPS Daemon
+URL: https://pcp.io
+Requires: perl-PCP-PMDA = %{version}-%{release}
+
+%description pmda-gpsd
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+collecting metrics about a GPS Daemon.
+#end pcp-pmda-gpsd
+
+#
+# pcp-pmda-docker
+#
+%package pmda-docker
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics from the Docker daemon
+URL: https://pcp.io
+Requires: pcp = %{version}-%{release} pcp-libs = %{version}-%{release}
+
+%description pmda-docker
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+collecting metrics using the Docker daemon REST API.
+#end pcp-pmda-docker
+
+#
+# pcp-pmda-lustre
+#
+%package pmda-lustre
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics for the Lustre Filesytem
+URL: https://pcp.io
+Requires: perl-PCP-PMDA = %{version}-%{release}
+
+%description pmda-lustre
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+collecting metrics about the Lustre Filesystem.
+#end pcp-pmda-lustre
+
+#
+# pcp-pmda-lustrecomm
+#
+%package pmda-lustrecomm
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics for the Lustre Filesytem Comms
+URL: https://pcp.io
+Requires: pcp = %{version}-%{release}
+Requires: pcp-libs = %{version}-%{release}
+
+%description pmda-lustrecomm
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+collecting metrics about the Lustre Filesystem Comms.
+#end pcp-pmda-lustrecomm
+
+#
+# pcp-pmda-memcache
+#
+%package pmda-memcache
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics for Memcached
+URL: https://pcp.io
+Requires: perl-PCP-PMDA = %{version}-%{release}
+
+%description pmda-memcache
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+collecting metrics about Memcached.
+#end pcp-pmda-memcache
+
+#
+# pcp-pmda-mysql
+#
+%package pmda-mysql
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics for MySQL
+URL: https://pcp.io
+Requires: perl-PCP-PMDA = %{version}-%{release}
+Requires: perl(DBI) perl(DBD::mysql)
+BuildRequires: perl(DBI) perl(DBD::mysql)
+
+%description pmda-mysql
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+collecting metrics about the MySQL database.
+#end pcp-pmda-mysql
+
+#
+# pcp-pmda-named
+#
+%package pmda-named
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics for Named
+URL: https://pcp.io
+Requires: perl-PCP-PMDA = %{version}-%{release}
+
+%description pmda-named
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+collecting metrics about the Named nameserver.
+#end pcp-pmda-named
+
+# pcp-pmda-netfilter
+#
+%package pmda-netfilter
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics for Netfilter framework
+URL: https://pcp.io
+Requires: perl-PCP-PMDA = %{version}-%{release}
+
+%description pmda-netfilter
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+collecting metrics about the Netfilter packet filtering framework.
+#end pcp-pmda-netfilter
+
+#
+# pcp-pmda-news
+#
+%package pmda-news
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics for Usenet News
+URL: https://pcp.io
+Requires: perl-PCP-PMDA = %{version}-%{release}
+
+%description pmda-news
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+collecting metrics about Usenet News.
+#end pcp-pmda-news
+
+#
+# pcp-pmda-nginx
+#
+%package pmda-nginx
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics for the Nginx Webserver
+URL: https://pcp.io
+Requires: perl-PCP-PMDA = %{version}-%{release}
+Requires: perl(LWP::UserAgent)
+BuildRequires: perl(LWP::UserAgent)
+
+%description pmda-nginx
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+collecting metrics about the Nginx Webserver.
+#end pcp-pmda-nginx
+
+#
+# pcp-pmda-oracle
+#
+%package pmda-oracle
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics for the Oracle database
+URL: https://pcp.io
+Requires: perl-PCP-PMDA = %{version}-%{release}
+Requires: perl(DBI)
+BuildRequires: perl(DBI)
+
+%description pmda-oracle
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+collecting metrics about the Oracle database.
+#end pcp-pmda-oracle
+
+#
+# pcp-pmda-pdns
+#
+%package pmda-pdns
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics for PowerDNS
+URL: https://pcp.io
+Requires: perl-PCP-PMDA = %{version}-%{release}
+
+%description pmda-pdns
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+collecting metrics about the PowerDNS.
+#end pcp-pmda-pdns
+
+#
+# pcp-pmda-postfix
+#
+%package pmda-postfix
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics for the Postfix (MTA)
+URL: https://pcp.io
+Requires: perl-PCP-PMDA = %{version}-%{release}
+Requires: perl-Time-HiRes
+%if 0%{?fedora} > 16 || 0%{?rhel} > 5
+Requires: postfix-perl-scripts
+BuildRequires: postfix-perl-scripts
+%endif
+%if 0%{?rhel} <= 5
+Requires: postfix
+BuildRequires: postfix
+%endif
+%if "%{_vendor}" == "suse"
+Requires: postfix-doc
+BuildRequires: postfix-doc
+%endif
+
+%description pmda-postfix
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+collecting metrics about the Postfix (MTA).
+#end pcp-pmda-postfix
+
+#
+# pcp-pmda-rsyslog
+#
+%package pmda-rsyslog
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics for Rsyslog
+URL: https://pcp.io
+Requires: perl-PCP-PMDA = %{version}-%{release}
+
+%description pmda-rsyslog
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+collecting metrics about Rsyslog.
+#end pcp-pmda-rsyslog
+
+#
+# pcp-pmda-samba
+#
+%package pmda-samba
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics for Samba
+URL: https://pcp.io
+Requires: perl-PCP-PMDA = %{version}-%{release}
+
+%description pmda-samba
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+collecting metrics about Samba.
+#end pcp-pmda-samba
+
+#
+# pcp-pmda-slurm
+#
+%package pmda-slurm
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics for the SLURM Workload Manager
+URL: https://pcp.io
+Requires: perl-PCP-PMDA = %{version}-%{release}
+
+%description pmda-slurm
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+collecting metrics from the SLURM Workload Manager.
+#end pcp-pmda-slurm
+
+%if !%{disable_snmp}
+#
+# pcp-pmda-snmp
+#
+%package pmda-snmp
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics for Simple Network Management Protocol
+URL: https://pcp.io
+Requires: perl-PCP-PMDA = %{version}-%{release}
+# There are no perl-Net-SNMP packages in rhel, disable unless non-rhel or epel5
+%if 0%{?rhel} == 0 || 0%{?rhel} < 6
+Requires: perl(Net::SNMP)
+%endif
+
+%description pmda-snmp
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+collecting metrics about SNMP.
+#end pcp-pmda-snmp
+%endif
+
+#
+# pcp-pmda-vmware
+#
+%package pmda-vmware
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics for VMware
+URL: https://pcp.io
+Requires: perl-PCP-PMDA = %{version}-%{release}
+
+%description pmda-vmware
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+collecting metrics for VMware.
+#end pcp-pmda-vmware
+
+#
+# pcp-pmda-zimbra
+#
+%package pmda-zimbra
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics for Zimbra
+URL: https://pcp.io
+Requires: perl-PCP-PMDA = %{version}-%{release}
+
+%description pmda-zimbra
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+collecting metrics about Zimbra.
+#end pcp-pmda-zimbra
+
+#
+# pcp-pmda-dm
+#
+%package pmda-dm
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics for the Device Mapper Cache and Thin Client
+URL: https://pcp.io
+Requires: pcp-libs = %{version}-%{release}
+BuildRequires: device-mapper-devel
+%description pmda-dm
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+collecting metrics about the Device Mapper Cache and Thin Client.
+# end pcp-pmda-dm
+
+
+%if !%{disable_bcc}
+#
+# pcp-pmda-bcc
+#
+%package pmda-bcc
+License: ASL 2.0 and GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics from eBPF/BCC modules
+URL: https://pcp.io
+Requires: python3-bcc
+Requires: python3-pcp
+%description pmda-bcc
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+extracting performance metrics from eBPF/BCC Python modules.
+# end pcp-pmda-bcc
+%endif
+
+%if !%{disable_bpftrace}
+#
+# pcp-pmda-bpftrace
+#
+%package pmda-bpftrace
+License: ASL 2.0 and GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics from bpftrace scripts
+URL: https://pcp.io
+Requires: bpftrace >= 0.9.2
+Requires: python3-pcp
+Requires: python3 >= 3.6
+%description pmda-bpftrace
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+extracting performance metrics from bpftrace scripts.
+# end pcp-pmda-bpftrace
+%endif
+
+%if !%{disable_python2} || !%{disable_python3}
+#
+# pcp-pmda-gluster
+#
+%package pmda-gluster
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics for the Gluster filesystem
+URL: https://pcp.io
+%if !%{disable_python3}
+Requires: python3-pcp
+%else
+Requires: %{__python2}-pcp
+%endif
+%description pmda-gluster
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+collecting metrics about the gluster filesystem.
+# end pcp-pmda-gluster
+
+#
+# pcp-pmda-nfsclient
+#
+%package pmda-nfsclient
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics for NFS Clients
+URL: https://pcp.io
+%if !%{disable_python3}
+Requires: python3-pcp
+%else
+Requires: %{__python2}-pcp
+%endif
+%description pmda-nfsclient
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+collecting metrics for NFS Clients.
+#end pcp-pmda-nfsclient
+
+#
+# pcp-pmda-postgresql
+#
+%package pmda-postgresql
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics for PostgreSQL
+URL: https://pcp.io
+%if !%{disable_python3}
+Requires: python3-pcp
+Requires: python3-psycopg2
+BuildRequires: python3-psycopg2
+%else
+Requires: %{__python2}-pcp
+Requires: %{__python2}-psycopg2
+BuildRequires: %{__python2}-psycopg2
+%endif
+%description pmda-postgresql
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+collecting metrics about the PostgreSQL database.
+#end pcp-pmda-postgresql
+
+#
+# pcp-pmda-zswap
+#
+%package pmda-zswap
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics for compressed swap
+URL: https://pcp.io
+%if !%{disable_python3}
+Requires: python3-pcp
+%else
+Requires: %{__python2}-pcp
+%endif
+%description pmda-zswap
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+collecting metrics about compressed swap.
+# end pcp-pmda-zswap
+
+#
+# pcp-pmda-unbound
+#
+%package pmda-unbound
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics for the Unbound DNS Resolver
+URL: https://pcp.io
+%if !%{disable_python3}
+Requires: python3-pcp
+%else
+Requires: %{__python2}-pcp
+%endif
+%description pmda-unbound
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+collecting metrics about the Unbound DNS Resolver.
+# end pcp-pmda-unbound
+
+#
+# pcp-pmda-mic
+#
+%package pmda-mic
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics for Intel MIC cards
+URL: https://pcp.io
+%if !%{disable_python3}
+Requires: python3-pcp
+%else
+Requires: %{__python2}-pcp
+%endif
+%description pmda-mic
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+collecting metrics about Intel MIC cards.
+# end pcp-pmda-mic
+
+#
+# pcp-pmda-haproxy
+#
+%package pmda-haproxy
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics for HAProxy
+URL: https://pcp.io
+%if !%{disable_python3}
+Requires: python3-pcp
+%else
+Requires: %{__python2}-pcp
+%endif
+%description pmda-haproxy
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+extracting performance metrics from HAProxy over the HAProxy stats socket.
+# end pcp-pmda-haproxy
+
+#
+# pcp-pmda-libvirt
+#
+%package pmda-libvirt
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics for virtual machines
+URL: https://pcp.io
+%if !%{disable_python3}
+Requires: python3-pcp
+Requires: libvirt-python3 python3-lxml
+BuildRequires: libvirt-python3 python3-lxml
+%else
+%if 0%{?rhel} == 0 || 0%{?fedora} >= 27
+Requires: %{__python2}-pcp
+Requires: %{__python2}-libvirt %{__python2}-lxml
+BuildRequires: %{__python2}-libvirt %{__python2}-lxml
+%endif
+%if 0%{?rhel} > 5
+Requires: %{__python2}-pcp
+Requires: libvirt-%{__python2} %{__python2}-lxml
+BuildRequires: libvirt-%{__python2} %{__python2}-lxml
+%endif
+%endif
+%description pmda-libvirt
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+extracting virtualisation statistics from libvirt about behaviour of guest
+and hypervisor machines.
+# end pcp-pmda-libvirt
+
+#
+# pcp-pmda-elasticsearch
+#
+%package pmda-elasticsearch
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics for Elasticsearch
+URL: https://pcp.io
+%if !%{disable_python3}
+Requires: python3-pcp
+%else
+Requires: %{__python2}-pcp
+%endif
+%description pmda-elasticsearch
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+collecting metrics about Elasticsearch.
+#end pcp-pmda-elasticsearch
+
+#
+# pcp-pmda-lio
+#
+%package pmda-lio
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics for the LIO subsystem
+URL: https://pcp.io
+%if !%{disable_python3}
+Requires: python3-pcp
+Requires: python3-rtslib
+BuildRequires: python3-rtslib
+%else
+Requires: %{__python2}-pcp
+Requires: %{__python2}-rtslib
+BuildRequires: %{__python2}-rtslib
+%endif
+%description pmda-lio
+This package provides a PMDA to gather performance metrics from the kernels
+iSCSI target interface (LIO). The metrics are stored by LIO within the Linux
+kernels configfs filesystem. The PMDA provides per LUN level stats, and a
+summary instance per iSCSI target, which aggregates all LUN metrics within the
+target.
+#end pcp-pmda-lio
+
+#
+# pcp-pmda-openmetrics
+#
+%package pmda-openmetrics
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics from OpenMetrics endpoints
+URL: https://pcp.io
+Requires: pcp-libs = %{version}-%{release}
+%if !%{disable_python3}
+Requires: python3-pcp
+Requires: python3-requests
+BuildRequires: python3-requests
+%else
+Requires: %{__python2}-pcp
+Requires: %{__python2}-requests
+BuildRequires: %{__python2}-requests
+%endif
+Obsoletes: pcp-pmda-prometheus < 5.0.0
+Provides: pcp-pmda-prometheus < 5.0.0
+
+%description pmda-openmetrics
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+extracting metrics from OpenMetrics (https://openmetrics.io/) endpoints.
+#end pcp-pmda-openmetrics
+
+#
+# pcp-pmda-lmsensors
+#
+%package pmda-lmsensors
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics for hardware sensors
+URL: https://pcp.io
+Requires: pcp-libs = %{version}-%{release}
+%if !%{disable_python3}
+Requires: python3-pcp
+%else
+Requires: %{__python2}-pcp
+%endif
+# rewritten in python, so there is no longer a debuginfo package
+Obsoletes: pcp-pmda-lmsensors-debuginfo < 4.2.0
+%description pmda-lmsensors
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+collecting metrics about the Linux hardware monitoring sensors.
+# end pcp-pmda-lmsensors
+
+#
+# pcp-pmda-netcheck
+#
+%package pmda-netcheck
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics for simple network checks
+URL: https://pcp.io
+Requires: pcp-libs = %{version}-%{release}
+%if !%{disable_python3}
+Requires: python3-pcp
+%else
+Requires: %{__python2}-pcp
+%endif
+%description pmda-netcheck
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+collecting metrics from simple network checks.
+# end pcp-pmda-netcheck
+
+%endif
+
+%if !%{disable_mssql}
+#
+# pcp-pmda-mssql
+#
+%package pmda-mssql
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics for Microsoft SQL Server
+URL: https://pcp.io
+Requires: pcp-libs = %{version}-%{release}
+%if !%{disable_python3}
+Requires: python3-pcp
+%else
+Requires: %{__python2}-pcp
+%endif
+%description pmda-mssql
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+collecting metrics from Microsoft SQL Server.
+# end pcp-pmda-mssql
+%endif
+
+%if !%{disable_json}
+#
+# pcp-pmda-json
+#
+%package pmda-json
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics for JSON data
+URL: https://pcp.io
+%if !%{disable_python3}
+Requires: python3-pcp
+Requires: python3-jsonpointer python3-six
+BuildRequires: python3-jsonpointer python3-six
+%else
+Requires: %{__python2}-pcp
+Requires: %{__python2}-jsonpointer %{__python2}-six
+BuildRequires: %{__python2}-jsonpointer %{__python2}-six
+%endif
+%description pmda-json
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+collecting metrics output in JSON.
+# end pcp-pmda-json
+%endif
+
+#
+# C pmdas
+# pcp-pmda-apache
+#
+%package pmda-apache
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics for the Apache webserver
+URL: https://pcp.io
+Requires: pcp-libs = %{version}-%{release}
+%description pmda-apache
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+collecting metrics about the Apache webserver.
+# end pcp-pmda-apache
+
+#
+# pcp-pmda-bash
+#
+%package pmda-bash
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics for the Bash shell
+URL: https://pcp.io
+Requires: pcp-libs = %{version}-%{release}
+%description pmda-bash
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+collecting metrics about the Bash shell.
+# end pcp-pmda-bash
+
+#
+# pcp-pmda-cifs
+#
+%package pmda-cifs
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics for the CIFS protocol
+URL: https://pcp.io
+Requires: pcp-libs = %{version}-%{release}
+%description pmda-cifs
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+collecting metrics about the Common Internet Filesytem.
+# end pcp-pmda-cifs
+
+#
+# pcp-pmda-cisco
+#
+%package pmda-cisco
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics for Cisco routers
+URL: https://pcp.io
+Requires: pcp-libs = %{version}-%{release}
+%description pmda-cisco
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+collecting metrics about Cisco routers.
+# end pcp-pmda-cisco
+
+#
+# pcp-pmda-gfs2
+#
+%package pmda-gfs2
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics for the GFS2 filesystem
+URL: https://pcp.io
+Requires: pcp-libs = %{version}-%{release}
+%description pmda-gfs2
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+collecting metrics about the Global Filesystem v2.
+# end pcp-pmda-gfs2
+
+#
+# pcp-pmda-logger
+#
+%package pmda-logger
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics from arbitrary log files
+URL: https://pcp.io
+Requires: pcp-libs = %{version}-%{release}
+%description pmda-logger
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+collecting metrics from a specified set of log files (or pipes).  The PMDA
+supports both sampled and event-style metrics.
+# end pcp-pmda-logger
+
+#
+# pcp-pmda-mailq
+#
+%package pmda-mailq
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics for the sendmail queue
+URL: https://pcp.io
+Requires: pcp-libs = %{version}-%{release}
+%description pmda-mailq
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+collecting metrics about email queues managed by sendmail.
+# end pcp-pmda-mailq
+
+#
+# pcp-pmda-mounts
+#
+%package pmda-mounts
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics for filesystem mounts
+URL: https://pcp.io
+Requires: pcp-libs = %{version}-%{release}
+%description pmda-mounts
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+collecting metrics about filesystem mounts.
+# end pcp-pmda-mounts
+
+#
+# pcp-pmda-nvidia-gpu
+#
+%package pmda-nvidia-gpu
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics for the Nvidia GPU
+URL: https://pcp.io
+Requires: pcp-libs = %{version}-%{release}
+%description pmda-nvidia-gpu
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+collecting metrics about Nvidia GPUs.
+# end pcp-pmda-nvidia-gpu
+
+#
+# pcp-pmda-roomtemp
+#
+%package pmda-roomtemp
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics for the room temperature
+URL: https://pcp.io
+Requires: pcp = %{version}-%{release}
+Requires: pcp-libs = %{version}-%{release}
+%description pmda-roomtemp
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+collecting metrics about the room temperature.
+# end pcp-pmda-roomtemp
+
+%if !%{disable_rpm}
+#
+# pcp-pmda-rpm
+#
+%package pmda-rpm
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics for the RPM package manager
+URL: https://pcp.io
+Requires: pcp = %{version}-%{release}
+Requires: pcp-libs = %{version}-%{release}
+%description pmda-rpm
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+collecting metrics about the installed RPM packages.
+%endif
+# end pcp-pmda-rpm
+
+
+#
+# pcp-pmda-sendmail
+#
+%package pmda-sendmail
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics for Sendmail
+URL: https://pcp.io
+Requires: pcp = %{version}-%{release}
+Requires: pcp-libs = %{version}-%{release}
+%description pmda-sendmail
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+collecting metrics about Sendmail traffic.
+# end pcp-pmda-sendmail
+
+#
+# pcp-pmda-shping
+#
+%package pmda-shping
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics for shell command responses
+URL: https://pcp.io
+Requires: pcp-libs = %{version}-%{release}
+%description pmda-shping
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+collecting metrics about quality of service and response time measurements of
+arbitrary shell commands.
+# end pcp-pmda-shping
+
+#
+# pcp-pmda-smart
+#
+%package pmda-smart
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics for S.M.A.R.T values
+URL: https://pcp.io
+Requires: pcp-libs = %{version}-%{release}
+%description pmda-smart
+This package contains the PCP Performance Metric Domain Agent (PMDA) for
+collecting metrics of disk S.M.A.R.T values making use of data from the
+smartmontools package.
+#end pcp-pmda-smart
+
+#
+# pcp-pmda-summary
+#
+%package pmda-summary
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) summary metrics from pmie
+URL: https://pcp.io
+Requires: pcp = %{version}-%{release}
+Requires: pcp-libs = %{version}-%{release}
+%description pmda-summary
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+collecting metrics about other installed PMDAs.
+# end pcp-pmda-summary
+
+%if !%{disable_systemd}
+#
+# pcp-pmda-systemd
+#
+%package pmda-systemd
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics from the Systemd journal
+URL: https://pcp.io
+Requires: pcp-libs = %{version}-%{release}
+%description pmda-systemd
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+collecting metrics from the Systemd journal.
+# end pcp-pmda-systemd
+%endif
+
+#
+# pcp-pmda-trace
+#
+%package pmda-trace
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics for application tracing
+URL: https://pcp.io
+Requires: pcp-libs = %{version}-%{release}
+%description pmda-trace
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+collecting metrics about trace performance data in applications.
+# end pcp-pmda-trace
+
+#
+# pcp-pmda-weblog
+#
+%package pmda-weblog
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) metrics from web server logs
+URL: https://pcp.io
+Requires: pcp = %{version}-%{release}
+Requires: pcp-libs = %{version}-%{release}
+%description pmda-weblog
+This package contains the PCP Performance Metrics Domain Agent (PMDA) for
+collecting metrics about web server logs.
+# end pcp-pmda-weblog
+# end C pmdas
+
+%package zeroconf
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) Zeroconf Package
+URL: https://pcp.io
+Requires: pcp pcp-doc pcp-system-tools
+Requires: pcp-pmda-dm pcp-pmda-nfsclient
+%description zeroconf
+This package contains configuration tweaks and files to increase metrics
+gathering frequency, several extended pmlogger configurations, as well as
+automated pmie diagnosis, alerting and self-healing for the localhost.
+A cron script also writes daily performance summary reports similar to
+those written by sysstat.
+
+%if !%{disable_python2}
+#
+# python2-pcp. This is the PCP library bindings for python.
+#
+%package -n %{__python2}-pcp
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) Python bindings and documentation
+URL: https://pcp.io
+Requires: pcp = %{version}-%{release} pcp-libs = %{version}-%{release}
+%if 0%{?fedora} >= 26 || 0%{?rhel} > 7
+# on these platforms, python2-pcp replaces python-pcp
+Obsoletes: python-pcp < %{version}
+%endif
+%if 0%{?rhel} == 5
+Requires: python%{default_python}
+%else
+Requires: %{__python2}
+%endif
+
+%description -n %{__python2}-pcp
+This python PCP module contains the language bindings for
+Performance Metric API (PMAPI) monitor tools and Performance
+Metric Domain Agent (PMDA) collector tools written in Python.
+%endif
+
+%if !%{disable_python3}
+#
+# python3-pcp. This is the PCP library bindings for python3.
+#
+%package -n python3-pcp
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) Python3 bindings and documentation
+URL: https://pcp.io
+Requires: pcp = %{version}-%{release} pcp-libs = %{version}-%{release}
+Requires: python3
+
+%description -n python3-pcp
+This python PCP module contains the language bindings for
+Performance Metric API (PMAPI) monitor tools and Performance
+Metric Domain Agent (PMDA) collector tools written in Python3.
+%endif
+
+%if !%{disable_python2} || !%{disable_python3}
+#
+# pcp-system-tools
+#
+%package system-tools
+License: GPLv2+
+Summary: Performance Co-Pilot (PCP) System and Monitoring Tools
+URL: https://pcp.io
+%if !%{disable_python3}
+Requires: python3-pcp = %{version}-%{release}
+%else
+Requires: %{__python2}-pcp = %{version}-%{release}
+%endif
+Requires: pcp-libs = %{version}-%{release}
+%if !%{disable_dstat}
+# https://fedoraproject.org/wiki/Packaging:Guidelines "Renaming/Replacing Existing Packages"
+Provides: dstat = %{version}-%{release}
+Provides: /usr/bin/dstat
+Obsoletes: dstat <= 0.8
+%endif
+
+%description system-tools
+This PCP module contains additional system monitoring tools written
+in the Python language.
+%endif
+
+%if !%{disable_qt}
+#
+# pcp-gui package for Qt tools
+#
+%package gui
+License: GPLv2+ and LGPLv2+ and LGPLv2+ with exceptions
+Summary: Visualization tools for the Performance Co-Pilot toolkit
+URL: https://pcp.io
+Requires: pcp = %{version}-%{release} pcp-libs = %{version}-%{release}
+Requires: liberation-sans-fonts
+BuildRequires: hicolor-icon-theme
+
+%description gui
+Visualization tools for the Performance Co-Pilot toolkit.
+The pcp-gui package primarily includes visualization tools for
+monitoring systems using live and archived Performance Co-Pilot
+(PCP) sources.
+%endif
+
+#
+# pcp-doc package
+#
+%package doc
+License: GPLv2+ and CC-BY
+%if !%{disable_noarch}
+BuildArch: noarch
+%endif
+Summary: Documentation and tutorial for the Performance Co-Pilot
+URL: https://pcp.io
+# http://fedoraproject.org/wiki/Packaging:Conflicts "Splitting Packages"
+# (all man pages migrated to pcp-doc during great package split of '15)
+Conflicts: pcp-pmda-infiniband < 3.10.5
+
+%description doc
+Documentation and tutorial for the Performance Co-Pilot
+Performance Co-Pilot (PCP) provides a framework and services to support
+system-level performance monitoring and performance management.
+
+The pcp-doc package provides useful information on using and
+configuring the Performance Co-Pilot (PCP) toolkit for system
+level performance management.  It includes tutorials, HOWTOs,
+and other detailed documentation about the internals of core
+PCP utilities and daemons, and the PCP graphical tools.
+
+#
+# pcp-selinux package
+#
+%if !%{disable_selinux}
+%package selinux
+License: GPLv2+ and CC-BY
+Summary: Selinux policy package
+URL: https://pcp.io
+BuildRequires: selinux-policy-devel
+BuildRequires: selinux-policy-targeted
+%if 0%{?rhel} == 5
+BuildRequires: setools
+%else
+BuildRequires: setools-console
+%endif
+Requires: policycoreutils selinux-policy-targeted
+
+%description selinux
+This package contains SELinux support for PCP.  The package contains
+interface rules, type enforcement and file context adjustments for an
+updated policy package.
+%endif
+
+%prep
+%setup -q
+%patch1 -p1
+%patch2 -p1
+%patch3 -p1
+%patch4 -p1
+
+%build
+%if !%{disable_python2} && 0%{?default_python} != 3
+export PYTHON=python%{?default_python}
+%endif
+%configure %{?_with_initd} %{?_with_doc} %{?_with_dstat} %{?_with_ib} %{?_with_podman} %{?_with_statsd} %{?_with_perfevent} %{?_with_bcc} %{?_with_bpftrace} %{?_with_json} %{?_with_snmp} %{?_with_nutcracker} %{?_with_python2}
+make %{?_smp_mflags} default_pcp
+
+%install
+rm -Rf $RPM_BUILD_ROOT
+export NO_CHOWN=true DIST_ROOT=$RPM_BUILD_ROOT
+make install_pcp
+
+PCP_GUI='pmchart|pmconfirm|pmdumptext|pmmessage|pmquery|pmsnap|pmtime'
+
+# Fix stuff we do/don't want to ship
+rm -f $RPM_BUILD_ROOT/%{_libdir}/*.a
+
+# remove sheet2pcp until BZ 830923 and BZ 754678 are resolved.
+rm -f $RPM_BUILD_ROOT/%{_bindir}/sheet2pcp $RPM_BUILD_ROOT/%{_mandir}/man1/sheet2pcp.1*
+
+# remove {config,platform}sz.h as these are not multilib friendly.
+rm -f $RPM_BUILD_ROOT/%{_includedir}/pcp/configsz.h
+rm -f $RPM_BUILD_ROOT/%{_includedir}/pcp/platformsz.h
+
+%if %{disable_infiniband}
+# remove pmdainfiniband on platforms lacking IB devel packages.
+rm -f $RPM_BUILD_ROOT/%{_pmdasdir}/ib
+rm -fr $RPM_BUILD_ROOT/%{_pmdasdir}/infiniband
+%endif
+
+%if %{disable_mssql}
+# remove pmdamssql on platforms lacking MSODBC driver packages.
+rm -fr $RPM_BUILD_ROOT/%{_pmdasdir}/mssql
+%endif
+
+%if %{disable_selinux}
+rm -fr $RPM_BUILD_ROOT/%{_selinuxdir}
+%endif
+
+%if %{disable_qt}
+rm -fr $RPM_BUILD_ROOT/%{_pixmapdir}
+rm -fr $RPM_BUILD_ROOT/%{_hicolordir}
+rm -fr $RPM_BUILD_ROOT/%{_confdir}/pmsnap
+rm -fr $RPM_BUILD_ROOT/%{_localstatedir}/lib/pcp/config/pmsnap
+rm -fr $RPM_BUILD_ROOT/%{_localstatedir}/lib/pcp/config/pmchart
+rm -f $RPM_BUILD_ROOT/%{_localstatedir}/lib/pcp/config/pmafm/pcp-gui
+rm -f $RPM_BUILD_ROOT/%{_datadir}/applications/pmchart.desktop
+rm -f `find $RPM_BUILD_ROOT/%{_mandir}/man1 | grep -E "$PCP_GUI"`
+%else
+rm -rf $RPM_BUILD_ROOT/usr/share/doc/pcp-gui
+desktop-file-validate $RPM_BUILD_ROOT/%{_datadir}/applications/pmchart.desktop
+%endif
+
+%if %{disable_xlsx}
+rm -f $RPM_BUILD_ROOT/%{_bashcompdir}/pcp2xlsx
+%endif
+
+%if 0%{?rhel} || 0%{?fedora}
+# Fedora and RHEL default local only access for pmcd and pmlogger
+sed -i -e '/^# .*_LOCAL=1/s/^# //' $RPM_BUILD_ROOT/%{_sysconfdir}/sysconfig/{pmcd,pmlogger}
+%endif
+
+# default chkconfig off (all RPM platforms)
+for f in $RPM_BUILD_ROOT/%{_initddir}/{pcp,pmcd,pmlogger,pmie,pmmgr,pmproxy}; do
+	test -f "$f" || continue
+	sed -i -e '/^# chkconfig/s/:.*$/: - 95 05/' -e '/^# Default-Start:/s/:.*$/:/' $f
+done
+
+# list of PMDAs in the base pkg
+ls -1 $RPM_BUILD_ROOT/%{_pmdasdir} |\
+  grep -E -v '^simple|sample|trivial|txmon' |\
+  grep -E -v '^perfevent|perfalloc.1' |\
+  grep -E -v '^ib$|^infiniband' |\
+  grep -E -v '^activemq' |\
+  grep -E -v '^bonding' |\
+  grep -E -v '^bind2' |\
+  grep -E -v '^dbping' |\
+  grep -E -v '^docker' |\
+  grep -E -v '^ds389log'|\
+  grep -E -v '^ds389' |\
+  grep -E -v '^elasticsearch' |\
+  grep -E -v '^gpfs' |\
+  grep -E -v '^gpsd' |\
+  grep -E -v '^lio' |\
+  grep -E -v '^lustre' |\
+  grep -E -v '^lustrecomm' |\
+  grep -E -v '^memcache' |\
+  grep -E -v '^mysql' |\
+  grep -E -v '^named' |\
+  grep -E -v '^netfilter' |\
+  grep -E -v '^news' |\
+  grep -E -v '^nfsclient' |\
+  grep -E -v '^nginx' |\
+  grep -E -v '^nutcracker' |\
+  grep -E -v '^oracle' |\
+  grep -E -v '^openmetrics' |\
+  grep -E -v '^pdns' |\
+  grep -E -v '^podman' |\
+  grep -E -v '^postfix' |\
+  grep -E -v '^postgresql' |\
+  grep -E -v '^redis' |\
+  grep -E -v '^rsyslog' |\
+  grep -E -v '^samba' |\
+  grep -E -v '^slurm' |\
+  grep -E -v '^snmp' |\
+  grep -E -v '^statsd' |\
+  grep -E -v '^vmware' |\
+  grep -E -v '^zimbra' |\
+  grep -E -v '^dm' |\
+  grep -E -v '^apache' |\
+  grep -E -v '^bash' |\
+  grep -E -v '^cifs' |\
+  grep -E -v '^cisco' |\
+  grep -E -v '^gfs2' |\
+  grep -E -v '^libvirt' |\
+  grep -E -v '^lmsensors' |\
+  grep -E -v '^logger' |\
+  grep -E -v '^mailq' |\
+  grep -E -v '^mounts' |\
+  grep -E -v '^mssql' |\
+  grep -E -v '^netcheck' |\
+  grep -E -v '^nvidia' |\
+  grep -E -v '^roomtemp' |\
+  grep -E -v '^sendmail' |\
+  grep -E -v '^shping' |\
+  grep -E -v '^smart' |\
+  grep -E -v '^summary' |\
+  grep -E -v '^trace' |\
+  grep -E -v '^weblog' |\
+  grep -E -v '^rpm' |\
+  grep -E -v '^json' |\
+  grep -E -v '^mic' |\
+  grep -E -v '^bcc' |\
+  grep -E -v '^bpftrace' |\
+  grep -E -v '^gluster' |\
+  grep -E -v '^zswap' |\
+  grep -E -v '^unbound' |\
+  grep -E -v '^haproxy' |\
+  sed -e 's#^#'%{_pmdasdir}'\/#' >base_pmdas.list
+
+# all base pcp package files except those split out into sub-packages
+ls -1 $RPM_BUILD_ROOT/%{_bindir} |\
+  grep -E -v 'pmiostat|zabbix|zbxpcp|dstat|pmrep' |\
+  grep -E -v 'pcp2spark|pcp2graphite|pcp2influxdb|pcp2zabbix' |\
+  grep -E -v 'pcp2elasticsearch|pcp2json|pcp2xlsx|pcp2xml' |\
+  grep -E -v 'pmdbg|pmclient|pmerr|genpmda' |\
+sed -e 's#^#'%{_bindir}'\/#' >base_bin.list
+ls -1 $RPM_BUILD_ROOT/%{_bashcompdir} |\
+  grep -E -v 'pcp2spark|pcp2graphite|pcp2influxdb|pcp2zabbix' |\
+  grep -E -v 'pcp2elasticsearch|pcp2json|pcp2xlsx|pcp2xml' |\
+  grep -E -v 'pmrep|pmdumptext' |\
+sed -e 's#^#'%{_bashcompdir}'\/#' >base_bashcomp.list
+
+# Separate the pcp-system-tools package files.
+# pmiostat is a back-compat symlink to its pcp(1) sub-command variant
+# so its also in pcp-system-tools.
+%if !%{disable_python2} || !%{disable_python3}
+ls -1 $RPM_BUILD_ROOT/%{_bindir} |\
+  egrep -e 'pmiostat|pmrep|dstat' |\
+  sed -e 's#^#'%{_bindir}'\/#' >pcp-system-tools.list
+ls -1 $RPM_BUILD_ROOT/%{_libexecdir}/pcp/bin |\
+  egrep -e 'atop|collectl|dmcache|dstat|free|iostat|ipcs|lvmcache|mpstat' \
+        -e 'numastat|pidstat|shping|tapestat|uptime|verify' |\
+  sed -e 's#^#'%{_libexecdir}/pcp/bin'\/#' >>pcp-system-tools.list
+%endif
+# Separate the pcp-selinux package files.
+%if !%{disable_selinux}
+ls -1 $RPM_BUILD_ROOT/%{_selinuxdir} |\
+  sed -e 's#^#'%{_selinuxdir}'\/#' > pcp-selinux.list
+ls -1 $RPM_BUILD_ROOT/%{_libexecdir}/pcp/bin |\
+  grep -E 'selinux-setup' |\
+  sed -e 's#^#'%{_libexecdir}/pcp/bin'\/#' >> pcp-selinux.list
+%endif
+
+ls -1 $RPM_BUILD_ROOT/%{_libexecdir}/pcp/bin |\
+%if !%{disable_python2} || !%{disable_python3}
+  grep -E -v 'atop|collectl|dmcache|dstat|free|iostat|ipcs|lvmcache|mpstat' |\
+  grep -E -v 'numastat|shping|tapestat|uptime|verify|selinux-setup' |\
+%endif
+  grep -E -v 'pmlogger_daily_report' |\
+  sed -e 's#^#'%{_libexecdir}/pcp/bin'\/#' >base_exec.list
+ls -1 $RPM_BUILD_ROOT/%{_booksdir} |\
+  sed -e 's#^#'%{_booksdir}'\/#' > pcp-doc.list
+ls -1 $RPM_BUILD_ROOT/%{_mandir}/man1 |\
+  sed -e 's#^#'%{_mandir}'\/man1\/#' >>pcp-doc.list
+ls -1 $RPM_BUILD_ROOT/%{_mandir}/man5 |\
+  sed -e 's#^#'%{_mandir}'\/man5\/#' >>pcp-doc.list
+ls -1 $RPM_BUILD_ROOT/%{_datadir}/pcp/demos/tutorials |\
+  sed -e 's#^#'%{_datadir}/pcp/demos/tutorials'\/#' >>pcp-doc.list
+%if !%{disable_qt}
+ls -1 $RPM_BUILD_ROOT/%{_pixmapdir} |\
+  sed -e 's#^#'%{_pixmapdir}'\/#' > pcp-gui.list
+ls -1 $RPM_BUILD_ROOT/%{_hicolordir} |\
+  sed -e 's#^#'%{_hicolordir}'\/#' >> pcp-gui.list
+cat base_bin.list base_exec.list base_bashcomp.list |\
+  grep -E "$PCP_GUI" >> pcp-gui.list
+%endif
+ls -1 $RPM_BUILD_ROOT/%{_logconfdir}/ |\
+    sed -e 's#^#'%{_logconfdir}'\/#' |\
+    grep -E -v 'zeroconf' >pcp-logconf.list
+ls -1 $RPM_BUILD_ROOT/%{_ieconfdir}/ |\
+    sed -e 's#^#'%{_ieconfdir}'\/#' |\
+    grep -E -v 'zeroconf' >pcp-ieconf.list
+cat base_pmdas.list base_bin.list base_exec.list base_bashcomp.list \
+    pcp-logconf.list pcp-ieconf.list |\
+  grep -E -v 'pmdaib|pmmgr|pmsnap|2pcp|pmdas/systemd|zeroconf' |\
+  grep -E -v "$PCP_GUI|pixmaps|hicolor|pcp-doc|tutorials|selinux" |\
+  grep -E -v %{_confdir} | grep -E -v %{_logsdir} > base.list
+
+# all devel pcp package files except those split out into sub packages
+ls -1 $RPM_BUILD_ROOT/%{_mandir}/man3 |\
+sed -e 's#^#'%{_mandir}'\/man3\/#' | grep -v '3pm' >>pcp-doc.list
+ls -1 $RPM_BUILD_ROOT/%{_datadir}/pcp/demos |\
+sed -e 's#^#'%{_datadir}'\/pcp\/demos\/#' | grep -E -v tutorials >> devel.list
+ls -1 $RPM_BUILD_ROOT/%{_bindir} |\
+grep -E 'pmdbg|pmclient|pmerr|genpmda' |\
+sed -e 's#^#'%{_bindir}'\/#' >>devel.list
+
+%pre testsuite
+test -d %{_testsdir} || mkdir -p -m 755 %{_testsdir}
+getent group pcpqa >/dev/null || groupadd -r pcpqa
+getent passwd pcpqa >/dev/null || \
+  useradd -c "PCP Quality Assurance" -g pcpqa -d %{_testsdir} -M -r -s /bin/bash pcpqa 2>/dev/null
+chown -R pcpqa:pcpqa %{_testsdir} 2>/dev/null
+exit 0
+
+%post testsuite
+chown -R pcpqa:pcpqa %{_testsdir} 2>/dev/null
+%if 0%{?rhel}
+%if !%{disable_systemd}
+    systemctl restart pmcd >/dev/null 2>&1
+    systemctl restart pmlogger >/dev/null 2>&1
+    systemctl enable pmcd >/dev/null 2>&1
+    systemctl enable pmlogger >/dev/null 2>&1
+%else
+    /sbin/chkconfig --add pmcd >/dev/null 2>&1
+    /sbin/chkconfig --add pmlogger >/dev/null 2>&1
+    /sbin/service pmcd condrestart
+    /sbin/service pmlogger condrestart
+%endif
+%endif
+exit 0
+
+%pre
+getent group pcp >/dev/null || groupadd -r pcp
+getent passwd pcp >/dev/null || \
+  useradd -c "Performance Co-Pilot" -g pcp -d %{_localstatedir}/lib/pcp -M -r -s /sbin/nologin pcp
+exit 0
+
+%preun manager
+if [ "$1" -eq 0 ]
+then
+%if !%{disable_systemd}
+    systemctl --no-reload disable pmmgr.service >/dev/null 2>&1
+    systemctl stop pmmgr.service >/dev/null 2>&1
+%else
+    /sbin/service pmmgr stop >/dev/null 2>&1
+    /sbin/chkconfig --del pmmgr >/dev/null 2>&1
+%endif
+fi
+
+%if !%{disable_rpm}
+%preun pmda-rpm
+%{pmda_remove "$1" "rpm"}
+%endif
+
+%if !%{disable_systemd}
+%preun pmda-systemd
+%{pmda_remove "$1" "systemd"}
+%endif
+
+%if !%{disable_infiniband}
+%preun pmda-infiniband
+%{pmda_remove "$1" "infiniband"}
+%endif
+
+%if !%{disable_perfevent}
+%preun pmda-perfevent
+%{pmda_remove "$1" "perfevent"}
+%endif
+
+%if !%{disable_podman}
+%preun pmda-podman
+%{pmda_remove "$1" "podman"}
+%endif
+
+%if !%{disable_statsd}
+%preun pmda-statsd
+%{pmda_remove "$1" "statsd"}
+%endif
+
+%if !%{disable_json}
+%preun pmda-json
+%{pmda_remove "$1" "json"}
+%endif
+
+%preun pmda-nginx
+%{pmda_remove "$1" "nginx"}
+
+%preun pmda-oracle
+%{pmda_remove "$1" "oracle"}
+
+%preun pmda-postgresql
+%{pmda_remove "$1" "postgresql"}
+
+%preun pmda-postfix
+%{pmda_remove "$1" "postfix"}
+
+%preun pmda-elasticsearch
+%{pmda_remove "$1" "elasticsearch"}
+
+%if !%{disable_snmp}
+%preun pmda-snmp
+%{pmda_remove "$1" "snmp"}
+%endif
+
+%preun pmda-mysql
+%{pmda_remove "$1" "mysql"}
+
+%preun pmda-activemq
+%{pmda_remove "$1" "activemq"}
+
+%preun pmda-bind2
+%{pmda_remove "$1" "bind2"}
+
+%preun pmda-bonding
+%{pmda_remove "$1" "bonding"}
+
+%preun pmda-dbping
+%{pmda_remove "$1" "dbping"}
+
+%preun pmda-docker
+%{pmda_remove "$1" "docker"}
+
+%preun pmda-ds389
+%{pmda_remove "$1" "ds389"}
+
+%preun pmda-ds389log
+%{pmda_remove "$1" "ds389log"}
+
+%preun pmda-gpfs
+%{pmda_remove "$1" "gpfs"}
+
+%preun pmda-gpsd
+%{pmda_remove "$1" "gpsd"}
+
+%preun pmda-lio
+%{pmda_remove "$1" "lio"}
+
+%preun pmda-openmetrics
+%{pmda_remove "$1" "openmetrics"}
+
+%preun pmda-lustre
+%{pmda_remove "$1" "lustre"}
+
+%preun pmda-lustrecomm
+%{pmda_remove "$1" "lustrecomm"}
+
+%preun pmda-memcache
+%{pmda_remove "$1" "memcache"}
+
+%preun pmda-named
+%{pmda_remove "$1" "named"}
+
+%preun pmda-netfilter
+%{pmda_remove "$1" "netfilter"}
+
+%preun pmda-news
+%{pmda_remove "$1" "news"}
+
+%preun pmda-nfsclient
+%{pmda_remove "$1" "nfsclient"}
+
+%if !%{disable_nutcracker}
+%preun pmda-nutcracker
+%{pmda_remove "$1" "nutcracker"}
+%endif
+
+%preun pmda-pdns
+%{pmda_remove "$1" "pdns"}
+
+%preun pmda-rsyslog
+%{pmda_remove "$1" "rsyslog"}
+
+%preun pmda-redis
+%{pmda_remove "$1" "redis"}
+
+%preun pmda-samba
+%{pmda_remove "$1" "samba"}
+
+%preun pmda-vmware
+%{pmda_remove "$1" "vmware"}
+
+%preun pmda-zimbra
+%{pmda_remove "$1" "zimbra"}
+
+%preun pmda-dm
+%{pmda_remove "$1" "dm"}
+
+%if !%{disable_bcc}
+%preun pmda-bcc
+%{pmda_remove "$1" "bcc"}
+%endif
+
+%if !%{disable_bpftrace}
+%preun pmda-bpftrace
+%{pmda_remove "$1" "bpftrace"}
+%endif
+
+%if !%{disable_python2} || !%{disable_python3}
+%preun pmda-gluster
+%{pmda_remove "$1" "gluster"}
+
+%preun pmda-zswap
+%{pmda_remove "$1" "zswap"}
+
+%preun pmda-unbound
+%{pmda_remove "$1" "unbound"}
+
+%preun pmda-mic
+%{pmda_remove "$1" "mic"}
+
+%preun pmda-haproxy
+%{pmda_remove "$1" "haproxy"}
+
+%preun pmda-libvirt
+%{pmda_remove "$1" "libvirt"}
+
+%preun pmda-lmsensors
+%{pmda_remove "$1" "lmsensors"}
+
+%if !%{disable_mssql}
+%preun pmda-mssql
+%{pmda_remove "$1" "mssql"}
+%endif
+
+%preun pmda-netcheck
+%{pmda_remove "$1" "netcheck"}
+
+%endif
+
+%preun pmda-apache
+%{pmda_remove "$1" "apache"}
+
+%preun pmda-bash
+%{pmda_remove "$1" "bash"}
+
+%preun pmda-cifs
+%{pmda_remove "$1" "cifs"}
+
+%preun pmda-cisco
+%{pmda_remove "$1" "cisco"}
+
+%preun pmda-gfs2
+%{pmda_remove "$1" "gfs2"}
+
+%preun pmda-logger
+%{pmda_remove "$1" "logger"}
+
+%preun pmda-mailq
+%{pmda_remove "$1" "mailq"}
+
+%preun pmda-mounts
+%{pmda_remove "$1" "mounts"}
+
+%preun pmda-nvidia-gpu
+%{pmda_remove "$1" "nvidia"}
+
+%preun pmda-roomtemp
+%{pmda_remove "$1" "roomtemp"}
+
+%preun pmda-sendmail
+%{pmda_remove "$1" "sendmail"}
+
+%preun pmda-shping
+%{pmda_remove "$1" "shping"}
+
+%preun pmda-smart
+%{pmda_remove "$1" "smart"}
+
+%preun pmda-summary
+%{pmda_remove "$1" "summary"}
+
+%preun pmda-trace
+%{pmda_remove "$1" "trace"}
+
+%preun pmda-weblog
+%{pmda_remove "$1" "weblog"}
+
+%if !%{disable_systemd}
+%preun zeroconf
+if [ "$1" -eq 0 ]
+then
+    %systemd_preun pmlogger_daily_report.timer
+    %systemd_preun pmlogger_daily_report.service
+    %systemd_preun pmlogger_daily_report-poll.timer
+    %systemd_preun pmlogger_daily_report-poll.service
+fi
+%endif
+
+%preun
+if [ "$1" -eq 0 ]
+then
+    # stop daemons before erasing the package
+    %if !%{disable_systemd}
+       %systemd_preun pmlogger.service
+       %systemd_preun pmie.service
+       %systemd_preun pmproxy.service
+       %systemd_preun pmcd.service
+	systemctl stop pmlogger.service >/dev/null 2>&1
+	systemctl stop pmie.service >/dev/null 2>&1
+	systemctl stop pmproxy.service >/dev/null 2>&1
+	systemctl stop pmcd.service >/dev/null 2>&1
+    %else
+	/sbin/service pmlogger stop >/dev/null 2>&1
+	/sbin/service pmie stop >/dev/null 2>&1
+	/sbin/service pmproxy stop >/dev/null 2>&1
+	/sbin/service pmcd stop >/dev/null 2>&1
+
+	/sbin/chkconfig --del pcp >/dev/null 2>&1
+	/sbin/chkconfig --del pmcd >/dev/null 2>&1
+	/sbin/chkconfig --del pmlogger >/dev/null 2>&1
+	/sbin/chkconfig --del pmie >/dev/null 2>&1
+	/sbin/chkconfig --del pmproxy >/dev/null 2>&1
+    %endif
+    # cleanup namespace state/flag, may still exist
+    PCP_PMNS_DIR=%{_pmnsdir}
+    rm -f "$PCP_PMNS_DIR/.NeedRebuild" >/dev/null 2>&1
+fi
+
+%post manager
+chown -R pcp:pcp %{_logsdir}/pmmgr 2>/dev/null
+%if !%{disable_systemd}
+    systemctl condrestart pmmgr.service >/dev/null 2>&1
+%else
+    /sbin/chkconfig --add pmmgr >/dev/null 2>&1
+    /sbin/service pmmgr condrestart
+%endif
+
+%post zeroconf
+PCP_PMDAS_DIR=%{_pmdasdir}
+PCP_SYSCONFIG_DIR=%{_sysconfdir}/sysconfig
+PCP_PMCDCONF_PATH=%{_confdir}/pmcd/pmcd.conf
+# auto-install important PMDAs for RH Support (if not present already)
+for PMDA in dm nfsclient ; do
+    if ! grep -q "$PMDA/pmda$PMDA" "$PCP_PMCDCONF_PATH"
+    then
+	touch "$PCP_PMDAS_DIR/$PMDA/.NeedInstall"
+    fi
+done
+# increase default pmlogger recording frequency
+sed -i 's/^\#\ PMLOGGER_INTERVAL.*/PMLOGGER_INTERVAL=10/g' "$PCP_SYSCONFIG_DIR/pmlogger"
+# auto-enable these usually optional pmie rules
+pmieconf -c enable dmthin
+%if 0%{?rhel}
+%if !%{disable_systemd}
+    systemctl restart pmcd >/dev/null 2>&1
+    systemctl restart pmlogger >/dev/null 2>&1
+    systemctl restart pmie >/dev/null 2>&1
+    systemctl enable pmcd >/dev/null 2>&1
+    systemctl enable pmlogger >/dev/null 2>&1
+    systemctl enable pmie >/dev/null 2>&1
+%else
+    /sbin/chkconfig --add pmcd >/dev/null 2>&1
+    /sbin/chkconfig --add pmlogger >/dev/null 2>&1
+    /sbin/chkconfig --add pmie >/dev/null 2>&1
+    /sbin/service pmcd condrestart
+    /sbin/service pmlogger condrestart
+    /sbin/service pmie condrestart
+%endif
+%endif
+
+%if !%{disable_selinux}
+%post selinux
+%{selinux_handle_policy "$1" "pcpupstream"}
+
+%triggerin selinux -- docker-selinux
+%{selinux_handle_policy "$1" "pcpupstream-docker"}
+
+%triggerin selinux -- container-selinux
+%{selinux_handle_policy "$1" "pcpupstream-container"}
+%endif
+
+%post
+PCP_PMNS_DIR=%{_pmnsdir}
+chown -R pcp:pcp %{_logsdir}/pmcd 2>/dev/null
+chown -R pcp:pcp %{_logsdir}/pmlogger 2>/dev/null
+chown -R pcp:pcp %{_logsdir}/sa 2>/dev/null
+chown -R pcp:pcp %{_logsdir}/pmie 2>/dev/null
+chown -R pcp:pcp %{_logsdir}/pmproxy 2>/dev/null
+touch "$PCP_PMNS_DIR/.NeedRebuild"
+chmod 644 "$PCP_PMNS_DIR/.NeedRebuild"
+%if !%{disable_systemd}
+    %systemd_postun_with_restart pmcd.service
+    %systemd_post pmcd.service
+    %systemd_postun_with_restart pmlogger.service
+    %systemd_post pmlogger.service
+    %systemd_postun_with_restart pmie.service
+    %systemd_post pmie.service
+    systemctl condrestart pmproxy.service >/dev/null 2>&1
+%else
+    /sbin/chkconfig --add pmcd >/dev/null 2>&1
+    /sbin/service pmcd condrestart
+    /sbin/chkconfig --add pmlogger >/dev/null 2>&1
+    /sbin/service pmlogger condrestart
+    /sbin/chkconfig --add pmie >/dev/null 2>&1
+    /sbin/service pmie condrestart
+    /sbin/chkconfig --add pmproxy >/dev/null 2>&1
+    /sbin/service pmproxy condrestart
+%endif
+
+cd "$PCP_PMNS_DIR" && ./Rebuild -s && rm -f .NeedRebuild
+cd
+
+%if 0%{?fedora} >= 26 || 0%{?rhel} > 7
+%ldconfig_scriptlets libs
+%else
+%post libs -p /sbin/ldconfig
+%postun libs -p /sbin/ldconfig
+%endif
+
+%if !%{disable_selinux}
+%preun selinux
+%{selinux_handle_policy "$1" "pcpupstream"}
+
+%triggerun selinux -- docker-selinux
+%{selinux_handle_policy "$1" "pcpupstream-docker"}
+
+%triggerun selinux -- container-selinux
+%{selinux_handle_policy "$1" "pcpupstream-container"}
+
+%endif
+%files -f base.list
+#
+# Note: there are some headers (e.g. domain.h) and in a few cases some
+# C source files that rpmlint complains about. These are not devel files,
+# but rather they are (slightly obscure) PMDA config files.
+#
+%doc CHANGELOG COPYING INSTALL.md README.md VERSION.pcp pcp.lsm
+
+%dir %{_confdir}
+%dir %{_pmdasdir}
+%dir %{_datadir}/pcp
+%dir %{_libexecdir}/pcp
+%dir %{_libexecdir}/pcp/bin
+%dir %{_localstatedir}/lib/pcp
+%dir %{_localstatedir}/lib/pcp/config
+%dir %attr(0775,pcp,pcp) %{_tempsdir}
+%dir %attr(0775,pcp,pcp) %{_tempsdir}/bash
+%dir %attr(0775,pcp,pcp) %{_tempsdir}/json
+%dir %attr(0775,pcp,pcp) %{_tempsdir}/mmv
+%dir %attr(0775,pcp,pcp) %{_tempsdir}/pmie
+%dir %attr(0775,pcp,pcp) %{_tempsdir}/pmlogger
+%dir %attr(0775,pcp,pcp) %{_tempsdir}/pmproxy
+%dir %attr(0700,root,root) %{_tempsdir}/pmcd
+
+%dir %{_datadir}/pcp/lib
+%{_datadir}/pcp/lib/ReplacePmnsSubtree
+%{_datadir}/pcp/lib/bashproc.sh
+%{_datadir}/pcp/lib/lockpmns
+%{_datadir}/pcp/lib/pmdaproc.sh
+%{_datadir}/pcp/lib/utilproc.sh
+%{_datadir}/pcp/lib/rc-proc.sh
+%{_datadir}/pcp/lib/rc-proc.sh.minimal
+%{_datadir}/pcp/lib/unlockpmns
+
+%dir %attr(0775,pcp,pcp) %{_logsdir}
+%attr(0775,pcp,pcp) %{_logsdir}/pmcd
+%attr(0775,pcp,pcp) %{_logsdir}/pmlogger
+%attr(0775,pcp,pcp) %{_logsdir}/pmie
+%attr(0775,pcp,pcp) %{_logsdir}/pmproxy
+%{_localstatedir}/lib/pcp/pmns
+%{_initddir}/pcp
+%{_initddir}/pmcd
+%{_initddir}/pmlogger
+%{_initddir}/pmie
+%{_initddir}/pmproxy
+%if !%{disable_systemd}
+%{_unitdir}/pmcd.service
+%{_unitdir}/pmlogger.service
+%{_unitdir}/pmie.service
+%{_unitdir}/pmproxy.service
+# services and timers replacing the old cron scripts
+%{_unitdir}/pmlogger_check.service
+%{_unitdir}/pmlogger_check.timer
+%{_unitdir}/pmlogger_daily.service
+%{_unitdir}/pmlogger_daily.timer
+%{_unitdir}/pmlogger_daily-poll.service
+%{_unitdir}/pmlogger_daily-poll.timer
+%{_unitdir}/pmie_check.service
+%{_unitdir}/pmie_check.timer
+%{_unitdir}/pmie_daily.service
+%{_unitdir}/pmie_daily.timer
+%config(noreplace) %{_sysconfdir}/sysconfig/pmie_timers
+%config(noreplace) %{_sysconfdir}/sysconfig/pmlogger_timers
+%else
+# cron scripts
+%config(noreplace) %{_sysconfdir}/cron.d/pcp-pmlogger
+%config(noreplace) %{_sysconfdir}/cron.d/pcp-pmie
+%endif
+%config(noreplace) %{_sysconfdir}/sasl2/pmcd.conf
+%config(noreplace) %{_sysconfdir}/sysconfig/pmlogger
+%config(noreplace) %{_sysconfdir}/sysconfig/pmproxy
+%config(noreplace) %{_sysconfdir}/sysconfig/pmcd
+%config %{_sysconfdir}/pcp.env
+%dir %{_confdir}/pipe.conf.d
+%dir %{_confdir}/labels
+%dir %{_confdir}/pmcd
+%config(noreplace) %{_confdir}/pmcd/pmcd.conf
+%config(noreplace) %{_confdir}/pmcd/pmcd.options
+%config(noreplace) %{_confdir}/pmcd/rc.local
+%dir %{_confdir}/pmproxy
+%config(noreplace) %{_confdir}/pmproxy/pmproxy.options
+%config(noreplace) %{_confdir}/pmproxy/pmproxy.conf
+%dir %{_confdir}/pmie
+%dir %{_confdir}/pmie/control.d
+%config(noreplace) %{_confdir}/pmie/control
+%config(noreplace) %{_confdir}/pmie/control.d/local
+%dir %{_confdir}/pmlogger
+%dir %{_confdir}/pmlogger/control.d
+%config(noreplace) %{_confdir}/pmlogger/control
+%config(noreplace) %{_confdir}/pmlogger/control.d/local
+%dir %attr(0775,pcp,pcp) %{_confdir}/nssdb
+%dir %{_confdir}/discover
+%config(noreplace) %{_confdir}/discover/pcp-kube-pods.conf
+%if !%{disable_libuv}
+%dir %{_confdir}/pmseries
+%config(noreplace) %{_confdir}/pmseries/pmseries.conf
+%endif
+
+%ghost %dir %attr(0775,pcp,pcp) %{_localstatedir}/run/pcp
+%{_localstatedir}/lib/pcp/config/pmafm
+%dir %attr(0775,pcp,pcp) %{_localstatedir}/lib/pcp/config/pmie
+%{_localstatedir}/lib/pcp/config/pmie
+%{_localstatedir}/lib/pcp/config/pmieconf
+%dir %attr(0775,pcp,pcp) %{_localstatedir}/lib/pcp/config/pmlogger
+%{_localstatedir}/lib/pcp/config/pmlogger/*
+%{_localstatedir}/lib/pcp/config/pmlogrewrite
+%dir %attr(0775,pcp,pcp) %{_localstatedir}/lib/pcp/config/pmda
+
+%{_datadir}/zsh/site-functions/_pcp
+%if !%{disable_sdt}
+%{_tapsetdir}/pmcd.stp
+%endif
+
+%files zeroconf
+%{_libexecdir}/pcp/bin/pmlogger_daily_report
+%if !%{disable_systemd}
+# systemd services for pmlogger_daily_report to replace the cron script
+%{_unitdir}/pmlogger_daily_report.service
+%{_unitdir}/pmlogger_daily_report.timer
+%{_unitdir}/pmlogger_daily_report-poll.service
+%{_unitdir}/pmlogger_daily_report-poll.timer
+%else
+%config(noreplace) %{_sysconfdir}/cron.d/pcp-pmlogger-daily-report
+%endif
+%{_ieconfdir}/zeroconf
+%{_logconfdir}/zeroconf
+
+#additional pmlogger config files
+
+%files conf
+%dir %{_includedir}/pcp
+%{_includedir}/pcp/builddefs
+%{_includedir}/pcp/buildrules
+%config %{_sysconfdir}/pcp.conf
+%dir %{_localstatedir}/lib/pcp/config/derived
+%config %{_localstatedir}/lib/pcp/config/derived/*
+
+%files libs
+%{_libdir}/libpcp.so.3
+%{_libdir}/libpcp_gui.so.2
+%{_libdir}/libpcp_mmv.so.1
+%{_libdir}/libpcp_pmda.so.3
+%{_libdir}/libpcp_trace.so.2
+%{_libdir}/libpcp_import.so.1
+%{_libdir}/libpcp_web.so.1
+
+%files libs-devel
+%{_libdir}/libpcp.so
+%{_libdir}/libpcp_gui.so
+%{_libdir}/libpcp_mmv.so
+%{_libdir}/libpcp_pmda.so
+%{_libdir}/libpcp_trace.so
+%{_libdir}/libpcp_import.so
+%{_libdir}/libpcp_web.so
+%{_libdir}/pkgconfig/libpcp.pc
+%{_libdir}/pkgconfig/libpcp_pmda.pc
+%{_libdir}/pkgconfig/libpcp_import.pc
+%{_includedir}/pcp/*.h
+
+%files devel -f devel.list
+%{_datadir}/pcp/examples
+
+# PMDAs that ship src and are not for production use
+# straight out-of-the-box, for devel or QA use only.
+%{_pmdasdir}/simple
+%{_pmdasdir}/sample
+%{_pmdasdir}/trivial
+%{_pmdasdir}/txmon
+
+%files testsuite
+%defattr(-,pcpqa,pcpqa)
+%{_testsdir}
+
+%files manager
+%{_initddir}/pmmgr
+%if !%{disable_systemd}
+%{_unitdir}/pmmgr.service
+%endif
+%{_libexecdir}/pcp/bin/pmmgr
+%attr(0775,pcp,pcp) %{_logsdir}/pmmgr
+%config(missingok,noreplace) %{_confdir}/pmmgr
+%config(noreplace) %{_confdir}/pmmgr/pmmgr.options
+
+%files import-sar2pcp
+%{_bindir}/sar2pcp
+
+%files import-iostat2pcp
+%{_bindir}/iostat2pcp
+
+%files import-mrtg2pcp
+%{_bindir}/mrtg2pcp
+
+%files import-ganglia2pcp
+%{_bindir}/ganglia2pcp
+
+%files import-collectl2pcp
+%{_bindir}/collectl2pcp
+
+%if !%{disable_podman}
+%files pmda-podman
+%{_pmdasdir}/podman
+%endif
+
+%if !%{disable_statsd}
+%files pmda-statsd
+%{_pmdasdir}/statsd
+%config(noreplace) %{_pmdasdir}/statsd/pmdastatsd.ini
+%endif
+
+%if !%{disable_perfevent}
+%files pmda-perfevent
+%{_pmdasdir}/perfevent
+%config(noreplace) %{_pmdasdir}/perfevent/perfevent.conf
+%endif
+
+%if !%{disable_infiniband}
+%files pmda-infiniband
+%{_pmdasdir}/ib
+%{_pmdasdir}/infiniband
+%endif
+
+%files pmda-activemq
+%{_pmdasdir}/activemq
+
+%files pmda-bonding
+%{_pmdasdir}/bonding
+
+%files pmda-bind2
+%{_pmdasdir}/bind2
+
+%files pmda-dbping
+%{_pmdasdir}/dbping
+
+%files pmda-ds389log
+%{_pmdasdir}/ds389log
+
+%files pmda-ds389
+%{_pmdasdir}/ds389
+
+%files pmda-elasticsearch
+%{_pmdasdir}/elasticsearch
+
+%files pmda-gpfs
+%{_pmdasdir}/gpfs
+
+%files pmda-gpsd
+%{_pmdasdir}/gpsd
+
+%files pmda-docker
+%{_pmdasdir}/docker
+
+%files pmda-lio
+%{_pmdasdir}/lio
+
+%files pmda-openmetrics
+%{_pmdasdir}/openmetrics
+
+%files pmda-lustre
+%{_pmdasdir}/lustre
+
+%files pmda-lustrecomm
+%{_pmdasdir}/lustrecomm
+
+%files pmda-memcache
+%{_pmdasdir}/memcache
+
+%files pmda-mysql
+%{_pmdasdir}/mysql
+
+%files pmda-named
+%{_pmdasdir}/named
+
+%files pmda-netfilter
+%{_pmdasdir}/netfilter
+
+%files pmda-news
+%{_pmdasdir}/news
+
+%files pmda-nginx
+%{_pmdasdir}/nginx
+
+%files pmda-nfsclient
+%{_pmdasdir}/nfsclient
+
+%if !%{disable_nutcracker}
+%files pmda-nutcracker
+%{_pmdasdir}/nutcracker
+%endif
+
+%files pmda-oracle
+%{_pmdasdir}/oracle
+
+%files pmda-pdns
+%{_pmdasdir}/pdns
+
+%files pmda-postfix
+%{_pmdasdir}/postfix
+
+%files pmda-postgresql
+%{_pmdasdir}/postgresql
+%config(noreplace) %{_pmdasdir}/postgresql/pmdapostgresql.conf
+
+%files pmda-redis
+%{_pmdasdir}/redis
+
+%files pmda-rsyslog
+%{_pmdasdir}/rsyslog
+
+%files pmda-samba
+%{_pmdasdir}/samba
+
+%if !%{disable_snmp}
+%files pmda-snmp
+%{_pmdasdir}/snmp
+%endif
+
+%files pmda-slurm
+%{_pmdasdir}/slurm
+
+%files pmda-vmware
+%{_pmdasdir}/vmware
+
+%files pmda-zimbra
+%{_pmdasdir}/zimbra
+
+%files pmda-dm
+%{_pmdasdir}/dm
+%{_ieconfdir}/dm
+
+%if !%{disable_bcc}
+%files pmda-bcc
+%{_pmdasdir}/bcc
+%endif
+
+%if !%{disable_bpftrace}
+%files pmda-bpftrace
+%{_pmdasdir}/bpftrace
+%endif
+
+%if !%{disable_python2} || !%{disable_python3}
+%files pmda-gluster
+%{_pmdasdir}/gluster
+
+%files pmda-zswap
+%{_pmdasdir}/zswap
+
+%files pmda-unbound
+%{_pmdasdir}/unbound
+
+%files pmda-mic
+%{_pmdasdir}/mic
+
+%files pmda-haproxy
+%{_pmdasdir}/haproxy
+
+%files pmda-libvirt
+%{_pmdasdir}/libvirt
+
+%files export-pcp2elasticsearch
+%{_bindir}/pcp2elasticsearch
+%{_bashcompdir}/pcp2elasticsearch
+
+%files export-pcp2graphite
+%{_bindir}/pcp2graphite
+%{_bashcompdir}/pcp2graphite
+
+%files export-pcp2influxdb
+%{_bindir}/pcp2influxdb
+%{_bashcompdir}/pcp2influxdb
+
+%files export-pcp2json
+%{_bindir}/pcp2json
+%{_bashcompdir}/pcp2json
+
+%files export-pcp2spark
+%{_bindir}/pcp2spark
+%{_bashcompdir}/pcp2spark
+
+%if !%{disable_xlsx}
+%files export-pcp2xlsx
+%{_bindir}/pcp2xlsx
+%{_bashcompdir}/pcp2xlsx
+%endif
+
+%files export-pcp2xml
+%{_bindir}/pcp2xml
+%{_bashcompdir}/pcp2xml
+
+%files export-pcp2zabbix
+%{_bindir}/pcp2zabbix
+%{_bashcompdir}/pcp2zabbix
+
+%files pmda-lmsensors
+%{_pmdasdir}/lmsensors
+
+%files pmda-netcheck
+%{_pmdasdir}/netcheck
+
+%endif
+
+%files export-zabbix-agent
+%{_libdir}/zabbix
+%{_sysconfdir}/zabbix/zabbix_agentd.d/zbxpcp.conf
+
+%if !%{disable_mssql}
+%files pmda-mssql
+%{_pmdasdir}/mssql
+%endif
+
+%if !%{disable_json}
+%files pmda-json
+%{_pmdasdir}/json
+%endif
+
+%files pmda-apache
+%{_pmdasdir}/apache
+
+%files pmda-bash
+%{_pmdasdir}/bash
+
+%files pmda-cifs
+%{_pmdasdir}/cifs
+
+%files pmda-cisco
+%{_pmdasdir}/cisco
+
+%files pmda-gfs2
+%{_pmdasdir}/gfs2
+
+%files pmda-logger
+%{_pmdasdir}/logger
+
+%files pmda-mailq
+%{_pmdasdir}/mailq
+
+%files pmda-mounts
+%{_pmdasdir}/mounts
+
+%files pmda-nvidia-gpu
+%{_pmdasdir}/nvidia
+
+%files pmda-roomtemp
+%{_pmdasdir}/roomtemp
+
+%if !%{disable_rpm}
+%files pmda-rpm
+%{_pmdasdir}/rpm
+%endif
+
+%files pmda-sendmail
+%{_pmdasdir}/sendmail
+
+%files pmda-shping
+%{_pmdasdir}/shping
+
+%files pmda-smart
+%{_pmdasdir}/smart
+
+%files pmda-summary
+%{_pmdasdir}/summary
+
+%if !%{disable_systemd}
+%files pmda-systemd
+%{_pmdasdir}/systemd
+%endif
+
+%files pmda-trace
+%{_pmdasdir}/trace
+
+%files pmda-weblog
+%{_pmdasdir}/weblog
+
+%files -n perl-PCP-PMDA -f perl-pcp-pmda.list
+
+%files -n perl-PCP-MMV -f perl-pcp-mmv.list
+
+%files -n perl-PCP-LogImport -f perl-pcp-logimport.list
+
+%files -n perl-PCP-LogSummary -f perl-pcp-logsummary.list
+
+%if !%{disable_python2}
+%files -n %{__python2}-pcp -f python-pcp.list.rpm
+%endif
+
+%if !%{disable_python3}
+%files -n python3-pcp -f python3-pcp.list.rpm
+%endif
+
+%if !%{disable_qt}
+%files gui -f pcp-gui.list
+
+%{_confdir}/pmsnap
+%config(noreplace) %{_confdir}/pmsnap/control
+%{_localstatedir}/lib/pcp/config/pmsnap
+%{_localstatedir}/lib/pcp/config/pmchart
+%{_localstatedir}/lib/pcp/config/pmafm/pcp-gui
+%{_datadir}/applications/pmchart.desktop
+%{_bashcompdir}/pmdumptext
+%endif
+
+%files doc -f pcp-doc.list
+
+%if !%{disable_selinux}
+%files selinux -f pcp-selinux.list
+%dir %{_selinuxdir}
+%endif
+
+%if !%{disable_python2} || !%{disable_python3}
+%files system-tools -f pcp-system-tools.list
+%dir %{_confdir}/dstat
+%dir %{_confdir}/pmrep
+%config(noreplace) %{_confdir}/dstat/*
+%config(noreplace) %{_confdir}/pmrep/*
+%{_bashcompdir}/pmrep
+%endif
+
+%changelog
+* Tue Feb 25 2020 Nathan Scott <nathans@redhat.com> - 5.0.2-5
+- Fix /proc/interrupts parsing on s390x platforms (BZ 1798058)
+
+* Mon Feb 03 2020 Nathan Scott <nathans@redhat.com> - 5.0.2-4
+- Restrict pcp-pmda-mssql to ODBC architectures (BZ 1795804)
+- Fix pcp-pmda-activemq perl module installation (BZ 1788881)
+- Update archive discovery code with latest fixes (BZ 1785560)
+- Update bpftrace and BCC PMDAs architecture lists (BZ 1795798)
+
+* Tue Jan 21 2020 Nathan Scott <nathans@redhat.com> - 5.0.2-3
+- Fix issue with multilib pcp-devel installation (BZ 1788119)
+- Archive discovery fixes in pmproxy and libpcp_web (BZ 1785560)
+
+* Thu Dec 12 2019 Nathan Scott <nathans@redhat.com> - 5.0.2-2
+- Reenable infiniband PMDA in the rpm spec, deps fixed.
+
+* Wed Dec 11 2019 Nathan Scott <nathans@redhat.com> - 5.0.2-1
+- Update to latest PCP v5 sources via rebase (BZ 1723598)
+- Resolve selinux policy issue with bcc PMDA (BZ 1709237)
+- Resolve selinux policy issue with unbound PMDA (BZ 1778813)
+- Updates to perfevent PMDA for hv_24x7 events (BZ 1765434, 1779507)
+- Fix perl packaging dependency for postfix PMDA (BZ 1773459)
+- Fix pcp-dstat handling of large numbers of disks (BZ 1779419)
+- Fix pmie exit status on receipt of TERM signal (BZ 1780003)
+- Fix pmlogger timeout handling on fresh install (BZ 1780073)
+
+* Mon Nov 11 2019 Nathan Scott <nathans@redhat.com> - 5.0.1-1
+- Update to latest PCP v5 sources via rebase (BZ 1723598)
+- Resolve selinux policy installation issues (BZ 1730206)
+
+* Mon May 06 2019 Nathan Scott <nathans@redhat.com> - 4.3.2-2
+- Update metrics for device mapper VDO driver (BZ 1670548)
+- Update to a more recent PCP bug fix release (BZ 1685302)
+
+* Thu Jan 10 2019 Mark Goodwin <mgoodwin@redhat.com> - 4.3.0-3
+- add missing build deps on libuv for pmseries and libpcp_web (BZ 1630540)
+
+* Wed Dec 26 2018 Mark Goodwin <mgoodwin@redhat.com> - 4.3.0-2
+- Revert pmlogger_daily daystart patch (BZ 1662034)
+
+* Thu Jul 07 2016 Nathan Scott <nathans@redhat.com> - 3.11.3-2
+- Export filesys metrics with persistent DM naming (BZ 1349932)
+
+* Fri Jun 17 2016 Nathan Scott <nathans@redhat.com> - 3.11.3-1
+- Fix memory leak in derived metrics error handling (BZ 1331973)
+- Correctly propogate indom in mixed derived metrics (BZ 1337212, BZ 1336130)
+- Disallow stopping pmie/pmlogger daemons from cron (BZ 1336792)
+- Fail fast for easily detected bad pmcd configuration (BZ 1336210)
+- Implement primary (local) pmie concept in rc pmie (BZ 1323851)
+- Update to latest PCP sources.
+
+* Mon May 16 2016 Jitka Plesnikova <jplesnik@redhat.com> - 3.11.2-2.1
+- Perl 5.24 rebuild
+
+* Fri Apr 29 2016 Lukas Berk <lberk@redhat.com> - 3.11.2-1
+- Negative nice values reported incorrectly (BZ 1328432)
+- Multithreaded clients with concurrent pmNewContext improvements (BZ 1325363)
+- PMCD agent auto-restart (BZ 1323521)
+- Segv in libpcp during discovery error processing (BZ 1319288)
+- Update to latest PCP sources.
+
+* Fri Mar 18 2016 Dave Brolley <brolley@redhat.com> - 3.11.1-1
+- Call Remove script when uninstalling individual PMDAs (BZ 1304722)
+- Restrict pmcd.services to checking known pcp services (BZ 1286361)
+- Support for multi-archive contexts, across all clients (BZ 1262723)
+- Remove the default shotgun approach to stopping daemons (BZ 1210976)
+- Add mechanism for automatic recovery from PMDA timeouts (BZ 1065803)
+- Update to latest PCP sources.
+
+* Fri Jan 29 2016 Mark Goodwin <mgoodwin@redhat.com> - 3.11.0-1
+- Significant speedups to elapsed time stopping pmcd (BZ 1292027)
+- Fix python derived metric exception handling issues (BZ 1299806)
+- incorrect interpolation across <mark> record in a merged archive (BZ 1296750)
+- pcp requires pcp-compat pulling in a lot of unneeded pcp-pmda-* packages (BZ 1293466)
+- Update to latest PCP sources.
+
+* Wed Dec 16 2015 Lukas Berk <lberk@redhat.com> - 3.10.9-1
+- Add -V/--version support to several more commands (BZ 1284411)
+- Resolve a pcp-iostat(1) transient device exception (BZ 1249572)
+- Provides pmdapipe, an output-capturing domain agent (BZ 1163413)
+- Python PMAPI pmSetMode allows None timeval parameter (BZ 1284417)
+- Python PMI pmiPutValue now supports singular metrics (BZ 1285371)
+- Fix python PMAPI pmRegisterDerived wrapper interface (BZ 1286733)
+- Fix pmstat SEGV when run with graphical time control (BZ 1287678)
+- Make pmNonOptionsFromList error message less cryptic (BZ 1287778)
+- Drop unimplemented pmdumptext options from usage, man page (BZ 1289909)
+- Stop creating configuration files in tmp_t locations (BZ 1256125)
+- Update to latest PCP sources.
+
+* Fri Oct 30 2015 Mark Goodwin <mgoodwin@redhat.com> - 3.10.8-1
+- Update pmlogger to log an immediate sample first (BZ 1269921)
+- Add pmOption host and archive setter python APIs (BZ 1270176)
+- Replace old pmatop(1) man page with pcp-atop(1) (BZ 1270761)
+- Update to latest PCP sources.
+
+* Wed Sep 16 2015 Nathan Scott <nathans@redhat.com> - 3.10.7-1
+- Resolved pmchart sigsegv opening view without context (BZ 1256708)
+- Fixed pmchart memory corruption restoring Saved Hosts (BZ 1257009)
+- Fix perl PMDA API double-free on socket error path (BZ 1258862)
+- Fix python API pmGetOption(3) alignment interface (BZ 1262722)
+- Added missing RPM dependencies to several PMDA sub-packages.
+- Update to latest stable Vector release for pcp-vector-webapp.
+- Update to latest PCP sources.
+
+* Sat Sep 05 2015 Kalev Lember <klember@redhat.com> - 3.10.6-2.1
+- Rebuilt for librpm soname bump
+
+* Thu Aug 06 2015 Lukas Berk <lberk@redhat.com> - 3.10.6-2
+- Fix SDT related build error (BZ 1250894)
+
+* Tue Aug 04 2015 Nathan Scott <nathans@redhat.com> - 3.10.6-1
+- Fix pcp2graphite write method invocation failure (BZ 1243123)
+- Reduce diagnostics in pmdaproc unknown state case (BZ 1224431)
+- Derived metrics via multiple files, directory expansion (BZ 1235556)
+- Update to latest PCP sources.
+
+* Mon Jun 15 2015 Mark Goodwin <mgoodwin@redhat.com> - 3.10.5-1
+- Provide and use non-exit(1)ing pmGetConfig(3) variant (BZ 1187588)
+- Resolve a pmdaproc.sh pmlogger restart regression (BZ 1229458)
+- Replacement of pmatop/pcp-atop(1) utility (BZ 1160811, BZ 1018575)
+- Reduced installation size for minimal applications (BZ 1182184)
+- Ensure pmlogger start scripts wait on pmcd startup (BZ 1185760)
+- Need to run pmcd at least once before pmval -L will work (BZ 185749)
+
+* Wed Apr 15 2015 Nathan Scott <nathans@redhat.com> - 3.10.4-1
+- Update to latest PCP, pcp-webjs and Vector sources.
+- Packaging improvements after re-review (BZ 1204467)
+- Start pmlogger/pmie independent of persistent state (BZ 1185755)
+- Fix cron error reports for disabled pmlogger service (BZ 1208699)
+- Incorporate Vector from Netflix (https://github.com/Netflix/vector)
+- Sub-packages for pcp-webjs allowing choice and reducing used space.
+
+* Wed Mar 04 2015 Dave Brolley <brolley@redhat.com> - 3.10.3-2
+- papi 5.4.1 rebuild
+
+* Mon Mar 02 2015 Dave Brolley <brolley@redhat.com> - 3.10.3-1
+- Update to latest PCP sources.
+- New sub-package for pcp-import-ganglia2pcp.
+- Python3 support, enabled by default in f22 onward (BZ 1194324)
+
+* Mon Feb 23 2015 Slavek Kabrda <bkabrda@redhat.com> - 3.10.2-3
+- Only use Python 3 in Fedora >= 23, more info at
+  https://bugzilla.redhat.com/show_bug.cgi?id=1194324#c4
+
+* Mon Feb 23 2015 Nathan Scott <nathans@redhat.com> - 3.10.2-2
+- Initial changes to support python3 as default (BZ 1194324)
+
+* Fri Jan 23 2015 Dave Brolley <brolley@redhat.com> - 3.10.2-1
+- Update to latest PCP sources.
+- Improve pmdaInit diagnostics for DSO helptext (BZ 1182949)
+- Tighten up PMDA termination on pmcd stop (BZ 1180109)
+- Correct units for cgroup memory metrics (BZ 1180351)
+- Add the pcp2graphite(1) export script (BZ 1163986)
+
+* Mon Dec 01 2014 Nathan Scott <nathans@redhat.com> - 3.10.1-1
+- New conditionally-built pcp-pmda-perfevent sub-package.
+- Update to latest PCP sources.
+
+* Tue Nov 18 2014 Dave Brolley <brolley@redhat.com> - 3.10.0-2
+- papi 5.4.0 rebuild
+
+* Fri Oct 31 2014 Nathan Scott <nathans@redhat.com> - 3.10.0-1
+- Create new sub-packages for pcp-webjs and python3-pcp.
+- Fix __pmDiscoverServicesWithOptions(1) codes (BZ 1139529)
+- Update to latest PCP sources.
+
+* Fri Sep 05 2014 Nathan Scott <nathans@redhat.com> - 3.9.10-1
+- Convert PCP init scripts to systemd services (BZ 996438)
+- Fix pmlogsummary -S/-T time window reporting (BZ 1132476)
+- Resolve pmdumptext segfault with invalid host (BZ 1131779)
+- Fix signedness in some service discovery codes (BZ 1136166)
+- New conditionally-built pcp-pmda-papi sub-package.
+- Update to latest PCP sources.
+
+* Tue Aug 26 2014 Jitka Plesnikova <jplesnik@redhat.com> - 3.9.9-1.2
+- Perl 5.20 rebuild
+
+* Sun Aug 17 2014 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 3.9.9-1.1
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild
+
+* Wed Aug 13 2014 Nathan Scott <nathans@redhat.com> - 3.9.9-1
+- Update to latest PCP sources.
+
+* Wed Jul 16 2014 Mark Goodwin <mgoodwin@redhat.com> - 3.9.7-1
+- Update to latest PCP sources.
+
+* Wed Jun 18 2014 Dave Brolley <brolley@redhat.com> - 3.9.5-1
+- Daemon signal handlers no longer use unsafe APIs (BZ 847343)
+- Handle /var/run setups on a temporary filesystem (BZ 656659)
+- Resolve pmlogcheck sigsegv for some archives (BZ 1077432)
+- Ensure pcp-gui-{testsuite,debuginfo} packages get replaced.
+- Revive support for EPEL5 builds, post pcp-gui merge.
+- Update to latest PCP sources.
+
+* Fri Jun 06 2014 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 3.9.4-1.1
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild
+
+* Thu May 15 2014 Nathan Scott <nathans@redhat.com> - 3.9.4-1
+- Merged pcp-gui and pcp-doc packages into core PCP.
+- Allow for conditional libmicrohttpd builds in spec file.
+- Adopt slow-start capability in systemd PMDA (BZ 1073658)
+- Resolve pmcollectl network/disk mis-reporting (BZ 1097095)
+- Update to latest PCP sources.
+
+* Tue Apr 15 2014 Dave Brolley <brolley@redhat.com> - 3.9.2-1
+- Improve pmdarpm(1) concurrency complications (BZ 1044297)
+- Fix pmconfig(1) shell output string quoting (BZ 1085401)
+- Update to latest PCP sources.
+
+* Wed Mar 19 2014 Nathan Scott <nathans@redhat.com> - 3.9.1-1
+- Update to latest PCP sources.
+
+* Thu Feb 20 2014 Nathan Scott <nathans@redhat.com> - 3.9.0-2
+- Workaround further PowerPC/tapset-related build fallout.
+
+* Wed Feb 19 2014 Nathan Scott <nathans@redhat.com> - 3.9.0-1
+- Create new sub-packages for pcp-webapi and pcp-manager
+- Split configuration from pcp-libs into pcp-conf (multilib)
+- Fix pmdagluster to handle more volumes, fileops (BZ 1066544)
+- Update to latest PCP sources.
+
+* Wed Jan 29 2014 Nathan Scott <nathans@redhat.com> - 3.8.12-1
+- Resolves SNMP procfs file ICMP line parse issue (BZ 1055818)
+- Update to latest PCP sources.
+
+* Wed Jan 15 2014 Nathan Scott <nathans@redhat.com> - 3.8.10-1
+- Update to latest PCP sources.
+
+* Thu Dec 12 2013 Nathan Scott <nathans@redhat.com> - 3.8.9-1
+- Reduce set of exported symbols from DSO PMDAs (BZ 1025694)
+- Symbol-versioning for PCP shared libraries (BZ 1037771)
+- Fix pmcd/Avahi interaction with multiple ports (BZ 1035513)
+- Update to latest PCP sources.
+
+* Sun Nov 03 2013 Nathan Scott <nathans@redhat.com> - 3.8.8-1
+- Update to latest PCP sources (simple build fixes only).
+
+* Fri Nov 01 2013 Nathan Scott <nathans@redhat.com> - 3.8.6-1
+- Update to latest PCP sources.
+- Rework pmpost test which confused virus checkers (BZ 1024850)
+- Tackle pmatop reporting issues via alternate metrics (BZ 998735)
+
+* Fri Oct 18 2013 Nathan Scott <nathans@redhat.com> - 3.8.5-1
+- Update to latest PCP sources.
+- Disable pcp-pmda-infiniband sub-package on RHEL5 (BZ 1016368)
+
+* Mon Sep 16 2013 Nathan Scott <nathans@redhat.com> - 3.8.4-2
+- Disable the pcp-pmda-infiniband sub-package on s390 platforms.
+
+* Sun Sep 15 2013 Nathan Scott <nathans@redhat.com> - 3.8.4-1
+- Very minor release containing mostly QA related changes.
+- Enables many more metrics to be logged for Linux hosts.
+
+* Wed Sep 11 2013 Stan Cox <scox@redhat.com> - 3.8.3-2
+- Disable pmcd.stp on el5 ppc.
+
+* Mon Sep 09 2013 Nathan Scott <nathans@redhat.com> - 3.8.3-1
+- Default to Unix domain socket (authenticated) local connections.
+- Introduces new pcp-pmda-infiniband sub-package.
+- Disable systemtap-sdt-devel usage on ppc.
+
+* Sat Aug 03 2013 Petr Pisar <ppisar@redhat.com> - 3.8.2-1.1
+- Perl 5.18 rebuild
+
+* Wed Jul 31 2013 Nathan Scott <nathans@redhat.com> - 3.8.2-1
+- Update to latest PCP sources.
+- Integrate gluster related stats with PCP (BZ 969348)
+- Fix for iostat2pcp not parsing iostat output (BZ 981545)
+- Start pmlogger with usable config by default (BZ 953759)
+- Fix pmatop failing to start, gives stacktrace (BZ 963085)
+
+* Wed Jun 19 2013 Nathan Scott <nathans@redhat.com> - 3.8.1-1
+- Update to latest PCP sources.
+- Fix log import silently dropping >1024 metrics (BZ 968210)
+- Move some commonly used tools on the usual PATH (BZ 967709)
+- Improve pmatop handling of missing proc metrics (BZ 963085)
+- Stop out-of-order records corrupting import logs (BZ 958745)
+
+* Tue May 14 2013 Nathan Scott <nathans@redhat.com> - 3.8.0-1
+- Update to latest PCP sources.
+- Validate metric names passed into pmiAddMetric (BZ 958019)
+- Install log directories with correct ownership (BZ 960858)
+
+* Fri Apr 19 2013 Nathan Scott <nathans@redhat.com> - 3.7.2-1
+- Update to latest PCP sources.
+- Ensure root namespace exists at the end of install (BZ 952977)
+
+* Wed Mar 20 2013 Nathan Scott <nathans@redhat.com> - 3.7.1-1
+- Update to latest PCP sources.
+- Migrate all tempfiles correctly to the new tempdir hierarchy.
+
+* Sun Mar 10 2013 Nathan Scott <nathans@redhat.com> - 3.7.0-1
+- Update to latest PCP sources.
+- Migrate all configuration files below the /etc/pcp hierarchy.
+
+* Thu Feb 14 2013 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 3.6.10-2.1
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild
+
+* Wed Nov 28 2012 Nathan Scott <nathans@redhat.com> - 3.6.10-2
+- Ensure tmpfile directories created in %%files section.
+- Resolve tmpfile create/teardown race conditions.
+
+* Mon Nov 19 2012 Nathan Scott <nathans@redhat.com> - 3.6.10-1
+- Update to latest PCP sources.
+- Resolve tmpfile security flaws: CVE-2012-5530
+- Introduces new "pcp" user account for all daemons to use.
+
+* Fri Oct 12 2012 Nathan Scott <nathans@redhat.com> - 3.6.9-1
+- Update to latest PCP sources.
+- Fix pmcd sigsegv in NUMA/CPU indom setup (BZ 858384)
+- Fix sar2pcp uninitialised perl variable warning (BZ 859117)
+- Fix pcp.py and pmcollectl with older python versions (BZ 852234)
+
+* Fri Sep 14 2012 Nathan Scott <nathans@redhat.com> - 3.6.8-1
+- Update to latest PCP sources.
+
+* Wed Sep 05 2012 Nathan Scott <nathans@redhat.com> - 3.6.6-1.1
+- Move configure step from prep to build section of spec (BZ 854128)
+
+* Tue Aug 28 2012 Mark Goodwin <mgoodwin@redhat.com> - 3.6.6-1
+- Update to latest PCP sources, see installed CHANGELOG for details.
+- Introduces new python-pcp and pcp-testsuite sub-packages.
+
+* Thu Aug 16 2012 Mark Goodwin <mgoodwin@redhat.com> - 3.6.5-1
+- Update to latest PCP sources, see installed CHANGELOG for details.
+- Fix security flaws: CVE-2012-3418 CVE-2012-3419 CVE-2012-3420 and CVE-2012-3421 (BZ 848629)
+
+* Thu Jul 19 2012 Mark Goodwin <mgoodwin@redhat.com>
+- pmcd and pmlogger services are not supposed to be enabled by default (BZ 840763) - 3.6.3-1.3
+
+* Thu Jun 21 2012 Mark Goodwin <mgoodwin@redhat.com>
+- remove pcp-import-sheet2pcp subpackage due to missing deps (BZ 830923) - 3.6.3-1.2
+
+* Fri May 18 2012 Dan Hork <dan[at]danny.cz> - 3.6.3-1.1
+- fix build on s390x
+
+* Mon Apr 30 2012 Mark Goodwin - 3.6.3-1
+- Update to latest PCP sources
+
+* Thu Apr 26 2012 Mark Goodwin - 3.6.2-1
+- Update to latest PCP sources
+
+* Thu Apr 12 2012 Mark Goodwin - 3.6.1-1
+- Update to latest PCP sources
+
+* Thu Mar 22 2012 Mark Goodwin - 3.6.0-1
+- use %%configure macro for correct libdir logic
+- update to latest PCP sources
+
+* Thu Dec 15 2011 Mark Goodwin - 3.5.11-2
+- patched configure.in for libdir=/usr/lib64 on ppc64
+
+* Thu Dec 01 2011 Mark Goodwin - 3.5.11-1
+- Update to latest PCP sources.
+
+* Fri Nov 04 2011 Mark Goodwin - 3.5.10-1
+- Update to latest PCP sources.
+
+* Mon Oct 24 2011 Mark Goodwin - 3.5.9-1
+- Update to latest PCP sources.
+
+* Mon Aug 08 2011 Mark Goodwin - 3.5.8-1
+- Update to latest PCP sources.
+
+* Fri Aug 05 2011 Mark Goodwin - 3.5.7-1
+- Update to latest PCP sources.
+
+* Fri Jul 22 2011 Mark Goodwin - 3.5.6-1
+- Update to latest PCP sources.
+
+* Tue Jul 19 2011 Mark Goodwin - 3.5.5-1
+- Update to latest PCP sources.
+
+* Thu Feb 03 2011 Mark Goodwin - 3.5.0-1
+- Update to latest PCP sources.
+
+* Thu Sep 30 2010 Mark Goodwin - 3.4.0-1
+- Update to latest PCP sources.
+
+* Fri Jul 16 2010 Mark Goodwin - 3.3.3-1
+- Update to latest PCP sources.
+
+* Sat Jul 10 2010 Mark Goodwin - 3.3.2-1
+- Update to latest PCP sources.
+
+* Tue Jun 29 2010 Mark Goodwin - 3.3.1-1
+- Update to latest PCP sources.
+
+* Fri Jun 25 2010 Mark Goodwin - 3.3.0-1
+- Update to latest PCP sources.
+
+* Thu Mar 18 2010 Mark Goodwin - 3.1.2-1
+- Update to latest PCP sources.
+
+* Wed Jan 27 2010 Mark Goodwin - 3.1.0-1
+- BuildRequires: initscripts for %%{_vendor} == redhat.
+
+* Thu Dec 10 2009 Mark Goodwin - 3.0.3-1
+- BuildRequires: initscripts for FC12.
+
+* Wed Dec 02 2009 Mark Goodwin - 3.0.2-1
+- Added sysfs.kernel metrics, rebased to minor community release.
+
+* Mon Oct 19 2009 Martin Hicks <mort@sgi.com> - 3.0.1-2
+- Remove IB dependencies.  The Infiniband PMDA is being moved to
+  a stand-alone package.
+- Move cluster PMDA to a stand-alone package.
+
+* Fri Oct 09 2009 Mark Goodwin <mgoodwin@redhat.com> - 3.0.0-9
+- This is the initial import for Fedora
+- See 3.0.0 details in CHANGELOG