Merge branch 'master' of git://git.pcp.io/pcp into qt
[pcp.git] / qa / common.check
blob39edb55c94c4374a15e326831061a37a8f344ea6
2 # common preliminary check procedures for QA scripts
4 # Copyright (c) 2014-2016 Red Hat.
5 # Copyright (c) 1997-2002 Silicon Graphics, Inc.  All Rights Reserved.
8 if [ ! -f localconfig ]
9 then
10     ./mk.localconfig
13 # need to know what version we're running
14 . ./localconfig
16 # common routine for preventing a test from running on some platforms
17 # use: _notrun "Reason for not running this test is ..."
18
19 _notrun()
21     echo $@ >$here/$seq.notrun
22     echo "$seq: [not run] `cat $here/$seq.notrun`"
23     exit 0
26 # common routine for failing a test in a standard way
27 # use: _fail "Reason for failing this test is ..."
29 _fail()
31     echo FAIL: $@ 1>&2
32     status=1
33     exit $status
36 # calculate the size of a given fail, echo it on standard output
37
38 _filesize()
40     filename=$1
42     if [ $PCP_PLATFORM = darwin ]
43     then
44         # Mac OS X format
45         # stat(1) format
46         # 234881026 5304024 -rwxr-xr-x 1 kenj kenj 0 2016 "May  4 14:00:42 2011" "Apr 27 20:14:16 2011" "Apr 27 20:14:16 2011" "Apr 27 20:14:16 2011" 4096 8 0 441
47         stat $filename 2>&1 | $PCP_AWK_PROG '{ print $8 }'
48     else
49         # stat(1) format
50         #   File: `441'
51         #   Size: 2016          Blocks: 8          IO Block: 4096   regular file
52         # Device: 816h/2070d    Inode: 758237      Links: 1
53         # Access: (0755/-rwxr-xr-x)  Uid: ( 1000/    kenj)   Gid: ( 1000/    kenj)
54         # Access: 2011-05-09 06:52:58.000000000 +1000
55         # Modify: 2011-02-27 14:42:30.000000000 +1100
56         # Change: 2011-02-28 19:21:27.000000000 +1100
57         stat $filename 2>&1 | $PCP_AWK_PROG '$1 == "Size:" { print $2 }'
58     fi
61 # determine whether sufficient free space exists to run a test;
62 # passed in parameter is the size needed, in megabytes.
63
64 _check_freespace()
66     needspace=$1
68     # Filesystem           1M-blocks Used Available Use% Mounted on
69     # /dev/sda5                57349     24838     29621  46% /
70     case "$PCP_PLATFORM"
71     in
72         darwin)
73             free=`df -m . | $PCP_AWK_PROG 'NR == 2 { print $4 }'`
74             ;;
75         *)
76             free=`df -mP . | $PCP_AWK_PROG 'NR == 2 { print $4 }'`
77             ;;
78     esac
80     if [ -z "$free" ]
81     then
82         echo "Cannot determine free space (df -mP fails)"
83     elif [ "$free" -lt "$needspace" ]
84     then
85         echo "Insufficient free space ($free MB, need $needspace MB)"
86     fi
89 # save and restore configuration files in a way that labels which test
90 # was responsible in the event of a test abort, but also preserves the
91 # mode and ownership of the configuration file
93 _save_config()
95     if [ -f "$1" ]
96     then
97         $sudo rm -f "$1.$seq"
98         $sudo mv "$1" "$1.$seq"
99         $sudo cp "$1.$seq" "$1"
100     elif [ -d "$1" ]
101     then
102         $sudo rm -rf "$1.$seq"
103         $sudo mv "$1" "$1.$seq"
104         $sudo cp -r "$1.$seq" "$1"
105     else
106         echo "Botch: _save_config: $1 does not exist"
107     fi
110 _restore_config()
112     if [ -f "$1.$seq" ]
113     then
114         $sudo rm -f "$1"
115         $sudo mv "$1.$seq" "$1"
116     elif [ -d "$1.$seq" ]
117     then
118         $sudo rm -rf "$1"
119         $sudo mv "$1.$seq" "$1"
120     else
121         echo "Warning: _restore_config: $1.$seq does not exist"
122     fi
125 # check that a given agent (argument 1) is up and running;
126 # indicated by return status and agent warnings to stdout.
128 _check_agent() 
130     agent=$1
131     quiet=$2
132     sts=0
134     [ X"$quiet" = "X" ] && quiet=false
136     pminfo -f $agent 2>&1 | \
137         $PCP_AWK_PROG '
138 BEGIN           { value=0; metric=0; warn=0 }
139 NF==0           { next }
140 / value /       { value++; next }
141 /^'$agent'/         { metric++
142                   if ($0 !~ /:/) next
143                 }
144                 { warn++ }
145 END             { if (warn) printf "%d warnings, ",warn
146                   printf "%d metrics and %d values\n",metric,value
147                 }' > $tmp.fetch 2>&1
149     pminfo -v $agent 2>&1 | LC_COLLATE=POSIX sort >$tmp.verify
150     $quiet || cat $tmp.fetch
151     if grep warnings $tmp.fetch > /dev/null 2>&1
152     then
153         # X warnings, Y metrics and Z values
154         num_warn=`sed -n -e '/warnings/s/ .*//p' < $tmp.fetch`
155         if [ "$num_warn" -gt 0 ]
156         then
157             echo "Warnings when fetching $agent metrics:"
158             cat $tmp.verify
159             sts=1
160         fi
161     else
162         num_warn=0
163     fi
165     return $sts
169 # prepare and cleanup pmda routines work together to ensure
170 # pmcd+pmda state is left as it was at the start of a test.
172 _prepare_pmda()
174     __agent=$1
175     __names=$2
177     iam=$__agent
178     [ "X$__names" = "X" ] && __names=$iam
179     done_clean=false
180     install_on_cleanup=false
181     pminfo $__names >/dev/null 2>&1 && install_on_cleanup=true
182     # copy the pmcd config file to restore state later.
183     _save_config $PCP_PMCDCONF_PATH
184     unset ROOT MAKEFLAGS
187 _cleanup_pmda()
189     __agent=$1
190     __iopts=$2
192     if $done_clean
193     then
194         :
195     else
196         _restore_config $PCP_PMCDCONF_PATH
197         $sudo $PCP_RC_DIR/pcp restart | _filter_pcp_start
198         _wait_for_pmcd
199         _wait_for_pmlogger
200         if $install_on_cleanup
201         then
202             [ "X$__iopts" = "X" ] && __iopts=/dev/null
203             ( cd $PCP_PMDAS_DIR/$__agent; $sudo ./Install <$__iopts >/dev/null 2>&1 )
204         else
205             ( cd $PCP_PMDAS_DIR/$__agent; $sudo ./Remove >/dev/null 2>&1 )
206         fi
207         _wait_for_pmcd
208         _wait_for_pmlogger
209         done_clean=true
210     fi
211     $sudo rm -f $tmp.*
214 _make_helptext()
216     __pmda=$1
217     __home=`pwd`
219     if [ -f $PCP_PMDAS_DIR/$__pmda/help.dir ]
220     then
221         # ./Install already run, or QA stumbled past to run newhelp
222         return 0
223     fi
225     cd $PCP_PMDAS_DIR/$__pmda
226     $sudo $PCP_BINADM_DIR/newhelp -n root help >$tmp.out 2>&1
227     if [ -f $PCP_PMDAS_DIR/$__pmda/help.dir ]
228     then
229         :
230     else
231         cat $tmp.out
232         echo "Arrgh ... failed to create help.dir for $pmda PMDA"
233         return 1
234     fi
235     cd $__home
236     return 0
240 # Get all IPv6 connection strings for a hosts interfaces, excluding loopback
242 _host_to_ipv6addrs()
244     ADDRESS=`pminfo -f -h "$1" network.interface.ipv6_addr | \
245     sed -e '/^$/d' -e '/^network/d' -e '/"lo"/d' -e 's/\/[0-9][0-9]*//g'`
246     LOCAL_LINK=`echo $ADDRESS | awk -F\" '{ printf "%s\n", $4 }' | grep -i "^fe80::"`
247     if [ ! -z "$LOCAL_LINK" ]; then
248         echo $ADDRESS | awk -F\" '{ printf "%s%%%s\n", $4, $2 }'
249     else
250         echo $ADDRESS | awk -F\" '{ printf "%s\n", $4 }'
251     fi
254 _host_to_ipaddr()
256     perl -MSocket -e '
257         my $packed_ip = gethostbyname("'$1'");
258         if (defined $packed_ip) {
259             my $ip_address = inet_ntoa($packed_ip);
260             print $ip_address;
261         }'
264 _ipaddr_to_host()
266     perl -MSocket -e '
267         my $iaddr = inet_aton("'$1'");
268         if (defined $iaddr) {
269             my $name  = gethostbyaddr($iaddr, AF_INET);
270             print $name;
271         }'
274 _host_to_fqdn()
276     ans=`hostname -f 2>/dev/null | grep '\.'`
277     if [ -z "$ans" ]
278     then
279         if which nslookup >/dev/null 2>&1
280         then
281             ans=`nslookup $1 2>&1 | sed -n -e '/^Name:[         ][      ]*/s///p'`
282         fi
283     fi
284     if [ -z "$ans" ]
285     then
286         if which domainname >/dev/null 2>&1
287         then
288             ans=`domainname | fgrep -v '(none)'`
289             [ -z "$ans" ] || ans="$1.$ans"
290         fi
291     fi
292     if [ -z "$ans" ]
293     then
294         # fake out localhost.localdomain if no working DNS
295         ans=localhost.localdomain
296     fi
297     echo "$ans"
300 _ipv6_localhost()
302     if [ ! -f /etc/hosts ]
303     then
304         echo >&2 "Arrgh ... cannot find /etc/hosts to determine IPv6 localhost name"
305         return
306     fi
307     for sniff in localhost6 ip6-localhost ipv6-localhost
308     do
309         if sed -e '/^#/d' -e 's/$/ /' /etc/hosts | grep -q "[   ]$sniff "
310         then
311             echo $sniff
312             return
313         fi
314     done
315     echo >&2 "Arrgh ... cannot determine IPv6 localhost name from /etc/hosts"
316     return
319 _check_metric()
321     if pminfo -h ${2-localhost} -f $1 2>&1 | grep " value " >/dev/null
322     then
323         :
324     else
325         echo "Check failed for metric \"$1\" at host \"${2-localhost}\" ... is PMDA installed?"
326         exit 1
327     fi
330 # wait_for_pmcd [maxdelay [host]]
332 _wait_for_pmcd()
334     # 20 seconds default seems like a reasonble max time to get going
335     #debug# set -x
336     _can_wait=${1-20}
337     _host=${2-localhost}
338     _i=0
339     _dead=true
340     #debug# ping -c 2 $_host
341     #debug# pcp -h $_host
342     #debug# pcp -h `hostname`
343     while [ $_i -lt $_can_wait ]
344     do
345         #debug# pmprobe -n $PCP_VAR_DIR/pmns/root_pmcd -h $_host pmcd.numclients
346         _sts=`pmprobe -n $PCP_VAR_DIR/pmns/root_pmcd -h $_host pmcd.numclients 2>/dev/null | $PCP_AWK_PROG '{print $2}'`
347         if [ "${_sts:-0}" -gt 0 ]
348         then
349             # numval really > 0, we're done
350             #
351             _dead=false
352             break
353         fi
354         sleep 1
355         _i=`expr $_i + 1`
356     done
357     if $_dead
358     then
359         date
360         echo "Arrgghhh ... pmcd at $_host failed to start after $_can_wait seconds"
361         echo "=== failing pmprobe ==="
362         echo "+ pmprobe -n $PCP_VAR_DIR/pmns/root_pmcd -h $_host pmcd.numclients"
363         pmprobe -n $PCP_VAR_DIR/pmns/root_pmcd -h $_host pmcd.numclients
364         case $_host
365         in
366             localhost|unix:|local:|`hostname`)
367                 # these are all local PMCD's
368                 #
369                 echo "=== pmcd.log ==="
370                 cat $PCP_LOG_DIR/pmcd/pmcd.log
372                 echo "likely looking processes ..."
373                 ps "$PCP_PS_ALL_FLAGS" | egrep "[p]m|[P]ID"
374                 ;;
375             *)
376                 # assume a remote PMCD
377                 #
378                 ssh pcpqa@$_host "sh -c '. \$PCP_DIR/etc/pcp.env; echo; echo "=== pmcd.log ==="; [ -f \$PCP_LOG_DIR/pmcd/pmcd.log ] && cat \$PCP_LOG_DIR/pmcd/pmcd.log; [ -f \$PCP_LOG_DIR/pmcd.log ] && cat \$PCP_LOG_DIR/pmcd.log; echo; echo likely looking processes ...; ( ps \$PCP_PS_ALL_FLAGS | egrep \"[p]m|[P]ID\" )'" </dev/null
379                 ;;
380         esac
381         status=2
382         exit $status
383     fi
386 # wait_for_pmlogger [pid logfile [maxdelay]]
388 _wait_for_pmlogger()
390     # 20 seconds default seems like a reasonable max time to get going
391     _maxdelay=20
393     case $# in
394         0)
395             _pid="-P"
396             dir_hostname=`hostname || echo localhost`
397             _logfile="$PCP_LOG_DIR/pmlogger/$dir_hostname/pmlogger.log" 
398             _iam="primary"
399             ;;
400         2)
401             _pid=$1
402             _logfile=$2
403             _iam="pid=$_pid"
404             ;;
405         3)
406             _pid=$1
407             _logfile=$2
408             _maxdelay=$3
409             _iam="pid=$_pid"
410             ;;
411         *)
412             echo "_wait_for_pmlogger(): wrong number of arguments"
413             status=1
414             exit $status
415             ;;
416     esac
418     #debug# set -x
419     _i=0
420     _dead=true
421     rm -f $tmp._wait_for_pmlogger.pmlc
422     while [ $_i -lt $_maxdelay ]
423     do
424         #debug# ps -ef | grep "[^0-9]$_pid[^0-9]"
425         echo "pmlc $_pid" >> $tmp._wait_for_pmlogger.pmlc
426         if pmlc $_pid </dev/null 2>&1 \
427                 | tee -a $tmp._wait_for_pmlogger.pmlc \
428                 | egrep "Connection refused|Transport endpoint is not connected" >/dev/null
429         then
430             sleep 1
431             _i=`expr $_i + 1`
432         else
433             # pmlogger socket has been set up ...
434             _dead=false
435             # give pmlogger a chance to detect that pmlc has gone away
436             # so the port is free
437             sleep 1
438             break
439         fi
440     done
441     if $_dead
442     then
443         date
444         echo "Arrgghhh ... pmlogger ($_iam) failed to start after $_maxdelay seconds"
445         echo "at `date`."
446         echo "pmlogger log ($_logfile) ..."
447         cat $_logfile
448         echo
450         #  If pmlc could not connect to pmlogger, report details
451         if [ -s $tmp._wait_for_pmlogger.pmlc ]
452         then
453             echo "pmlc output ..."
454             cat $tmp._wait_for_pmlogger.pmlc
455             echo
456         fi
458         #  If pmlogger could not connect to PMCD, find which host it was
459         #  connecting to, and get the pmcd.log file from that host.
460         cat $_logfile | $PCP_AWK_PROG '/pmlogger: Cannot connect to PMCD on host/' \
461           | sed -e '    s/pmlogger: Cannot connect to PMCD on host "//g' \
462           -e '  s/": .*//g' >$tmp._wait_for_pmlogger.host
463         if [ -s $tmp._wait_for_pmlogger.host ]
464         then
465             _pmcdhost=`cat $tmp._wait_for_pmlogger.host`
466             echo "pmcd log ($_pmcdhost:$PCP_LOG_DIR/pmcd/pmcd.log) ..."
467             if [ -r /hosts/$_pmcdhost$PCP_LOG_DIR/pmcd/pmcd.log ]
468             then
469                 cat /hosts/$_pmcdhost$PCP_LOG_DIR/pmcd/pmcd.log
470             elif [ -r /hosts/$_pmcdhost$PCP_LOG_DIR/pmcd.log ]
471             then
472                 cat /hosts/$_pmcdhost$PCP_LOG_DIR/pmcd.log
473             else
474                 if [ "`hostname | sed -e 's/\..*//'`" != $_pmcdhost ]
475                 then
476                     if scp -q $_pmcdhost:$PCP_LOG_DIR/pmcd/pmcd.log \
477                       $tmp._wait_for_pmlogger.pmcdlog
478                     then
479                         cat $tmp._wait_for_pmlogger.pmcdlog
480                     elif scp -q $_pmcdhost:$PCP_LOG_DIR/pmcd.log \
481                       $tmp._wait_for_pmlogger.pmcdlog
482                     then
483                         cat $tmp._wait_for_pmlogger.pmcdlog
484                     fi
485                 else
486                     cat $PCP_LOG_DIR/pmcd/pmcd.log
487                 fi
488             fi
489         fi
490         base=`cat $_logfile | sed -n '/^Archive basename:[      ]*/s///p'`
491         if [ -n "$base" -a -f $base.0 ]
492         then
493             echo "archive created ..."
494             pmdumplog -l $base.0
495             nres=`pmdumplog $base.0 | grep '^[0-9]' | wc -l | sed -e 's/ //g'`
496             echo "archive contains $nres records"
497         else
498             echo "archive not created"
499         fi
500         echo
501         echo "local pmlogger map ..."
502         for map in $PCP_TMP_DIR/pmlogger/*
503         do
504             if [ "`echo $map`" = "$PCP_TMP_DIR"'/pmlogger/*' ]
505             then
506                 echo "No files in $PCP_TMP_DIR/pmlogger !?"
507             else
508                 ls -l $map
509                 cat $map
510             fi
511         done
512         echo
513         echo "Likely looking processes ..."
514         ps $PCP_PS_ALL_FLAGS | egrep '[p]m|[P]ID'
515         status=2
516         exit $status
517     fi
518     rm -f $tmp._wait_for_pmlogger.*
521 # Start a pmlogger with appropriate privs that it can create
522 # portmap files in PCP_TMP_DIR (requires pcp or root account)
524 # Couple of side-effects to be aware of:
525 # Returns with $pid containing the backgrounded pmlogger PID;
526 # Creates the pmlogger archive, logfile, etc as root/pcp, not
527 # as the user running QA (so, tmp cleanup needs to use sudo).
529 _start_up_pmlogger()
531     cat >$tmp.cmd <<End-of-File
532 #!/bin/sh
533 pmlogger $@ &
534 echo pid=\$!
535 End-of-File
537     __user=root
538     id pcp >/dev/null 2>&1 && __user=pcp
540     $sudo -u $__user sh $tmp.cmd $@ >$tmp.pid
541     eval `cat $tmp.pid`
544 # wait for a pmlogger process to end that is not our child
545 # (else we could just use shell wait command).  Instead we
546 # must keep tabs on the PID file and bail when its gone.
548 _wait_pmlogger_end()
550     #debug# set -x
551     _pid=$1
553     _i=0
554     while true
555     do
556         if [ -f "$PCP_TMP_DIR/pmlogger/$_pid" ]
557         then
558             _i=`expr $_i + 1`
559             if [ "$_i" -ge 100 ]
560             then
561                 echo "_wait_pmlogger_end: failed to see $PCP_TMP_DIR/pmlogger/$_pid removed after 100 iterations"
562                 #debug# set +x
563                 return
564             fi
565             pmsleep 0.1
566         else
567             # now there is an ugly race condition at the end of pmloger
568             # ... once the control file has been removed (as per the test
569             # above) the pmlogger log file is not complete until the atexit()
570             # code is run ... so hang around waiting for the process to
571             # go away
572             #
573             _i=0
574             while true
575             do
576                 if sudo kill -s 0 $_pid 2>/dev/null
577                 then
578                     # process still exists
579                     _i=`expr $_i + 1`
580                     if [ "$_i" -ge 100 ]
581                     then
582                         echo "_wait_pmlogger_end: failed to see pid $_pid exit after 100 iterations"
583                         #debug# set +x
584                         return
585                     fi
586                     pmsleep 0.1
587                 else
588                     # process has really exited
589                     #debug# set +x
590                     return
591                 fi
592             done
593         fi
594     done
597 # Wait for pmcd to end
599 _wait_pmcd_end()
601     #debug# set -x
603     _pid=`cat $PCP_RUN_DIR/pmcd.pid 2>/dev/null`
604     if [ -z "$_pid" ]
605     then
606         # no $PCP_RUN_DIR/pmcd.pid file, try ps(1) the hard way
607         #
608         _pid=`$PCP_PS_PROG $PCP_PS_ALL_FLAGS \
609         | sed -n -e '/\[p]mcd /{
610 s/^[^   ]*//
611 s/^[    ]*//
612 s/[     ].*//
615     fi
616     if [ -z "$_pid" ]
617     then
618         #debug# set +x
619         return
620     fi
622     _i=0
623     while true
624     do
625         if sudo kill -s 0 $_pid 2>/dev/null
626         then
627             # process still exists
628             _i=`expr $_i + 1`
629             if [ "$_i" -ge 100 ]
630             then
631                 echo "_wait_pmcd_end: failed to see pid $_pid exit after 100 iterations"
632                 #debug# set +x
633                 return
634             fi
635             pmsleep 0.1
636         else
637             # process has really exited
638             #debug# set +x
639             return
640         fi
641     done
644 # ensure primary logger allows pmlc state changes
646 _writable_primary_logger()
648     _configfile="$PCP_VAR_DIR/config/pmlogger/config.default"
650     echo "_open_primary_logger checking config file: $_configfile" >>$here/$seq.full
652     # first, move aside the default configuration file
653     _save_config "$_configfile"
655     # next, create a new default configuration file
656     PMLOGCONF="$PCP_BINADM_DIR/pmlogconf"
657     test -f "$_configfile" || \
658         $sudo $PMLOGCONF -q -h localhost "$_configfile" >>$here/$seq.full 2>&1
660     # finally, open it up to local access from pmlc
661     sed <"$_configfile" >$tmp.sed-i \
662         -e 's/^allow localhost.*$/allow localhost : all;/g' \
663         -e 's/^allow local:.*$/allow local:* : all;/g'
664     $sudo cp $tmp.sed-i "$_configfile"
665     rm -f $tmp.sed-i
668 # restore primary logger pmlc access restrictions
670 _restore_primary_logger()
672     _configfile="$PCP_VAR_DIR/config/pmlogger/config.default"
674     # if there was an initial configuration, put it back
675     if test -f "$_configfile.$seq"
676     then
677         _restore_config "$_configfile"
678     else
679         # otherwise, close out access from local pmlc once more
680         if test -f "$_configfile"
681         then
682             sed <"$_configfile" >$tmp.sed-i \
683                 -e 's/^allow localhost.*$/allow localhost : enquire;/g' \
684                 -e 's/^allow local:.*$/allow local:* : enquire;/g'
685             $sudo cp $tmp.sed-i "$_configfile"
686             rm -f $tmp.sed-i
687         fi
688     fi
691 # purify support
693 # typical usage:
695 # At the top before outputting $seq.out but after setting $seq ...
696 #   _check_purify prog
698 # Main code...
699 #   _setup_purify prog
700 #   _run_purify [arg1] [arg2]
703 # initial setup for running purify
704 # creates purified binary in $_purify_dir
706 _setup_purify()
708     # Need to change these to match Purify setup locally, if you
709     # have Purify!
710     #
711     LM_LICENSE_FILE=27000@snort.melbourne.sgi.com
712     RSU_LICENSE_MAP=/usr/Rational/config/LICENSE_MAP
713     export LM_LICENSE_FILE RSU_LICENSE_MAP
715     rm -f $here/$seq.full
716     _path=$1
717     _prog=`echo $_path | sed -e 's#.*/##'`
718     _pure_prog="$_prog.pure"
719     _purify_dir=$tmp.purify
721     rm -rf $_purify_dir
722     mkdir $_purify_dir
723     cp $_path $_purify_dir
724     _here=`pwd`
725     cd $_purify_dir
727     cat >.purify<<EOF
728 suppress umr _write
729 suppress miu
731     unset PURIFYOPTIONS PUREOPTIONS
732     purify -log-file=stderr $_prog >out 2>&1
733     if [ ! -x $_prog.pure ]
734     then
735         cat out
736         echo "Hmm ... purify failed to create $_prog.pure"
737         exit
738     fi
739     cd $_here
742 _run_purify()
744     args=$* 
746     _here=`pwd`
747     cd $_purify_dir
748     $_purify_dir/$_pure_prog $args > $tmp._purify.out 2>&1
749     cat $tmp._purify.out >>$_here/$seq.full
750     if grep -i expired $tmp._purify.out >/dev/null; then
751         cat $tmp._purify.out
752     else
753         _filter_purify < $tmp._purify.out
754     fi
755     cd $_here
758 _filter_purify()
760     $PCP_AWK_PROG '
761 state == 0 && /License successfully checked out/        { state = 1; next }
762 state == 0 && /Purify checking enabled/                 { state = 1; next }
763 state == 1                                              { print }' \
764     | sed \
765         -e 's/pid [0-9][0-9]*/pid PID/g' \
766         -e "s;$_purify_dir;TMP;g" \
767         -e '/reserved for Purify internal use/d' \
768         -e 's/suppressed chunks/suppressed blocks/g' \
769     | $PCP_AWK_PROG -v extra="$PURIFY_FILTER_EXTRA" '
770 /Purify instrumented/           { skip = 0 }
771 /bytes leaked\./                { print "..."; skip = 1; next }
772 skip == 1                       { next }
773                                 { print }
774 /Purify Heap Analysis/          { print "..."; skip = 1 }
775 /Basic memory usage \(including Purify/         { print "..."; skip = 1 }
776 extra != "" && /Current file descriptors/       { print "..."; skip = 1 }' \
777     | (if [ "$PURIFY_FILTER_EXTRA" ]
778     then sed -e 's/in use: [0-9][0-9]*/in use: N/'
779     else cat -
780     fi)
783 _check_purify()
785     [ $# -eq 1 ] || _notrun "_check_purify needs executable as argument"
786     _path=$1
787     which purify >/dev/null 2>&1
788     [ $? -eq 0 ] || _notrun "No purify binary found"
791 _check_display()
793     # note: non-X systems (MacOSX, Windows) must pass here unchallenged
794     if [ -z "$PCPQA_CLOSE_X_SERVER" ]
795     then
796         _notrun "\$PCPQA_CLOSE_X_SERVER not set in ./common.config"
797         # NOTREACHED
798     fi
799     which xdpyinfo >/dev/null 2>&1
800     if [ $? -eq 0 ]
801     then
802         DISPLAY=$PCPQA_CLOSE_X_SERVER xdpyinfo >/dev/null 2>&1 || \
803             _notrun "Failed sanity check on DISPLAY $PCPQA_CLOSE_X_SERVER"
804     fi
805     export DISPLAY=$PCPQA_CLOSE_X_SERVER
808 _check_containers()
810     [ $PCP_PLATFORM = linux ] || _notrun "Linux-specific containers testing"
811     _contain=`pmprobe -v pmcd.feature.containers | awk '{ print $3 }'`
812     [ $_contain = 1 ] || _notrun "Running kernel does not support containers"
813     pminfo -f pmcd.agent.type 2>/dev/null | grep linux | grep -q 'value 4'
814     [ $? = 0 ] || _notrun "pmdalinux has insufficient privileges as a DSO"
817 # good output from dbpmda looks like ...
818 # dbpmda> open pipe /var/lib/pcp/pmdas/papi/pmdapapi -d 126
819 # ...
820 # dbpmda> fetch papi.system.TOT_INS
821 # PMID(s): 126.0.14
822 # pmResult dump from 0x25c6e00 timestamp: 0.000000 10:00:00.000 numpmid: 1
823 #   126.0.14 (<noname>): numval: 1 valfmt: 1 vlist[]:
824 #      value 2616
826 _check_papi()
828     [ -f $PCP_PMDAS_DIR/papi/pmdapapi ] || _notrun "no executable for the papi PMDA"
829     [ -f $PCP_PMDAS_DIR/papi/root ] || _notrun "no PMNS for the papi PMDA"
831     $sudo dbpmda -n $PCP_PMDAS_DIR/papi/root -ie <<EOF >$tmp.papi.check
832 open pipe $PCP_PMDAS_DIR/papi/pmdapapi -d 126 -l $tmp.papi.log
833 attr "username" "root"
834 attr 11 "0"
835 fetch papi.system.TOT_INS
837     echo "papi.log ..." >>$here/$seq.full
838     cat $tmp.papi.log >>$here/$seq.full
839     $sudo rm $tmp.papi.log
840     echo "_check_papi ..." >>$here/$seq.full
841     cat $tmp.papi.check >>$here/$seq.full
842     if grep ' value [0-9][0-9]*$' <$tmp.papi.check >/dev/null
843     then
844         :
845     else
846         _notrun "PAPI counters not available on this platform"
847     fi
850 _check_papi_native()
852     $sudo dbpmda -n $PCP_PMDAS_DIR/papi/root -ie <<EOF >$tmp.papi.check
853 open pipe $PCP_PMDAS_DIR/papi/pmdapapi -d 126
854 attr "username" "root"
855 attr 11 "0"
856 traverse papi.system.perf
858     echo "_check_papi_native ..." >>$here/$seq.full
859     cat $tmp.papi.check >>$here/$seq.full
860     if grep "Error PDU: Unknown metric name" <$tmp.papi.check >/dev/null
861     then
862         _notrun "PAPI native metrics not available on this platform"
863     fi
866 # valgrind support
868 # typical usage:
870 # At the top before outputting $seq.out but after setting $seq ...
871 #   _check_valgrind
873 # Main code...
874 #   _run_valgrind app [arg1 [arg2] ... ]
877 _check_valgrind()
879     which valgrind >/dev/null 2>&1
880     [ $? -eq 0 ] || _notrun "No valgrind binary found"
883 # Note: because we may be avoiding leaks in system libraries
884 # via the suppressions, there is potential indeterminism for
885 # the following case:
886 # -All heap blocks were freed -- no leaks are possible
887 # +LEAK SUMMARY:
888 # +definitely lost: 0 bytes in 0 blocks
889 # +indirectly lost: 0 bytes in 0 blocks
891 # Note
892 #       last 5 sed expressions are for broken valgrind(1) on
893 #       Debian strech circa 2016
895 _filter_valgrind()
897    noleak="LEAK SUMMARY:\ndefinitely lost: 0 bytes in 0 blocks\nindirectly lost: 0 bytes in 0 blocks"
898     sed \
899         -e 's/^==*[1-9][0-9]*==* *//' \
900         -e '/^$/d' \
901         -e '/^Copyright (/d' \
902         -e '/^Using Valgrind-/d' \
903         -e '/^Parent PID:/d' \
904         -e '/^HEAP SUMMARY:/d' \
905         -e '/^in use at exit:/d' \
906         -e '/^total heap usage:/d' \
907         -e '/^possibly lost:/d' \
908         -e '/^still reachable:/d' \
909         -e '/^suppressed:/d' \
910         -e '/^Reachable blocks (those to which a pointer was found)/d' \
911         -e '/^To see them, rerun with:/d' \
912         -e '/^For counts of detected and suppressed errors,/d' \
913         -e '/^ERROR SUMMARY:/s/ (suppressed: [^)]*)/ .../' \
914         -e "s/^All heap blocks were freed -- .*/$noleak/g" \
915         -e '/WARNING: Serious error when reading debug info/d' \
916         -e '/When reading debug info from /d' \
917         -e '/Ignoring non-Dwarf2\/3\/4 block in .debug_info/d' \
918         -e '/Last block truncated in .debug_info; ignoring/d' \
919         -e '/parse_CU_Header: is neither DWARF2 nor DWARF3 nor DWARF4/d' \
920     # end
923 _run_valgrind()
925     __version=`valgrind --version | sed -e 's/valgrind-//'`
926     if [ -f $here/valgrind-suppress-$__version ]
927     then
928         __extra="--suppressions=$here/valgrind-suppress-$__version"
929         echo "Warning: using extra $__extra" >>$here/$seq.full
930     else
931         __extra=''
932     fi
933     valgrind \
934         --leak-check=full --read-var-info=yes --gen-suppressions=all \
935         --suppressions=$here/valgrind-suppress $__extra \
936         --log-file=$tmp._valgrind \
937             $* 2>$tmp._valgrind.err >$tmp._valgrind.out
938     echo "=== std out ==="
939     cat $tmp._valgrind.out
940     echo "=== std err ==="
941     cat $tmp._valgrind.err
942     echo "=== valgrind report ===" >>$here/$seq.full
943     cat $tmp._valgrind >>$here/$seq.full
944     echo "=== filtered valgrind report ==="
945     _filter_valgrind <$tmp._valgrind
948 # Alternate invocation, using valgrind-silence as an assertion.
949 # Produces no stdout/stderr from valgrind - except in case of errors!
950 # Uses same suppression logic as _run_valgrind.
952 # Usage:                    $_valgrind_clean_assert CMD ARGS ...
953 # just as you'd have used   CMD ARGS ...
954 # alone, or                 |filtered
955 # or                        & backgrounded
957 # It works even if valgrind is not available (expanding to nothing).
959 _valgrind_clean_assert=
960 if which valgrind >/dev/null 2>&1; then
961     __version=`valgrind --version | sed -e 's/valgrind-//'`
962     if [ -f $here/valgrind-suppress-$__version ]
963     then
964         __extra="--suppressions=$here/valgrind-suppress-$__version"
965         echo "Warning: using extra $__extra" >>$here/$seq.full
966     else
967         __extra=''
968     fi
969     valgrind --help >$tmp.valgrind.help 2>&1
970     grep -q .--vgdb= <$tmp.valgrind.help && __extra="$__extra --vgdb=no"
971     valgrind --help 2>&1 | grep -q show-leak-kinds
972     if grep -q .--show-leak-kinds= <$tmp.valgrind.help
973     then
974         __extra="$__extra --show-leak-kinds=definite"
975     else
976         if grep -q .--show-possibly-lost= <$tmp.valgrind.help
977         then
978             __extra="$__extra --show-reachable=no --show-possibly-lost=no"
979         else
980             __extra="$__extra --show-reachable=no"
981         fi
982     fi
983     rm -f $tmp.valgrind.help
984     _valgrind_clean_assert="valgrind -q \
985              --leak-check=full --read-var-info=yes --gen-suppressions=all \
986              --suppressions=$here/valgrind-suppress $__extra \
987              --log-fd=1"
991 # Checks that given_value is in range of correct_value +/- tolerance.
992 # Tolerance can be an absolute value or a percentage of the correct value
993 # (see examples with tolerances below).
994 # Outputs suitable message to stdout if it's not in range.
996 # A verbose option, -v, may be used as the LAST argument
998 # e.g. 
999 # foo: 0.0298 = 0.03 +/- 5%
1000 # _within_tolerance "foo" 0.0298 0.03 5%  
1002 # foo: 0.0298 = 0.03 +/- 0.01
1003 # _within_tolerance "foo" 0.0298 0.03 0.01
1005 # foo: 0.0298 = 0.03 -0.01 +0.002
1006 # _within_tolerance "foo" 0.0298 0.03 0.01 0.002
1008 # foo: verbose output of 0.0298 = 0.03 +/- 5% 
1009 # _within_tolerance "foo" 0.0298 0.03 5% -v 
1011 _within_tolerance()
1013   _name=$1
1014   _given_val=$2
1015   _correct_val=$3
1016   _mintol=$4
1017   _maxtol=$_mintol
1018   _verbose=0
1019   _debug=false
1021   # maxtol arg is optional
1022   # verbose arg is optional
1023   if [ $# -ge 5 ]
1024   then 
1025      if [ "$5" = "-v" ]
1026      then
1027         _verbose=1
1028      else
1029         _maxtol=$5
1030      fi
1031   fi
1032   if [ $# -ge 6 ]
1033   then
1034      [ "$6" = "-v" ] && _verbose=1
1035   fi
1037   # find min with or without %
1038   _mintolerance=`echo $_mintol | sed -e 's/%//'` 
1039   if [ $_mintol = $_mintolerance ]
1040   then 
1041       _min=`echo "scale=5; $_correct_val-$_mintolerance" | bc`
1042   else
1043       _min=`echo "scale=5; $_correct_val-$_mintolerance*0.01*$_correct_val" | bc`
1044   fi
1046   # find max with or without %
1047   _maxtolerance=`echo $_maxtol | sed -e 's/%//'` 
1048   if [ $_maxtol = $_maxtolerance ]
1049   then 
1050       _max=`echo "scale=5; $_correct_val+$_maxtolerance" | bc`
1051   else
1052       _max=`echo "scale=5; $_correct_val+$_maxtolerance*0.01*$_correct_val" | bc`
1053   fi
1055   $_debug && echo "min = $_min"
1056   $_debug && echo "max = $_max"
1058   cat <<EOF > $tmp._bc.1
1059 scale=5;
1060 if ($_min <= $_given_val) 1;
1061 if ($_min > $_given_val) 0; 
1064   cat <<EOF > $tmp._bc.2
1065 scale=5;
1066 if ($_given_val <= $_max) 1;
1067 if ($_given_val > $_max) 0;
1070   _above_min=`bc < $tmp._bc.1`
1071   _below_max=`bc < $tmp._bc.2`
1073   _in_range=`expr $_above_min \& $_below_max` 
1075   # fix up min, max precision for output
1076   # can vary for 5.3, 6.2
1077   _min=`echo $_min | sed -e 's/0*$//'` # get rid of trailling zeroes
1078   _max=`echo $_max | sed -e 's/0*$//'` # get rid of trailling zeroes
1080   if [ $_in_range -eq 1 ] 
1081   then
1082         [ $_verbose -eq 1 ] && echo $_name is in range
1083         return 0
1084   else
1085         [ $_verbose -eq 1 ] && echo $_name has value of $_given_val
1086         [ $_verbose -eq 1 ] && echo $_name is NOT in range $_min .. $_max       
1087         return 1
1088   fi
1091 # comment pmlogger_check and pmsnap entries in the crontab file
1092 # (also cron.pmcheck and cron.pmsnap entries for backwards compatibility)
1093 # Usage: _remove_cron backup sudo
1095 # backup - where to keep the old crontab file
1096 # sudo - location of sudo
1098 _remove_cron()
1100     rc_backup=${1:-crontab}
1101     rc_sudo=${2:-sudo}
1103     $rc_sudo rm -f $rc_backup
1104     if $rc_sudo crontab -l 2>/dev/null >$rc_backup
1105     then
1106         :
1107     else
1108         # error, make sure the backup is empty so no changes are made
1109         echo >$rc_backup
1110     fi
1112     if [ -s $rc_backup ]
1113     then
1114         $rc_sudo cat $rc_backup \
1115         | sed \
1116             -e 's/^[^#].*pmlogger_check/#&/' \
1117             -e 's/^[^#].*pmsnap/#&/' \
1118             -e 's/^[^#].*cron.pmcheck/#&/' \
1119             -e 's/^[^#].*cron.pmsnap/#&/' \
1120         | $rc_sudo crontab > /dev/null 2>&1
1121     fi
1124 # restore crontab back to original state
1125 # Usage: _restore_cron backup sudo
1127 # backup - where to keep the old crontab file
1128 # sudo - location of sudo
1130 _restore_cron()
1132     rc_backup=${1:-crontab}
1133     rc_sudo=${2:-sudo}
1135     if [ -s $rc_backup ]
1136     then
1137         $rc_sudo rm -f rc_cron_out rc_cron_check rc_cron_diff
1138         if $rc_sudo crontab $rc_backup >rc_cron_out 2>&1
1139         then
1140             # check everything is OK
1141             #
1142             $rc_sudo crontab -l >rc_cron_check
1143             sed -e '/^#/d' $rc_backup >$rc_backup.clean
1144             sed -e '/^#/d' rc_cron_check >rc_cron_check.clean
1145             if diff -u $rc_backup.clean rc_cron_check.clean >rc_cron_diff 2>&1
1146             then
1147                 :
1148             else
1149                 echo "_restore_cron: Warning: could not restore crontab to original state"
1150                 echo "               Unexpected differences ..."
1151                 diff -u $rc_backup rc_cron_check
1152             fi
1153             $rc_sudo rm -f rc_cron_check rc_cron_diff
1154         else
1155             echo "_restore_cron: Warning: could not restore crontab to original state"
1156             echo "               crontab(1) failed ..."
1157             cat rc_cron_out
1158         fi
1159         $rc_sudo rm -f rc_cron_out rc_cron_check rc_cron_diff
1160     fi
1163 # get offset into an archive relative to the first pmResult
1164 # past the preamble
1166 # Usage: _arch_start archive [offset]
1168 _arch_start()
1170     pmdumplog -z $1 \
1171     | $PCP_AWK_PROG '
1172 /^[0-9][0-9]:[0-9][0-9]:/       { if ($3 ~ /pmcd.pmlogger.host/) next
1173                                   split($1, t, ":")
1174                                   t[3] += '"${2-0}"'
1175                                   while (t[3] < 0) {
1176                                     t[3] += 60
1177                                     t[2]--
1178                                   }
1179                                   while (t[3] > 60) {
1180                                     t[3] -= 60
1181                                     t[2]++
1182                                   }
1183                                   while (t[2] < 0) {
1184                                     t[2] += 60
1185                                     t[1]--
1186                                   }
1187                                   while (t[2] > 60) {
1188                                     t[2] -= 60
1189                                     t[1]++
1190                                   }
1191                                   while (t[1] < 0)
1192                                     t[1] += 24
1193                                   while (t[1] > 23)
1194                                     t[1] -= 24
1195                                   printf "@%02d:%02d:%06.3f",t[1],t[2],t[3]
1196                                   exit
1197                                 }'
1200 # get an unused ipc port ... returned on std out, empty for failure
1201 # Usage: _get_port tcp|udp low_port high_port
1203 _get_port()
1205     [ $# -ne 3 ] && return
1206     __proto=$1
1207     __port=$2
1208     while [ $__port -le "$3" ]
1209     do
1210         if fuser $__port/$__proto >/dev/null 2>&1
1211         then
1212             :
1213         else
1214             echo $__port
1215             return
1216         fi
1217         __port=`expr $__port + 1`
1218     done
1221 # get host endianness ("le" or "be")
1222 _get_endian()
1224     check=`echo a | od -x 2>&1 | sed -e 's/^0[^ ]* *//' -e 's/ //g' -e '/^$/d'`
1225     case "$check"
1226     in
1227     0a61) echo le ;;
1228     610a) echo be ;;
1229     *)
1230         echo "Arrgh ... od -x returned something odd ($check)"
1231         echo a | od -x
1232         status=1
1233         exit
1234         ;;
1235     esac
1238 # get host word size ("32" or "64")
1239 _get_word_size()
1241     machine=`uname -m`
1242     case "$machine"
1243     in
1244     i?86|athlon|ppc)
1245         size=32
1246         # but, apps are 64-bit on my Mac OS X
1247         [ $PCP_PLATFORM = darwin ] && size=64
1248         ;;
1249     x86_64|ia64|ppc64|ppc64le|s390x|aarch64)
1250         size=64
1251         ;;
1252     *)
1253         echo "uname gave machine type with unknown word size ($machine)"
1254         status=1
1255         exit
1256         ;;
1257     esac
1258     echo $size
1261 # _all_hostnames host - generate all hostnames (or IP addresses) for this host,
1262 #                       that map to some network interface, excluding loopback
1264 _all_hostnames()
1266     touch $tmp._addr
1267     ssh pcpqa@$1 </dev/null netstat -in 2>/dev/null >$tmp._tmp
1268     if grep 'Network.*Address' $tmp._tmp >/dev/null
1269     then
1270         # This is the IRIX version of netstat -in, get IP addr from the
1271         # Address field
1272         # 
1273         # Name   Mtu   Network         Address            Ipkts Ierrs ...
1274         # ef0    1500  134.14.55.128   134.14.55.149  712168207    10 ...
1275         #                              134.14.55.159      
1276         #                              134.14.55.147      
1277         # ef2*   1500  none            none                   0     0 ...
1278         # lo0    32992 127             127.0.0.1       23628402     0 ...
1279         #
1280         $PCP_AWK_PROG <$tmp._tmp >$tmp._addr '
1281 /^lo/                                                                   { next }
1282 NF >= 4 && $4 ~ /^[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*$/  { print $4 }
1283 NF == 1 && $1 ~ /^[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*$/  { print $1 }
1284 END                                                                     { print "End-of-List" }'
1285     else
1286         ssh pcpqa@$1 </dev/null /sbin/ifconfig 2>/dev/null >$tmp._tmp
1287         if grep 'UP.*RUNNING' $tmp._tmp >/dev/null
1288         then
1289             # This is the Linux version of ifconfig, get IP addr from the
1290             # inet addr: line
1291             #
1292             # eth0      Link encap:Ethernet  HWaddr 00:90:27:98:EE:A8  
1293             #           inet addr:134.14.55.176  Bcast:134.14.55.255  ...
1294             #           UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
1295             #           ...
1296             #
1297             # lo        Link encap:Local Loopback  
1298             #           inet addr:127.0.0.1  Mask:255.0.0.0
1299             #           UP LOOPBACK RUNNING  MTU:16436  Metric:1
1300             #           ...
1301             #
1302             # Note addr: tag is not present in some ifconfig output
1303             #
1304             $PCP_AWK_PROG <$tmp._tmp '
1305 /^lo/                                           { skip=1; next }
1306 skip == 1 && NF > 0                             { next }
1307 skip == 1                                       { skip = 0 }
1308 $1 == "inet" && $2 ~ /addr:/                    { print $2 }
1309 $1 == "inet" && $2 ~ /^[0-9]/                   { print $2 }
1310 END                                             { print "End-of-List" }' \
1311             | sed -e 's/addr://' >$tmp._addr
1312         else
1313             # Nothing we can do really, as there is no way of passing
1314             # an error back from here, other than returning an empty
1315             # list
1316             return
1317         fi
1318     fi
1319     cat $tmp._addr \
1320     | while read __ip
1321     do
1322         if [ "$__ip" = "End-of-List" ]
1323         then
1324             echo
1325             break
1326         fi
1327         # check that ip addr is reachable
1328         if ping -c 1 $__ip >/dev/null 2>&1
1329         then
1330             __host=`_ipaddr_to_host $__ip`
1331             if [ ! -z "$__host" ]
1332             then
1333                 $PCP_ECHO_PROG $PCP_ECHO_N ",$__host""$PCP_ECHO_C"
1334             else
1335                 $PCP_ECHO_PROG $PCP_ECHO_N ",$__ip""$PCP_ECHO_C"
1336             fi
1337         fi
1338     done \
1339     | sed -e 's/^,//'
1342 # _all_ipaddrs - generate all IP addresses for this host,
1343 #                       that map to some network interface, excluding
1344 #                       loopback, slip, ppp
1346 # See _all_hostnames() above for comments on the method used.
1348 _all_ipaddrs()
1350     touch $tmp._addr
1351     if [ "$1" = "localhost" ]
1352     then 
1353         netstat -in 2>/dev/null >$tmp._tmp
1354     else
1355         ssh pcpqa@$1 </dev/null netstat -in 2>/dev/null >$tmp._tmp
1356     fi
1357     if grep 'Network.*Address' $tmp._tmp >/dev/null
1358     then
1359         # this is the IRIX version of netstat -in, get IP addr from the
1360         # Address field
1361         #
1362         $PCP_AWK_PROG <$tmp._tmp >$tmp._addr '
1363 /^lo/ || /^sl/ || /^pp/                                                 { next }
1364 NF >= 4 && $4 ~ /^[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*$/  { print $4 }
1365 NF == 1 && $1 ~ /^[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*$/  { print $1 }
1366 END                                                                     { print "End-of-List" }'
1367     else
1368         if [ "$1" = "localhost" ]
1369         then 
1370             /sbin/ifconfig 2>/dev/null >$tmp._tmp
1371         else
1372             ssh pcpqa@$1 </dev/null /sbin/ifconfig 2>/dev/null >$tmp._tmp
1373         fi
1374         if grep 'UP.*RUNNING' $tmp._tmp >/dev/null
1375         then
1376             # This is the Linux version of ifconfig, get IP addr from the
1377             # inet addr: line
1378             #
1379 # ppp0      Link encap:Point-to-Point Protocol
1380 #           inet addr:134.14.52.219  P-t-P:134.14.52.189  Mask:255.255.255.255
1381 #           UP POINTOPOINT RUNNING NOARP MULTICAST  MTU:1522  Metric:1
1382 #           RX packets:50119 errors:0 dropped:0 overruns:0 frame:0
1383 #           TX packets:47474 errors:0 dropped:0 overruns:0 carrier:0
1384 #           collisions:0 txqueuelen:3
1385 #           RX bytes:7017171 (6.6 Mb)  TX bytes:3952015 (3.7 Mb)
1386             #
1387             # Note addr: tag is not present in some ifconfig output,
1388             #      AND UP comes first!
1389             #
1390             $PCP_AWK_PROG <$tmp._tmp '
1391 /^[a-z]/                                        { loopback = 0 }
1392 /^lo/                                           { loopback = 1; next }
1393 $1 == "inet" && $2 ~ /addr:/                    { save = $2; next }
1394 $1 == "inet" && $2 ~ /^[0-9]/                   { save = $2; next }
1395 $1 == "TX"                                      { if (loopback == 0 && save != 0)
1396                                                     print save
1397                                                   save = 0
1398                                                 }
1399 END                                             { print "End-of-List" }' \
1400             | sed -e 's/addr://' >$tmp._addr
1401         else
1402             # Nothing we can do really, as there is no way of passing
1403             # an error back from here, other than returning an empty
1404             # list
1405             return
1406         fi
1407     fi
1408     cat $tmp._addr \
1409     | while read __ip
1410     do
1411         if [ "$__ip" = "End-of-List" ]
1412         then
1413             echo
1414             break
1415         fi
1416         $PCP_ECHO_PROG $PCP_ECHO_N ",$__ip""$PCP_ECHO_C"
1417     done \
1418     | sed -e 's/^,//'
1421 # fqdn for localhost
1423 _get_fqdn()
1425     _host_to_fqdn `hostname`
1428 # Distro-specific filtering for init, rc scripts, chkconfig, et al
1430 _filter_init_distro()
1432     if [ -f /etc/mandriva-release ]
1433     then
1434         # looks like this is a Mandriva bug ... see
1435         # http://mandriva.598463.n5.nabble.com/Bug-24409-initscripts-New-netfs-provides-local-fs-scripts-can-t-be-turned-off-td869820.html
1436         #
1437         sed \
1438             -e '/Warning: netfs is needed by pcp in runlevel/d'
1439     else
1440         cat
1441     fi
1444 # deal with chkconfig et al
1445 # assumes $sudo is set correctly
1446 # try very hard to _not_ emit messages unless serious errors encountered
1448 _change_config()
1450     if [ $PCP_PLATFORM = linux ]
1451     then
1452         pat=$1
1453         [ "$1" = "verbose" ] && pat=""
1455         _have_systemctl=false
1456         which systemctl >/dev/null 2>&1 && _have_systemctl=true
1457         if [ -z "$pat" ]
1458         then
1459             _have_service=true
1460         elif [ -n "$PCP_SYSTEMDUNIT_DIR" -a -f $PCP_SYSTEMDUNIT_DIR/$pat.service ]
1461         then
1462             _have_service=true
1463         else
1464             _have_service=false
1465         fi
1466         if $_have_systemctl && $_have_service
1467         then
1468             # Run with systemd whenever it is available now
1469             #
1470             case "$2"
1471             in
1472                 on)     act=enable ;;
1473                 off)    act=disable ;;
1474                 *)
1475                     echo "_change_config: Error: \$2=$2 not \"on\" or \"off\" as expected"
1476                     exit 1
1477                     ;;
1478             esac
1479             if [ -n "$pat" ]
1480             then
1481                 $sudo systemctl $act $pat.service >$tmp._tmp 2>$tmp._err
1482                 [ $? -eq 0 ] || cat $tmp._tmp
1483             fi
1484         elif which chkconfig >/dev/null 2>&1
1485         then
1486             # Try the older RedHat and SuSE way ..
1487             #
1488             [ -n "$pat" ] && $sudo chkconfig $pat $2 2>&1 \
1489             | sed \
1490                 -e '/^insserv: warning: current start runlevel(s) .* of script .pcp./d' \
1491                 -e '/^insserv: Service .* is missed in the runlevels /d' \
1492             # end
1493         elif [ -x /usr/sbin/sysv-rc-conf ]
1494         then
1495             # Try the Debian and Ubuntu way ..
1496             #
1497             [ -n "$pat" ] && $sudo /usr/sbin/sysv-rc-conf $pat $2
1498         elif which rc-update >/dev/null 2>&1
1499         then
1500             # Try the Gentoo way ..
1501             #
1502             if [ -n "$pat" ]
1503             then
1504                 case $2
1505                 in
1506                     on)         act=add ;;
1507                     off)        act=delete ;;
1508                     *)
1509                         echo "_change_config: Error: \$2=$2 not \"on\" or \"off\" as expected"
1510                         exit 1
1511                         ;;
1512                 esac
1513                 $sudo rc-update $act $pat default >$tmp._tmp 2>&1
1514                 [ $? -eq 0 ] || cat $tmp._tmp
1515             fi
1516         elif [ -f /etc/slackware-version ]
1517         then
1518             # Slackware uses BSD-style init, so no control
1519             :
1520         else
1521             # I have no clue!
1522             #
1523             echo "_change_config: Error: cannot change config \"$1 $2\""
1524             exit 1
1525         fi
1526     elif [ $PCP_PLATFORM = solaris ]
1527     then
1528         # Try the Solaris way ..
1529         #
1530         if which svcadm >/dev/null 2>&1
1531         then
1532             case $1 
1533             in
1534                 pmcd)       pat=pmcd ;;
1535                 pmlogger)   pat=pmlogger ;;
1536                 verbose)    pat="" ;;
1537                 *)          pat=$1 ;;
1538             esac
1539             if [ -n "$pat" ]
1540             then
1541                 if [ "$2" = on ]
1542                 then
1543                     state=`svcs -l svc:/application/pcp/$pat | sed -n '/^state[         ]/s///p'`
1544                     [ -n "$state" -a "$state" != "online" ] \
1545                         && $sudo svcadm clear svc:/application/pcp/$pat
1546                     $sudo svcadm enable svc:/application/pcp/$pat
1547                 elif [ "$2" = off ]
1548                 then
1549                     $sudo svcadm disable svc:/application/pcp/$pat
1550                 else
1551                     echo "_change_config: Error: \$2=$2 not \"on\" or \"off\" as expected"
1552                     exit 1
1553                 fi
1554             fi
1555         else
1556             echo "_change_config: Error: cannot find svcs for Solaris"
1557             exit 1
1558         fi
1559     elif [ $PCP_PLATFORM = darwin ]
1560     then
1561         case $1 
1562         in
1563             pmcd)       pat=PMCD ;;
1564             pmlogger)   pat=PMLOGGER ;;
1565             pmie)       pat=PMIE ;;
1566             pmproxy)    pat=PMPROXY ;;
1567             pmmgr)      pat=PMMGR ;;
1568             pmwebd)     pat=PMWEBD ;;
1569             verbose)    pat="" ;;
1570             *)          pat=$1 ;;
1571         esac
1572         if [ -n "$pat" ]
1573         then
1574             state=`sed -n -e "/^$pat=/{"'
1575 s/.*=//
1576 s/-//g
1578 }' /etc/hostconfig`
1579             if [ -z "$state" ]
1580             then
1581                 echo "_change_config: Error: No $pat control line in /etc/hostconfig"
1582                 echo "You need to add a $pat=-YES- line to this file"
1583                 exit 1
1584             fi
1585             if [ "$2" = "on" ]
1586             then
1587                 req_state=YES
1588             elif [ "$2" = "off" ]
1589             then
1590                 req_state=NO
1591             else
1592                 echo "_change_config: Error: bad state ($2) should be on or off"
1593                 exit 1
1594             fi
1595             if [ "$state" != "$req_state" ]
1596             then
1597                 sed </etc/hostconfig >$tmp._state \
1598                     -e "/^$pat=/s/-.*/-$req_state-/"
1599                 sudo cp $tmp._state /etc/hostconfig
1600             fi
1601         fi
1602     elif [ $PCP_PLATFORM = freebsd ]
1603     then
1604         # no control for FreeBSD
1605         :
1606     elif [ $PCP_PLATFORM = netbsd ]
1607     then
1608         # no control for NetBSD
1609         :
1610     elif [ $PCP_PLATFORM = openbsd ]
1611     then
1612         # no control for OpenBSD
1613         :
1614     else
1615         # I have no idea what to do for this platform!
1616         #
1617         echo "_change_config: Error: cannot \"$1 $2\" for $PCP_PLATFORM"
1618         exit 1
1619     fi 2>&1 \
1620     | _filter_init_distro
1623 _get_config()
1625     if [ "$PCP_PLATFORM" = linux ]
1626     then
1627         case $1 
1628         in
1629             pmlogger|pmcd) pat=$1 ;;
1630             verbose) pat="" ;;
1631             *)  pat=$1 ;;
1632         esac
1634         _have_systemctl=false
1635         which systemctl >/dev/null 2>&1 && _have_systemctl=true
1636         if [ -z "$pat" ]
1637         then
1638             _have_service=true
1639         elif [ -n "$PCP_SYSTEMDUNIT_DIR" -a -f $PCP_SYSTEMDUNIT_DIR/$pat.service ]
1640         then
1641             _have_service=true
1642         else
1643             _have_service=false
1644         fi
1645         if $_have_systemctl && $_have_service
1646         then
1647             # Run with systemd whenever it is available now
1648             #
1649             if [ -z "$pat" ]
1650             then
1651                 # unconditionally "on", or no such option
1652                 #
1653                 echo on
1654             else
1655                 if systemctl -q is-enabled $pat.service >/dev/null 2>&1
1656                 then
1657                     echo on
1658                 else
1659                     echo off
1660                 fi
1661             fi
1662         elif which chkconfig >/dev/null 2>&1
1663         then
1664             # Try the older RedHat and SuSE way ..
1665             #
1666             if [ -z "$pat" ]
1667             then
1668                 # unconditionally "on", or no such option
1669                 #
1670                 echo on
1671             else
1672                 if chkconfig $pat >$tmp.__tmp 2>&1
1673                 then
1674                     # success from chkconfig is only useful if no output
1675                     # was generated ... in the latter case, grep the output
1676                     # for hints (this is for SuSE SLES9 in particular)
1677                     #
1678                     if [ -s $tmp.__tmp ]
1679                     then
1680                         if grep ' on$' $tmp.__tmp >/dev/null
1681                         then
1682                             echo on
1683                         elif grep ' off$' $tmp.__tmp >/dev/null
1684                         then
1685                             echo off
1686                         else
1687                             echo off
1688                         fi
1689                     else
1690                         echo on
1691                     fi
1692                 else
1693                     echo off
1694                 fi
1695             fi
1696         elif [ -x /usr/sbin/sysv-rc-conf ]
1697         then
1698             # Try the Debian and Ubuntu way ..
1699             #
1700             if [ -z "$pat" ]
1701             then
1702                 # unconditionally "on", or no such option
1703                 #
1704                 echo on
1705             else
1706                 if $sudo /usr/sbin/sysv-rc-conf $pat
1707                 then
1708                     echo on
1709                 else
1710                     echo off
1711                 fi
1712             fi
1713         elif which rc-update >/dev/null 2>&1
1714         then
1715             # Try the Gentoo way ..
1716             #
1717             if [ -z "$pat" ]
1718             then
1719                 # unconditionally "on", or no such option
1720                 #
1721                 echo on
1722             else
1723                 if rc-update show default | grep $pat >/dev/null
1724                 then
1725                     echo on
1726                 else
1727                     echo off
1728                 fi
1729             fi
1730         elif [ -f /etc/slackware-version ]
1731         then
1732             # Slackware uses BSD-style init, so no control
1733             :
1734         else
1735             echo "_change_config: Error: don't know how to change config for Linux"
1736             exit 1
1737         fi
1738     elif [ $PCP_PLATFORM = solaris ]
1739     then
1740         if which svcs >/dev/null 2>&1
1741         then
1742             case $1 
1743             in
1744                 pmlogger|pmcd) pat=$1 ;;
1745                 verbose) pat="" ;;
1746                 *) pat=$1 ;;
1747             esac
1748             if [ -z "$pat" ]
1749             then
1750                 # unconditionally "on", or no such option
1751                 #
1752                 echo on
1753             else
1754                 state=`svcs -H svc:/application/pcp/$pat | sed -e 's/[  ].*//'`
1755                 case "$state"
1756                 in
1757                     online|maintenance)
1758                         echo on
1759                         ;;
1760                     offline|disabled)
1761                         echo off
1762                         ;;
1763                     *)
1764                         echo "_change_config: Error: smf ($state) from svcs not expected"
1765                         exit 1
1766                         ;;
1767                 esac
1768             fi
1769         else
1770             echo "_change_config: Error: cannot find svcs for Solaris"
1771             exit 1
1772         fi
1773     elif [ $PCP_PLATFORM = darwin ]
1774     then
1775         case $1 
1776         in
1777             pmcd)       pat=PMCD ;;
1778             pmlogger)   pat=PMLOGGER ;;
1779             pmie)       pat=PMIE ;;
1780             verbose)    pat="" ;;
1781             *)          pat=$1 ;;
1782         esac
1783         if [ -n "$pat" ]
1784         then
1785             state=`sed -n -e "/^$pat=/{"'
1786 s/.*=//
1787 s/-//g
1789 }' /etc/hostconfig`
1790             if [ -z "$state" ]
1791             then
1792                 echo "_change_config: Error: No $pat control line in /etc/hostconfig" >&2
1793                 echo "You need to add a $pat=-YES- line to this file" >&2
1794                 exit 1
1795             fi
1796             if [ "$state" = "YES" ]
1797             then
1798                 echo on
1799             elif [ "$state" = "NO" ]
1800             then
1801                 echo off
1802             else
1803                 echo "_change_config: Error: bad state ($state) should be YES or NO" >&2
1804                 exit 1
1805             fi
1806         fi
1807     elif [ $PCP_PLATFORM = freebsd ]
1808     then
1809         # no control for FreeBSD
1810         :
1811     elif [ $PCP_PLATFORM = netbsd ]
1812     then
1813         # no control for NetBSD
1814         :
1815     elif [ $PCP_PLATFORM = openbsd ]
1816     then
1817         # no control for OpenBSD
1818         :
1819     else
1820         echo "_change_config: Error: cannot \"$1 $2\" for $PCP_PLATFORM"
1821     fi
1824 # disable all system pmloggers running via the control file(s)
1826 _disable_loggers()
1828     [ -z "$PCP_PMLOGGERCONTROL_PATH" ] && \
1829                 PCP_PMLOGGERCONTROL_PATH="$PCP_VAR_DIR/config/pmlogger/control"
1830     if [ -f $PCP_PMLOGGERCONTROL_PATH ]
1831     then
1832         [ ! -f $tmp.control ] && \
1833                 $sudo cp $PCP_PMLOGGERCONTROL_PATH $tmp.control
1834     fi
1835     if [ -d $PCP_PMLOGGERCONTROL_PATH.d ]
1836     then
1837         [ ! -d $tmp.control.d ] && \
1838                 $sudo cp -a $PCP_PMLOGGERCONTROL_PATH.d $tmp.control.d
1839         $sudo rm -fr $PCP_PMLOGGERCONTROL_PATH.d
1840     fi
1841     cat <<End-of-File >$tmp._tmp
1842 # dummy file created by qa/$seq on `date`
1843 # the goal here is to have a controlled primary logger that does
1844 # not make requests to pmcd!
1845 \$version=1.1
1846 LOCALHOSTNAME y n PCP_LOG_DIR/pmlogger/LOCALHOSTNAME -c /dev/null
1847 End-of-File
1848     $sudo cp $tmp._tmp $PCP_PMLOGGERCONTROL_PATH
1851 _restore_loggers()
1853     [ -z "$PCP_PMLOGGERCONTROL_PATH" ] && \
1854                 PCP_PMLOGGERCONTROL_PATH="$PCP_VAR_DIR/config/pmlogger/control"
1855     if [ -d $tmp.control.d ]
1856     then
1857         $sudo cp -a $tmp.control.d $PCP_PMLOGGERCONTROL_PATH.d
1858         $sudo rm -fr $tmp.control.d
1859     fi
1860     [ -f $tmp.control ] && \
1861         $sudo cp $tmp.control $PCP_PMLOGGERCONTROL_PATH
1864 # _check_core [dir]
1865 # checks for core files in dir (defaults to .)
1867 _check_core()
1869     if [ -z "$1" ]
1870     then
1871         dir=""
1872     else
1873         if [ -d $1 ]
1874         then
1875             dir=$1/
1876         else
1877             echo "_check_core: aaargh $1 is not a directory!"
1878             return
1879         fi
1880     fi
1881     if [ "`echo ${dir}core*`" != "${dir}core*" ]
1882     then
1883         [ -z "$here" ] && here=/tmp
1884         [ -z "$seq" ] && seq=9999
1885         $PCP_ECHO_PROG $PCP_ECHO_N "Dumped core! (saved in $here as""$PCP_ECHO_C"
1886         for c in ${dir}core*
1887         do
1888             d=`basename $c`
1889             $sudo mv $c $here/$seq.$d
1890             $PCP_ECHO_PROG $PCP_ECHO_N " $seq.$d""$PCP_ECHO_C"
1891         done
1892         echo ")"
1893         status=1
1894     fi
1897 # prepare for a save-able pmcd and pmda configuration.
1899 _prepare_pmda_install()
1901     [ -z "$1" ] && echo "Error: bad _prepare_pmda_install call"
1902     iam=$1
1904     # copy the pmcd config file to restore state later.
1905     _save_config $PCP_PMCDCONF_PATH
1907     cd $PCP_PMDAS_DIR/$iam
1908     if [ -f Makefile -o -f GNUmakefile ] ; then
1909         if $sudo ${MAKE:-make} clobber >$tmp._tmp 2>&1 ; then
1910             :
1911         else
1912             cat $tmp._tmp
1913             echo "Arrgh, ${MAKE:-make} clobber failed"
1914             exit
1915         fi
1916     fi
1918     # start from a known starting point
1919     $sudo ./Remove >/dev/null 2>&1
1920     [ -f $PCP_VAR_DIR/config/$iam/$iam.conf ] && \
1921         $sudo mv $PCP_VAR_DIR/config/$iam/$iam.conf $tmp.$iam.conf
1924 # restore a saved pmcd configuration and ensure pmda back in place.
1926 _restore_pmda_install()
1928     [ -z "$1" ] && echo "Error: bad _restore_pmda_install call"
1929     iam=$1
1930     signal=$PCP_BINADM_DIR/pmsignal
1932     [ -f $PCP_VAR_DIR/config/$iam/$iam.conf.$seq ] \
1933         && $sudo mv $PCP_VAR_DIR/config/$iam/$iam.conf.$seq $PCP_VAR_DIR/config/$iam/$iam.conf
1935     if diff $PCP_PMCDCONF_PATH.$seq $PCP_PMCDCONF_PATH > /dev/null 2>&1
1936     then
1937         _restore_config $PCP_PMCDCONF_PATH
1938     else
1939 # do a default install which ensures the pmns and any views are installed
1941         cd $PCP_PMDAS_DIR/$iam
1942         $sudo ./Install < /dev/null > /dev/null 2>&1
1944 # PMDA may have been installed differently to default. As everything is
1945 # installed we can use the old pmcd.conf file to restore state.
1947         if diff $PCP_PMCDCONF_PATH.$seq $PCP_PMCDCONF_PATH > /dev/null 2>&1
1948         then
1949             _restore_config $PCP_PMCDCONF_PATH
1950         else
1951             _restore_config $PCP_PMCDCONF_PATH
1952             $sudo $signal -a -s HUP pmcd
1953         fi
1954     fi
1957 # find a local port that is not in use, optionally starting from a suggested port
1959 _find_free_port()
1961     base=$1
1962     [ -z "$base" ] && base=54321
1964     while $PCP_BINADM_DIR/telnet-probe -c localhost $base
1965     do
1966         base=`expr $base + 1`
1967     done
1968     echo $base
1971 # get pid for the running primary pmlogger
1973 _get_primary_logger_pid()
1975     root="$PCP_TMP_DIR/pmlogger/primary"
1976     if [ ! -L "$root" ]
1977     then
1978         echo ""
1979     elif which realpath >/dev/null 2>&1
1980     then
1981         symroot=`realpath "$root"`
1982         basename "$symroot"
1983     else
1984         symroot=`ls -l "$root" | sed -e 's/.*-> //'`
1985         if [ -z "$symroot" ]
1986         then
1987             echo "Arrgh, cannot get symlink for device for root fs ..."
1988             ls -l "$root"
1989             exit
1990         fi
1991         basename "$symroot"
1992     fi
1995 _get_libpcp_config()
1997     pmconfig -L -s > $tmp.config
1998     . $tmp.config
1999     rm $tmp.config