[dm-devel] [PATCH 3/6] dm raid45 target: introduce message parser

heinzm at redhat.com heinzm at redhat.com
Mon Jun 15 17:21:11 UTC 2009


This patch adds the dm-message parser module.

Heinz

 drivers/md/{dm-message.h.orig => dm-message.h} |   91 ++++++++++++++++++++++++
 1 files changed, 91 insertions(+), 0 deletions(-)

diff --git a/drivers/md/dm-message.h.orig b/drivers/md/dm-message.h
index e69de29..2024534 100644
--- a/drivers/md/dm-message.h.orig
+++ b/drivers/md/dm-message.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2007,2008 Red Hat, Inc. All rights reserved.
+ *
+ * Module Author: Heinz Mauelshagen <Mauelshagen at RedHat.de>
+ *
+ * General device-mapper message interface argument parser.
+ *
+ * This file is released under the GPL.
+ *
+ */
+
+#ifndef DM_MESSAGE_H
+#define DM_MESSAGE_H
+
+/* Factor out to dm.h. */
+/* Reference to array end. */
+#define ARRAY_END(a)    ((a) + ARRAY_SIZE(a))
+
+/* Message return bits. */
+enum dm_message_return {
+	dm_msg_ret_ambiguous,		/* Action ambiguous. */
+	dm_msg_ret_inval,		/* Action invalid. */
+	dm_msg_ret_undef,		/* Action undefined. */
+
+	dm_msg_ret_option,		/* Option error. */
+	dm_msg_ret_arg,			/* Argument error. */
+	dm_msg_ret_argcount,		/* Argument count error. */
+};
+
+/* Message argument type conversions. */
+enum dm_message_argument_type {
+	dm_msg_base_t,		/* Basename string. */
+	dm_msg_str_t,		/* String. */
+	dm_msg_int_t,		/* Signed int. */
+	dm_msg_uint_t,		/* Unsigned int. */
+	dm_msg_uint64_t,	/* Unsigned int 64. */
+};
+
+/* A message option. */
+struct dm_message_option {
+	unsigned num_options;
+	char **options;
+	unsigned long *actions;
+};
+
+/* Message arguments and types. */
+struct dm_message_argument {
+	unsigned num_args;
+	unsigned long **ptr;
+	enum dm_message_argument_type types[];
+};
+
+/* Client message. */
+struct dm_msg {
+	unsigned long action;		/* Identified action. */
+	unsigned long ret;		/* Return bits. */
+	unsigned num_specs;		/* # of sepcifications listed. */
+	struct dm_msg_spec *specs;	/* Specification list. */
+	struct dm_msg_spec *spec;	/* Specification selected. */
+};
+
+/* Secification of the message. */
+struct dm_msg_spec {
+	const char *cmd;	/* Name of the command (i.e. 'bandwidth'). */
+	unsigned long action;
+	struct dm_message_option *options;
+	struct dm_message_argument *args;
+	unsigned long parm;	/* Parameter to pass through to callback. */
+	/* Function to process for action. */
+	int (*f) (struct dm_msg *msg, void *context);
+};
+
+/* Parameter access macros. */
+#define	DM_MSG_PARM(msg) ((msg)->spec->parm)
+
+#define	DM_MSG_STR_ARGS(msg, idx) ((char *) *(msg)->spec->args->ptr[idx])
+#define	DM_MSG_INT_ARGS(msg, idx) ((int) *(msg)->spec->args->ptr[idx])
+#define	DM_MSG_UINT_ARGS(msg, idx) ((unsigned) DM_MSG_INT_ARG(msg, idx))
+#define	DM_MSG_UINT64_ARGS(msg, idx) ((uint64_t)  *(msg)->spec->args->ptr[idx])
+
+#define	DM_MSG_STR_ARG(msg)	DM_MSG_STR_ARGS(msg, 0)
+#define	DM_MSG_INT_ARG(msg)	DM_MSG_INT_ARGS(msg, 0)
+#define	DM_MSG_UINT_ARG(msg)	DM_MSG_UINT_ARGS(msg, 0)
+#define	DM_MSG_UINT64_ARG(msg)	DM_MSG_UINT64_ARGS(msg, 0)
+
+
+/* Parse a message and its options and optionally call a function back. */
+int dm_message_parse(const char *caller, struct dm_msg *msg, void *context,
+		     int argc, char **argv);
+
+#endif
 drivers/md/{dm-message.c.orig => dm-message.c} |  183 ++++++++++++++++++++++++
 1 files changed, 183 insertions(+), 0 deletions(-)

diff --git a/drivers/md/dm-message.c.orig b/drivers/md/dm-message.c
index e69de29..a66b015 100644
--- a/drivers/md/dm-message.c.orig
+++ b/drivers/md/dm-message.c
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2007,2008 Red Hat Inc. All rights reserved.
+ *
+ * Module Author: Heinz Mauelshagen <heinzm at redhat.com>
+ *
+ * General device-mapper message interface argument parser.
+ *
+ * This file is released under the GPL.
+ *
+ * device-mapper message parser.
+ *
+ */
+
+#include "dm.h"
+#include "dm-message.h"
+#include <linux/kernel.h>
+
+#define DM_MSG_PREFIX	"dm_message"
+
+/* Basename of a path. */
+static inline char *
+basename(char *s)
+{
+	char *p = strrchr(s, '/');
+
+	return p ? p + 1 : s;
+}
+
+/* Get an argument depending on type. */
+static void
+message_arguments(struct dm_msg *msg, int argc, char **argv)
+{
+
+	if (argc) {
+		int i;
+		struct dm_message_argument *args = msg->spec->args;
+
+		for (i = 0; i < args->num_args; i++) {
+			int r;
+			unsigned long **ptr = args->ptr;
+			enum dm_message_argument_type type = args->types[i];
+
+			switch (type) {
+			case dm_msg_base_t:
+				((char **) ptr)[i] = basename(argv[i]);
+				break;
+
+			case dm_msg_str_t:
+				((char **) ptr)[i] = argv[i];
+				break;
+
+			case dm_msg_int_t:
+				r = sscanf(argv[i], "%d", ((int **) ptr)[i]);
+				goto check;
+
+			case dm_msg_uint_t:
+				r = sscanf(argv[i], "%u",
+					   ((unsigned **) ptr)[i]);
+				goto check;
+
+			case dm_msg_uint64_t:
+				r = sscanf(argv[i], "%llu",
+					   ((unsigned long long **) ptr)[i]);
+
+check:
+				if (r != 1) {
+					set_bit(dm_msg_ret_undef, &msg->ret);
+					set_bit(dm_msg_ret_arg, &msg->ret);
+				}
+			}
+		}
+	}
+}
+
+/* Parse message options. */
+static void
+message_options_parse(struct dm_msg *msg, int argc, char **argv)
+{
+	int hit = 0;
+	unsigned long *action;
+	size_t l1 = strlen(*argv), l_hit = 0;
+	struct dm_message_option *o = msg->spec->options;
+	char **option, **option_end = o->options + o->num_options;
+
+	for (option = o->options, action = o->actions;
+	     option < option_end; option++, action++) {
+		size_t l2 = strlen(*option);
+
+		if (!strnicmp(*argv, *option, min(l1, l2))) {
+			hit++;
+			l_hit = l2;
+			set_bit(*action, &msg->action);
+		}
+	}
+
+	/* Assume error. */
+	msg->ret = 0;
+	set_bit(dm_msg_ret_option, &msg->ret);
+	if (!hit || l1 > l_hit)
+		set_bit(dm_msg_ret_undef, &msg->ret);	/* Undefined option. */
+	else if (hit > 1)
+		set_bit(dm_msg_ret_ambiguous, &msg->ret); /* Ambiguous option.*/
+	else {
+		clear_bit(dm_msg_ret_option, &msg->ret); /* Option OK. */
+		message_arguments(msg, --argc, ++argv);
+	}
+}
+
+static inline void
+print_ret(const char *caller, unsigned long ret)
+{
+	struct {
+		unsigned long err;
+		const char *err_str;
+	} static err_msg[] = {
+		{ dm_msg_ret_ambiguous, "message ambiguous" },
+		{ dm_msg_ret_inval, "message invalid" },
+		{ dm_msg_ret_undef, "message undefined" },
+		{ dm_msg_ret_arg, "message argument" },
+		{ dm_msg_ret_argcount, "message argument count" },
+		{ dm_msg_ret_option, "option" },
+	}, *e = ARRAY_END(err_msg);
+
+	while (e-- > err_msg) {
+		if (test_bit(e->err, &ret))
+			DMERR("%s %s", caller, e->err_str);
+	}
+}
+
+/* Parse a message action. */
+int
+dm_message_parse(const char *caller, struct dm_msg *msg, void *context,
+		 int argc, char **argv)
+{
+	int hit = 0;
+	size_t l1, l_hit = 0;
+	struct dm_msg_spec *s, *s_hit = NULL,
+			   *s_end = msg->specs + msg->num_specs;
+
+	if (argc < 2)
+		return -EINVAL;
+
+	l1 = strlen(*argv);
+	for (s = msg->specs; s < s_end; s++) {
+		size_t l2 = strlen(s->cmd);
+
+		if (!strnicmp(*argv, s->cmd, min(l1, l2))) {
+			hit++;
+			l_hit = l2;
+			s_hit = s;
+		}
+	}
+
+	msg->ret = 0;
+	if (!hit || l1 > l_hit)	/* No hit or message string too long. */
+		set_bit(dm_msg_ret_undef, &msg->ret);
+	else if (hit > 1)	/* Ambiguous message. */
+		set_bit(dm_msg_ret_ambiguous, &msg->ret);
+	else if (argc - 2 != s_hit->args->num_args) {
+		set_bit(dm_msg_ret_undef, &msg->ret);
+		set_bit(dm_msg_ret_argcount, &msg->ret);
+	}
+
+	if (msg->ret)
+		goto bad;
+
+	msg->action = 0;
+	msg->spec = s_hit;
+	set_bit(s_hit->action, &msg->action);
+	message_options_parse(msg, --argc, ++argv);
+
+	if (!msg->ret)
+		return msg->spec->f(msg, context);
+
+bad:
+	print_ret(caller, msg->ret);
+	return -EINVAL;
+}
+EXPORT_SYMBOL(dm_message_parse);
+
+MODULE_DESCRIPTION(DM_NAME " device-mapper target message parser");
+MODULE_AUTHOR("Heinz Mauelshagen <hjm at redhat.com>");
+MODULE_LICENSE("GPL");




More information about the dm-devel mailing list