summaryrefslogtreecommitdiffstats
path: root/qarsh_packet.c
diff options
context:
space:
mode:
authorNate Straz <nstraz@redhat.com>2005-09-13 16:01:28 +0000
committerNathan Straz <nstraz@redhat.com>2008-09-23 09:37:44 -0400
commitbf489daffc4902db3a9eb95d485fd867ac1ea524 (patch)
treec022f12c9d1bb8b56b566976cf5127b37112bbf1 /qarsh_packet.c
parentc38e0fba0a10d5af0bb25f674177cb6404f73991 (diff)
downloadqarsh-bf489daffc4902db3a9eb95d485fd867ac1ea524.tar.gz
qarsh-bf489daffc4902db3a9eb95d485fd867ac1ea524.tar.xz
qarsh-bf489daffc4902db3a9eb95d485fd867ac1ea524.zip
Flatten the qarsh tree.
Diffstat (limited to 'qarsh_packet.c')
-rw-r--r--qarsh_packet.c850
1 files changed, 850 insertions, 0 deletions
diff --git a/qarsh_packet.c b/qarsh_packet.c
new file mode 100644
index 0000000..76fadf1
--- /dev/null
+++ b/qarsh_packet.c
@@ -0,0 +1,850 @@
+
+#include <string.h>
+#include <assert.h>
+#include <sys/wait.h>
+
+#include <libxml/parser.h>
+#include <libxml/xpath.h>
+
+#include "qarsh_packet.h"
+
+/* Prototypes */
+static char *get_xpath_string(xmlXPathContextPtr ctxt, const char *xpath_query);
+
+int parse_qp_hello(xmlXPathContextPtr ctxt, struct qa_packet *qp);
+int parse_qp_returncode(xmlXPathContextPtr ctxt, struct qa_packet *qp);
+int parse_qp_ack(xmlXPathContextPtr ctxt, struct qa_packet *qp);
+int parse_qp_runcmd(xmlXPathContextPtr ctxt, struct qa_packet *qp);
+int parse_qp_cmdexit(xmlXPathContextPtr ctxt, struct qa_packet *qp);
+int parse_qp_setuser(xmlXPathContextPtr ctxt, struct qa_packet *qp);
+int parse_qp_kill(xmlXPathContextPtr ctxt, struct qa_packet *qp);
+int parse_qp_recvfile(xmlXPathContextPtr ctxt, struct qa_packet *qp);
+int parse_qp_sendfile(xmlXPathContextPtr ctxt, struct qa_packet *qp);
+int parse_qp_rstat(xmlXPathContextPtr ctxt, struct qa_packet *qp);
+
+void string_qp_hello(xmlNodePtr node, struct qa_packet *qp);
+void string_qp_returncode(xmlNodePtr node, struct qa_packet *qp);
+void string_qp_runcmd(xmlNodePtr node, struct qa_packet *qp);
+void string_qp_ack(xmlNodePtr node, struct qa_packet *qp);
+void string_qp_cmdexit(xmlNodePtr node, struct qa_packet *qp);
+void string_qp_setuser(xmlNodePtr node, struct qa_packet *qp);
+void string_qp_kill(xmlNodePtr node, struct qa_packet *qp);
+void string_qp_recvfile(xmlNodePtr node, struct qa_packet *qp);
+void string_qp_sendfile(xmlNodePtr node, struct qa_packet *qp);
+void string_qp_rstat(xmlNodePtr node, struct qa_packet *qp);
+
+void free_qp_hello(struct qa_packet *qp);
+void free_qp_returncode(struct qa_packet *qp);
+void free_qp_runcmd(struct qa_packet *qp);
+void free_qp_setuser(struct qa_packet *qp);
+void free_qp_recvfile(struct qa_packet *qp);
+void free_qp_sendfile(struct qa_packet *qp);
+void free_qp_rstat(struct qa_packet *qp);
+
+void dump_qp_ack(struct qa_packet *qp);
+void dump_qp_runcmd(struct qa_packet *qp);
+void dump_qp_returncode(struct qa_packet *qp);
+void dump_qp_cmdexit(struct qa_packet *qp);
+void dump_qp_setuser(struct qa_packet *qp);
+void dump_qp_kill(struct qa_packet *qp);
+void dump_qp_recvfile(struct qa_packet *qp);
+void dump_qp_sendfile(struct qa_packet *qp);
+void dump_qp_rstat(struct qa_packet *qp);
+
+
+struct packet_internals {
+ char *pi_name;
+ int (*pi_parse)(xmlXPathContextPtr ctxt, struct qa_packet *qp);
+ void (*pi_string)(xmlNodePtr node, struct qa_packet *qp);
+ void (*pi_free)(struct qa_packet *qp);
+ void (*pi_dump)(struct qa_packet *qp);
+} qa_pi[] = {
+ {
+ .pi_name = "",
+ .pi_parse = NULL,
+ .pi_string = NULL,
+ .pi_free = NULL,
+ .pi_dump = NULL
+
+ }, {
+ .pi_name = "hello",
+ .pi_parse = parse_qp_hello,
+ .pi_string = string_qp_hello,
+ .pi_free = free_qp_hello
+ }, {
+ .pi_name = "returncode",
+ .pi_parse = parse_qp_returncode,
+ .pi_string = string_qp_returncode,
+ .pi_free = free_qp_returncode,
+ .pi_dump = dump_qp_returncode
+ }, {
+ .pi_name = "runcmd",
+ .pi_parse = parse_qp_runcmd,
+ .pi_string = string_qp_runcmd,
+ .pi_free = free_qp_runcmd,
+ .pi_dump = dump_qp_runcmd
+ }, {
+ .pi_name = "ack",
+ .pi_parse = parse_qp_ack,
+ .pi_string = string_qp_ack,
+ .pi_free = NULL,
+ .pi_dump = dump_qp_ack
+ }, {
+ .pi_name = "cmdexit",
+ .pi_parse = parse_qp_cmdexit,
+ .pi_string = string_qp_cmdexit,
+ .pi_free = NULL,
+ .pi_dump = dump_qp_cmdexit
+ }, {
+ .pi_name = "setuser",
+ .pi_parse = parse_qp_setuser,
+ .pi_string = string_qp_setuser,
+ .pi_free = free_qp_setuser,
+ .pi_dump = dump_qp_setuser
+ }, {
+ .pi_name = "kill",
+ .pi_parse = parse_qp_kill,
+ .pi_string = string_qp_kill,
+ .pi_free = NULL,
+ .pi_dump = dump_qp_kill
+ }, {
+ .pi_name = "recvfile",
+ .pi_parse = parse_qp_recvfile,
+ .pi_string = string_qp_recvfile,
+ .pi_free = free_qp_recvfile,
+ .pi_dump = dump_qp_recvfile
+ }, {
+ .pi_name = "sendfile",
+ .pi_parse = parse_qp_sendfile,
+ .pi_string = string_qp_sendfile,
+ .pi_free = free_qp_sendfile,
+ .pi_dump = dump_qp_sendfile
+ }, {
+ .pi_name = "rstat",
+ .pi_parse = parse_qp_rstat,
+ .pi_string = string_qp_rstat,
+ .pi_free = free_qp_rstat,
+ .pi_dump = dump_qp_rstat
+ }
+};
+
+#define QP_TYPES (sizeof qa_pi / sizeof *qa_pi)
+#define QP_NAME(n) qa_pi[n].pi_name
+
+
+/* XML Strings */
+const xmlChar *QP_QARSH_XML = (xmlChar *)"qarsh";
+const xmlChar *QP_PACKET_XML = (xmlChar *)"packet";
+const xmlChar *QP_TYPE_XML = (xmlChar *)"type";
+const xmlChar *QP_PARAM_XML = (xmlChar *)"param";
+const xmlChar *QP_NAME_XML = (xmlChar *)"name";
+const xmlChar *QP_SEQ_XML = (xmlChar *)"seq";
+
+enum qa_packet_type
+parse_packet_type(char *s)
+{
+ int i;
+ for (i = 0; i < QP_TYPES; i++) {
+ if (strcasecmp(s, QP_NAME(i)) == 0) {
+ return (enum qa_packet_type)i;
+ }
+ }
+ return QP_INVALID;
+}
+
+char *
+qp_packet_type(enum qa_packet_type t)
+{
+ return QP_NAME(t);
+}
+
+
+/*
+ * Packet parsing functions
+ */
+int
+parse_qp_hello(xmlXPathContextPtr ctxt, struct qa_packet *qp)
+{
+ qp->qp_hello.qp_greeting = get_xpath_string(ctxt,
+ "param[@name='greeting']");
+ return 0;
+}
+
+int
+parse_qp_returncode(xmlXPathContextPtr ctxt, struct qa_packet *qp)
+{
+ char *s;
+ s = get_xpath_string(ctxt, "param[@name='rc']");
+ qp->qp_returncode.qp_rc = atoi(s);
+ free(s);
+ s = get_xpath_string(ctxt, "param[@name='errno']");
+ qp->qp_returncode.qp_errno = atoi(s);
+ free(s);
+ qp->qp_returncode.qp_strerror = get_xpath_string(ctxt,
+ "param[@name='strerror']");
+ return 0;
+}
+
+int
+parse_qp_runcmd(xmlXPathContextPtr ctxt, struct qa_packet *qp)
+{
+ char *s;
+ qp->qp_runcmd.qp_cmdline = get_xpath_string(ctxt,
+ "param[@name='cmdline']");
+ s = get_xpath_string(ctxt, "param[@name='stdin']");
+ qp->qp_runcmd.qp_stdin_port = atoi(s);
+ free(s);
+ s = get_xpath_string(ctxt, "param[@name='stdout']");
+ qp->qp_runcmd.qp_stdout_port = atoi(s);
+ free(s);
+ s = get_xpath_string(ctxt, "param[@name='stderr']");
+ qp->qp_runcmd.qp_stderr_port = atoi(s);
+ free(s);
+ return 0;
+}
+
+int
+parse_qp_ack(xmlXPathContextPtr ctxt, struct qa_packet *qp)
+{
+ char *s;
+ s = get_xpath_string(ctxt, "param[@name='type']");
+ qp->qp_ack.qp_ack_type = parse_packet_type(s);
+ free(s);
+ s = get_xpath_string(ctxt, "param[@name='seq']");
+ qp->qp_ack.qp_ack_seq = atoi(s);
+ free(s);
+ return 0;
+}
+
+int
+parse_qp_cmdexit(xmlXPathContextPtr ctxt, struct qa_packet *qp)
+{
+ char *s;
+
+ s = get_xpath_string(ctxt, "param[@name='status']");
+ qp->qp_cmdexit.qp_status = atoi(s);
+ free(s);
+ return 0;
+}
+
+int
+parse_qp_setuser(xmlXPathContextPtr ctxt, struct qa_packet *qp)
+{
+ qp->qp_setuser.qp_user = get_xpath_string(ctxt, "param[@name='user']");
+ qp->qp_setuser.qp_group = get_xpath_string(ctxt, "param[@name='group']");
+ return 0;
+}
+
+int
+parse_qp_kill(xmlXPathContextPtr ctxt, struct qa_packet *qp)
+{
+ char *s;
+
+ s = get_xpath_string(ctxt, "param[@name='signal']");
+ qp->qp_kill.qp_sig = atoi(s);
+ free(s);
+ return 0;
+}
+
+int
+parse_qp_recvfile(xmlXPathContextPtr ctxt, struct qa_packet *qp)
+{
+ char *s;
+
+ qp->qp_recvfile.qp_path = get_xpath_string(ctxt, "param[@name='path']");
+
+ s = get_xpath_string(ctxt, "param[@name='if_port']");
+ qp->qp_recvfile.qp_if_port = atoi(s);
+ free(s);
+
+ s = get_xpath_string(ctxt, "param[@name='count']");
+ qp->qp_recvfile.qp_count = atoi(s);
+ free(s);
+
+ s = get_xpath_string(ctxt, "param[@name='mode']");
+ qp->qp_recvfile.qp_mode = atoi(s);
+ free(s);
+
+ return 0;
+}
+
+int
+parse_qp_sendfile(xmlXPathContextPtr ctxt, struct qa_packet *qp)
+{
+ char *s;
+
+ qp->qp_sendfile.qp_path = get_xpath_string(ctxt, "param[@name='path']");
+ s = get_xpath_string(ctxt, "param[@name='of_port']");
+ qp->qp_sendfile.qp_of_port = atoi(s);
+ free(s);
+ s = get_xpath_string(ctxt, "param[@name='count']");
+ qp->qp_sendfile.qp_count = atoi(s);
+ free(s);
+ return 0;
+}
+
+int
+parse_qp_rstat(xmlXPathContextPtr ctxt, struct qa_packet *qp)
+{
+ char *s;
+
+ qp->qp_rstat.qp_path = get_xpath_string(ctxt, "param[@name='path']");
+
+ s = get_xpath_string(ctxt, "param[@name='st_mode']");
+ qp->qp_rstat.qp_st_mode = atoi(s);
+ free(s);
+
+ s = get_xpath_string(ctxt, "param[@name='st_uid']");
+ qp->qp_rstat.qp_st_uid = atoi(s);
+ free(s);
+
+ s = get_xpath_string(ctxt, "param[@name='st_gid']");
+ qp->qp_rstat.qp_st_gid = atoi(s);
+ free(s);
+
+ s = get_xpath_string(ctxt, "param[@name='st_size']");
+ qp->qp_rstat.qp_st_size = atol(s);
+ free(s);
+
+ return 0;
+}
+
+
+struct qa_packet *
+parse_packet(xmlXPathContextPtr ctxt)
+{
+ struct qa_packet *qp = NULL;
+ char *s;
+
+ qp = malloc(sizeof *qp);
+ assert(qp);
+ memset(qp, 0, sizeof *qp);
+
+ s = get_xpath_string(ctxt, "@type");
+ qp->qp_type = parse_packet_type(s);
+ free(s);
+ s = get_xpath_string(ctxt, "@seq");
+ qp->qp_seq = atoi(s);
+ free(s);
+
+ if (qa_pi[qp->qp_type].pi_parse)
+ qa_pi[qp->qp_type].pi_parse(ctxt, qp);
+ else {
+ printf("Packet type %s not implemented yet\n", s);
+ free(qp);
+ qp = NULL;
+ }
+ return qp;
+}
+
+struct qa_packet *
+parse_packets(char *buf, int n)
+{
+ xmlDocPtr doc;
+ xmlXPathContextPtr context;
+ xmlXPathObjectPtr obj = NULL;
+ struct qa_packet *qp = NULL;
+
+ doc = xmlParseMemory(buf, n);
+
+ /* If we can't parse the packet, we don't care about it */
+ if (doc == NULL) return NULL;
+
+ context = xmlXPathNewContext(doc);
+ obj = xmlXPathEvalExpression((xmlChar *)"//packet", context);
+ if (obj == NULL) {
+ printf("didn't find anything\n");
+ goto free_context;
+ }
+ if (obj->type != XPATH_NODESET || obj->nodesetval->nodeNr == 0) {
+ printf("didn't find anything\n");
+ goto free_obj;
+ }
+ if (obj->nodesetval->nodeNr > 1) {
+ printf("One packet at a time please!\n");
+ }
+ context->node = xmlXPathNodeSetItem(obj->nodesetval, 0);
+ qp = parse_packet(context);
+
+free_obj:
+ xmlXPathFreeObject(obj);
+free_context:
+ xmlXPathFreeContext(context);
+ xmlFreeDoc(doc);
+ return qp;
+}
+
+
+static char *
+get_xpath_string(xmlXPathContextPtr ctxt, const char *xpath_query)
+{
+ xmlXPathObjectPtr obj = NULL;
+ char querystr[512];
+ char *ret;
+
+ snprintf(querystr, 512, "string(%s)", xpath_query);
+ obj = xmlXPathEvalExpression((xmlChar *)querystr, ctxt);
+
+ if (obj == NULL) return NULL;
+ if (obj->type != XPATH_STRING) {
+ xmlXPathFreeObject(obj);
+ return NULL;
+ }
+
+ ret = strdup((char *)obj->stringval);
+ xmlXPathFreeObject(obj);
+ return ret;
+}
+
+/*
+ * Packet serialization functions
+ *
+ * for converting structs to XML
+ */
+xmlNodePtr
+make_param(char *name, char *value)
+{
+ xmlNodePtr param = xmlNewNode(NULL, QP_PARAM_XML);
+ xmlNewProp(param, QP_NAME_XML, (xmlChar *)name);
+ xmlNodeSetContent(param, xmlEncodeSpecialChars(NULL, (xmlChar *)value));
+ return param;
+}
+
+void string_qp_hello(xmlNodePtr node, struct qa_packet *qp)
+{
+ xmlAddChild(node, make_param("greeting", qp->qp_hello.qp_greeting));
+}
+void string_qp_returncode(xmlNodePtr node, struct qa_packet *qp)
+{
+ char tmpstr[32];
+
+ snprintf(tmpstr, 32, "%d", qp->qp_returncode.qp_rc);
+ xmlAddChild(node, make_param("rc", tmpstr));
+ snprintf(tmpstr, 32, "%d", qp->qp_returncode.qp_errno);
+ xmlAddChild(node, make_param("errno", tmpstr));
+ xmlAddChild(node, make_param("strerror", qp->qp_returncode.qp_strerror));
+}
+void string_qp_runcmd(xmlNodePtr node, struct qa_packet *qp)
+{
+ char tmpstr[32];
+ xmlAddChild(node, make_param("cmdline", qp->qp_runcmd.qp_cmdline));
+ snprintf(tmpstr, 32, "%d", qp->qp_runcmd.qp_stdin_port);
+ xmlAddChild(node, make_param("stdin", tmpstr));
+ snprintf(tmpstr, 32, "%d", qp->qp_runcmd.qp_stdout_port);
+ xmlAddChild(node, make_param("stdout", tmpstr));
+ snprintf(tmpstr, 32, "%d", qp->qp_runcmd.qp_stderr_port);
+ xmlAddChild(node, make_param("stderr", tmpstr));
+}
+void string_qp_ack(xmlNodePtr node, struct qa_packet *qp)
+{
+ char tmpstr[32];
+
+ xmlAddChild(node, make_param("type",
+ QP_NAME(qp->qp_ack.qp_ack_type)));
+ snprintf(tmpstr, 32, "%d", qp->qp_ack.qp_ack_seq);
+ xmlAddChild(node, make_param("seq", tmpstr));
+}
+
+void string_qp_cmdexit(xmlNodePtr node, struct qa_packet *qp)
+{
+ char tmpstr[32];
+
+ snprintf(tmpstr, 32, "%d", qp->qp_cmdexit.qp_pid);
+ xmlAddChild(node, make_param("pid", tmpstr));
+ snprintf(tmpstr, 32, "%d", qp->qp_cmdexit.qp_status);
+ xmlAddChild(node, make_param("status", tmpstr));
+}
+
+void string_qp_setuser(xmlNodePtr node, struct qa_packet *qp)
+{
+ xmlAddChild(node, make_param("user", qp->qp_setuser.qp_user));
+ if (qp->qp_setuser.qp_group) {
+ xmlAddChild(node, make_param("group", qp->qp_setuser.qp_group));
+ }
+}
+
+void string_qp_kill(xmlNodePtr node, struct qa_packet *qp)
+{
+ char tmpstr[32];
+
+ snprintf(tmpstr, 32, "%d", qp->qp_kill.qp_sig);
+ xmlAddChild(node, make_param("signal", tmpstr));
+}
+
+void string_qp_recvfile(xmlNodePtr node, struct qa_packet *qp)
+{
+ char tmpstr[32];
+
+ xmlAddChild(node, make_param("path", qp->qp_recvfile.qp_path));
+
+ snprintf(tmpstr, 32, "%d", qp->qp_recvfile.qp_if_port);
+ xmlAddChild(node, make_param("if_port", tmpstr));
+
+ snprintf(tmpstr, 32, "%d", qp->qp_recvfile.qp_count);
+ xmlAddChild(node, make_param("count", tmpstr));
+
+ snprintf(tmpstr, 32, "%d", qp->qp_recvfile.qp_mode);
+ xmlAddChild(node, make_param("mode", tmpstr));
+}
+
+void string_qp_sendfile(xmlNodePtr node, struct qa_packet *qp)
+{
+ char tmpstr[32];
+
+ xmlAddChild(node, make_param("path", qp->qp_sendfile.qp_path));
+ snprintf(tmpstr, 32, "%d", qp->qp_sendfile.qp_of_port);
+ xmlAddChild(node, make_param("of_port", tmpstr));
+ snprintf(tmpstr, 32, "%d", qp->qp_sendfile.qp_count);
+ xmlAddChild(node, make_param("count", tmpstr));
+}
+
+void string_qp_rstat(xmlNodePtr node, struct qa_packet *qp)
+{
+ char tmpstr[32];
+
+ xmlAddChild(node, make_param("path", qp->qp_rstat.qp_path));
+ snprintf(tmpstr, 32, "%d", qp->qp_rstat.qp_st_mode);
+ xmlAddChild(node, make_param("st_mode", tmpstr));
+ snprintf(tmpstr, 32, "%d", qp->qp_rstat.qp_st_uid);
+ xmlAddChild(node, make_param("st_uid", tmpstr));
+ snprintf(tmpstr, 32, "%d", qp->qp_rstat.qp_st_gid);
+ xmlAddChild(node, make_param("st_gid", tmpstr));
+ snprintf(tmpstr, 32, "%ld", qp->qp_rstat.qp_st_size);
+ xmlAddChild(node, make_param("st_size", tmpstr));
+}
+
+/* Must pass in a pointer, but not a malloc'ed pointer */
+char *
+qptostr(struct qa_packet *qp, char **qpstr, int *qpsize)
+{
+ xmlDocPtr doc;
+ xmlNodePtr node;
+ char tmpstr[32];
+
+ if (qp->qp_type == QP_INVALID) return NULL;
+
+ doc = xmlNewDoc((xmlChar *)XML_DEFAULT_VERSION);
+
+ /* Add <qarsh> */
+ node = xmlNewDocNode(doc, NULL, QP_QARSH_XML, NULL);
+ xmlDocSetRootElement(doc, node);
+
+ /* Add <packet type="foo"> */
+ node = xmlNewChild(node, NULL, QP_PACKET_XML, NULL);
+ xmlNewProp(node, QP_TYPE_XML, (xmlChar *)QP_NAME(qp->qp_type));
+ snprintf(tmpstr, 32, "%d", qp->qp_seq);
+ xmlNewProp(node, QP_SEQ_XML, (xmlChar *)tmpstr);
+
+ if (qa_pi[qp->qp_type].pi_string) {
+ qa_pi[qp->qp_type].pi_string(node, qp);
+ }
+ xmlDocDumpMemory(doc, (xmlChar **)qpstr, qpsize);
+ xmlFreeDoc(doc);
+ return *qpstr;
+}
+
+/*
+ * Packet construction functions
+ */
+struct qa_packet *
+make_qp_hello(char *greeting)
+{
+ struct qa_packet *qp;
+
+ qp = malloc(sizeof *qp);
+ assert(qp);
+ memset(qp, 0, sizeof *qp);
+
+ qp->qp_type = QP_HELLO;
+ qp->qp_hello.qp_greeting = strdup(greeting);
+
+ return qp;
+}
+
+struct qa_packet *
+make_qp_returncode(int rc, int eno, char *strerr)
+{
+ struct qa_packet *qp;
+
+ qp = malloc(sizeof *qp);
+ assert(qp);
+ memset(qp, 0, sizeof *qp);
+
+ qp->qp_type = QP_RETURNCODE;
+ qp->qp_returncode.qp_rc = rc;
+ qp->qp_returncode.qp_errno = eno;
+ qp->qp_returncode.qp_strerror = strdup(strerr);
+
+ return qp;
+}
+
+struct qa_packet *
+make_qp_ack(enum qa_packet_type t, int i)
+{
+ struct qa_packet *qp;
+ qp = malloc(sizeof *qp);
+ assert(qp);
+ memset(qp, 0, sizeof *qp);
+
+ qp->qp_type = QP_ACK;
+ qp->qp_ack.qp_ack_type = t;
+ qp->qp_ack.qp_ack_seq = i;
+
+ return qp;
+}
+
+struct qa_packet *
+make_qp_runcmd(char *cmdline, int p_in, int p_out, int p_err)
+{
+ struct qa_packet *qp;
+ qp = malloc(sizeof *qp);
+ assert(qp);
+ memset(qp, 0, sizeof *qp);
+
+ qp->qp_type = QP_RUNCMD;
+ qp->qp_runcmd.qp_cmdline = strdup(cmdline);
+ qp->qp_runcmd.qp_stdin_port = p_in;
+ qp->qp_runcmd.qp_stdout_port = p_out;
+ qp->qp_runcmd.qp_stderr_port = p_err;
+
+ return qp;
+}
+
+struct qa_packet *
+make_qp_cmdexit(pid_t pid, int status)
+{
+ struct qa_packet *qp;
+ qp = malloc(sizeof *qp);
+ assert(qp);
+ memset(qp, 0, sizeof *qp);
+
+ qp->qp_type = QP_CMDEXIT;
+ qp->qp_cmdexit.qp_pid = pid;
+ qp->qp_cmdexit.qp_status = status;
+
+ return qp;
+}
+
+struct qa_packet *
+make_qp_setuser(char *user, char *group)
+{
+ struct qa_packet *qp;
+ qp = malloc(sizeof *qp);
+ assert(qp);
+ memset(qp, 0, sizeof *qp);
+
+ qp->qp_type = QP_SETUSER;
+ qp->qp_setuser.qp_user = strdup(user);
+ if (group) qp->qp_setuser.qp_group = strdup(group);
+
+ return qp;
+}
+
+struct qa_packet *
+make_qp_kill(int sig)
+{
+ struct qa_packet *qp;
+ qp = malloc(sizeof *qp);
+ assert(qp);
+ memset(qp, 0, sizeof *qp);
+
+ qp->qp_type = QP_KILL;
+ qp->qp_kill.qp_sig = sig;
+
+ return qp;
+}
+
+struct qa_packet *
+make_qp_recvfile(const char *path, int if_port, size_t count, mode_t mode)
+{
+ struct qa_packet *qp;
+ qp = malloc(sizeof *qp);
+ assert(qp);
+ memset(qp, 0, sizeof *qp);
+
+ qp->qp_type = QP_RECVFILE;
+ qp->qp_recvfile.qp_path = strdup(path);
+ qp->qp_recvfile.qp_if_port = if_port;
+ qp->qp_recvfile.qp_count = count;
+ qp->qp_recvfile.qp_mode = mode;
+
+ return qp;
+}
+
+struct qa_packet *
+make_qp_sendfile(const char *path, int of_port, size_t count)
+{
+ struct qa_packet *qp;
+ qp = malloc(sizeof *qp);
+ assert(qp);
+ memset(qp, 0, sizeof *qp);
+
+ qp->qp_type = QP_SENDFILE;
+ qp->qp_sendfile.qp_path = strdup(path);
+ qp->qp_sendfile.qp_of_port = of_port;
+ qp->qp_sendfile.qp_count = count;
+ return qp;
+}
+
+struct qa_packet *
+make_qp_rstat(const char *path, const struct stat *sb)
+{
+ struct qa_packet *qp;
+ qp = malloc(sizeof *qp);
+ assert(qp);
+ memset(qp, 0, sizeof *qp);
+
+ qp->qp_type = QP_RSTAT;
+ qp->qp_rstat.qp_path = strdup(path);
+ if (sb) {
+ qp->qp_rstat.qp_st_mode = sb->st_mode;
+ qp->qp_rstat.qp_st_uid = sb->st_uid;
+ qp->qp_rstat.qp_st_gid = sb->st_gid;
+ qp->qp_rstat.qp_st_size = sb->st_size;
+ }
+ return qp;
+}
+
+/*
+ * Packet deallocation functions
+ */
+#define condfree(x) if (x) { free(x); }
+void
+free_qp_hello(struct qa_packet *qp)
+{
+ condfree(qp->qp_hello.qp_greeting);
+}
+
+void
+free_qp_returncode(struct qa_packet *qp)
+{
+ condfree(qp->qp_returncode.qp_strerror);
+}
+void
+free_qp_runcmd(struct qa_packet *qp)
+{
+ condfree(qp->qp_runcmd.qp_cmdline);
+}
+
+void
+free_qp_setuser(struct qa_packet *qp)
+{
+ condfree(qp->qp_setuser.qp_user);
+ condfree(qp->qp_setuser.qp_group);
+}
+
+void
+free_qp_recvfile(struct qa_packet *qp)
+{
+ condfree(qp->qp_recvfile.qp_path);
+}
+
+void
+free_qp_sendfile(struct qa_packet *qp)
+{
+ condfree(qp->qp_sendfile.qp_path);
+}
+
+void
+free_qp_rstat(struct qa_packet *qp)
+{
+ condfree(qp->qp_rstat.qp_path);
+}
+
+
+void
+qpfree(struct qa_packet *qp)
+{
+ if (qp) {
+ if (qa_pi[qp->qp_type].pi_free) {
+ qa_pi[qp->qp_type].pi_free(qp);
+ }
+ free(qp);
+ }
+}
+#undef condfree
+
+/*
+ * Packet printing functions
+ *
+ * For printing out packets for debugging purposes
+ */
+void
+dump_qp_ack(struct qa_packet *qp)
+{
+ printf("\t%s #%d\n", QP_NAME(qp->qp_ack.qp_ack_type),
+ qp->qp_ack.qp_ack_seq);
+}
+
+void
+dump_qp_runcmd(struct qa_packet *qp)
+{
+ printf("\tcmdline: %s\n", qp->qp_runcmd.qp_cmdline);
+}
+
+void
+dump_qp_returncode(struct qa_packet *qp)
+{
+ printf("\trc: %d\n", qp->qp_returncode.qp_rc);
+}
+
+void
+dump_qp_cmdexit(struct qa_packet *qp)
+{
+ if (WIFEXITED(qp->qp_cmdexit.qp_status)) {
+ printf("\texited: %d\n", WEXITSTATUS(qp->qp_cmdexit.qp_status));
+ } else if (WIFSIGNALED(qp->qp_cmdexit.qp_status)) {
+ printf("\tsignaled: %d\n", WTERMSIG(qp->qp_cmdexit.qp_status));
+ } else {
+ printf("\tstatus: %d\n", qp->qp_cmdexit.qp_status);
+ }
+}
+
+void
+dump_qp_setuser(struct qa_packet *qp)
+{
+ printf("\tuser: %s\n", qp->qp_setuser.qp_user);
+ printf("\tgroup: %s\n", qp->qp_setuser.qp_group);
+}
+
+void
+dump_qp_kill(struct qa_packet *qp)
+{
+ printf("\tsig: %d\n", qp->qp_kill.qp_sig);
+}
+
+void
+dump_qp_recvfile(struct qa_packet *qp)
+{
+ printf("\tpath: %s\n", qp->qp_recvfile.qp_path);
+ printf("\tif_port: %d\n", qp->qp_recvfile.qp_if_port);
+ printf("\tcount: %d\n", qp->qp_recvfile.qp_count);
+ printf("\tmode: %o\n", qp->qp_recvfile.qp_mode);
+}
+
+void
+dump_qp_sendfile(struct qa_packet *qp)
+{
+ printf("\tpath: %s\n", qp->qp_sendfile.qp_path);
+ printf("\tof_port: %d\n", qp->qp_sendfile.qp_of_port);
+ printf("\tcount: %d\n", qp->qp_sendfile.qp_count);
+}
+
+void
+dump_qp_rstat(struct qa_packet *qp)
+{
+ printf("\tpath: %s\n", qp->qp_rstat.qp_path);
+ printf("\tst_mode: %o\n", qp->qp_rstat.qp_st_mode);
+ printf("\tst_uid: %d\n", qp->qp_rstat.qp_st_uid);
+ printf("\tst_gid: %d\n", qp->qp_rstat.qp_st_gid);
+ printf("\tst_size: %ld\n", qp->qp_rstat.qp_st_size);
+}
+
+void
+dump_qp(struct qa_packet *qp)
+{
+ printf("%s #%d\n", QP_NAME(qp->qp_type), qp->qp_seq);
+ if (qa_pi[qp->qp_type].pi_dump) {
+ qa_pi[qp->qp_type].pi_dump(qp);
+ }
+}