diff --git a/cts/environment.py b/cts/environment.py
index 0abfd10d65..de1d099365 100644
--- a/cts/environment.py
+++ b/cts/environment.py
@@ -1,663 +1,663 @@
 '''
 Classes related to producing and searching logs
 '''
 
 __copyright__='''
 Copyright (C) 2014 Andrew Beekhof <andrew@beekhof.net>
 Licensed under the GNU GPL.
 '''
 
 #
 # This program is free software; you can redistribute it and/or
 # modify it under the terms of the GNU General Public License
 # as published by the Free Software Foundation; either version 2
 # of the License, or (at your option) any later version.
 #
 # This program is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 # GNU General Public License for more details.
 #
 # You should have received a copy of the GNU General Public License
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA.
 
 import types, string, select, sys, time, re, os, struct, signal, socket
 import time, syslog, random, traceback, base64, pickle, binascii, fcntl
 
 from cts.remote import *
 
 class Environment:
 
     def __init__(self, args):
         print repr(self)
         self.data = {}
         self.Nodes = []
 
         self["DeadTime"] = 300
         self["StartTime"] = 300
         self["StableTime"] = 30
         self["tests"] = []
         self["IPagent"] = "IPaddr2"
         self["DoStandby"] = 1
         self["DoFencing"] = 1
         self["XmitLoss"] = "0.0"
         self["RecvLoss"] = "0.0"
         self["ClobberCIB"] = 0
         self["CIBfilename"] = None
         self["CIBResource"] = 0
         self["DoBSC"]    = 0
         self["use_logd"] = 0
         self["oprofile"] = []
         self["warn-inactive"] = 0
         self["ListTests"] = 0
         self["benchmark"] = 0
         self["LogWatcher"] = "any"
         self["SyslogFacility"] = "daemon"
         self["LogFileName"] = "/var/log/messages"
         self["Schema"] = "pacemaker-2.0"
-        self["Stack"] = "openais"
+        self["Stack"] = "corosync"
         self["stonith-type"] = "external/ssh"
         self["stonith-params"] = "hostlist=all,livedangerously=yes"
         self["loop-minutes"] = 60
         self["valgrind-prefix"] = None
         self["valgrind-procs"] = "cib crmd attrd pengine stonith-ng"
         self["valgrind-opts"] = """--leak-check=full --show-reachable=yes --trace-children=no --num-callers=25 --gen-suppressions=all --suppressions="""+CTSvars.CTS_home+"""/cts.supp"""
 
         self["experimental-tests"] = 0
         self["container-tests"] = 0
         self["valgrind-tests"] = 0
         self["unsafe-tests"] = 1
         self["loop-tests"] = 1
         self["scenario"] = "random"
         self["stats"] = 0
 
         self.RandomGen = random.Random()
         self.logger = LogFactory()
 
         self.SeedRandom()
         self.rsh = RemoteFactory().getInstance()
 
         self.target = "localhost"
 
         self.parse_args(args)
         self.discover()
         self.validate()
 
     def SeedRandom(self, seed=None):
         if not seed:
             seed = int(time.time())
 
         if self.has_key("RandSeed"):
             self.logger.log("New random seed is: " + str(seed))
         else:
             self.logger.log("Random seed is: " + str(seed))
 
         self["RandSeed"] = seed
         self.RandomGen.seed(str(seed))
 
     def dump(self):
         keys = []
         for key in self.data.keys():
             keys.append(key)
 
         keys.sort()
         for key in keys:
             self.logger.debug("Environment["+key+"]:\t"+str(self[key]))
 
     def keys(self):
         return self.data.keys()
 
     def has_key(self, key):
         if key == "nodes":
             return True
 
         return self.data.has_key(key)
 
     def __getitem__(self, key):
         if key == "nodes":
             return self.Nodes
 
         elif key == "Name":
             return self.get_stack_short()
 
         elif self.data.has_key(key):
             return self.data[key]
 
         else:
             return None
 
     def __setitem__(self, key, value):
         if key == "Stack":
             self.set_stack(value)
 
         elif key == "node-limit":
             self.data[key] = value
             self.filter_nodes()
 
         elif key == "nodes":
             self.Nodes = []
             for node in value:
                 # I don't think I need the IP address, etc. but this validates
                 # the node name against /etc/hosts and/or DNS, so it's a
                 # GoodThing(tm).
                 try:
                     n = node.strip()
                     gethostbyname_ex(n)
                     self.Nodes.append(n) 
                 except:
                     self.logger.log(node+" not found in DNS... aborting")
                     raise
 
             self.filter_nodes()
 
         else:
             self.data[key] = value
 
     def RandomNode(self):
         '''Choose a random node from the cluster'''
         return self.RandomGen.choice(self["nodes"])
 
     def set_stack(self, name):
         # Normalize stack names
         if name == "heartbeat" or name == "lha":
             self.data["Stack"] = "heartbeat"
 
         elif name == "openais" or name == "ais"  or name == "whitetank":
             self.data["Stack"] = "openais (whitetank)"
 
         elif name == "corosync" or name == "cs" or name == "mcp":
             self.data["Stack"] = "corosync 2.x"
 
         elif name == "cman":
             self.data["Stack"] = "corosync (cman)"
 
         elif name == "v1":
             self.data["Stack"] = "corosync (plugin v1)"
 
         elif name == "v0":
             self.data["Stack"] = "corosync (plugin v0)"
 
         else:
             print "Unknown stack: "+name
             sys.exit(1)
 
     def get_stack_short(self):
         # Create the Cluster Manager object
         if not self.data.has_key("Stack"):
             return "unknown"
 
         elif self.data["Stack"] == "heartbeat":
             return "crm-lha"
 
         elif self.data["Stack"] == "corosync 2.x":
             return "crm-mcp"
 
         elif self.data["Stack"] == "corosync (cman)":
             return "crm-cman"
         
         elif self.data["Stack"] == "corosync (plugin v1)":
             return "crm-plugin-v1"
         
         elif self.data["Stack"] == "corosync (plugin v0)":
             return "crm-plugin-v0"
 
         else:
             LogFactory().log("Unknown stack: "+self.data["stack"])
             sys.exit(1)
 
     def detect_syslog(self):
         # Detect syslog variant
         if not self.has_key("syslogd"):
             if self["have_systemd"]:
                 # Systemd
                 self["syslogd"] = self.rsh(self.target, "systemctl list-units | grep syslog.*\.service.*active.*running | sed 's:.service.*::'", stdout=1).strip()
             else:
                 # SYS-V
                 self["syslogd"] = self.rsh(self.target, "chkconfig --list | grep syslog.*on | awk '{print $1}' | head -n 1", stdout=1).strip()
 
             if not self.has_key("syslogd") or not self["syslogd"]:
                 # default
                 self["syslogd"] = "rsyslog"
 
     def detect_at_boot(self):
         # Detect if the cluster starts at boot
         if not self.has_key("at-boot"):
             atboot = 0
 
             if self["have_systemd"]:
             # Systemd
                 atboot = atboot or not self.rsh(self.target, "systemctl is-enabled heartbeat.service")
                 atboot = atboot or not self.rsh(self.target, "systemctl is-enabled corosync.service")
                 atboot = atboot or not self.rsh(self.target, "systemctl is-enabled pacemaker.service")
             else:
                 # SYS-V
                 atboot = atboot or not self.rsh(self.target, "chkconfig --list | grep -e corosync.*on -e heartbeat.*on -e pacemaker.*on")
 
             self["at-boot"] = atboot
 
     def detect_ip_offset(self):
         # Try to determin an offset for IPaddr resources
         if self["CIBResource"] and not self.has_key("IPBase"):
             network=self.rsh(self.target, "ip addr | grep inet | grep -v -e link -e inet6 -e '/32' -e ' lo' | awk '{print $2}'", stdout=1).strip()
             self["IPBase"] = self.rsh(self.target, "nmap -sn -n %s | grep 'scan report' | awk '{print $NF}' | sed 's:(::' | sed 's:)::' | sort -V | tail -n 1" % network, stdout=1).strip()
             if not self["IPBase"]:
                 self["IPBase"] = " fe80::1234:56:7890:1000"
                 self.logger.log("Could not determine an offset for IPaddr resources.  Perhaps nmap is not installed on the nodes.")
                 self.logger.log("Defaulting to '%s', use --test-ip-base to override" % self["IPBase"])
 
             elif int(self["IPBase"].split('.')[3]) >= 240:
                 self.logger.log("Could not determine an offset for IPaddr resources. Upper bound is too high: %s %s"
                                 % (self["IPBase"], self["IPBase"].split('.')[3]))
                 self["IPBase"] = " fe80::1234:56:7890:1000"
                 self.logger.log("Defaulting to '%s', use --test-ip-base to override" % self["IPBase"])
 
     def filter_nodes(self):
         if self["node-limit"] > 0:
             if len(self["nodes"]) > self["node-limit"]:
                 self.logger.log("Limiting the number of nodes configured=%d (max=%d)"
                                 %(len(self["nodes"]), self["node-limit"]))
                 while len(self["nodes"]) > self["node-limit"]:
                     self["nodes"].pop(len(self["nodes"])-1)
 
     def validate(self):
         if len(self["nodes"]) < 1:
             print "No nodes specified!"
             sys.exit(1)
 
     def discover(self):
         self.target = random.Random().choice(self["nodes"])
 
         master = socket.gethostname()
 
         # Use the IP where possible to avoid name lookup failures
         for ip in socket.gethostbyname_ex(master)[2]:
             if ip != "127.0.0.1":
                 master = ip
                 break;
         self["cts-master"] = master
 
         if self.has_key("have_systemd"):
             self["have_systemd"] = not rsh(discover, "systemctl list-units")
 
         self.detect_syslog()
         self.detect_at_boot()
         self.detect_ip_offset()
 
         self.validate()
 
     def parse_args(self, args):
         skipthis=None
 
         if not args:
             args=sys.argv[1:]
 
         for i in range(0, len(args)):
             if skipthis:
                 skipthis=None
                 continue
 
             elif args[i] == "-l" or args[i] == "--limit-nodes":
                 skipthis=1
                 self["node-limit"] = int(args[i+1])
 
             elif args[i] == "-r" or args[i] == "--populate-resources":
                 self["CIBResource"] = 1
                 self["ClobberCIB"] = 1
 
             elif args[i] == "--outputfile":
                 skipthis=1
                 self["OutputFile"] = args[i+1]
                 LogFactory().add_file(self["OutputFile"])
 
             elif args[i] == "-L" or args[i] == "--logfile":
                 skipthis=1
                 self["LogWatcher"] = "remote"
                 self["LogAuditDisabled"] = 1
                 self["LogFileName"] = args[i+1]
 
             elif args[i] == "--ip" or args[i] == "--test-ip-base":
                 skipthis=1
                 self["IPBase"] = args[i+1]
                 self["CIBResource"] = 1
                 self["ClobberCIB"] = 1
 
             elif args[i] == "--oprofile":
                 skipthis=1
                 self["oprofile"] = args[i+1].split(' ')
 
             elif args[i] == "--trunc":
                 self["TruncateLog"]=1
 
             elif args[i] == "--list-tests" or args[i] == "--list" :
                 self["ListTests"]=1
 
             elif args[i] == "--benchmark":
                 self["benchmark"]=1
 
             elif args[i] == "--bsc":
                 self["DoBSC"] = 1
                 self["scenario"] = "basic-sanity"
 
             elif args[i] == "--qarsh":
                 RemoteFactory().enable_qarsh()
 
             elif args[i] == "--stonith" or args[i] == "--fencing":
                 skipthis=1
                 if args[i+1] == "1" or args[i+1] == "yes":
                     self["DoFencing"]=1
                 elif args[i+1] == "0" or args[i+1] == "no":
                     self["DoFencing"]=0
                 elif args[i+1] == "rhcs" or args[i+1] == "xvm" or args[i+1] == "virt":
                     self["DoStonith"]=1
                     self["stonith-type"] = "fence_xvm"
                     self["stonith-params"] = "pcmk_arg_map=domain:uname,delay=0"
                 elif args[i+1] == "scsi":
                     self["DoStonith"]=1
                     self["stonith-type"] = "fence_scsi"
                     self["stonith-params"] = "delay=0"
                 elif args[i+1] == "ssh" or args[i+1] == "lha":
                     self["DoStonith"]=1
                     self["stonith-type"] = "external/ssh"
                     self["stonith-params"] = "hostlist=all,livedangerously=yes"
                 elif args[i+1] == "north":
                     self["DoStonith"]=1
                     self["stonith-type"] = "fence_apc"
                     self["stonith-params"] = "ipaddr=north-apc,login=apc,passwd=apc,pcmk_host_map=north-01:2;north-02:3;north-03:4;north-04:5;north-05:6;north-06:7;north-07:9;north-08:10;north-09:11;north-10:12;north-11:13;north-12:14;north-13:15;north-14:18;north-15:17;north-16:19;"
                 elif args[i+1] == "south":
                     self["DoStonith"]=1
                     self["stonith-type"] = "fence_apc"
                     self["stonith-params"] = "ipaddr=south-apc,login=apc,passwd=apc,pcmk_host_map=south-01:2;south-02:3;south-03:4;south-04:5;south-05:6;south-06:7;south-07:9;south-08:10;south-09:11;south-10:12;south-11:13;south-12:14;south-13:15;south-14:18;south-15:17;south-16:19;"
                 elif args[i+1] == "east":
                     self["DoStonith"]=1
                     self["stonith-type"] = "fence_apc"
                     self["stonith-params"] = "ipaddr=east-apc,login=apc,passwd=apc,pcmk_host_map=east-01:2;east-02:3;east-03:4;east-04:5;east-05:6;east-06:7;east-07:9;east-08:10;east-09:11;east-10:12;east-11:13;east-12:14;east-13:15;east-14:18;east-15:17;east-16:19;"
                 elif args[i+1] == "west":
                     self["DoStonith"]=1
                     self["stonith-type"] = "fence_apc"
                     self["stonith-params"] = "ipaddr=west-apc,login=apc,passwd=apc,pcmk_host_map=west-01:2;west-02:3;west-03:4;west-04:5;west-05:6;west-06:7;west-07:9;west-08:10;west-09:11;west-10:12;west-11:13;west-12:14;west-13:15;west-14:18;west-15:17;west-16:19;"
                 elif args[i+1] == "openstack":
                     self["DoStonith"]=1
                     self["stonith-type"] = "fence_openstack"
                     
                     print "Obtaining OpenStack credentials from the current environment"
                     self["stonith-params"] = "region=%s,tenant=%s,auth=%s,user=%s,password=%s" % (
                         os.environ['OS_REGION_NAME'],
                         os.environ['OS_TENANT_NAME'],
                         os.environ['OS_AUTH_URL'],
                         os.environ['OS_USERNAME'],
                         os.environ['OS_PASSWORD']
                     )
                     
                 elif args[i+1] == "rhevm":
                     self["DoStonith"]=1
                     self["stonith-type"] = "fence_rhevm"
                     
                     print "Obtaining RHEV-M credentials from the current environment"
                     self["stonith-params"] = "login=%s,passwd=%s,ipaddr=%s,ipport=%s,ssl=1,shell_timeout=10" % (
                         os.environ['RHEVM_USERNAME'],
                         os.environ['RHEVM_PASSWORD'],
                         os.environ['RHEVM_SERVER'],
                         os.environ['RHEVM_PORT'],
                     )
                     
                 else:
                     self.usage(args[i+1])
 
             elif args[i] == "--stonith-type":
                 self["stonith-type"] = args[i+1]
                 skipthis=1
 
             elif args[i] == "--stonith-args":
                 self["stonith-params"] = args[i+1]
                 skipthis=1
 
             elif args[i] == "--standby":
                 skipthis=1
                 if args[i+1] == "1" or args[i+1] == "yes":
                     self["DoStandby"] = 1
                 elif args[i+1] == "0" or args[i+1] == "no":
                     self["DoStandby"] = 0
                 else:
                     self.usage(args[i+1])
 
             elif args[i] == "--clobber-cib" or args[i] == "-c":
                 self["ClobberCIB"] = 1
                 
             elif args[i] == "--cib-filename":
                 skipthis=1
                 self["CIBfilename"] = args[i+1]
 
             elif args[i] == "--xmit-loss":
                 try:
                     float(args[i+1])
                 except ValueError:
                     print ("--xmit-loss parameter should be float")
                     self.usage(args[i+1])
                 skipthis=1
                 self["XmitLoss"] = args[i+1]
 
             elif args[i] == "--recv-loss":
                 try:
                     float(args[i+1])
                 except ValueError:
                     print ("--recv-loss parameter should be float")
                     self.usage(args[i+1])
                 skipthis=1
                 self["RecvLoss"] = args[i+1]
 
             elif args[i] == "--choose":
                 skipthis=1
                 self["tests"].append(args[i+1])
                 self["scenario"] = "sequence"
 
             elif args[i] == "--nodes":
                 skipthis=1
                 self["nodes"] = args[i+1].split(' ')
 
             elif args[i] == "-g" or args[i] == "--group" or args[i] == "--dsh-group":
                 skipthis=1
                 self["OutputFile"] = "%s/cluster-%s.log" % (os.environ['HOME'], args[i+1])
                 LogFactory().add_file(self["OutputFile"], "CTS")
 
                 dsh_file = "%s/.dsh/group/%s" % (os.environ['HOME'], args[i+1])
 
                 # Hacks to make my life easier
                 if args[i+1] == "r6":
                     self["Stack"] = "cman"
                     self["DoStonith"]=1
                     self["stonith-type"] = "fence_xvm"
                     self["stonith-params"] = "delay=0"
                     self["IPBase"] = " fe80::1234:56:7890:4000"
 
                 elif args[i+1] == "virt1":
                     self["Stack"] = "corosync"
                     self["DoStonith"]=1
                     self["stonith-type"] = "fence_xvm"
                     self["stonith-params"] = "delay=0"
                     self["IPBase"] = " fe80::1234:56:7890:1000"
 
                 elif args[i+1] == "east16" or args[i+1] == "nsew":
                     self["Stack"] = "corosync"
                     self["DoStonith"]=1
                     self["stonith-type"] = "fence_apc"
                     self["stonith-params"] = "ipaddr=east-apc,login=apc,passwd=apc,pcmk_host_map=east-01:2;east-02:3;east-03:4;east-04:5;east-05:6;east-06:7;east-07:9;east-08:10;east-09:11;east-10:12;east-11:13;east-12:14;east-13:15;east-14:18;east-15:17;east-16:19;"
                     self["IPBase"] = " fe80::1234:56:7890:2000"
 
                     if args[i+1] == "east16":
                         # Requires newer python than available via nsew
                         self["IPagent"] = "Dummy"
 
                 elif args[i+1] == "corosync8":
                     self["Stack"] = "corosync"
                     self["DoStonith"]=1
                     self["stonith-type"] = "fence_rhevm"
 
                     print "Obtaining RHEV-M credentials from the current environment"
                     self["stonith-params"] = "login=%s,passwd=%s,ipaddr=%s,ipport=%s,ssl=1,shell_timeout=10" % (
                         os.environ['RHEVM_USERNAME'],
                         os.environ['RHEVM_PASSWORD'],
                         os.environ['RHEVM_SERVER'],
                         os.environ['RHEVM_PORT'],
                    )
                     self["IPBase"] = " fe80::1234:56:7890:3000"
 
                 if os.path.isfile(dsh_file):
                     self["nodes"] = []
                     f = open(dsh_file, 'r')
                     for line in f:
                         l = line.strip().rstrip()
                         if not l.startswith('#'):
                             self["nodes"].append(l)
                     f.close()
 
                 else:
                     print("Unknown DSH group: %s" % args[i+1])
 
             elif args[i] == "--syslog-facility" or args[i] == "--facility":
                 skipthis=1
                 self["SyslogFacility"] = args[i+1]
                 
             elif args[i] == "--seed":
                 skipthis=1
                 self.SeedRandom(args[i+1])
 
             elif args[i] == "--warn-inactive":
                 self["warn-inactive"] = 1
 
             elif args[i] == "--schema":
                 skipthis=1
                 self["Schema"] = args[i+1]
 
             elif args[i] == "--ais":
                 self["Stack"] = "openais"
 
             elif args[i] == "--at-boot" or args[i] == "--cluster-starts-at-boot":
                 skipthis=1
                 if args[i+1] == "1" or args[i+1] == "yes":
                     self["at-boot"] = 1
                 elif args[i+1] == "0" or args[i+1] == "no":
                     self["at-boot"] = 0
                 else:
                     self.usage(args[i+1])
 
             elif args[i] == "--heartbeat" or args[i] == "--lha":
                 self["Stack"] = "heartbeat"
 
             elif args[i] == "--hae":
                 self["Stack"] = "openais"
                 self["Schema"] = "hae"
 
             elif args[i] == "--stack":
                 if args[i+1] == "fedora" or args[i+1] == "fedora-17" or args[i+1] == "fedora-18":
                     self["Stack"] = "corosync"
                 elif args[i+1] == "rhel-6":
                     self["Stack"] = "cman"
                 elif args[i+1] == "rhel-7":
                     self["Stack"] = "corosync"
                 else:
                     self["Stack"] = args[i+1]
                 skipthis=1
 
             elif args[i] == "--once":
                 self["scenario"] = "all-once"
 
             elif args[i] == "--boot":
                 self["scenario"] = "boot"
 
             elif args[i] == "--valgrind-tests":
                 self["valgrind-tests"] = 1
 
             elif args[i] == "--no-loop-tests":
                 self["loop-tests"] = 0
 
             elif args[i] == "--loop-minutes":
                 skipthis=1
                 try:
                     self["loop-minutes"]=int(args[i+1])
                 except ValueError:
                     self.usage(args[i])
 
             elif args[i] == "--no-unsafe-tests":
                 self["unsafe-tests"] = 0
 
             elif args[i] == "--experimental-tests":
                 self["experimental-tests"] = 1
 
             elif args[i] == "--container-tests":
                 self["container-tests"] = 1
 
             elif args[i] == "--set":
                 skipthis=1
                 (name, value) = args[i+1].split('=')
                 self[name] = value
                 print "Setting %s = %s" % (name, value)
                 
             elif args[i] == "--":
                 break
 
             else:
                 try:
                     NumIter=int(args[i])
                     self["iterations"] = NumIter
                 except ValueError:
                     self.usage(args[i])
 
     def usage(arg, status=1):
         print "Illegal argument %s" % (arg)
         print "usage: " + sys.argv[0] +" [options] number-of-iterations"
         print "\nCommon options: "
         print "\t [--nodes 'node list']        list of cluster nodes separated by whitespace"
         print "\t [--group | -g 'name']        use the nodes listed in the named DSH group (~/.dsh/groups/$name)"
         print "\t [--limit-nodes max]          only use the first 'max' cluster nodes supplied with --nodes"
         print "\t [--stack (v0|v1|cman|corosync|heartbeat|openais)]    which cluster stack is installed"
         print "\t [--list-tests]               list the valid tests"
         print "\t [--benchmark]                add the timing information"
         print "\t "
         print "Options that CTS will usually auto-detect correctly: "
         print "\t [--logfile path]             where should the test software look for logs from cluster nodes"
         print "\t [--syslog-facility name]     which syslog facility should the test software log to"
         print "\t [--at-boot (1|0)]            does the cluster software start at boot time"
         print "\t [--test-ip-base ip]          offset for generated IP address resources"
         print "\t "
         print "Options for release testing: "
         print "\t [--populate-resources | -r]  generate a sample configuration"
         print "\t [--choose name]              run only the named test"
         print "\t [--stonith (1 | 0 | yes | no | rhcs | ssh)]"
         print "\t [--once]                     run all valid tests once"
         print "\t "
         print "Additional (less common) options: "
         print "\t [--clobber-cib | -c ]        erase any existing configuration"
         print "\t [--outputfile path]          optional location for the test software to write logs to"
         print "\t [--trunc]                    truncate logfile before starting"
         print "\t [--xmit-loss lost-rate(0.0-1.0)]"
         print "\t [--recv-loss lost-rate(0.0-1.0)]"
         print "\t [--standby (1 | 0 | yes | no)]"
         print "\t [--fencing (1 | 0 | yes | no | rhcs | lha | openstack )]"
         print "\t [--stonith-type type]"
         print "\t [--stonith-args name=value]"
         print "\t [--bsc]"
         print "\t [--no-loop-tests]            dont run looping/time-based tests"
         print "\t [--no-unsafe-tests]          dont run tests that are unsafe for use with ocfs2/drbd"
         print "\t [--valgrind-tests]           include tests using valgrind"
         print "\t [--experimental-tests]       include experimental tests"
         print "\t [--container-tests]          include pacemaker_remote tests that run in lxc container resources"
         print "\t [--oprofile 'node list']     list of cluster nodes to run oprofile on]"
         print "\t [--qarsh]                    use the QARSH backdoor to access nodes instead of SSH"
         print "\t [--seed random_seed]"
         print "\t [--set option=value]"
         print "\t "
         print "\t Example: "
         print "\t    python sys.argv[0] -g virt1 --stack cs -r --stonith ssh --schema pacemaker-1.0 500"
 
         sys.exit(status)
 
 class EnvFactory:
     instance = None
     def __init__(self):
         pass
 
     def getInstance(self, args=None):
         if not EnvFactory.instance:
             EnvFactory.instance = Environment(args)
         return EnvFactory.instance
diff --git a/lib/cluster/membership.c b/lib/cluster/membership.c
index 479af6393e..94105060fb 100644
--- a/lib/cluster/membership.c
+++ b/lib/cluster/membership.c
@@ -1,736 +1,736 @@
 /*
  * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
  * This library is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 #include <crm_internal.h>
 
 #ifndef _GNU_SOURCE
 #  define _GNU_SOURCE
 #endif
 
 #include <sys/param.h>
 #include <sys/types.h>
 #include <stdio.h>
 #include <unistd.h>
 #include <string.h>
 #include <glib.h>
 #include <crm/common/ipc.h>
 #include <crm/cluster/internal.h>
 #include <crm/msg_xml.h>
 #include <crm/stonith-ng.h>
 
 GHashTable *crm_peer_cache = NULL;
 GHashTable *crm_remote_peer_cache = NULL;
 unsigned long long crm_peer_seq = 0;
 gboolean crm_have_quorum = FALSE;
 
 int
 crm_remote_peer_cache_size(void)
 {
     if (crm_remote_peer_cache == NULL) {
         return 0;
     }
     return g_hash_table_size(crm_remote_peer_cache);
 }
 
 void
 crm_remote_peer_cache_add(const char *node_name)
 {
     crm_node_t *node = g_hash_table_lookup(crm_remote_peer_cache, node_name);
 
     if (node == NULL) {
             crm_trace("added %s to remote cache", node_name);
             node = calloc(1, sizeof(crm_node_t));
             node->flags = crm_remote_node;
             CRM_ASSERT(node);
             node->uname = strdup(node_name);
             node->uuid = strdup(node_name);
             node->state = strdup(CRM_NODE_MEMBER);
             g_hash_table_replace(crm_remote_peer_cache, node->uname, node);
     }
 }
 
 void
 crm_remote_peer_cache_remove(const char *node_name)
 {
     g_hash_table_remove(crm_remote_peer_cache, node_name);
 }
 
 static void
 remote_cache_refresh_helper(xmlNode *cib, const char *xpath, const char *field, int flags)
 {
     const char *remote = NULL;
     crm_node_t *node = NULL;
     xmlXPathObjectPtr xpathObj = NULL;
     int max = 0;
     int lpc = 0;
 
     xpathObj = xpath_search(cib, xpath);
     max = numXpathResults(xpathObj);
     for (lpc = 0; lpc < max; lpc++) {
         xmlNode *xml = getXpathResult(xpathObj, lpc);
 
         CRM_LOG_ASSERT(xml != NULL);
         if(xml != NULL) {
             remote = crm_element_value(xml, field);
         }
 
         if (remote) {
             crm_trace("added %s to remote cache", remote);
             node = calloc(1, sizeof(crm_node_t));
             node->flags = flags;
             CRM_ASSERT(node);
             node->uname = strdup(remote);
             node->uuid = strdup(remote);
             node->state = strdup(CRM_NODE_MEMBER);
             g_hash_table_replace(crm_remote_peer_cache, node->uname, node);
         }
     }
     freeXpathObject(xpathObj);
 }
 
 void crm_remote_peer_cache_refresh(xmlNode *cib)
 {
     const char *xpath = NULL;
 
     g_hash_table_remove_all(crm_remote_peer_cache);
 
     /* remote nodes associated with a cluster resource */
     xpath = "//" XML_TAG_CIB "//" XML_CIB_TAG_CONFIGURATION "//" XML_CIB_TAG_RESOURCE "//" XML_TAG_META_SETS "//" XML_CIB_TAG_NVPAIR "[@name='remote-node']";
     remote_cache_refresh_helper(cib, xpath, "value", crm_remote_node | crm_remote_container);
 
     /* baremetal nodes defined by connection resources*/
     xpath = "//" XML_TAG_CIB "//" XML_CIB_TAG_CONFIGURATION "//" XML_CIB_TAG_RESOURCE "[@type='remote'][@provider='pacemaker']";
     remote_cache_refresh_helper(cib, xpath, "id", crm_remote_node | crm_remote_baremetal);
 
     /* baremetal nodes we have seen in the config that may or may not have connection
      * resources associated with them anymore */
     xpath = "//" XML_TAG_CIB "//" XML_CIB_TAG_STATUS "//" XML_CIB_TAG_STATE "[@remote_node='true']";
     remote_cache_refresh_helper(cib, xpath, "id", crm_remote_node | crm_remote_baremetal);
 }
 
 gboolean
 crm_is_peer_active(const crm_node_t * node)
 {
     if(node == NULL) {
         return FALSE;
     }
 
     if (is_set(node->flags, crm_remote_node)) {
         /* remote nodes are never considered active members. This
          * guarantees they will never be considered for DC membership.*/
         return FALSE;
     }
 #if SUPPORT_COROSYNC
     if (is_openais_cluster()) {
         return crm_is_corosync_peer_active(node);
     }
 #endif
 #if SUPPORT_HEARTBEAT
     if (is_heartbeat_cluster()) {
         return crm_is_heartbeat_peer_active(node);
     }
 #endif
     crm_err("Unhandled cluster type: %s", name_for_cluster_type(get_cluster_type()));
     return FALSE;
 }
 
 static gboolean
 crm_reap_dead_member(gpointer key, gpointer value, gpointer user_data)
 {
     crm_node_t *node = value;
     crm_node_t *search = user_data;
 
     if (search == NULL) {
         return FALSE;
 
     } else if (search->id && node->id != search->id) {
         return FALSE;
 
     } else if (search->id == 0 && safe_str_neq(node->uname, search->uname)) {
         return FALSE;
 
     } else if (crm_is_peer_active(value) == FALSE) {
         crm_notice("Removing %s/%u from the membership list", node->uname, node->id);
         return TRUE;
     }
     return FALSE;
 }
 
 guint
 reap_crm_member(uint32_t id, const char *name)
 {
     int matches = 0;
     crm_node_t search;
 
     if (crm_peer_cache == NULL) {
         crm_trace("Nothing to do, cache not initialized");
         return 0;
     }
 
     search.id = id;
     search.uname = name ? strdup(name) : NULL;
     matches = g_hash_table_foreach_remove(crm_peer_cache, crm_reap_dead_member, &search);
     if(matches) {
         crm_notice("Purged %d peers with id=%u and/or uname=%s from the membership cache",
                    matches, search.id, search.uname);
 
     } else {
         crm_info("No peers with id=%u and/or uname=%s exist", id, name);
     }
 
     free(search.uname);
     return matches;
 }
 
 static void
 crm_count_peer(gpointer key, gpointer value, gpointer user_data)
 {
     guint *count = user_data;
     crm_node_t *node = value;
 
     if (crm_is_peer_active(node)) {
         *count = *count + 1;
     }
 }
 
 guint
 crm_active_peers(void)
 {
     guint count = 0;
 
     if (crm_peer_cache) {
         g_hash_table_foreach(crm_peer_cache, crm_count_peer, &count);
     }
     return count;
 }
 
 static void
 destroy_crm_node(gpointer data)
 {
     crm_node_t *node = data;
 
     crm_trace("Destroying entry for node %u: %s", node->id, node->uname);
 
     free(node->addr);
     free(node->uname);
     free(node->state);
     free(node->uuid);
     free(node->expected);
     free(node);
 }
 
 void
 crm_peer_init(void)
 {
     if (crm_peer_cache == NULL) {
         crm_peer_cache = g_hash_table_new_full(crm_strcase_hash, crm_strcase_equal, free, destroy_crm_node);
     }
 
     if (crm_remote_peer_cache == NULL) {
         crm_remote_peer_cache = g_hash_table_new_full(crm_strcase_hash, crm_strcase_equal, NULL, destroy_crm_node);
     }
 }
 
 void
 crm_peer_destroy(void)
 {
     if (crm_peer_cache != NULL) {
         crm_trace("Destroying peer cache with %d members", g_hash_table_size(crm_peer_cache));
         g_hash_table_destroy(crm_peer_cache);
         crm_peer_cache = NULL;
     }
 
     if (crm_remote_peer_cache != NULL) {
         crm_trace("Destroying remote peer cache with %d members", g_hash_table_size(crm_remote_peer_cache));
         g_hash_table_destroy(crm_remote_peer_cache);
         crm_remote_peer_cache = NULL;
     }
 }
 
 void (*crm_status_callback) (enum crm_status_type, crm_node_t *, const void *) = NULL;
 
 void
 crm_set_status_callback(void (*dispatch) (enum crm_status_type, crm_node_t *, const void *))
 {
     crm_status_callback = dispatch;
 }
 
 static void crm_dump_peer_hash(int level, const char *caller)
 {
     GHashTableIter iter;
     const char *id = NULL;
     crm_node_t *node = NULL;
 
     g_hash_table_iter_init(&iter, crm_peer_cache);
     while (g_hash_table_iter_next(&iter, (gpointer *) &id, (gpointer *) &node)) {
         do_crm_log(level, "%s: Node %u/%s = %p - %s", caller, node->id, node->uname, node, id);
     }
 }
 
 static gboolean crm_hash_find_by_data(gpointer key, gpointer value, gpointer user_data)
 {
     if(value == user_data) {
         return TRUE;
     }
     return FALSE;
 }
 
 crm_node_t *
 crm_find_peer_full(unsigned int id, const char *uname, int flags)
 {
     crm_node_t *node = NULL;
 
     CRM_ASSERT(id > 0 || uname != NULL);
 
     crm_peer_init();
 
     if (flags & CRM_GET_PEER_REMOTE) {
         node = g_hash_table_lookup(crm_remote_peer_cache, uname);
     }
 
     if (node == NULL && (flags & CRM_GET_PEER_CLUSTER)) {
         node = crm_find_peer(id, uname);
     }
     return node;
 }
 
 crm_node_t *
 crm_get_peer_full(unsigned int id, const char *uname, int flags)
 {
     crm_node_t *node = NULL;
 
     CRM_ASSERT(id > 0 || uname != NULL);
 
     crm_peer_init();
 
     if (flags & CRM_GET_PEER_REMOTE) {
         node = g_hash_table_lookup(crm_remote_peer_cache, uname);
     }
 
     if (node == NULL && (flags & CRM_GET_PEER_CLUSTER)) {
         node = crm_get_peer(id, uname);
     }
     return node;
 }
 
 crm_node_t *
 crm_find_peer(unsigned int id, const char *uname)
 {
     GHashTableIter iter;
     crm_node_t *node = NULL;
     crm_node_t *by_id = NULL;
     crm_node_t *by_name = NULL;
 
     CRM_ASSERT(id > 0 || uname != NULL);
 
     crm_peer_init();
 
     if (uname != NULL) {
         g_hash_table_iter_init(&iter, crm_peer_cache);
         while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &node)) {
             if(node->uname && strcasecmp(node->uname, uname) == 0) {
                 crm_trace("Name match: %s = %p", node->uname, node);
                 by_name = node;
                 break;
             }
         }
     }
 
     if (id > 0) {
         g_hash_table_iter_init(&iter, crm_peer_cache);
         while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &node)) {
             if(node->id == id) {
                 crm_trace("ID match: %u = %p", node->id, node);
                 by_id = node;
                 break;
             }
         }
     }
 
     node = by_id; /* Good default */
     if(by_id == by_name) {
         /* Nothing to do if they match (both NULL counts) */
         crm_trace("Consistent: %p for %u/%s", by_id, id, uname);
 
     } else if(by_id == NULL && by_name) {
         crm_trace("Only one: %p for %u/%s", by_name, id, uname);
 
         if(id && by_name->id) {
             crm_dump_peer_hash(LOG_WARNING, __FUNCTION__);
             crm_crit("Node %u and %u share the same name '%s'",
                      id, by_name->id, uname);
             node = NULL; /* Create a new one */
 
         } else {
             node = by_name;
         }
 
     } else if(by_name == NULL && by_id) {
         crm_trace("Only one: %p for %u/%s", by_id, id, uname);
 
         if(uname && by_id->uname) {
             crm_dump_peer_hash(LOG_WARNING, __FUNCTION__);
             crm_crit("Node '%s' and '%s' share the same cluster nodeid %u: assuming '%s' is correct",
                      uname, by_id->uname, id, uname);
         }
 
     } else if(uname && by_id->uname) {
         crm_warn("Node '%s' and '%s' share the same cluster nodeid: %u", by_id->uname, by_name->uname, id);
 
     } else if(id && by_name->id) {
         crm_warn("Node %u and %u share the same name: '%s'", by_id->id, by_name->id, uname);
 
     } else {
         /* Simple merge */
 
         /* Only corosync based clusters use nodeid's
          *
          * The functions that call crm_update_peer_state() only know nodeid
          * so 'by_id' is authorative when merging
          *
          * Same for crm_update_peer_proc()
          */
         crm_dump_peer_hash(LOG_DEBUG, __FUNCTION__);
 
         crm_info("Merging %p into %p", by_name, by_id);
         g_hash_table_foreach_remove(crm_peer_cache, crm_hash_find_by_data, by_name);
     }
 
     return node;
 }
 
 #if SUPPORT_COROSYNC
 static guint
 crm_remove_conflicting_peer(crm_node_t *node)
 {
     int matches = 0;
     GHashTableIter iter;
     crm_node_t *existing_node = NULL;
 
     if (node->id == 0 || node->uname == NULL) {
         return 0;
     }
 
 #  if !SUPPORT_PLUGIN
     if (corosync_cmap_has_config("nodelist") != 0) {
         return 0;
     }
 #  endif
 
     g_hash_table_iter_init(&iter, crm_peer_cache);
     while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &existing_node)) {
         if (existing_node->id > 0
             && existing_node->id != node->id
             && existing_node->uname != NULL
             && strcasecmp(existing_node->uname, node->uname) == 0) {
 
             if (crm_is_peer_active(existing_node)) {
                 continue;
             }
 
             crm_warn("Removing cached offline node %u/%s which has conflicting uname with %u",
                      existing_node->id, existing_node->uname, node->id);
 
             g_hash_table_iter_remove(&iter);
             matches++;
         }
     }
 
     return matches;
 }
 #endif
 
 /* coverity[-alloc] Memory is referenced in one or both hashtables */
 crm_node_t *
 crm_get_peer(unsigned int id, const char *uname)
 {
     crm_node_t *node = NULL;
     char *uname_lookup = NULL;
 
     CRM_ASSERT(id > 0 || uname != NULL);
 
     crm_peer_init();
 
     node = crm_find_peer(id, uname);
 
     /* if uname wasn't provided, and find_peer did not turn up a uname based on id.
      * we need to do a lookup of the node name using the id in the cluster membership. */
     if ((node == NULL || node->uname == NULL) && (uname == NULL)) { 
         uname_lookup = get_node_name(id);
     }
 
     if (uname_lookup) {
         crm_trace("Inferred a name of '%s' for node %u", uname, id);
         uname = uname_lookup;
 
         /* try to turn up the node one more time now that we know the uname. */
         if (node == NULL) {
             node = crm_find_peer(id, uname);
         }
     }
 
 
     if (node == NULL) {
         char *uniqueid = crm_generate_uuid();
 
         node = calloc(1, sizeof(crm_node_t));
         CRM_ASSERT(node);
 
         crm_info("Created entry %s/%p for node %s/%u (%d total)",
                  uniqueid, node, uname, id, 1 + g_hash_table_size(crm_peer_cache));
         g_hash_table_replace(crm_peer_cache, uniqueid, node);
     }
 
     if(id > 0 && uname && (node->id == 0 || node->uname == NULL)) {
         crm_info("Node %u is now known as %s", id, uname);
     }
 
     if(id > 0 && node->id == 0) {
         node->id = id;
     }
 
     if(uname && node->uname == NULL) {
         int lpc, len = strlen(uname);
 
         for (lpc = 0; lpc < len; lpc++) {
             if (uname[lpc] >= 'A' && uname[lpc] <= 'Z') {
                 crm_warn("Node names with capitals are discouraged, consider changing '%s' to something else",
                          uname);
                 break;
             }
         }
 
         node->uname = strdup(uname);
         if (crm_status_callback) {
             crm_status_callback(crm_status_uname, node, NULL);
         }
+
+#if SUPPORT_COROSYNC
+        if (is_openais_cluster()) {
+            crm_remove_conflicting_peer(node);
+        }
+#endif
     }
 
     if(node->uuid == NULL) {
         const char *uuid = crm_peer_uuid(node);
 
         if (uuid) {
             crm_info("Node %u has uuid %s", id, uuid);
 
         } else {
             crm_info("Cannot obtain a UUID for node %u/%s", id, node->uname);
         }
     }
 
     free(uname_lookup);
 
-#if SUPPORT_COROSYNC
-    if (is_openais_cluster()) {
-        crm_remove_conflicting_peer(node);
-    }
-#endif
-
     return node;
 }
 
 crm_node_t *
 crm_update_peer(const char *source, unsigned int id, uint64_t born, uint64_t seen, int32_t votes,
                 uint32_t children, const char *uuid, const char *uname, const char *addr,
                 const char *state)
 {
 #if SUPPORT_PLUGIN
     gboolean addr_changed = FALSE;
     gboolean votes_changed = FALSE;
 #endif
     crm_node_t *node = NULL;
 
     id = get_corosync_id(id, uuid);
     node = crm_get_peer(id, uname);
 
     CRM_ASSERT(node != NULL);
 
     if (node->uuid == NULL) {
         if (is_openais_cluster()) {
             /* Yes, overrule whatever was passed in */
             crm_peer_uuid(node);
 
         } else if (uuid != NULL) {
             node->uuid = strdup(uuid);
         }
     }
 
     if (children > 0) {
         crm_update_peer_proc(source, node, children, state);
     }
 
     if (state != NULL) {
         crm_update_peer_state(source, node, state, seen);
     }
 #if SUPPORT_HEARTBEAT
     if (born != 0) {
         node->born = born;
     }
 #endif
 
 #if SUPPORT_PLUGIN
     /* These were only used by the plugin */
     if (born != 0) {
         node->born = born;
     }
 
     if (votes > 0 && node->votes != votes) {
         votes_changed = TRUE;
         node->votes = votes;
     }
 
     if (addr != NULL) {
         if (node->addr == NULL || crm_str_eq(node->addr, addr, FALSE) == FALSE) {
             addr_changed = TRUE;
             free(node->addr);
             node->addr = strdup(addr);
         }
     }
     if (addr_changed || votes_changed) {
         crm_info("%s: Node %s: id=%u state=%s addr=%s%s votes=%d%s born=" U64T " seen=" U64T
                  " proc=%.32x", source, node->uname, node->id, node->state,
                  node->addr, addr_changed ? " (new)" : "", node->votes,
                  votes_changed ? " (new)" : "", node->born, node->last_seen, node->processes);
     }
 #endif
 
     return node;
 }
 
 void
 crm_update_peer_proc(const char *source, crm_node_t * node, uint32_t flag, const char *status)
 {
     uint32_t last = 0;
     gboolean changed = FALSE;
 
     CRM_CHECK(node != NULL, crm_err("%s: Could not set %s to %s for NULL",
                                     source, peer2text(flag), status); return);
 
     last = node->processes;
     if (status == NULL) {
         node->processes = flag;
         if (node->processes != last) {
             changed = TRUE;
         }
 
     } else if (safe_str_eq(status, ONLINESTATUS)) {
         if ((node->processes & flag) == 0) {
             set_bit(node->processes, flag);
             changed = TRUE;
         }
 #if SUPPORT_PLUGIN
     } else if (safe_str_eq(status, CRM_NODE_MEMBER)) {
         if (flag > 0 && node->processes != flag) {
             node->processes = flag;
             changed = TRUE;
         }
 #endif
 
     } else if (node->processes & flag) {
         clear_bit(node->processes, flag);
         changed = TRUE;
     }
 
     if (changed) {
         if (status == NULL && flag <= crm_proc_none) {
             crm_info("%s: Node %s[%u] - all processes are now offline", source, node->uname,
                      node->id);
         } else {
             crm_info("%s: Node %s[%u] - %s is now %s", source, node->uname, node->id,
                      peer2text(flag), status);
         }
 
         if (crm_status_callback) {
             crm_status_callback(crm_status_processes, node, &last);
         }
     } else {
         crm_trace("%s: Node %s[%u] - %s is unchanged (%s)", source, node->uname, node->id,
                   peer2text(flag), status);
     }
 }
 
 void
 crm_update_peer_expected(const char *source, crm_node_t * node, const char *expected)
 {
     char *last = NULL;
     gboolean changed = FALSE;
 
     CRM_CHECK(node != NULL, crm_err("%s: Could not set 'expected' to %s", source, expected);
               return);
 
     last = node->expected;
     if (expected != NULL && safe_str_neq(node->expected, expected)) {
         node->expected = strdup(expected);
         changed = TRUE;
     }
 
     if (changed) {
         crm_info("%s: Node %s[%u] - expected state is now %s (was %s)", source, node->uname, node->id,
                  expected, last);
         free(last);
     } else {
         crm_trace("%s: Node %s[%u] - expected state is unchanged (%s)", source, node->uname,
                   node->id, expected);
     }
 }
 
 void
 crm_update_peer_state(const char *source, crm_node_t * node, const char *state, int membership)
 {
     char *last = NULL;
     gboolean changed = FALSE;
 
     CRM_CHECK(node != NULL, crm_err("%s: Could not set 'state' to %s", source, state);
               return);
 
     last = node->state;
     if (state != NULL && safe_str_neq(node->state, state)) {
         node->state = strdup(state);
         changed = TRUE;
     }
 
     if (membership != 0 && safe_str_eq(node->state, CRM_NODE_MEMBER)) {
         node->last_seen = membership;
     }
 
     if (changed) {
         crm_notice("%s: Node %s[%u] - state is now %s (was %s)", source, node->uname, node->id, state, last);
         if (crm_status_callback) {
             enum crm_status_type status_type = crm_status_nstate;
             if (is_set(node->flags, crm_remote_node)) {
                 status_type = crm_status_rstate;
             }
             crm_status_callback(status_type, node, last);
         }
         free(last);
     } else {
         crm_trace("%s: Node %s[%u] - state is unchanged (%s)", source, node->uname, node->id,
                   state);
     }
 }
 
 int
 crm_terminate_member(int nodeid, const char *uname, void *unused)
 {
     /* Always use the synchronous, non-mainloop version */
     return stonith_api_kick(nodeid, uname, 120, TRUE);
 }
 
 int
 crm_terminate_member_no_mainloop(int nodeid, const char *uname, int *connection)
 {
     return stonith_api_kick(nodeid, uname, 120, TRUE);
 }
diff --git a/lib/services/services_linux.c b/lib/services/services_linux.c
index dd7bb642b8..961ff18f33 100644
--- a/lib/services/services_linux.c
+++ b/lib/services/services_linux.c
@@ -1,789 +1,807 @@
 /*
  * Copyright (C) 2010 Andrew Beekhof <andrew@beekhof.net>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
  * This software is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
 #include <crm_internal.h>
 
 #ifndef _GNU_SOURCE
 #  define _GNU_SOURCE
 #endif
 
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/wait.h>
 #include <errno.h>
 #include <unistd.h>
 #include <dirent.h>
 #include <fcntl.h>
 #include <string.h>
 #include <sys/time.h>
 #include <sys/resource.h>
 
 #ifdef HAVE_SYS_SIGNALFD_H
 #include <sys/signalfd.h>
 #endif
 
 #include "crm/crm.h"
 #include "crm/common/mainloop.h"
 #include "crm/services.h"
 
 #include "services_private.h"
 
 #if SUPPORT_CIBSECRETS
 #  include "crm/common/cib_secrets.h"
 #endif
 
 static inline void
 set_fd_opts(int fd, int opts)
 {
     int flag;
 
     if ((flag = fcntl(fd, F_GETFL)) >= 0) {
         if (fcntl(fd, F_SETFL, flag | opts) < 0) {
             crm_err("fcntl() write failed");
         }
     } else {
         crm_err("fcntl() read failed");
     }
 }
 
 static gboolean
 svc_read_output(int fd, svc_action_t * op, bool is_stderr)
 {
     char *data = NULL;
     int rc = 0, len = 0;
     char buf[500];
     static const size_t buf_read_len = sizeof(buf) - 1;
 
 
     if (fd < 0) {
         crm_trace("No fd for %s", op->id);
         return FALSE;
     }
 
     if (is_stderr && op->stderr_data) {
         len = strlen(op->stderr_data);
         data = op->stderr_data;
         crm_trace("Reading %s stderr into offset %d", op->id, len);
 
     } else if (is_stderr == FALSE && op->stdout_data) {
         len = strlen(op->stdout_data);
         data = op->stdout_data;
         crm_trace("Reading %s stdout into offset %d", op->id, len);
 
     } else {
         crm_trace("Reading %s %s", op->id, is_stderr?"stderr":"stdout", len);
     }
 
     do {
         rc = read(fd, buf, buf_read_len);
         if (rc > 0) {
             crm_trace("Got %d characters starting with %.20s", rc, buf);
             buf[rc] = 0;
             data = realloc(data, len + rc + 1);
             len += sprintf(data + len, "%s", buf);
 
         } else if (errno != EINTR) {
             /* error or EOF
              * Cleanup happens in pipe_done()
              */
             rc = FALSE;
             break;
         }
 
     } while (rc == buf_read_len || rc < 0);
 
     if (is_stderr) {
         op->stderr_data = data;
     } else {
         op->stdout_data = data;
     }
 
     return rc;
 }
 
 static int
 dispatch_stdout(gpointer userdata)
 {
     svc_action_t *op = (svc_action_t *) userdata;
 
     return svc_read_output(op->opaque->stdout_fd, op, FALSE);
 }
 
 static int
 dispatch_stderr(gpointer userdata)
 {
     svc_action_t *op = (svc_action_t *) userdata;
 
     return svc_read_output(op->opaque->stderr_fd, op, TRUE);
 }
 
 static void
 pipe_out_done(gpointer user_data)
 {
     svc_action_t *op = (svc_action_t *) user_data;
 
     crm_trace("%p", op);
 
     op->opaque->stdout_gsource = NULL;
     if (op->opaque->stdout_fd > STDOUT_FILENO) {
         close(op->opaque->stdout_fd);
     }
     op->opaque->stdout_fd = -1;
 }
 
 static void
 pipe_err_done(gpointer user_data)
 {
     svc_action_t *op = (svc_action_t *) user_data;
 
     op->opaque->stderr_gsource = NULL;
     if (op->opaque->stderr_fd > STDERR_FILENO) {
         close(op->opaque->stderr_fd);
     }
     op->opaque->stderr_fd = -1;
 }
 
 static struct mainloop_fd_callbacks stdout_callbacks = {
     .dispatch = dispatch_stdout,
     .destroy = pipe_out_done,
 };
 
 static struct mainloop_fd_callbacks stderr_callbacks = {
     .dispatch = dispatch_stderr,
     .destroy = pipe_err_done,
 };
 
 static void
 set_ocf_env(const char *key, const char *value, gpointer user_data)
 {
     if (setenv(key, value, 1) != 0) {
         crm_perror(LOG_ERR, "setenv failed for key:%s and value:%s", key, value);
     }
 }
 
 static void
 set_ocf_env_with_prefix(gpointer key, gpointer value, gpointer user_data)
 {
     char buffer[500];
 
     snprintf(buffer, sizeof(buffer), "OCF_RESKEY_%s", (char *)key);
     set_ocf_env(buffer, value, user_data);
 }
 
 static void
 add_OCF_env_vars(svc_action_t * op)
 {
     if (!op->standard || strcasecmp("ocf", op->standard) != 0) {
         return;
     }
 
     if (op->params) {
         g_hash_table_foreach(op->params, set_ocf_env_with_prefix, NULL);
     }
 
     set_ocf_env("OCF_RA_VERSION_MAJOR", "1", NULL);
     set_ocf_env("OCF_RA_VERSION_MINOR", "0", NULL);
     set_ocf_env("OCF_ROOT", OCF_ROOT_DIR, NULL);
     set_ocf_env("OCF_EXIT_REASON_PREFIX", PCMK_OCF_REASON_PREFIX, NULL);
 
     if (op->rsc) {
         set_ocf_env("OCF_RESOURCE_INSTANCE", op->rsc, NULL);
     }
 
     if (op->agent != NULL) {
         set_ocf_env("OCF_RESOURCE_TYPE", op->agent, NULL);
     }
 
     /* Notes: this is not added to specification yet. Sept 10,2004 */
     if (op->provider != NULL) {
         set_ocf_env("OCF_RESOURCE_PROVIDER", op->provider, NULL);
     }
 }
 
 gboolean
 recurring_action_timer(gpointer data)
 {
     svc_action_t *op = data;
 
     crm_debug("Scheduling another invokation of %s", op->id);
 
     /* Clean out the old result */
     free(op->stdout_data);
     op->stdout_data = NULL;
     free(op->stderr_data);
     op->stderr_data = NULL;
 
     services_action_async(op, NULL);
     return FALSE;
 }
 
 /* Returns FALSE if 'op' should be free'd by the caller */
 gboolean
 operation_finalize(svc_action_t * op)
 {
     int recurring = 0;
 
     if (op->interval) {
         if (op->cancel) {
             op->status = PCMK_LRM_OP_CANCELLED;
             cancel_recurring_action(op);
         } else {
             recurring = 1;
             op->opaque->repeat_timer = g_timeout_add(op->interval,
                                                      recurring_action_timer, (void *)op);
         }
     }
 
     if (op->opaque->callback) {
         op->opaque->callback(op);
     }
 
     op->pid = 0;
 
     if (!recurring) {
         /*
          * If this is a recurring action, do not free explicitly.
          * It will get freed whenever the action gets cancelled.
          */
         services_action_free(op);
         return TRUE;
     }
     return FALSE;
 }
 
 static void
 operation_finished(mainloop_child_t * p, pid_t pid, int core, int signo, int exitcode)
 {
     svc_action_t *op = mainloop_child_userdata(p);
     char *prefix = g_strdup_printf("%s:%d", op->id, op->pid);
 
     mainloop_clear_child_userdata(p);
     op->status = PCMK_LRM_OP_DONE;
     CRM_ASSERT(op->pid == pid);
 
     crm_trace("%s %p %p", prefix, op->opaque->stderr_gsource, op->opaque->stdout_gsource);
     if (op->opaque->stderr_gsource) {
         /* Make sure we have read everything from the buffer.
          * Depending on the priority mainloop gives the fd, operation_finished
          * could occur before all the reads are done.  Force the read now.*/
         crm_trace("%s dispatching stderr", prefix);
         dispatch_stderr(op);
         crm_trace("%s: %p", op->id, op->stderr_data);
         mainloop_del_fd(op->opaque->stderr_gsource);
         op->opaque->stderr_gsource = NULL;
     }
 
     if (op->opaque->stdout_gsource) {
         /* Make sure we have read everything from the buffer.
          * Depending on the priority mainloop gives the fd, operation_finished
          * could occur before all the reads are done.  Force the read now.*/
         crm_trace("%s dispatching stdout", prefix);
         dispatch_stdout(op);
         crm_trace("%s: %p", op->id, op->stdout_data);
         mainloop_del_fd(op->opaque->stdout_gsource);
         op->opaque->stdout_gsource = NULL;
     }
 
     if (signo) {
         if (mainloop_child_timeout(p)) {
             crm_warn("%s - timed out after %dms", prefix, op->timeout);
             op->status = PCMK_LRM_OP_TIMEOUT;
             op->rc = PCMK_OCF_TIMEOUT;
 
         } else {
             do_crm_log_unlikely((op->cancel) ? LOG_INFO : LOG_WARNING,
                                 "%s - terminated with signal %d", prefix, signo);
             op->status = PCMK_LRM_OP_ERROR;
             op->rc = PCMK_OCF_SIGNAL;
         }
 
     } else {
         op->rc = exitcode;
         crm_debug("%s - exited with rc=%d", prefix, exitcode);
     }
 
     g_free(prefix);
     prefix = g_strdup_printf("%s:%d:stderr", op->id, op->pid);
     crm_log_output(LOG_NOTICE, prefix, op->stderr_data);
 
     g_free(prefix);
     prefix = g_strdup_printf("%s:%d:stdout", op->id, op->pid);
     crm_log_output(LOG_DEBUG, prefix, op->stdout_data);
 
     g_free(prefix);
     operation_finalize(op);
 }
 
 static void
 services_handle_exec_error(svc_action_t * op, int error)
 {
     op->rc = PCMK_OCF_EXEC_ERROR;
     op->status = PCMK_LRM_OP_ERROR;
 
     /* Need to mimic the return codes for each standard as thats what we'll convert back from in get_uniform_rc() */
     if (safe_str_eq(op->standard, "lsb") && safe_str_eq(op->action, "status")) {
         switch (error) {    /* see execve(2) */
             case ENOENT:   /* No such file or directory */
             case EISDIR:   /* Is a directory */
                 op->rc = PCMK_LSB_STATUS_NOT_INSTALLED;
                 op->status = PCMK_LRM_OP_NOT_INSTALLED;
                 break;
             case EACCES:   /* permission denied (various errors) */
                 /* LSB status ops don't support 'not installed' */
                 break;
         }
 
 #if SUPPORT_NAGIOS
     } else if (safe_str_eq(op->standard, "nagios")) {
         switch (error) {
             case ENOENT:   /* No such file or directory */
             case EISDIR:   /* Is a directory */
                 op->rc = NAGIOS_NOT_INSTALLED;
                 op->status = PCMK_LRM_OP_NOT_INSTALLED;
                 break;
             case EACCES:   /* permission denied (various errors) */
                 op->rc = NAGIOS_INSUFFICIENT_PRIV;
                 break;
         }
 #endif
 
     } else {
         switch (error) {
             case ENOENT:   /* No such file or directory */
             case EISDIR:   /* Is a directory */
                 op->rc = PCMK_OCF_NOT_INSTALLED; /* Valid for LSB */
                 op->status = PCMK_LRM_OP_NOT_INSTALLED;
                 break;
             case EACCES:   /* permission denied (various errors) */
                 op->rc = PCMK_OCF_INSUFFICIENT_PRIV; /* Valid for LSB */
                 break;
         }
     }
 }
 
+static void
+action_launch_child(svc_action_t *op)
+{
+    int lpc;
+
+    /* SIGPIPE is ignored (which is different from signal blocking) by the gnutls library.
+     * Depending on the libqb version in use, libqb may set SIGPIPE to be ignored as well. 
+     * We do not want this to be inherited by the child process. By resetting this the signal
+     * to the default behavior, we avoid some potential odd problems that occur during OCF
+     * scripts when SIGPIPE is ignored by the environment. */
+    signal(SIGPIPE, SIG_DFL);
+
+#if defined(HAVE_SCHED_SETSCHEDULER)
+    if (sched_getscheduler(0) != SCHED_OTHER) {
+        struct sched_param sp;
+
+        memset(&sp, 0, sizeof(sp));
+        sp.sched_priority = 0;
+
+        if (sched_setscheduler(0, SCHED_OTHER, &sp) == -1) {
+            crm_perror(LOG_ERR, "Could not reset scheduling policy to SCHED_OTHER for %s", op->id);
+        }
+    }
+#endif
+    if (setpriority(PRIO_PROCESS, 0, 0) == -1) {
+        crm_perror(LOG_ERR, "Could not reset process priority to 0 for %s", op->id);
+    }
+
+    /* Man: The call setpgrp() is equivalent to setpgid(0,0)
+     * _and_ compiles on BSD variants too
+     * need to investigate if it works the same too.
+     */
+    setpgid(0, 0);
+
+    /* close all descriptors except stdin/out/err and channels to logd */
+    for (lpc = getdtablesize() - 1; lpc > STDERR_FILENO; lpc--) {
+        close(lpc);
+    }
+
+#if SUPPORT_CIBSECRETS
+    if (replace_secret_params(op->rsc, op->params) < 0) {
+        /* replacing secrets failed! */
+        if (safe_str_eq(op->action,"stop")) {
+            /* don't fail on stop! */
+            crm_info("proceeding with the stop operation for %s", op->rsc);
+
+        } else {
+            crm_err("failed to get secrets for %s, "
+                    "considering resource not configured", op->rsc);
+            _exit(PCMK_OCF_NOT_CONFIGURED);
+        }
+    }
+#endif
+    /* Setup environment correctly */
+    add_OCF_env_vars(op);
+
+    /* execute the RA */
+    execvp(op->opaque->exec, op->opaque->args);
+
+    /* Most cases should have been already handled by stat() */
+    services_handle_exec_error(op, errno);
+
+    _exit(op->rc);
+}
+
+static void
+action_synced_wait(svc_action_t * op, sigset_t mask)
+{
+
+#ifndef HAVE_SYS_SIGNALFD_H
+    CRM_ASSERT(FALSE);
+#else
+    int status = 0;
+    int timeout = op->timeout;
+    int sfd = -1;
+    time_t start = -1;
+    struct pollfd fds[3];
+    int wait_rc = 0;
+
+    sfd = signalfd(-1, &mask, SFD_NONBLOCK);
+    if (sfd < 0) {
+        crm_perror(LOG_ERR, "signalfd() failed");
+    }
+
+    fds[0].fd = op->opaque->stdout_fd;
+    fds[0].events = POLLIN;
+    fds[0].revents = 0;
+
+    fds[1].fd = op->opaque->stderr_fd;
+    fds[1].events = POLLIN;
+    fds[1].revents = 0;
+
+    fds[2].fd = sfd;
+    fds[2].events = POLLIN;
+    fds[2].revents = 0;
+
+    crm_trace("Waiting for %d", op->pid);
+    start = time(NULL);
+    do {
+        int poll_rc = poll(fds, 3, timeout);
+
+        if (poll_rc > 0) {
+            if (fds[0].revents & POLLIN) {
+                svc_read_output(op->opaque->stdout_fd, op, FALSE);
+            }
+
+            if (fds[1].revents & POLLIN) {
+                svc_read_output(op->opaque->stderr_fd, op, TRUE);
+            }
+
+            if (fds[2].revents & POLLIN) {
+                struct signalfd_siginfo fdsi;
+                ssize_t s;
+
+                s = read(sfd, &fdsi, sizeof(struct signalfd_siginfo));
+                if (s != sizeof(struct signalfd_siginfo)) {
+                    crm_perror(LOG_ERR, "Read from signal fd %d failed", sfd);
+
+                } else if (fdsi.ssi_signo == SIGCHLD) {
+                    wait_rc = waitpid(op->pid, &status, WNOHANG);
+
+                    if (wait_rc < 0){
+                        crm_perror(LOG_ERR, "waitpid() for %d failed", op->pid);
+
+                    } else if (wait_rc > 0) {
+                        break;
+                    }
+                }
+            }
+
+        } else if (poll_rc == 0) {
+            timeout = 0;
+            break;
+
+        } else if (poll_rc < 0) {
+            if (errno != EINTR) {
+                crm_perror(LOG_ERR, "poll() failed");
+                break;
+            }
+        }
+
+        timeout = op->timeout - (time(NULL) - start) * 1000;
+
+    } while ((op->timeout < 0 || timeout > 0));
+
+    crm_trace("Child done: %d", op->pid);
+    if (wait_rc <= 0) {
+        int killrc = kill(op->pid, SIGKILL);
+
+        op->rc = PCMK_OCF_UNKNOWN_ERROR;
+        if (op->timeout > 0 && timeout <= 0) {
+            op->status = PCMK_LRM_OP_TIMEOUT;
+            crm_warn("%s:%d - timed out after %dms", op->id, op->pid, op->timeout);
+
+        } else {
+            op->status = PCMK_LRM_OP_ERROR;
+        }
+
+        if (killrc && errno != ESRCH) {
+            crm_err("kill(%d, KILL) failed: %d", op->pid, errno);
+        }
+        /*
+         * From sigprocmask(2):
+         * It is not possible to block SIGKILL or SIGSTOP.  Attempts to do so are silently ignored.
+         *
+         * This makes it safe to skip WNOHANG here
+         */
+        waitpid(op->pid, &status, 0);
+
+    } else if (WIFEXITED(status)) {
+        op->status = PCMK_LRM_OP_DONE;
+        op->rc = WEXITSTATUS(status);
+        crm_info("Managed %s process %d exited with rc=%d", op->id, op->pid, op->rc);
+
+    } else if (WIFSIGNALED(status)) {
+        int signo = WTERMSIG(status);
+
+        op->status = PCMK_LRM_OP_ERROR;
+        crm_err("Managed %s process %d exited with signal=%d", op->id, op->pid, signo);
+    }
+#ifdef WCOREDUMP
+    if (WCOREDUMP(status)) {
+        crm_err("Managed %s process %d dumped core", op->id, op->pid);
+    }
+#endif
+
+    svc_read_output(op->opaque->stdout_fd, op, FALSE);
+    svc_read_output(op->opaque->stderr_fd, op, TRUE);
+
+    close(op->opaque->stdout_fd);
+    close(op->opaque->stderr_fd);
+    close(sfd);
+
+#endif
+
+}
+
 /* Returns FALSE if 'op' should be free'd by the caller */
 gboolean
 services_os_action_execute(svc_action_t * op, gboolean synchronous)
 {
-    int lpc;
     int stdout_fd[2];
     int stderr_fd[2];
     sigset_t mask;
     sigset_t old_mask;
     struct stat st;
 
     if (pipe(stdout_fd) < 0) {
         crm_err("pipe() failed");
     }
 
     if (pipe(stderr_fd) < 0) {
         crm_err("pipe() failed");
     }
 
     /* Fail fast */
     if(stat(op->opaque->exec, &st) != 0) {
         int rc = errno;
         crm_warn("Cannot execute '%s': %s (%d)", op->opaque->exec, pcmk_strerror(rc), rc);
         services_handle_exec_error(op, rc);
         if (!synchronous) {
             return operation_finalize(op);
         }
         return FALSE;
     }
 
     if (synchronous) {
         sigemptyset(&mask);
         sigaddset(&mask, SIGCHLD);
         sigemptyset(&old_mask);
 
         if (sigprocmask(SIG_BLOCK, &mask, &old_mask) < 0) {
             crm_perror(LOG_ERR, "sigprocmask() failed");
         }
     }
 
     op->pid = fork();
     switch (op->pid) {
         case -1:
             {
                 int rc = errno;
 
                 close(stdout_fd[0]);
                 close(stdout_fd[1]);
                 close(stderr_fd[0]);
                 close(stderr_fd[1]);
 
                 crm_err("Could not execute '%s': %s (%d)", op->opaque->exec, pcmk_strerror(rc), rc);
                 services_handle_exec_error(op, rc);
                 if (!synchronous) {
                     return operation_finalize(op);
                 }
                 return FALSE;
             }
         case 0:                /* Child */
-
-        /* SIGPIPE is ignored (which is different from signal blocking) by the gnutls library.
-         * Depending on the libqb version in use, libqb may set SIGPIPE to be ignored as well. 
-         * We do not want this to be inherited by the child process. By resetting this the signal
-         * to the default behavior, we avoid some potential odd problems that occur during OCF
-         * scripts when SIGPIPE is ignored by the environment. */
-        signal(SIGPIPE, SIG_DFL);
-
-#if defined(HAVE_SCHED_SETSCHEDULER)
-            if (sched_getscheduler(0) != SCHED_OTHER) {
-                struct sched_param sp;
-
-                memset(&sp, 0, sizeof(sp));
-                sp.sched_priority = 0;
-
-                if (sched_setscheduler(0, SCHED_OTHER, &sp) == -1) {
-                    crm_perror(LOG_ERR, "Could not reset scheduling policy to SCHED_OTHER for %s", op->id);
-                }
-            }
-#endif
-            if (setpriority(PRIO_PROCESS, 0, 0) == -1) {
-                crm_perror(LOG_ERR, "Could not reset process priority to 0 for %s", op->id);
-            }
-
-            /* Man: The call setpgrp() is equivalent to setpgid(0,0)
-             * _and_ compiles on BSD variants too
-             * need to investigate if it works the same too.
-             */
-            setpgid(0, 0);
             close(stdout_fd[0]);
             close(stderr_fd[0]);
             if (STDOUT_FILENO != stdout_fd[1]) {
                 if (dup2(stdout_fd[1], STDOUT_FILENO) != STDOUT_FILENO) {
                     crm_err("dup2() failed (stdout)");
                 }
                 close(stdout_fd[1]);
             }
             if (STDERR_FILENO != stderr_fd[1]) {
                 if (dup2(stderr_fd[1], STDERR_FILENO) != STDERR_FILENO) {
                     crm_err("dup2() failed (stderr)");
                 }
                 close(stderr_fd[1]);
             }
 
-            /* close all descriptors except stdin/out/err and channels to logd */
-            for (lpc = getdtablesize() - 1; lpc > STDERR_FILENO; lpc--) {
-                close(lpc);
-            }
-
-#if SUPPORT_CIBSECRETS
-            if (replace_secret_params(op->rsc, op->params) < 0) {
-                /* replacing secrets failed! */
-                if (safe_str_eq(op->action,"stop")) {
-                    /* don't fail on stop! */
-                    crm_info("proceeding with the stop operation for %s", op->rsc);
-
-                } else {
-                    crm_err("failed to get secrets for %s, "
-                            "considering resource not configured", op->rsc);
-                    _exit(PCMK_OCF_NOT_CONFIGURED);
-                }
-            }
-#endif
-            /* Setup environment correctly */
-            add_OCF_env_vars(op);
-
-            /* execute the RA */
-            execvp(op->opaque->exec, op->opaque->args);
-
-            /* Most cases should have been already handled by stat() */
-            services_handle_exec_error(op, errno);
-            _exit(op->rc);
+            action_launch_child(op);
     }
 
     /* Only the parent reaches here */
     close(stdout_fd[1]);
     close(stderr_fd[1]);
 
     op->opaque->stdout_fd = stdout_fd[0];
     set_fd_opts(op->opaque->stdout_fd, O_NONBLOCK);
 
     op->opaque->stderr_fd = stderr_fd[0];
     set_fd_opts(op->opaque->stderr_fd, O_NONBLOCK);
 
     if (synchronous) {
-#ifndef HAVE_SYS_SIGNALFD_H
-        CRM_ASSERT(FALSE);
-#else
-        int status = 0;
-        int timeout = op->timeout;
-        int sfd = -1;
-        time_t start = -1;
-        struct pollfd fds[3];
-        int wait_rc = 0;
-
-        sfd = signalfd(-1, &mask, SFD_NONBLOCK);
-        if (sfd < 0) {
-            crm_perror(LOG_ERR, "signalfd() failed");
-        }
-
-        fds[0].fd = op->opaque->stdout_fd;
-        fds[0].events = POLLIN;
-        fds[0].revents = 0;
-
-        fds[1].fd = op->opaque->stderr_fd;
-        fds[1].events = POLLIN;
-        fds[1].revents = 0;
-
-        fds[2].fd = sfd;
-        fds[2].events = POLLIN;
-        fds[2].revents = 0;
-
-        crm_trace("Waiting for %d", op->pid);
-        start = time(NULL);
-        do {
-            int poll_rc = poll(fds, 3, timeout);
-
-            if (poll_rc > 0) {
-                if (fds[0].revents & POLLIN) {
-                    svc_read_output(op->opaque->stdout_fd, op, FALSE);
-                }
-
-                if (fds[1].revents & POLLIN) {
-                    svc_read_output(op->opaque->stderr_fd, op, TRUE);
-                }
-
-                if (fds[2].revents & POLLIN) {
-                    struct signalfd_siginfo fdsi;
-                    ssize_t s;
-
-                    s = read(sfd, &fdsi, sizeof(struct signalfd_siginfo));
-                    if (s != sizeof(struct signalfd_siginfo)) {
-                        crm_perror(LOG_ERR, "Read from signal fd %d failed", sfd);
-
-                    } else if (fdsi.ssi_signo == SIGCHLD) {
-                        wait_rc = waitpid(op->pid, &status, WNOHANG);
-
-                        if (wait_rc < 0){
-                            crm_perror(LOG_ERR, "waitpid() for %d failed", op->pid);
-
-                        } else if (wait_rc > 0) {
-                            break;
-                        }
-                    }
-                }
-
-            } else if (poll_rc == 0) {
-                timeout = 0;
-                break;
-
-            } else if (poll_rc < 0) {
-                if (errno != EINTR) {
-                    crm_perror(LOG_ERR, "poll() failed");
-                    break;
-                }
-            }
-
-            timeout = op->timeout - (time(NULL) - start) * 1000;
-
-        } while ((op->timeout < 0 || timeout > 0));
-
-        crm_trace("Child done: %d", op->pid);
-        if (wait_rc <= 0) {
-            int killrc = kill(op->pid, SIGKILL);
-
-            op->rc = PCMK_OCF_UNKNOWN_ERROR;
-            if (op->timeout > 0 && timeout <= 0) {
-                op->status = PCMK_LRM_OP_TIMEOUT;
-                crm_warn("%s:%d - timed out after %dms", op->id, op->pid, op->timeout);
-
-            } else {
-                op->status = PCMK_LRM_OP_ERROR;
-            }
-
-            if (killrc && errno != ESRCH) {
-                crm_err("kill(%d, KILL) failed: %d", op->pid, errno);
-            }
-            /*
-             * From sigprocmask(2):
-             * It is not possible to block SIGKILL or SIGSTOP.  Attempts to do so are silently ignored.
-             *
-             * This makes it safe to skip WNOHANG here
-             */
-            waitpid(op->pid, &status, 0);
-
-        } else if (WIFEXITED(status)) {
-            op->status = PCMK_LRM_OP_DONE;
-            op->rc = WEXITSTATUS(status);
-            crm_info("Managed %s process %d exited with rc=%d", op->id, op->pid, op->rc);
-
-        } else if (WIFSIGNALED(status)) {
-            int signo = WTERMSIG(status);
-
-            op->status = PCMK_LRM_OP_ERROR;
-            crm_err("Managed %s process %d exited with signal=%d", op->id, op->pid, signo);
-        }
-#ifdef WCOREDUMP
-        if (WCOREDUMP(status)) {
-            crm_err("Managed %s process %d dumped core", op->id, op->pid);
-        }
-#endif
-
-        svc_read_output(op->opaque->stdout_fd, op, FALSE);
-        svc_read_output(op->opaque->stderr_fd, op, TRUE);
-
-        close(op->opaque->stdout_fd);
-        close(op->opaque->stderr_fd);
-        close(sfd);
+        action_synced_wait(op, mask);
 
         if (sigismember(&old_mask, SIGCHLD) == 0) {
             if (sigprocmask(SIG_UNBLOCK, &mask, NULL) < 0) {
                 crm_perror(LOG_ERR, "sigprocmask() to unblocked failed");
             }
         }
-#endif
 
     } else {
+
         crm_trace("Async waiting for %d - %s", op->pid, op->opaque->exec);
         mainloop_child_add(op->pid, op->timeout, op->id, op, operation_finished);
 
         op->opaque->stdout_gsource = mainloop_add_fd(op->id,
                                                      G_PRIORITY_LOW,
                                                      op->opaque->stdout_fd, op, &stdout_callbacks);
 
         op->opaque->stderr_gsource = mainloop_add_fd(op->id,
                                                      G_PRIORITY_LOW,
                                                      op->opaque->stderr_fd, op, &stderr_callbacks);
     }
 
     return TRUE;
 }
 
 GList *
 services_os_get_directory_list(const char *root, gboolean files, gboolean executable)
 {
     GList *list = NULL;
     struct dirent **namelist;
     int entries = 0, lpc = 0;
     char buffer[PATH_MAX];
 
     entries = scandir(root, &namelist, NULL, alphasort);
     if (entries <= 0) {
         return list;
     }
 
     for (lpc = 0; lpc < entries; lpc++) {
         struct stat sb;
 
         if ('.' == namelist[lpc]->d_name[0]) {
             free(namelist[lpc]);
             continue;
         }
 
         snprintf(buffer, sizeof(buffer), "%s/%s", root, namelist[lpc]->d_name);
 
         if (stat(buffer, &sb)) {
             continue;
         }
 
         if (S_ISDIR(sb.st_mode)) {
             if (files) {
                 free(namelist[lpc]);
                 continue;
             }
 
         } else if (S_ISREG(sb.st_mode)) {
             if (files == FALSE) {
                 free(namelist[lpc]);
                 continue;
 
             } else if (executable
                        && (sb.st_mode & S_IXUSR) == 0
                        && (sb.st_mode & S_IXGRP) == 0 && (sb.st_mode & S_IXOTH) == 0) {
                 free(namelist[lpc]);
                 continue;
             }
         }
 
         list = g_list_append(list, strdup(namelist[lpc]->d_name));
 
         free(namelist[lpc]);
     }
 
     free(namelist);
     return list;
 }
 
 GList *
 resources_os_list_lsb_agents(void)
 {
     return get_directory_list(LSB_ROOT_DIR, TRUE, TRUE);
 }
 
 GList *
 resources_os_list_ocf_providers(void)
 {
     return get_directory_list(OCF_ROOT_DIR "/resource.d", FALSE, TRUE);
 }
 
 GList *
 resources_os_list_ocf_agents(const char *provider)
 {
     GList *gIter = NULL;
     GList *result = NULL;
     GList *providers = NULL;
 
     if (provider) {
         char buffer[500];
 
         snprintf(buffer, sizeof(buffer), "%s/resource.d/%s", OCF_ROOT_DIR, provider);
         return get_directory_list(buffer, TRUE, TRUE);
     }
 
     providers = resources_os_list_ocf_providers();
     for (gIter = providers; gIter != NULL; gIter = gIter->next) {
         GList *tmp1 = result;
         GList *tmp2 = resources_os_list_ocf_agents(gIter->data);
 
         if (tmp2) {
             result = g_list_concat(tmp1, tmp2);
         }
     }
     g_list_free_full(providers, free);
     return result;
 }
 
 #if SUPPORT_NAGIOS
 GList *
 resources_os_list_nagios_agents(void)
 {
     GList *plugin_list = NULL;
     GList *result = NULL;
     GList *gIter = NULL;
 
     plugin_list = get_directory_list(NAGIOS_PLUGIN_DIR, TRUE, TRUE);
 
     /* Make sure both the plugin and its metadata exist */
     for (gIter = plugin_list; gIter != NULL; gIter = gIter->next) {
         const char *plugin = gIter->data;
         char *metadata = g_strdup_printf(NAGIOS_METADATA_DIR "/%s.xml", plugin);
         struct stat st;
 
         if (stat(metadata, &st) == 0) {
             result = g_list_append(result, strdup(plugin));
         }
 
         g_free(metadata);
     }
     g_list_free_full(plugin_list, free);
     return result;
 }
 #endif
diff --git a/mcp/corosync.c b/mcp/corosync.c
index 24f5c22b5b..24f3ba2753 100644
--- a/mcp/corosync.c
+++ b/mcp/corosync.c
@@ -1,474 +1,480 @@
 /*
  * Copyright (C) 2010 Andrew Beekhof <andrew@beekhof.net>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public
  * License as published by the Free Software Foundation; either
  * version 2 of the License, or (at your option) any later version.
  *
  * This software is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 #include <crm_internal.h>
 #include <pacemaker.h>
 
 #include <sys/utsname.h>
 #include <sys/stat.h>           /* for calls to stat() */
 #include <libgen.h>             /* For basename() and dirname() */
 
 #include <sys/types.h>
 #include <pwd.h>                /* For getpwname() */
 
 #include <corosync/hdb.h>
 #include <corosync/cfg.h>
 #include <corosync/cpg.h>
 #if HAVE_CONFDB
 #  include <corosync/confdb.h>
 #endif
 
 #include <crm/cluster/internal.h>
 #include <crm/common/mainloop.h>
 
 #if SUPPORT_CMAN
 #  include <libcman.h>
 #endif
 
 #if HAVE_CMAP
 #  include <corosync/cmap.h>
 #endif
 
 enum cluster_type_e stack = pcmk_cluster_unknown;
 static corosync_cfg_handle_t cfg_handle;
 
 /* =::=::=::= CFG - Shutdown stuff =::=::=::= */
 
 static void
 cfg_shutdown_callback(corosync_cfg_handle_t h, corosync_cfg_shutdown_flags_t flags)
 {
     crm_info("Corosync wants to shut down: %s",
              (flags == COROSYNC_CFG_SHUTDOWN_FLAG_IMMEDIATE) ? "immediate" :
              (flags == COROSYNC_CFG_SHUTDOWN_FLAG_REGARDLESS) ? "forced" : "optional");
 
     /* Never allow corosync to shut down while we're running */
     corosync_cfg_replyto_shutdown(h, COROSYNC_CFG_SHUTDOWN_FLAG_NO);
 }
 
 static corosync_cfg_callbacks_t cfg_callbacks = {
     .corosync_cfg_shutdown_callback = cfg_shutdown_callback,
 };
 
 static int
 pcmk_cfg_dispatch(gpointer user_data)
 {
     corosync_cfg_handle_t *handle = (corosync_cfg_handle_t *) user_data;
     cs_error_t rc = corosync_cfg_dispatch(*handle, CS_DISPATCH_ALL);
 
     if (rc != CS_OK) {
         return -1;
     }
     return 0;
 }
 
 static void
 cfg_connection_destroy(gpointer user_data)
 {
     crm_err("Connection destroyed");
     cfg_handle = 0;
 
     pcmk_shutdown(SIGTERM);
 }
 
 gboolean
 cluster_disconnect_cfg(void)
 {
     if (cfg_handle) {
         corosync_cfg_finalize(cfg_handle);
         cfg_handle = 0;
     }
 
     pcmk_shutdown(SIGTERM);
     return TRUE;
 }
 
 #define cs_repeat(counter, max, code) do {		\
 	code;						\
 	if(rc == CS_ERR_TRY_AGAIN || rc == CS_ERR_QUEUE_FULL) {  \
 	    counter++;					\
 	    crm_debug("Retrying operation after %ds", counter);	\
 	    sleep(counter);				\
 	} else {                                        \
             break;                                      \
 	}						\
     } while(counter < max)
 
 gboolean
 cluster_connect_cfg(uint32_t * nodeid)
 {
     cs_error_t rc;
     int fd = 0, retries = 0;
 
     static struct mainloop_fd_callbacks cfg_fd_callbacks = {
         .dispatch = pcmk_cfg_dispatch,
         .destroy = cfg_connection_destroy,
     };
 
     cs_repeat(retries, 30, rc = corosync_cfg_initialize(&cfg_handle, &cfg_callbacks));
 
     if (rc != CS_OK) {
         crm_err("corosync cfg init error %d", rc);
         return FALSE;
     }
 
     rc = corosync_cfg_fd_get(cfg_handle, &fd);
     if (rc != CS_OK) {
         crm_err("corosync cfg fd_get error %d", rc);
         goto bail;
     }
 
     retries = 0;
     cs_repeat(retries, 30, rc = corosync_cfg_local_get(cfg_handle, nodeid));
 
     if (rc != CS_OK) {
         crm_err("corosync cfg local_get error %d", rc);
         goto bail;
     }
 
     crm_debug("Our nodeid: %d", *nodeid);
     mainloop_add_fd("corosync-cfg", G_PRIORITY_DEFAULT, fd, &cfg_handle, &cfg_fd_callbacks);
 
     return TRUE;
 
   bail:
     corosync_cfg_finalize(cfg_handle);
     return FALSE;
 }
 
 /* =::=::=::= Configuration =::=::=::= */
 #if HAVE_CONFDB
 static int
 get_config_opt(confdb_handle_t config,
                hdb_handle_t object_handle, const char *key, char **value, const char *fallback)
 {
     size_t len = 0;
     char *env_key = NULL;
     const char *env_value = NULL;
     char buffer[256];
 
     if (*value) {
         free(*value);
         *value = NULL;
     }
 
     if (object_handle > 0) {
         if (CS_OK == confdb_key_get(config, object_handle, key, strlen(key), &buffer, &len)) {
             *value = strdup(buffer);
         }
     }
 
     if (*value) {
         crm_info("Found '%s' for option: %s", *value, key);
         return 0;
     }
 
     env_key = crm_concat("HA", key, '_');
     env_value = getenv(env_key);
     free(env_key);
 
     if (*value) {
         crm_info("Found '%s' in ENV for option: %s", *value, key);
         *value = strdup(env_value);
         return 0;
     }
 
     if (fallback) {
         crm_info("Defaulting to '%s' for option: %s", fallback, key);
         *value = strdup(fallback);
 
     } else {
         crm_info("No default for option: %s", key);
     }
 
     return -1;
 }
 
 static confdb_handle_t
 config_find_init(confdb_handle_t config)
 {
     cs_error_t rc = CS_OK;
     confdb_handle_t local_handle = OBJECT_PARENT_HANDLE;
 
     rc = confdb_object_find_start(config, local_handle);
     if (rc == CS_OK) {
         return local_handle;
     } else {
         crm_err("Couldn't create search context: %d", rc);
     }
     return 0;
 }
 
 static hdb_handle_t
 config_find_next(confdb_handle_t config, const char *name, confdb_handle_t top_handle)
 {
     cs_error_t rc = CS_OK;
     hdb_handle_t local_handle = 0;
 
     if (top_handle == 0) {
         crm_err("Couldn't search for %s: no valid context", name);
         return 0;
     }
 
     crm_trace("Searching for %s in " HDB_X_FORMAT, name, top_handle);
     rc = confdb_object_find(config, top_handle, name, strlen(name), &local_handle);
     if (rc != CS_OK) {
         crm_info("No additional configuration supplied for: %s", name);
         local_handle = 0;
     } else {
         crm_info("Processing additional %s options...", name);
     }
     return local_handle;
 }
 #else
 static int
 get_config_opt(uint64_t unused, cmap_handle_t object_handle, const char *key, char **value,
                const char *fallback)
 {
     int rc = 0, retries = 0;
 
     cs_repeat(retries, 5, rc = cmap_get_string(object_handle, key, value));
     if (rc != CS_OK) {
         crm_trace("Search for %s failed %d, defaulting to %s", key, rc, fallback);
         if (fallback) {
             *value = strdup(fallback);
         } else {
             *value = NULL;
         }
     }
     crm_trace("%s: %s", key, *value);
     return rc;
 }
 
 #endif
 
 #if HAVE_CONFDB
 #  define KEY_PREFIX ""
 #elif HAVE_CMAP
 #  define KEY_PREFIX "logging."
 #endif
 
 gboolean
 mcp_read_config(void)
 {
     int rc = CS_OK;
     int retries = 0;
 
     const char *const_value = NULL;
 
 #if HAVE_CONFDB
     char *value = NULL;
     confdb_handle_t config = 0;
     confdb_handle_t top_handle = 0;
     hdb_handle_t local_handle;
     static confdb_callbacks_t callbacks = { };
 
     do {
         rc = confdb_initialize(&config, &callbacks);
         if (rc != CS_OK) {
             retries++;
             printf("confdb connection setup failed: %s.  Retrying in %ds\n", ais_error2text(rc), retries);
             crm_info("confdb connection setup failed: %s.  Retrying in %ds", ais_error2text(rc), retries);
             sleep(retries);
 
         } else {
             break;
         }
 
     } while (retries < 5);
 #elif HAVE_CMAP
     cmap_handle_t local_handle;
     uint64_t config = 0;
 
     /* There can be only one (possibility if confdb isn't around) */
     do {
         rc = cmap_initialize(&local_handle);
         if (rc != CS_OK) {
             retries++;
             printf("cmap connection setup failed: %s.  Retrying in %ds\n", cs_strerror(rc), retries);
             crm_info("cmap connection setup failed: %s.  Retrying in %ds", cs_strerror(rc), retries);
             sleep(retries);
 
         } else {
             break;
         }
 
     } while (retries < 5);
 #endif
 
     if (rc != CS_OK) {
         printf("Could not connect to Cluster Configuration Database API, error %d\n", rc);
         crm_warn("Could not connect to Cluster Configuration Database API, error %d", rc);
         return FALSE;
     }
 
     stack = get_cluster_type();
     crm_info("Reading configure for stack: %s", name_for_cluster_type(stack));
 
     /* =::=::= Should we be here =::=::= */
     if (stack == pcmk_cluster_corosync) {
         set_daemon_option("cluster_type", "corosync");
         set_daemon_option("quorum_type", "corosync");
 
 #if HAVE_CONFDB
     } else if (stack == pcmk_cluster_cman) {
         set_daemon_option("cluster_type", "cman");
         set_daemon_option("quorum_type", "cman");
         enable_crmd_as_root(TRUE);
 
     } else if (stack == pcmk_cluster_classic_ais) {
         set_daemon_option("cluster_type", "openais");
         set_daemon_option("quorum_type", "pcmk");
 
         /* Look for a service block to indicate our plugin is loaded */
         top_handle = config_find_init(config);
         local_handle = config_find_next(config, "service", top_handle);
 
         while (local_handle) {
             get_config_opt(config, local_handle, "name", &value, NULL);
             if (safe_str_eq("pacemaker", value)) {
                 get_config_opt(config, local_handle, "ver", &value, "0");
                 if (safe_str_eq(value, "1")) {
                     get_config_opt(config, local_handle, "use_logd", &value, "no");
                     set_daemon_option("use_logd", value);
                     set_daemon_option("LOGD", value);
 
                     get_config_opt(config, local_handle, "use_mgmtd", &value, "no");
                     enable_mgmtd(crm_is_true(value));
 
                 } else {
                     crm_err("We can only start Pacemaker from init if using version 1"
                             " of the Pacemaker plugin for Corosync.  Terminating.");
                     crm_exit(DAEMON_RESPAWN_STOP);
                 }
                 break;
             }
             local_handle = config_find_next(config, "service", top_handle);
         }
         free(value);
 
 #endif
     } else {
         crm_err("Unsupported stack type: %s", name_for_cluster_type(stack));
         return FALSE;
     }
 
 #if HAVE_CONFDB
     top_handle = config_find_init(config);
     local_handle = config_find_next(config, "logging", top_handle);
 #endif
 
     /* =::=::= Logging =::=::= */
     if (daemon_option("debug")) {
         /* Syslog logging is already setup by crm_log_init() */
 
     } else {
         /* Check corosync */
         char *debug_enabled = NULL;
 
         get_config_opt(config, local_handle, KEY_PREFIX "debug", &debug_enabled, "off");
 
         if (crm_is_true(debug_enabled)) {
             set_daemon_option("debug", "1");
             if (get_crm_log_level() < LOG_DEBUG) {
                 set_crm_log_level(LOG_DEBUG);
             }
 
         } else {
             set_daemon_option("debug", "0");
         }
 
         free(debug_enabled);
     }
 
     const_value = daemon_option("debugfile");
     if (daemon_option("logfile")) {
         /* File logging is already setup by crm_log_init() */
 
     } else if(const_value) {
         /* From when we cared what options heartbeat used */
         set_daemon_option("logfile", const_value);
         crm_add_logfile(const_value);
 
     } else {
         /* Check corosync */
         char *logfile = NULL;
         char *logfile_enabled = NULL;
 
         get_config_opt(config, local_handle, KEY_PREFIX "to_logfile", &logfile_enabled, "on");
         get_config_opt(config, local_handle, KEY_PREFIX "logfile", &logfile, "/var/log/pacemaker.log");
 
         if (crm_is_true(logfile_enabled) == FALSE) {
             crm_trace("File logging disabled in corosync");
 
         } else if (crm_add_logfile(logfile)) {
             set_daemon_option("logfile", logfile);
 
         } else {
             crm_err("Couldn't create logfile: %s", logfile);
             set_daemon_option("logfile", "none");
         }
 
         free(logfile);
         free(logfile_enabled);
     }
 
     if (daemon_option("logfacility")) {
         /* Syslog logging is already setup by crm_log_init() */
 
     } else {
         /* Check corosync */
         char *syslog_enabled = NULL;
         char *syslog_facility = NULL;
 
         get_config_opt(config, local_handle, KEY_PREFIX "to_syslog", &syslog_enabled, "on");
         get_config_opt(config, local_handle, KEY_PREFIX "syslog_facility", &syslog_facility, "daemon");
 
         if (crm_is_true(syslog_enabled) == FALSE) {
             qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_FALSE);
             set_daemon_option("logfacility", "none");
 
         } else {
             qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_FACILITY, qb_log_facility2int(syslog_facility));
             qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_TRUE);
             set_daemon_option("logfacility", syslog_facility);
         }
 
         free(syslog_enabled);
         free(syslog_facility);
     }
 
+    const_value = daemon_option("logfacility");
+    if (const_value) {
+        /* cluster-glue module needs HA_LOGFACILITY */
+        setenv("HA_LOGFACILITY", const_value, 1);
+    }
+
 #if HAVE_CONFDB
     confdb_finalize(config);
 #elif HAVE_CMAP
     if(local_handle){
         gid_t gid = 0;
         if (crm_user_lookup(CRM_DAEMON_USER, NULL, &gid) < 0) {
             crm_warn("No group found for user %s", CRM_DAEMON_USER);
 
         } else {
             char key[PATH_MAX];
             snprintf(key, PATH_MAX, "uidgid.gid.%u", gid);
             rc = cmap_set_uint8(local_handle, key, 1);
             crm_notice("Configured corosync to accept connections from group %u: %s (%d)",
                        gid, ais_error2text(rc), rc);
         }
     }
     cmap_finalize(local_handle);
 #endif
 
     return TRUE;
 }
diff --git a/mcp/pacemaker.combined.upstart.in b/mcp/pacemaker.combined.upstart.in
index c680213875..9540019c6a 100644
--- a/mcp/pacemaker.combined.upstart.in
+++ b/mcp/pacemaker.combined.upstart.in
@@ -1,63 +1,64 @@
 # pacemaker-corosync - High-Availability cluster
 #
 # Starts Corosync cluster engine and Pacemaker cluster manager.
 
+stop on runlevel [0123456]
 kill timeout 3600
 respawn
 
 env prog=pacemakerd
 env rpm_sysconf=@sysconfdir@/sysconfig/pacemaker
 env rpm_lockfile=@localstatedir@/lock/subsys/pacemaker
 env deb_sysconf=@sysconfdir@/default/pacemaker
 env deb_lockfile=@localstatedir@/lock/pacemaker
 
 script
     [ -f "$rpm_sysconf" ] && . $rpm_sysconf
     [ -f "$deb_sysconf" ] && . $deb_sysconf
     exec $prog
 end script
 
 pre-start script
     # setup the software watchdog which corosync uses.
     # rewrite according to environment.
-    modprobe softdog soft_margin=60
+    [ -c /dev/watchdog ] || modprobe softdog soft_margin=60
     pidof corosync || start corosync
 
     # if you use corosync-notifyd, uncomment the line below.
     #start corosync-notifyd
 
     # give it time to fail.
     sleep 2
     pidof corosync || { exit 1; }
 end script
 
 post-start script
     [ -f "$rpm_sysconf" ] && . $rpm_sysconf
     [ -f "$deb_sysconf" ] && . $deb_sysconf
     [ -z "$LOCK_FILE" -a -d @sysconfdir@/sysconfig ] && LOCK_FILE="$rpm_lockfile"
     [ -z "$LOCK_FILE" -a -d @sysconfdir@/default ] && LOCK_FILE="$deb_lockfile"
     touch $LOCK_FILE
     pidof $prog > @localstatedir@/run/$prog.pid
 end script
 
 post-stop script
     [ -f "$rpm_sysconf" ] && . $rpm_sysconf
     [ -f "$deb_sysconf" ] && . $deb_sysconf
     [ -z "$LOCK_FILE" -a -d @sysconfdir@/sysconfig ] && LOCK_FILE="$rpm_lockfile"
     [ -z "$LOCK_FILE" -a -d @sysconfdir@/default ] && LOCK_FILE="$deb_lockfile"
     rm -f $LOCK_FILE
     rm -f @localstatedir@/run/$prog.pid
 
     # if you use watchdog of corosync, uncomment the line below.
     #pidof corosync || false
 
     pidof crmd || stop corosync
 
     # if you want to reboot a machine by watchdog of corosync when
     # pacemakerd disappeared unexpectedly, uncomment the line below
     # and invalidate above "respawn" stanza.
     #pidof crmd && killall -q -9 corosync
 
     # if you use corosync-notifyd, uncomment the line below.
     #stop corosync-notifyd || true
 end script