Blob Blame History Raw
BZ 1849511 - resolve covscan and other issues from upstream QA 
f7f1dd546 pmproxy: complete handling of HTTP/1.1 TRACE requests
cc662872b qa: add pcp-free-tera archive to pcp-testsuite package
80639d05b pmlogger_check.sh: major overhaul (diags and systemd fixups)
460b7ac2a src/pmlogger/rc_pmlogger: use --quick to pmlogger_check
0b3b4d4ee src/pmlogger/pmlogger_check.service.in: add --skip-primary arg to pmlogger_check
3a68366a8 src/pmlogger/pmlogger.service.in: change ancillary services from After to Before
5d65a6035 src/pmlogger/pmlogger_daily.sh: similar changes to pmlogger_check.sh
ace576907 src/pmlogger/pmlogger_check.sh: fix locking snarfoo
2b2c3db11 src/pmlogger/pmlogger_daily.sh: fix diagnostic spaghetti
4cc54287f pmproxy: allow URLs up to 8k in length

diff -auNr pcp-5.1.1-004/man/man1/pmlogger_check.1 pcp-5.1.1-005/man/man1/pmlogger_check.1
--- pcp-5.1.1-004/man/man1/pmlogger_check.1	2020-04-07 13:31:03.000000000 +1000
+++ pcp-5.1.1-005/man/man1/pmlogger_check.1	2020-06-22 20:08:18.454403788 +1000
@@ -19,7 +19,7 @@
 \f3pmlogger_daily\f1 \- administration of Performance Co-Pilot archive log files
 .SH SYNOPSIS
 .B $PCP_BINADM_DIR/pmlogger_check
-[\f3\-CNsTV?\f1]
+[\f3\-CNpqsTV?\f1]
 [\f3\-c\f1 \f2control\f1]
 [\f3\-l\f1 \f2logfile\f1]
 .br
@@ -269,6 +269,20 @@
 .TP
 \fB\-p\fR
 If this option is specified for
+.B pmlogger_check
+then any line from the control files for the
+.I primary
+.B pmlogger
+will be ignored.
+This option is intended for environments where some system daemon,
+like
+.BR systemd (1),
+is responsible for controlling (starting, stopping, restarting, etc.) the
+.I primary
+.BR pmlogger .
+.TP
+\fB\-p\fR
+If this option is specified for
 .B pmlogger_daily
 then the status of the daily processing is polled and if the daily
 .BR pmlogger (1)
@@ -296,6 +310,12 @@
 .B pmlogger_daily
 are mutually exclusive.
 .TP
+\fB\-q\fR
+If this option is specified for
+.B pmlogger_check
+then the script will ``quickstart'' avoiding any optional processing
+like file compression.
+.TP
 \fB\-r\fR, \fB\-\-norewrite\fR
 This command line option acts as an override and prevents all archive
 rewriting with
diff -auNr pcp-5.1.1-004/qa/1837 pcp-5.1.1-005/qa/1837
--- pcp-5.1.1-004/qa/1837	2020-06-22 20:00:17.636331169 +1000
+++ pcp-5.1.1-005/qa/1837	2020-06-22 20:08:18.457403819 +1000
@@ -1,6 +1,6 @@
 #!/bin/sh
 # PCP QA Test No. 1837
-# Exercise PMWEBAPI handling server OPTIONS.
+# Exercise PMWEBAPI handling server OPTIONS and TRACE.
 #
 # Copyright (c) 2020 Red Hat.  All Rights Reserved.
 #
@@ -43,7 +43,12 @@
 # real QA test starts here
 _service pmproxy restart >/dev/null 2>&1
 
-curl -isS --request-target "*" -X OPTIONS http://localhost:44322 \
+echo; echo "=== OPTIONS"
+curl -isS -X OPTIONS --request-target "*" http://localhost:44322 \
+	2>&1 | tee -a $here/$seq.full | _webapi_header_filter
+
+echo; echo "=== TRACE"
+curl -isS -X TRACE http://localhost:44322 \
 	2>&1 | tee -a $here/$seq.full | _webapi_header_filter
 
 echo >>$here/$seq.full
diff -auNr pcp-5.1.1-004/qa/1837.out pcp-5.1.1-005/qa/1837.out
--- pcp-5.1.1-004/qa/1837.out	2020-06-22 20:00:17.637331179 +1000
+++ pcp-5.1.1-005/qa/1837.out	2020-06-22 20:08:18.457403819 +1000
@@ -1,6 +1,17 @@
 QA output created by 1837
 
+=== OPTIONS
+
 Access-Control-Allow-Methods: GET, PUT, HEAD, POST, TRACE, OPTIONS
 Content-Length: 0
 Date: DATE
 HTTP/1.1 200 OK
+
+=== TRACE
+
+Accept: */*
+Content-Length: 0
+Date: DATE
+HTTP/1.1 200 OK
+Host: localhost:44322
+User-Agent: curl VERSION
diff -auNr pcp-5.1.1-004/qa/archives/GNUmakefile pcp-5.1.1-005/qa/archives/GNUmakefile
--- pcp-5.1.1-004/qa/archives/GNUmakefile	2020-03-19 15:15:42.000000000 +1100
+++ pcp-5.1.1-005/qa/archives/GNUmakefile	2020-06-22 20:08:18.461403861 +1000
@@ -35,6 +35,7 @@
 	  pcp-atop.0.xz pcp-atop.meta pcp-atop.index \
 	  pcp-atop-boot.0.xz pcp-atop-boot.meta pcp-atop-boot.index \
 	  pcp-dstat.0.xz pcp-dstat.meta pcp-dstat.index \
+	  pcp-free-tera.0.xz pcp-free-tera.meta.xz pcp-free-tera.index \
 	  pcp-hotatop.0.xz pcp-hotatop.meta pcp-hotatop.index \
 	  pcp-zeroconf.0.xz pcp-zeroconf.meta pcp-zeroconf.index \
 	  value-test.0.xz value-test.meta value-test.index \
diff -auNr pcp-5.1.1-004/qa/common.check pcp-5.1.1-005/qa/common.check
--- pcp-5.1.1-004/qa/common.check	2020-06-22 20:00:17.637331179 +1000
+++ pcp-5.1.1-005/qa/common.check	2020-06-22 20:08:18.459403840 +1000
@@ -2697,6 +2697,7 @@
     | col -b \
     | sed \
 	-e 's/^\(Content-Length:\) [1-9][0-9]*/\1 SIZE/g' \
+	-e 's/^\(User-Agent: curl\).*/\1 VERSION/g' \
 	-e 's/^\(Date:\).*/\1 DATE/g' \
 	-e 's/\(\"context\":\) [0-9][0-9]*/\1 CTXID/g' \
 	-e '/^Connection: Keep-Alive/d' \
diff -auNr pcp-5.1.1-004/src/pmlogger/pmlogger_check.service.in pcp-5.1.1-005/src/pmlogger/pmlogger_check.service.in
--- pcp-5.1.1-004/src/pmlogger/pmlogger_check.service.in	2020-05-22 16:40:09.000000000 +1000
+++ pcp-5.1.1-005/src/pmlogger/pmlogger_check.service.in	2020-06-22 20:08:18.452403767 +1000
@@ -6,7 +6,7 @@
 [Service]
 Type=oneshot
 TimeoutStartSec=25m
-Environment="PMLOGGER_CHECK_PARAMS=-C"
+Environment="PMLOGGER_CHECK_PARAMS=-C --skip-primary"
 EnvironmentFile=-@PCP_SYSCONFIG_DIR@/pmlogger_timers
 ExecStart=@PCP_BINADM_DIR@/pmlogger_check $PMLOGGER_CHECK_PARAMS
 WorkingDirectory=@PCP_VAR_DIR@
diff -auNr pcp-5.1.1-004/src/pmlogger/pmlogger_check.sh pcp-5.1.1-005/src/pmlogger/pmlogger_check.sh
--- pcp-5.1.1-004/src/pmlogger/pmlogger_check.sh	2020-05-04 09:52:04.000000000 +1000
+++ pcp-5.1.1-005/src/pmlogger/pmlogger_check.sh	2020-06-22 20:13:04.029416598 +1000
@@ -36,16 +36,24 @@
 echo >$tmp/lock
 prog=`basename $0`
 PROGLOG=$PCP_LOG_DIR/pmlogger/$prog.log
+MYPROGLOG=$PROGLOG.$$
 USE_SYSLOG=true
 
 _cleanup()
 {
+    if [ -s "$MYPROGLOG" ]
+    then
+	rm -f "$PROGLOG"
+	mv "$MYPROGLOG" "$PROGLOG"
+    else
+	rm -f "$MYPROGLOG"
+    fi
     $USE_SYSLOG && [ $status -ne 0 ] && \
     $PCP_SYSLOG_PROG -p daemon.error "$prog failed - see $PROGLOG"
-    [ -s "$PROGLOG" ] || rm -f "$PROGLOG"
     lockfile=`cat $tmp/lock 2>/dev/null`
     rm -f "$lockfile"
     rm -rf $tmp
+    $VERY_VERBOSE && echo "End: `date '+%F %T.%N'`"
 }
 trap "_cleanup; exit \$status" 0 1 2 3 15
 
@@ -86,6 +94,8 @@
 CHECK_RUNLEVEL=false
 START_PMLOGGER=true
 STOP_PMLOGGER=false
+QUICKSTART=false
+SKIP_PRIMARY=false
 
 echo > $tmp/usage
 cat >> $tmp/usage << EOF
@@ -94,6 +104,8 @@
   -l=FILE,--logfile=FILE  send important diagnostic messages to FILE
   -C                      query system service runlevel information
   -N,--showme             perform a dry run, showing what would be done
+  -p,--skip-primary       do not start or stop the primary pmlogger instance
+  -q,--quick              quick start, no compression
   -s,--stop               stop pmlogger processes instead of starting them
   -T,--terse              produce a terser form of output
   -V,--verbose            increase diagnostic verbosity
@@ -117,6 +129,7 @@
 	-C)	CHECK_RUNLEVEL=true
 		;;
 	-l)	PROGLOG="$2"
+		MYPROGLOG="$PROGLOG".$$
 		USE_SYSLOG=false
 		daily_args="${daily_args} -l $2.from.check"
 		shift
@@ -129,6 +142,10 @@
 		KILL="echo + kill"
 		daily_args="${daily_args} -N"
 		;;
+	-p)	SKIP_PRIMARY=true
+		;;
+	-q)	QUICKSTART=true
+		;;
 	-s)	START_PMLOGGER=false
 		STOP_PMLOGGER=true
 		;;
@@ -162,9 +179,15 @@
 
 _compress_now()
 {
-    # If $PCP_COMPRESSAFTER=0 in the control file(s), compress archives now.
-    # Invoked just before exit when this script has finished successfully.
-    $PCP_BINADM_DIR/pmlogger_daily -K $daily_args
+    if $QUICKSTART
+    then
+	$VERY_VERBOSE && echo "Skip compression, -q/--quick on command line"
+    else
+	# If $PCP_COMPRESSAFTER=0 in the control file(s), compress archives now.
+	# Invoked just before exit when this script has finished successfully.
+	$VERY_VERBOSE && echo "Doing compression ..."
+	$PCP_BINADM_DIR/pmlogger_daily -K $daily_args
+    fi
 }
 
 # after argument checking, everything must be logged to ensure no mail is
@@ -187,26 +210,37 @@
     #
     # Exception ($SHOWME, above) is for -N where we want to see the output.
     #
-    touch "$PROGLOG"
-    chown $PCP_USER:$PCP_GROUP "$PROGLOG" >/dev/null 2>&1
-    exec 1>"$PROGLOG" 2>&1
+    touch "$MYPROGLOG"
+    chown $PCP_USER:$PCP_GROUP "$MYPROGLOG" >/dev/null 2>&1
+    exec 1>"$MYPROGLOG" 2>&1
+fi
+
+if $VERY_VERBOSE
+then
+    echo "Start: `date '+%F %T.%N'`"
+    if `which pstree >/dev/null 2>&1`
+    then
+	echo "Called from:"
+	pstree -spa $$
+	echo "--- end of pstree output ---"
+    fi
 fi
 
 # if SaveLogs exists in the $PCP_LOG_DIR/pmlogger directory then save
-# $PROGLOG there as well with a unique name that contains the date and time
+# $MYPROGLOG there as well with a unique name that contains the date and time
 # when we're run
 #
 if [ -d $PCP_LOG_DIR/pmlogger/SaveLogs ]
 then
-    now="`date '+%Y%m%d.%H.%M'`"
-    link=`echo $PROGLOG | sed -e "s/$prog/SaveLogs\/$prog.$now/"`
+    now="`date '+%Y%m%d.%H.%M.%S'`"
+    link=`echo $MYPROGLOG | sed -e "s/$prog/SaveLogs\/$prog.$now/"`
     if [ ! -f "$link" ]
     then
 	if $SHOWME
 	then
-	    echo "+ ln $PROGLOG $link"
+	    echo "+ ln $MYPROGLOG $link"
 	else
-	    ln $PROGLOG $link
+	    ln $MYPROGLOG $link
 	fi
     fi
 fi
@@ -273,7 +307,7 @@
 
 _unlock()
 {
-    rm -f lock
+    rm -f "$1/lock"
     echo >$tmp/lock
 }
 
@@ -395,6 +429,41 @@
     echo "$pid"
 }
 
+# wait for the local pmcd to get going for a primary pmlogger
+# (borrowed from qa/common.check)
+#
+# wait_for_pmcd [maxdelay]
+#
+_wait_for_pmcd()
+{
+    # 5 seconds default seems like a reasonable max time to get going
+    _can_wait=${1-5}
+    _limit=`expr $_can_wait \* 10`
+    _i=0
+    _dead=true
+    while [ $_i -lt $_limit ]
+    do
+	_sts=`pmprobe pmcd.numclients 2>/dev/null | $PCP_AWK_PROG '{print $2}'`
+	if [ "${_sts:-0}" -gt 0 ]
+	then
+	    # numval really > 0, we're done
+	    #
+	    _dead=false
+	    break
+	fi
+	pmsleep 0.1
+	_i=`expr $_i + 1`
+    done
+    if $_dead
+    then
+	date
+	echo "Arrgghhh ... pmcd at localhost failed to start after $_can_wait seconds"
+	echo "=== failing pmprobes ==="
+	pmprobe pmcd.numclients
+	status=1
+    fi
+}
+
 _check_archive()
 {
     if [ ! -e "$logfile" ]
@@ -531,7 +600,17 @@
 	cd "$here"
 	line=`expr $line + 1`
 
-	$VERY_VERBOSE && echo "[$controlfile:$line] host=\"$host\" primary=\"$primary\" socks=\"$socks\" dir=\"$dir\" args=\"$args\""
+
+	if $VERY_VERBOSE 
+	then
+	    case "$host"
+	    in
+	    \#*|'')	# comment or empty
+			;;
+	    *)		echo "[$controlfile:$line] host=\"$host\" primary=\"$primary\" socks=\"$socks\" dir=\"$dir\" args=\"$args\""
+	    		;;
+	    esac
+	fi
 
 	case "$host"
 	in
@@ -599,6 +678,15 @@
 	    continue
 	fi
 
+	# if -s/--skip-primary on the command line, do not process
+	# a control file line for the primary pmlogger
+	#
+	if $SKIP_PRIMARY && [ $primary = y ]
+	then
+	    $VERY_VERBOSE && echo "Skip, -s/--skip-primary on command line"
+	    continue
+	fi
+
 	# substitute LOCALHOSTNAME marker in this config line
 	# (differently for directory and pcp -h HOST arguments)
 	#
@@ -610,7 +698,7 @@
 	then
 	    pflag=''
 	    [ $primary = y ] && pflag=' -P'
-	    echo "Check pmlogger$pflag -h $host ... in $dir ..."
+	    echo "Checking for: pmlogger$pflag -h $host ... in $dir ..."
 	fi
 
 	# check for directory duplicate entries
@@ -664,19 +752,25 @@
 	    delay=200	# tenths of a second
 	    while [ $delay -gt 0 ]
 	    do
-		if pmlock -v lock >$tmp/out 2>&1
+		if pmlock -v "$dir/lock" >$tmp/out 2>&1
 		then
-		    echo $dir/lock >$tmp/lock
+		    echo "$dir/lock" >$tmp/lock
+		    if $VERY_VERBOSE
+		    then
+			echo "Acquired lock:"
+			ls -l $dir/lock
+		    fi
 		    break
 		else
 		    [ -f $tmp/stamp ] || touch -t `pmdate -30M %Y%m%d%H%M` $tmp/stamp
-		    if [ -z "`find lock -newer $tmp/stamp -print 2>/dev/null`" ]
+		    find $tmp/stamp -newer "$dir/lock" -print 2>/dev/null >$tmp/tmp
+		    if [ -s $tmp/tmp ]
 		    then
-			if [ -f lock ]
+			if [ -f "$dir/lock" ]
 			then
 			    echo "$prog: Warning: removing lock file older than 30 minutes"
 			    LC_TIME=POSIX ls -l $dir/lock
-			    rm -f lock
+			    rm -f "$dir/lock"
 			else
 			    # there is a small timing window here where pmlock
 			    # might fail, but the lock file has been removed by
@@ -714,7 +808,7 @@
 			continue
 		    fi
 		fi
-		if [ -f lock ]
+		if [ -f "$dir/lock" ]
 		then
 		    echo "$prog: Warning: is another PCP cron job running concurrently?"
 		    LC_TIME=POSIX ls -l $dir/lock
@@ -753,6 +847,14 @@
 		    $VERY_VERBOSE && echo "primary pmlogger process $pid not running"
 		    pid=''
 		fi
+	    else
+		if $VERY_VERBOSE
+		then
+		    echo "$PCP_TMP_DIR/pmlogger/primary: missing?"
+		    echo "Contents of $PCP_TMP_DIR/pmlogger"
+		    ls -l $PCP_TMP_DIR/pmlogger
+		    echo "--- end of ls output ---"
+		fi
 	    fi
 	else
 	    for log in $PCP_TMP_DIR/pmlogger/[0-9]*
@@ -798,6 +900,17 @@
 		#
 		PM_LOG_PORT_DIR="$PCP_TMP_DIR/pmlogger"
 		rm -f "$PM_LOG_PORT_DIR/primary"
+		# We really starting the primary pmlogger to work, especially
+		# in the systemd world, so make sure pmcd is ready to accept
+		# connections.
+		#
+		_wait_for_pmcd
+		if [ "$status" = 1 ]
+		then
+		    $VERY_VERBOSE && echo "pmcd not running, skip primary pmlogger"
+		    _unlock "$dir"
+		    continue
+		fi
 	    else
 		args="-h $host $args"
 		envs=""
@@ -870,7 +983,7 @@
 	    then
 		echo
 		echo "+ ${sock_me}$PMLOGGER $args $LOGNAME"
-		_unlock
+		_unlock "$dir"
 		continue
 	    else
 		$PCP_BINADM_DIR/pmpost "start pmlogger from $prog for host $host"
@@ -903,7 +1016,7 @@
 	    $PCP_ECHO_PROG $PCP_ECHO_N "$pid ""$PCP_ECHO_C" >> $tmp/pmloggers
 	fi
 
-	_unlock
+	_unlock "$dir"
     done
 }
 
diff -auNr pcp-5.1.1-004/src/pmlogger/pmlogger_daily.sh pcp-5.1.1-005/src/pmlogger/pmlogger_daily.sh
--- pcp-5.1.1-004/src/pmlogger/pmlogger_daily.sh	2020-04-07 13:31:03.000000000 +1000
+++ pcp-5.1.1-005/src/pmlogger/pmlogger_daily.sh	2020-06-22 20:08:18.451403756 +1000
@@ -31,16 +31,24 @@
 echo >$tmp/lock
 prog=`basename $0`
 PROGLOG=$PCP_LOG_DIR/pmlogger/$prog.log
+MYPROGLOG=$PROGLOG.$$
 USE_SYSLOG=true
 
 _cleanup()
 {
+    if [ -s "$MYPROGLOG" ]
+    then
+	rm -f "$PROGLOG"
+	mv "$MYPROGLOG" "$PROGLOG"
+    else
+	rm -f "$MYPROGLOG"
+    fi
     $USE_SYSLOG && [ $status -ne 0 ] && \
     $PCP_SYSLOG_PROG -p daemon.error "$prog failed - see $PROGLOG"
-    [ -s "$PROGLOG" ] || rm -f "$PROGLOG"
     lockfile=`cat $tmp/lock 2>/dev/null`
     rm -f "$lockfile" "$PCP_RUN_DIR/pmlogger_daily.pid"
     rm -rf $tmp
+    $VERY_VERBOSE && echo "End: `date '+%F %T.%N'`"
 }
 trap "_cleanup; exit \$status" 0 1 2 3 15
 
@@ -215,8 +223,10 @@
 		fi
 		COMPRESSONLY=true
 		PROGLOG=$PCP_LOG_DIR/pmlogger/$prog-K.log
+		MYPROGLOG=$PROGLOG.$$
 		;;
 	-l)	PROGLOG="$2"
+		MYPROGLOG=$PROGLOG.$$
 		USE_SYSLOG=false
 		shift
 		;;
@@ -278,6 +288,7 @@
 		# $PCP_LOG_DIR/pmlogger/daily.<date>.trace
 		#
 		PROGLOG=$PCP_LOG_DIR/pmlogger/daily.`date "+%Y%m%d.%H.%M"`.trace
+		MYPROGLOG=$PROGLOG.$$
 		VERBOSE=true
 		VERY_VERBOSE=true
 		MYARGS="$MYARGS -V -V"
@@ -418,13 +429,23 @@
     #
     # Exception ($SHOWME, above) is for -N where we want to see the output.
     #
-    touch "$PROGLOG"
-    chown $PCP_USER:$PCP_GROUP "$PROGLOG" >/dev/null 2>&1
-    exec 1>"$PROGLOG" 2>&1
+    touch "$MYPROGLOG"
+    chown $PCP_USER:$PCP_GROUP "$MYPROGLOG" >/dev/null 2>&1
+    exec 1>"$MYPROGLOG" 2>&1
+fi
+
+if $VERY_VERBOSE
+then
+    echo "Start: `date '+%F %T.%N'`"
+    if `which pstree >/dev/null 2>&1`
+    then
+	echo "Called from:"
+	pstree -spa $$
+    fi
 fi
 
 # if SaveLogs exists in the $PCP_LOG_DIR/pmlogger directory then save
-# $PROGLOG there as well with a unique name that contains the date and time
+# $MYPROGLOG there as well with a unique name that contains the date and time
 # when we're run ... skip if -N (showme)
 #
 if $SHOWME
@@ -433,15 +454,15 @@
 else
     if [ -d $PCP_LOG_DIR/pmlogger/SaveLogs ]
     then
-	now="`date '+%Y%m%d.%H.%M'`"
-	link=`echo $PROGLOG | sed -e "s/$prog/SaveLogs\/$prog.$now/"`
+	now="`date '+%Y%m%d.%H.%M.%S'`"
+	link=`echo $MYPROGLOG | sed -e "s/$prog/SaveLogs\/$prog.$now/"`
 	if [ ! -f "$link" ]
 	then
 	    if $SHOWME
 	    then
-		echo "+ ln $PROGLOG $link"
+		echo "+ ln $MYPROGLOG $link"
 	    else
-		ln $PROGLOG $link
+		ln $MYPROGLOG $link
 	    fi
 	fi
     fi
@@ -487,19 +508,20 @@
 	delay=200	# tenths of a second
 	while [ $delay -gt 0 ]
 	do
-	    if pmlock -v lock >>$tmp/out 2>&1
+	    if pmlock -v "$1/lock" >>$tmp/out 2>&1
 	    then
-		echo $1/lock >$tmp/lock
+		echo "$1/lock" >$tmp/lock
 		break
 	    else
 		[ -f $tmp/stamp ] || touch -t `pmdate -30M %Y%m%d%H%M` $tmp/stamp
-		if [ ! -z "`find lock -newer $tmp/stamp -print 2>/dev/null`" ]
+		find $tmp/stamp -newer "$1/lock" -print 2>/dev/null >$tmp/tmp
+		if [ -s $tmp/tmp ]
 		then
-		    if [ -f lock ]
+		    if [ -f "$1/lock" ]
 		    then
 			_warning "removing lock file older than 30 minutes"
-			LC_TIME=POSIX ls -l $1/lock
-			rm -f lock
+			LC_TIME=POSIX ls -l "$1/lock"
+			rm -f "$1/lock"
 		    else
 			# there is a small timing window here where pmlock
 			# might fail, but the lock file has been removed by
@@ -517,10 +539,10 @@
 	then
 	    # failed to gain mutex lock
 	    #
-	    if [ -f lock ]
+	    if [ -f "$1/lock" ]
 	    then
 		_warning "is another PCP cron job running concurrently?"
-		LC_TIME=POSIX ls -l $1/lock
+		LC_TIME=POSIX ls -l "$1/lock"
 	    else
 		echo "$prog: `cat $tmp/out`"
 	    fi
@@ -534,7 +556,7 @@
 
 _unlock()
 {
-    rm -f lock
+    rm -f "$1/lock"
     echo >$tmp/lock
 }
 
@@ -703,6 +725,9 @@
 # if the directory containing the archive matches, then the name
 # of the file is the pid.
 #
+# The pid(s) (if any) appear on stdout, so be careful to send any
+# diagnostics to stderr.
+#
 _get_non_primary_logger_pid()
 {
     pid=''
@@ -713,7 +738,7 @@
 	then
 	    _host=`sed -n 2p <$log`
 	    _arch=`sed -n 3p <$log`
-	    $PCP_ECHO_PROG $PCP_ECHO_N "... try $log host=$_host arch=$_arch: ""$PCP_ECHO_C"
+	    $PCP_ECHO_PROG >&2 $PCP_ECHO_N "... try $log host=$_host arch=$_arch: ""$PCP_ECHO_C"
 	fi
 	# throw away stderr in case $log has been removed by now
 	match=`sed -e '3s@/[^/]*$@@' $log 2>/dev/null | \
@@ -721,19 +746,19 @@
 BEGIN				{ m = 0 }
 NR == 3 && $0 == "'$dir'"	{ m = 2; next }
 END				{ print m }'`
-	$VERY_VERBOSE && $PCP_ECHO_PROG $PCP_ECHO_N "match=$match ""$PCP_ECHO_C"
+	$VERY_VERBOSE && $PCP_ECHO_PROG >&2 $PCP_ECHO_N "match=$match ""$PCP_ECHO_C"
 	if [ "$match" = 2 ]
 	then
 	    pid=`echo $log | sed -e 's,.*/,,'`
 	    if _get_pids_by_name pmlogger | grep "^$pid\$" >/dev/null
 	    then
-		$VERY_VERBOSE && echo "pmlogger process $pid identified, OK"
+		$VERY_VERBOSE && echo >&2 "pmlogger process $pid identified, OK"
 		break
 	    fi
-	    $VERY_VERBOSE && echo "pmlogger process $pid not running, skip"
+	    $VERY_VERBOSE && echo >&2 "pmlogger process $pid not running, skip"
 	    pid=''
 	else
-	    $VERY_VERBOSE && echo "different directory, skip"
+	    $VERY_VERBOSE && echo >&2 "different directory, skip"
 	fi
     done
     echo "$pid"
@@ -1028,6 +1053,8 @@
 		pid=''
 	    fi
 	else
+	    # pid(s) on stdout, diagnostics on stderr
+	    #
 	    pid=`_get_non_primary_logger_pid`
 	    if $VERY_VERBOSE
 	    then
@@ -1458,7 +1485,7 @@
 	    fi
 	fi
 
-	_unlock
+	_unlock "$dir"
     done
 }
 
diff -auNr pcp-5.1.1-004/src/pmlogger/pmlogger.service.in pcp-5.1.1-005/src/pmlogger/pmlogger.service.in
--- pcp-5.1.1-004/src/pmlogger/pmlogger.service.in	2020-06-22 20:00:17.634331148 +1000
+++ pcp-5.1.1-005/src/pmlogger/pmlogger.service.in	2020-06-22 20:08:18.452403767 +1000
@@ -2,7 +2,7 @@
 Description=Performance Metrics Archive Logger
 Documentation=man:pmlogger(1)
 After=network-online.target pmcd.service
-After=pmlogger_check.timer pmlogger_check.path pmlogger_daily.timer pmlogger_daily-poll.timer
+Before=pmlogger_check.timer pmlogger_check.path pmlogger_daily.timer pmlogger_daily-poll.timer
 BindsTo=pmlogger_check.timer pmlogger_check.path pmlogger_daily.timer pmlogger_daily-poll.timer
 Wants=pmcd.service
 
diff -auNr pcp-5.1.1-004/src/pmlogger/rc_pmlogger pcp-5.1.1-005/src/pmlogger/rc_pmlogger
--- pcp-5.1.1-004/src/pmlogger/rc_pmlogger	2020-04-21 10:42:02.000000000 +1000
+++ pcp-5.1.1-005/src/pmlogger/rc_pmlogger	2020-06-22 20:08:18.453403777 +1000
@@ -96,7 +96,7 @@
     bgtmp=`mktemp -d $PCP_DIR/var/tmp/pcp.XXXXXXXXX` || exit 1
     trap "rm -rf $bgtmp; exit \$bgstatus" 0 1 2 3 15
 
-    pmlogger_check $VFLAG >$bgtmp/pmcheck.out 2>$bgtmp/pmcheck
+    pmlogger_check --quick $VFLAG >$bgtmp/pmcheck.out 2>$bgtmp/pmcheck
     bgstatus=$?
     if [ -s $bgtmp/pmcheck ]
     then
@@ -125,8 +125,6 @@
 	    false
 	else
 	    # Really start the pmlogger instances based on the control file.
-	    # Done in the background to avoid delaying the init script,
-	    # failure notification is external (syslog, log files).
 	    #
 	    $ECHO $PCP_ECHO_N "Starting pmlogger ..." "$PCP_ECHO_C"
 
@@ -234,11 +232,9 @@
 if [ $VERBOSE_CTL = on ]
 then				# For a verbose startup and shutdown
     ECHO=$PCP_ECHO_PROG
-    REBUILDOPT=''
     VFLAG='-V'
 else				# For a quiet startup and shutdown
     ECHO=:
-    REBUILDOPT=-s
     VFLAG=
 fi
 
diff -auNr pcp-5.1.1-004/src/pmproxy/src/http.c pcp-5.1.1-005/src/pmproxy/src/http.c
--- pcp-5.1.1-004/src/pmproxy/src/http.c	2020-06-22 20:00:17.635331158 +1000
+++ pcp-5.1.1-005/src/pmproxy/src/http.c	2020-06-22 20:08:18.460403851 +1000
@@ -324,17 +324,36 @@
 }
 
 static sds
-http_response_trace(struct client *client)
+http_response_trace(struct client *client, int sts)
 {
+    struct http_parser	*parser = &client->u.http.parser;
     dictIterator	*iterator;
     dictEntry		*entry;
-    sds			result = sdsempty();
+    char		buffer[64];
+    sds			header;
+
+    parser->http_major = parser->http_minor = 1;
+
+    header = sdscatfmt(sdsempty(),
+		"HTTP/%u.%u %u %s\r\n"
+		"%S: Keep-Alive\r\n",
+		parser->http_major, parser->http_minor,
+		sts, http_status_mapping(sts), HEADER_CONNECTION);
+    header = sdscatfmt(header, "%S: %u\r\n", HEADER_CONTENT_LENGTH, 0);
 
     iterator = dictGetSafeIterator(client->u.http.headers);
     while ((entry = dictNext(iterator)) != NULL)
-	result = sdscatfmt("%S: %S\r\n", dictGetKey(entry), dictGetVal(entry));
+	header = sdscatfmt(header, "%S: %S\r\n", dictGetKey(entry), dictGetVal(entry));
     dictReleaseIterator(iterator);
-    return result;
+
+    header = sdscatfmt(header, "Date: %s\r\n\r\n",
+		http_date_string(time(NULL), buffer, sizeof(buffer)));
+
+    if (pmDebugOptions.http && pmDebugOptions.desperate) {
+	fprintf(stderr, "trace response to client %p\n", client);
+	fputs(header, stderr);
+    }
+    return header;
 }
 
 static sds
@@ -418,7 +437,7 @@
 	if (client->u.http.parser.method == HTTP_OPTIONS)
 	    buffer = http_response_access(client, sts, options);
 	else if (client->u.http.parser.method == HTTP_TRACE)
-	    buffer = http_response_trace(client);
+	    buffer = http_response_trace(client, sts);
 	else	/* HTTP_HEAD */
 	    buffer = http_response_header(client, 0, sts, type);
 	suffix = NULL;
@@ -533,6 +552,8 @@
     if (servlet && servlet->on_release)
 	servlet->on_release(client);
     client->u.http.privdata = NULL;
+    client->u.http.servlet = NULL;
+    client->u.http.flags = 0;
 
     if (client->u.http.headers) {
 	dictRelease(client->u.http.headers);
@@ -696,29 +717,39 @@
 {
     struct client	*client = (struct client *)request->data;
     struct servlet	*servlet;
-    sds			buffer;
     int			sts;
 
     http_client_release(client);	/* new URL, clean slate */
-    /* server options - https://tools.ietf.org/html/rfc7231#section-4.3.7 */
-    if (length == 1 && *offset == '*' &&
-	client->u.http.parser.method == HTTP_OPTIONS) {
-	buffer = http_response_access(client, HTTP_STATUS_OK, HTTP_SERVER_OPTIONS);
-	client_write(client, buffer, NULL);
-    } else if ((servlet = servlet_lookup(client, offset, length)) != NULL) {
+    /* pass to servlets handling each of our internal request endpoints */
+    if ((servlet = servlet_lookup(client, offset, length)) != NULL) {
 	client->u.http.servlet = servlet;
-	if ((sts = client->u.http.parser.status_code) == 0) {
+	if ((sts = client->u.http.parser.status_code) != 0)
+	    http_error(client, sts, "failed to process URL");
+	else {
 	    if (client->u.http.parser.method == HTTP_OPTIONS ||
 		client->u.http.parser.method == HTTP_TRACE ||
 		client->u.http.parser.method == HTTP_HEAD)
 		client->u.http.flags |= HTTP_FLAG_NO_BODY;
-	    else
-		client->u.http.flags &= ~HTTP_FLAG_NO_BODY;
 	    client->u.http.headers = dictCreate(&sdsOwnDictCallBacks, NULL);
-	    return 0;
 	}
-	http_error(client, sts, "failed to process URL");
-    } else {
+    }
+    /* server options - https://tools.ietf.org/html/rfc7231#section-4.3.7 */
+    else if (client->u.http.parser.method == HTTP_OPTIONS) {
+	if (length == 1 && *offset == '*') {
+	    client->u.http.flags |= HTTP_FLAG_NO_BODY;
+	    client->u.http.headers = dictCreate(&sdsOwnDictCallBacks, NULL);
+	} else {
+	    sts = client->u.http.parser.status_code = HTTP_STATUS_BAD_REQUEST;
+	    http_error(client, sts, "no handler for OPTIONS");
+	}
+    }
+    /* server trace - https://tools.ietf.org/html/rfc7231#section-4.3.8 */
+    else if (client->u.http.parser.method == HTTP_TRACE) {
+	client->u.http.flags |= HTTP_FLAG_NO_BODY;
+	client->u.http.headers = dictCreate(&sdsOwnDictCallBacks, NULL);
+    }
+    /* nothing available to respond to this request - inform the client */
+    else {
 	sts = client->u.http.parser.status_code = HTTP_STATUS_BAD_REQUEST;
 	http_error(client, sts, "no handler for URL");
     }
@@ -734,7 +765,7 @@
     if (pmDebugOptions.http && pmDebugOptions.desperate)
 	printf("Body: %.*s\n(client=%p)\n", (int)length, offset, client);
 
-    if (servlet->on_body)
+    if (servlet && servlet->on_body)
 	return servlet->on_body(client, offset, length);
     return 0;
 }
@@ -828,7 +859,7 @@
     }
 
     client->u.http.privdata = NULL;
-    if (servlet->on_headers)
+    if (servlet && servlet->on_headers)
 	sts = servlet->on_headers(client, client->u.http.headers);
 
     /* HTTP Basic Auth for all servlets */
@@ -857,13 +888,31 @@
 {
     struct client	*client = (struct client *)request->data;
     struct servlet	*servlet = client->u.http.servlet;
+    sds			buffer;
+    int			sts;
 
     if (pmDebugOptions.http)
 	fprintf(stderr, "HTTP message complete (client=%p)\n", client);
 
-    if (servlet && servlet->on_done)
-	return servlet->on_done(client);
-    return 0;
+    if (servlet) {
+	if (servlet->on_done)
+	    return servlet->on_done(client);
+	return 0;
+    }
+
+    sts = HTTP_STATUS_OK;
+    if (client->u.http.parser.method == HTTP_OPTIONS) {
+	buffer = http_response_access(client, sts, HTTP_SERVER_OPTIONS);
+	client_write(client, buffer, NULL);
+	return 0;
+    }
+    if (client->u.http.parser.method == HTTP_TRACE) {
+	buffer = http_response_trace(client, sts);
+	client_write(client, buffer, NULL);
+	return 0;
+    }
+
+    return 1;
 }
 
 void
diff -auNr pcp-5.1.1.orig/qa/1608 pcp-5.1.1/qa/1608
--- pcp-5.1.1.orig/qa/1608	1970-01-01 10:00:00.000000000 +1000
+++ pcp-5.1.1/qa/1608	2020-06-23 12:16:04.005557293 +1000
@@ -0,0 +1,58 @@
+#!/bin/sh
+# PCP QA Test No. 1608
+# Exercise a long URL handling in pmproxy.
+#
+# Copyright (c) 2020 Red Hat.  All Rights Reserved.
+#
+
+seq=`basename $0`
+echo "QA output created by $seq"
+
+# get standard environment, filters and checks
+. ./common.product
+. ./common.filter
+. ./common.check
+
+_check_series
+which curl >/dev/null 2>&1 || _notrun "No curl binary installed"
+
+status=1	# failure is the default!
+$sudo rm -rf $tmp $tmp.* $seq.full
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+pmproxy_was_running=false
+[ -f $PCP_RUN_DIR/pmproxy.pid ] && pmproxy_was_running=true
+echo "pmproxy_was_running=$pmproxy_was_running" >>$here/$seq.full
+
+_cleanup()
+{
+    if $pmproxy_was_running
+    then
+        echo "Restart pmproxy ..." >>$here/$seq.full
+        _service pmproxy restart >>$here/$seq.full 2>&1
+        _wait_for_pmproxy
+    else
+        echo "Stopping pmproxy ..." >>$here/$seq.full
+        _service pmproxy stop >>$here/$seq.full 2>&1
+    fi
+    $sudo rm -f $tmp.*
+}
+
+_webapi_failure_filter()
+{
+    _webapi_header_filter | \
+    sed \
+	-e 's/pmproxy.[0-9][0-9]*.[0-9][0-9]*.[0-9][0-9]*/PMPROXY\/VERSION/g' \
+    #end
+}
+
+# real QA test starts here
+_service pmproxy restart >/dev/null 2>&1
+
+url="http://localhost:44322/pmapi/context"
+aaa=`head -c 10000 < /dev/zero | tr '\0' '\141'`
+curl -isS -X OPTIONS "${url}?${aaa}" | _webapi_failure_filter
+
+# success, all done
+status=0
+exit
diff -auNr pcp-5.1.1.orig/qa/1608.out pcp-5.1.1/qa/1608.out
--- pcp-5.1.1.orig/qa/1608.out	1970-01-01 10:00:00.000000000 +1000
+++ pcp-5.1.1/qa/1608.out	2020-06-23 12:16:04.005557293 +1000
@@ -0,0 +1,16 @@
+QA output created by 1608
+
+</body>
+</html>
+<body>
+<h1>414 URI Too Long</h1>
+<head><title>414 URI Too Long</title></head>
+<html>
+<p><b>unknown servlet</b>: request URL too long</p><hr>
+<p><small><i>PMPROXY/VERSION</i></small></p>
+Access-Control-Allow-Headers: Accept, Accept-Language, Content-Language, Content-Type
+Access-Control-Allow-Origin: *
+Content-Length: SIZE
+Content-Type: text/html
+Date: DATE
+HTTP/1.1 414 URI Too Long
diff -auNr pcp-5.1.1.orig/qa/group pcp-5.1.1/qa/group
--- pcp-5.1.1.orig/qa/group	2020-06-23 12:15:21.335094106 +1000
+++ pcp-5.1.1/qa/group	2020-06-23 12:16:54.256102754 +1000
@@ -1717,6 +1717,7 @@
 1600 pmseries pmcd pmproxy pmlogger local
 1601 pmseries pmproxy local
 1602 pmproxy local
+1608 pmproxy local
 1622 selinux local
 1623 libpcp_import collectl local
 1644 pmda.perfevent local
diff -auNr pcp-5.1.1.orig/src/pmproxy/src/http.c pcp-5.1.1/src/pmproxy/src/http.c
--- pcp-5.1.1.orig/src/pmproxy/src/http.c	2020-06-23 12:15:21.364094421 +1000
+++ pcp-5.1.1/src/pmproxy/src/http.c	2020-06-23 12:16:04.008557325 +1000
@@ -21,7 +21,9 @@
 static int chunked_transfer_size; /* pmproxy.chunksize, pagesize by default */
 static int smallest_buffer_size = 128;
 
-#define MAX_PARAMS_SIZE 4096
+/* https://tools.ietf.org/html/rfc7230#section-3.1.1 */
+#define MAX_URL_SIZE	8192
+#define MAX_PARAMS_SIZE 8000
 #define MAX_HEADERS_SIZE 128
 
 static sds HEADER_ACCESS_CONTROL_REQUEST_HEADERS,
@@ -720,8 +722,13 @@
     int			sts;
 
     http_client_release(client);	/* new URL, clean slate */
+
+    if (length >= MAX_URL_SIZE) {
+	sts = client->u.http.parser.status_code = HTTP_STATUS_URI_TOO_LONG;
+	http_error(client, sts, "request URL too long");
+    }
     /* pass to servlets handling each of our internal request endpoints */
-    if ((servlet = servlet_lookup(client, offset, length)) != NULL) {
+    else if ((servlet = servlet_lookup(client, offset, length)) != NULL) {
 	client->u.http.servlet = servlet;
 	if ((sts = client->u.http.parser.status_code) != 0)
 	    http_error(client, sts, "failed to process URL");