diff --git a/src/pcmk.c b/src/pcmk.c
index fc67f04..58c162b 100644
--- a/src/pcmk.c
+++ b/src/pcmk.c
@@ -1,490 +1,559 @@
 /* 
  * Copyright (C) 2011 Jiaju Zhang <jjzhang@suse.de>
  * Copyright (C) 2013-2014 Philipp Marek <philipp.marek@linbit.com>
  * 
  * 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 program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
+#include "b_config.h"
+
 #include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <errno.h>
 #include <inttypes.h>
 #include <unistd.h>
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <libxml/parser.h>
 #include <libxml/tree.h>
 #include "ticket.h"
 #include "log.h"
 #include "attr.h"
 #include "pcmk.h"
 #include "inline-fn.h"
 
 #ifdef LIBPACEMAKER
 #include <crm/common/results.h>
 #include <pacemaker.h>
 #endif
 
 #define COMMAND_MAX	2048
 
 const char * interpret_rv(int rv)
 {
 	static char text[64];
 
 	if (rv == 0)
 		return "0";
 
 	if (WIFSIGNALED(rv))
 		sprintf(text, "got signal %d", WTERMSIG(rv));
 	else
 		sprintf(text, "exit code %d", WEXITSTATUS(rv));
 
 	return text;
 }
 
 
+#ifdef LIBPACEMAKER
+static int pcmk_write_ticket_atomic(struct ticket_config *tk, bool grant)
+{
+    char *owner_s = NULL;
+    char *expires_s = NULL;
+    char *term_s = NULL;
+    char *grant_s = NULL;
+    char *booth_cfg_name = NULL;
+    GHashTable *attrs = NULL;
+    xmlNode *xml = NULL;
+    int rv;
+
+    attrs = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, free);
+    if (attrs == NULL) {
+        log_error("out of memory");
+        return -1;
+    }
+
+    if (grant) {
+        grant_s = strdup("true");
+    } else {
+        grant_s = strdup("false");
+    }
+
+    if (grant_s == NULL) {
+        log_error("out of memory");
+        return -1;
+    }
+
+    booth_cfg_name = strdup(booth_conf->name);
+
+    if (booth_cfg_name == NULL) {
+        log_error("out of memory");
+        free(grant_s);
+        return -1;
+    }
+
+    if (asprintf(&owner_s, "%" PRIi32, get_node_id(tk->leader)) == -1 ||
+        asprintf(&expires_s, "%" PRIi64, wall_ts(&tk->term_expires)) == -1 ||
+        asprintf(&term_s, "%" PRIi64, (int64_t) tk->current_term) == -1) {
+        log_error("out of memory");
+        free(owner_s);
+        free(expires_s);
+        free(term_s);
+        free(grant_s);
+        return -1;
+    }
+
+    g_hash_table_insert(attrs, (gpointer) "owner", owner_s);
+    g_hash_table_insert(attrs, (gpointer) "expires", expires_s);
+    g_hash_table_insert(attrs, (gpointer) "term", term_s);
+    g_hash_table_insert(attrs, (gpointer) "granted", grant_s);
+    g_hash_table_insert(attrs, (gpointer) "booth-cfg-name", booth_conf);
+
+    rv = pcmk_ticket_set_attr(&xml, tk->name, attrs, true);
+    g_hash_table_remove_all(attrs);
+    xmlFreeNode(xml);
+
+    if (rv != pcmk_rc_ok) {
+        log_error("pcmk_write_ticket_atomic: %s", pcmk_rc_str(rv));
+        return -1;
+    }
+
+    return 0;
+}
+#else
 static int pcmk_write_ticket_atomic(struct ticket_config *tk, bool grant)
 {
 	char cmd[COMMAND_MAX];
 	int rv;
 
 	/* The long format (--attr-value=) for attribute value is used instead of "-v",
 	* so that NO_ONE (which is -1) isn't seen as another option. */
 	rv = snprintf(cmd, COMMAND_MAX,
 			"crm_ticket -t '%s' "
 			"%s --force "
 			"-S owner --attr-value=%" PRIi32 " "
 			"-S expires --attr-value=%" PRIi64 " "
 			"-S term --attr-value=%" PRIi64 " "
 			"-S booth-cfg-name --attr-value=%s",
 			tk->name,
 			grant ? "-g" : "-r",
 			(int32_t)get_node_id(tk->leader),
 			(int64_t)wall_ts(&tk->term_expires),
 			(int64_t)tk->current_term,
 			booth_conf->name);
 
 	if (rv < 0 || rv >= COMMAND_MAX) {
 		log_error("pcmk_write_ticket_atomic: cannot format crm_ticket cmdline (probably too long)");
 		return -1;
 	}
 
 	rv = system(cmd);
 	log_debug("command: '%s' was executed", cmd);
 	if (rv != 0)
 		log_error("\"%s\" failed, %s", cmd, interpret_rv(rv));
 
 	return rv;
 }
+#endif
 
 
 static int pcmk_grant_ticket(struct ticket_config *tk)
 {
 
 	return pcmk_write_ticket_atomic(tk, true);
 }
 
 
 static int pcmk_revoke_ticket(struct ticket_config *tk)
 {
 
 	return pcmk_write_ticket_atomic(tk, false);
 }
 
 
 #ifdef LIBPACEMAKER
 static int pcmk_set_attr(struct ticket_config *tk, const char *attr, const char *val)
 {
     GHashTable *attrs = NULL;
     xmlNode *xml = NULL;
     int rv;
 
     attrs = g_hash_table_new(g_str_hash, g_str_equal);
     if (attrs == NULL) {
         log_error("out of memory");
         return -1;
     }
 
     g_hash_table_insert(attrs, (gpointer) attr, (gpointer) val);
 
     rv = pcmk_ticket_set_attr(&xml, tk->name, attrs, false);
     g_hash_table_destroy(attrs);
     xmlFreeNode(xml);
 
     if (rv != pcmk_rc_ok) {
         log_error("pcmk_set_attr: %s", pcmk_rc_str(rv));
         return -1;
     }
 
     return 0;
 }
 
 static int pcmk_del_attr(struct ticket_config *tk, const char *attr)
 {
     GList *attrs = NULL;
     xmlNode *xml = NULL;
     int rv;
 
     attrs = g_list_append(attrs, (gpointer) attr);
     if (attrs == NULL) {
         log_error("out of memory");
         return -1;
     }
 
     rv = pcmk_ticket_remove_attr(&xml, tk->name, attrs, false);
     g_list_free(attrs);
     xmlFreeNode(xml);
 
     if (rv != pcmk_rc_ok) {
         log_error("pcmk_del_attr: %s", pcmk_rc_str(rv));
         return -1;
     }
 
     return 0;
 }
 #else
 static int _run_crm_ticket(char *cmd)
 {
 	int i, rv;
 
 	/* If there are errors, there's not much we can do but retry ... */
 	for (i=0; i<3 &&
 			(rv = system(cmd));
 			i++) ;
 
 	log_debug("'%s' gave result %s", cmd, interpret_rv(rv));
 
 	return rv;
 }
 
 static int pcmk_set_attr(struct ticket_config *tk, const char *attr, const char *val)
 {
 	char cmd[COMMAND_MAX];
 	int rv;
 
 	rv = snprintf(cmd, COMMAND_MAX,
 		 "crm_ticket -t '%s' -S '%s' --attr-value='%s'",
 		 tk->name, attr, val);
 
 	if (rv < 0 || rv >= COMMAND_MAX) {
 		log_error("pcmk_set_attr: cannot format crm_ticket cmdline (probably too long)");
 		return -1;
 	}
 
 	return _run_crm_ticket(cmd);
 }
 
 static int pcmk_del_attr(struct ticket_config *tk, const char *attr)
 {
 	char cmd[COMMAND_MAX];
 	int rv;
 
 	rv = snprintf(cmd, COMMAND_MAX,
 		 "crm_ticket -t '%s' -D '%s'",
 		 tk->name, attr);
 
 	if (rv < 0 || rv >= COMMAND_MAX) {
 		log_error("pcmk_del_attr: cannot format crm_ticket cmdline (probably too long)");
 		return -1;
 	}
 
 	return _run_crm_ticket(cmd);
 }
 #endif
 
 
 typedef int (*attr_f)(struct booth_config *conf, struct ticket_config *tk,
 		      const char *name, const char *val);
 
 struct attr_tab
 {
 	const char *name;
 	attr_f handling_f;
 };
 
 static int save_expires(struct booth_config *conf, struct ticket_config *tk,
 			const char *name, const char *val)
 {
 	secs2tv(unwall_ts(atol(val)), &tk->term_expires);
 	return 0;
 }
 
 static int save_term(struct booth_config *conf, struct ticket_config *tk,
 		     const char *name, const char *val)
 {
 	tk->current_term = atol(val);
 	return 0;
 }
 
 static int parse_boolean(const char *val)
 {
 	long v;
 
 	if (!strncmp(val, "false", 5)) {
 		v = 0;
 	} else if (!strncmp(val, "true", 4)) {
 		v = 1;
 	} else {
 		v = atol(val);
 	}
 	return v;
 }
 
 static int save_granted(struct booth_config *conf, struct ticket_config *tk,
 			const char *name, const char *val)
 {
 	tk->is_granted = parse_boolean(val);
 	return 0;
 }
 
 static int save_owner(struct booth_config *conf, struct ticket_config *tk,
 		      const char *name, const char *val)
 {
 	/* No check, node could have been deconfigured. */
 	tk->leader = NULL;
 	return !find_site_by_id(conf, atol(val), &tk->leader);
 }
 
 static int ignore_attr(struct booth_config *conf, struct ticket_config *tk,
 		       const char *name, const char *val)
 {
 	return 0;
 }
 
 static int save_attr(struct ticket_config *tk, const char *name,
 		     const char *val)
 {
 	/* tell store_geo_attr not to store time, we don't have that
 	 * information available
 	 */
 	return store_geo_attr(tk, name, val, 1);
 }
 
 struct attr_tab attr_handlers[] = {
 	{ "expires", save_expires},
 	{ "term", save_term},
 	{ "granted", save_granted},
 	{ "owner", save_owner},
 	{ "id", ignore_attr},
 	{ "last-granted", ignore_attr},
 	{ "booth-cfg-name", ignore_attr},
 	{ NULL, 0},
 };
 
 
 /* get_attr is currently not used and has not been tested
  */
 static int pcmk_get_attr(struct ticket_config *tk, const char *attr, const char **vp)
 {
 	char cmd[COMMAND_MAX];
 	char line[BOOTH_ATTRVAL_LEN+1];
 	int rv = 0, pipe_rv;
 	int res;
 	FILE *p;
 
 
 	*vp = NULL;
 	res = snprintf(cmd, COMMAND_MAX,
 			"crm_ticket -t '%s' -G '%s' --quiet",
 			tk->name, attr);
 	if (res < 0 || res >= COMMAND_MAX) {
 		log_error("pcmk_get_attr: cannot format crm_ticket cmdline (probably too long)");
 		return -1;
 	}
 
 	p = popen(cmd, "r");
 	if (p == NULL) {
 		pipe_rv = errno;
 		log_error("popen error %d (%s) for \"%s\"",
 				pipe_rv, strerror(pipe_rv), cmd);
 		return (pipe_rv != 0 ? pipe_rv : EINVAL);
 	}
 	if (fgets(line, BOOTH_ATTRVAL_LEN, p) == NULL) {
 		rv = ENODATA;
 		goto out;
 	}
 
 	*vp = g_strdup(line);
 
 out:
 	pipe_rv = pclose(p);
 	if (!pipe_rv) {
 		log_debug("command \"%s\"", cmd);
 	} else if (WEXITSTATUS(pipe_rv) == 6) {
 		log_info("command \"%s\", ticket not found", cmd);
 	} else {
 		log_error("command \"%s\" %s", cmd, interpret_rv(pipe_rv));
 	}
 	return rv | pipe_rv;
 }
 
 static int save_attributes(struct booth_config *conf, struct ticket_config *tk,
 			   xmlDocPtr doc)
 {
 	int rv = 0, rc;
 	xmlNodePtr n;
 	xmlAttrPtr attr;
 	xmlChar *v;
 	struct attr_tab *atp;
 
 	n = xmlDocGetRootElement(doc);
 	if (n == NULL) {
 		tk_log_error("crm_ticket xml output empty");
 		return -EINVAL;
 	}
 	if (xmlStrcmp(n->name, (const xmlChar *)"ticket_state")) {
 		tk_log_error("crm_ticket xml root element not ticket_state");
 		return -EINVAL;
 	}
 	for (attr = n->properties; attr; attr = attr->next) {
 		v = xmlGetProp(n, attr->name);
 		for (atp = attr_handlers; atp->name; atp++) {
 			if (!strcmp(atp->name, (const char *) attr->name)) {
 				rc = atp->handling_f(conf, tk,
 						     (const char *) attr->name,
 						     (const char *) v);
 				break;
 			}
 		}
 		if (!atp->name) {
 			rc = save_attr(tk, (const char *) attr->name,
 				       (const char *) v);
 		}
 		if (rc) {
 			tk_log_error("error storing attribute %s", attr->name);
 			rv |= rc;
 		}
 		xmlFree(v);
 	}
 	return rv;
 }
 
 
 #define CHUNK_SIZE 256
 
 static int parse_ticket_state(struct booth_config *conf, struct ticket_config *tk,
 			      FILE *p)
 {
 	int rv = 0;
 	GString *input = NULL;
 	char line[CHUNK_SIZE];
 	xmlDocPtr doc = NULL;
 	int opts = XML_PARSE_COMPACT | XML_PARSE_NONET;
 
 	/* skip first two lines of output */
 	if (fgets(line, CHUNK_SIZE-1, p) == NULL || fgets(line, CHUNK_SIZE-1, p) == NULL) {
 		tk_log_error("crm_ticket xml output empty");
 		rv = ENODATA;
 		goto out;
 	}
 	input = g_string_sized_new(CHUNK_SIZE);
 	if (!input) {
 		log_error("out of memory");
 		rv = -1;
 		goto out;
 	}
 	while (fgets(line, CHUNK_SIZE-1, p) != NULL) {
 		if (!g_string_append(input, line)) {
 			log_error("out of memory");
 			rv = -1;
 			goto out;
 		}
 	}
 
 	doc = xmlReadDoc((const xmlChar *) input->str, NULL, NULL, opts);
 	if (doc == NULL) {
 		const xmlError *errptr = xmlGetLastError();
 		if (errptr) {
 			tk_log_error("crm_ticket xml parse failed (domain=%d, level=%d, code=%d): %s",
 					errptr->domain, errptr->level,
 					errptr->code, errptr->message);
 		} else {
 			tk_log_error("crm_ticket xml parse failed");
 		}
 		rv = -EINVAL;
 		goto out;
 	}
 	rv = save_attributes(conf, tk, doc);
 
 out:
 	if (doc)
 		xmlFreeDoc(doc);
 	if (input)
 		g_string_free(input, TRUE);
 	return rv;
 }
 
 static int pcmk_load_ticket(struct booth_config *conf, struct ticket_config *tk)
 {
 	char cmd[COMMAND_MAX];
 	int rv = 0, pipe_rv;
 	int res;
 	FILE *p;
 
 	res = snprintf(cmd, COMMAND_MAX,
 			"crm_ticket -t '%s' -q",
 			tk->name);
 
 	if (res < 0 || res >= COMMAND_MAX) {
 		log_error("pcmk_load_ticket: cannot format crm_ticket cmdline (probably too long)");
 		return -1;
 	}
 
 	p = popen(cmd, "r");
 	if (p == NULL) {
 		pipe_rv = errno;
 		log_error("popen error %d (%s) for \"%s\"",
 				pipe_rv, strerror(pipe_rv), cmd);
 		return (pipe_rv != 0 ? pipe_rv : EINVAL);
 	}
 
 	rv = parse_ticket_state(conf, tk, p);
 
 	if (!tk->leader) {
 		/* Hmm, no site found for the ticket we have in the
 		 * CIB!?
 		 * Assume that the ticket belonged to us if it was
 		 * granted here!
 		 */
 		log_warn("%s: no site matches; site got reconfigured?",
 			tk->name);
 		if (tk->is_granted) {
 			log_warn("%s: granted here, assume it belonged to us",
 				tk->name);
 			set_leader(tk, local);
 		}
 	}
 
 	pipe_rv = pclose(p);
 	if (!pipe_rv) {
 		log_debug("command \"%s\"", cmd);
 	} else if (WEXITSTATUS(pipe_rv) == 6) {
 		log_info("command \"%s\", ticket not found", cmd);
 	} else {
 		log_error("command \"%s\" %s", cmd, interpret_rv(pipe_rv));
 	}
 	return rv | pipe_rv;
 }
 
 
 struct ticket_handler pcmk_handler = {
 	.grant_ticket   = pcmk_grant_ticket,
 	.revoke_ticket  = pcmk_revoke_ticket,
 	.load_ticket    = pcmk_load_ticket,
 	.set_attr    = pcmk_set_attr,
 	.get_attr    = pcmk_get_attr,
 	.del_attr    = pcmk_del_attr,
 };