[Ocfs2-tools-devel] [PATCH 25/39] o2cb client: Add the query messages

Joel Becker joel.becker at oracle.com
Fri Mar 14 16:52:48 PDT 2008


The "LISTCLUSTERS", "LISTMOUNTS", and "LISTFS" messages are added to
client_proto.c.  The receive_list() helper is added to client_proto.c as
well, and test_client is taught to send LISTCLUSTERS and read the
response.  ocfs2_controld.cman also learns how to respond to
LISTCLUSTERS.

Signed-off-by: Joel Becker <joel.becker at oracle.com>
---
 include/o2cb/o2cb_client_proto.h |   12 ++-
 libo2cb/client_proto.c           |  187 +++++++++++++++++++++++++++++++++++++-
 ocfs2_controld/cman.c            |   23 ++++-
 ocfs2_controld/main.c            |   74 +++++++++++++++
 ocfs2_controld/mount.c           |   46 +++++++++
 ocfs2_controld/ocfs2_controld.h  |    2 +
 ocfs2_controld/test_client.c     |  105 +++++++++++++++++-----
 7 files changed, 418 insertions(+), 31 deletions(-)

diff --git a/include/o2cb/o2cb_client_proto.h b/include/o2cb/o2cb_client_proto.h
index 61df7c3..b459223 100644
--- a/include/o2cb/o2cb_client_proto.h
+++ b/include/o2cb/o2cb_client_proto.h
@@ -25,8 +25,6 @@
 #ifndef __O2CB_CLIENT_PROTO_H
 #define __O2CB_CLIENT_PROTO_H
 
-#ifdef HAVE_CMAN
-
 /* Basic communication properties */
 #define OCFS2_CONTROLD_MAXLINE		256
 #define OCFS2_CONTROLD_MAXARGS		16
@@ -39,6 +37,11 @@ typedef enum {
 	CM_MRESULT,
 	CM_UNMOUNT,
 	CM_STATUS,
+	CM_LISTFS,
+	CM_LISTMOUNTS,
+	CM_LISTCLUSTERS,
+	CM_ITEMCOUNT,
+	CM_ITEM,
 } client_message;
 
 int client_listen(const char *path);
@@ -60,7 +63,8 @@ int receive_message(int fd, char *buf, client_message *message,
 		    char **argv);
 int receive_message_full(int fd, char *buf, client_message *message,
 			 char **argv, char **rest);
-
-#endif  /* HAVE_CMAN */
+void free_received_list(char **list);
+int receive_list(int fd, char *buf, char ***ret_list);
+int parse_status(char **args, int *error, char **error_msg);
 
 #endif  /* __O2CB_CLIENT_PROTO_H */
diff --git a/libo2cb/client_proto.c b/libo2cb/client_proto.c
index a152cfa..0811010 100644
--- a/libo2cb/client_proto.c
+++ b/libo2cb/client_proto.c
@@ -10,6 +10,7 @@
 
 #include <stdio.h>
 #include <string.h>
+#include <stdlib.h>
 #include <stdarg.h>
 #include <unistd.h>
 #include <errno.h>
@@ -39,6 +40,11 @@ DEFINE_MESSAGE(MOUNT, 5, "%s %s %s %s %s")
 DEFINE_MESSAGE(MRESULT, 4, "%s %s %d %s")
 DEFINE_MESSAGE(UNMOUNT, 3, "%s %s %s")
 DEFINE_MESSAGE(STATUS, 2, "%d %s")
+DEFINE_MESSAGE(LISTFS, 2, "%s %s")
+DEFINE_MESSAGE(LISTMOUNTS, 2, "%s %s")
+DEFINE_MESSAGE(LISTCLUSTERS, 0, "")
+DEFINE_MESSAGE(ITEMCOUNT, 1, "%u")
+DEFINE_MESSAGE(ITEM, 1, "%s")
 END_MESSAGES(message_list)
 
 const char *message_to_string(client_message message)
@@ -93,6 +99,7 @@ static int full_write(int fd, void *buf, size_t count)
 int send_message(int fd, client_message message, ...)
 {
 	int rc;
+	size_t len;
 	va_list args;
 	char mbuf[OCFS2_CONTROLD_MAXLINE];
 
@@ -101,6 +108,14 @@ int send_message(int fd, client_message message, ...)
 	rc = vsnprintf(mbuf, OCFS2_CONTROLD_MAXLINE,
 		       message_list[message].cm_format, args);
 	va_end(args);
+
+	/* Remove the trailing space from zero-argument messages */
+	if (!message_list[message].cm_argcount) {
+		len = strlen(mbuf);
+		if (mbuf[len - 1] == ' ')
+			mbuf[len - 1] = '\0';
+	}
+
 	if (rc >= OCFS2_CONTROLD_MAXLINE)
 		rc = -E2BIG;
 	else
@@ -169,7 +184,7 @@ int receive_message_full(int fd, char *buf, client_message *message,
 	for (i = 0; i < message_list_len; i++) {
 		len = strlen(message_list[i].cm_command);
 		if (!strncmp(buf, message_list[i].cm_command, len) &&
-		    (buf[len] == ' '))
+		    ((buf[len] == ' ') || (buf[len] == '\0')))
 			break;
 	}
 	if (i >= message_list_len) {
@@ -200,6 +215,176 @@ int receive_message(int fd, char *buf, client_message *message, char **argv)
 	return receive_message_full(fd, buf, message, argv, NULL);
 }
 
+static int parse_itemcount(char **args, unsigned int *count)
+{
+	int rc = 0;
+	unsigned long n;
+	char *ptr = NULL;
+
+	n = strtoul(args[0], &ptr, 10);
+	if (ptr && *ptr != '\0') {
+		fprintf(stderr, "Invalid error code string: %s", args[0]);
+		rc = -EINVAL;
+	} else if ((n == LONG_MAX) || (n > UINT_MAX)) {
+		fprintf(stderr, "Item count %lu out of range", n);
+		rc = -ERANGE;
+	} else {
+		*count = n;
+	}
+
+	return rc;
+}
+
+int parse_status(char **args, int *error, char **error_msg)
+{
+	int rc = 0;
+	long err;
+	char *ptr = NULL;
+
+	err = strtol(args[0], &ptr, 10);
+	if (ptr && *ptr != '\0') {
+		fprintf(stderr, "Invalid error code string: %s", args[0]);
+		rc = -EINVAL;
+	} else if ((err == LONG_MIN) || (err == LONG_MAX) ||
+		   (err < INT_MIN) || (err > INT_MAX)) {
+		fprintf(stderr, "Error code %ld out of range", err);
+		rc = -ERANGE;
+	} else {
+		*error_msg = args[1];
+		*error = err;
+	}
+
+	return rc;
+}
+
+
+/*
+ * A list is sent as
+ *
+ * ITEMCOUNT <count>
+ * ITEM <item>
+ *   x <count>
+ * STATUS 0 OK
+ *
+ * If there are errors in the middle, we'll get a STATUS error.
+ */
+int receive_list(int fd, char *buf, char ***ret_list)
+{
+	int rc, done = 0;
+	int error;
+	unsigned int count = 0, seen = 0;
+	char *error_msg;
+	client_message message;
+	char **list = NULL;
+	char *argv[OCFS2_CONTROLD_MAXARGS + 1];
+
+	/*
+	 * States are simple.  If list==NULL, we haven't gotten ITEMCOUNT
+	 * yet.  If list!=NULL and seen<count, we haven't gotten all of
+	 * our items yet.  Once list!=NULL and seen==count, we're ready for
+	 * our STATUS.
+	 */
+	while (!done) {
+		rc = receive_message(fd, buf, &message, argv);
+		if (rc < 0)
+			break;
+
+		switch (message) {
+			case CM_STATUS:
+				rc = parse_status(argv, &error, &error_msg);
+				if (rc) {
+					fprintf(stderr, "Bad status message: %s\n",
+						strerror(-rc));
+				} else if (error) {
+					rc = -error;
+					fprintf(stderr,
+						"Error %d from daemon: %s\n",
+						error, error_msg);
+				} else if (!list || (seen < count)) {
+					rc = -EINVAL;
+					fprintf(stderr,
+						"Unexpected STATUS 0 from daemon\n");
+				} else
+					done = 1;  /* Got it */
+				break;
+
+			case CM_ITEMCOUNT:
+				if (list) {
+					rc = -EINVAL;
+					fprintf(stderr,
+						"Unexpected itemcount\n");
+					break;
+				}
+
+				rc = parse_itemcount(argv, &count);
+				if (rc) {
+					fprintf(stderr, "Bad itemcount message: %s\n",
+						strerror(-rc));
+					break;
+				}
+
+				list = malloc(sizeof(char *) * (count + 1));
+				if (!list)
+					rc = -ENOMEM;
+				else
+					memset(list, 0,
+					       sizeof(char *) * (count + 1));
+				break;
+
+			case CM_ITEM:
+				if (!argv[0]) {
+					rc = -EINVAL;
+					fprintf(stderr,
+						"Bad item message\n");
+				} else if (!argv[0][0]) {
+					rc = -EINVAL;
+					fprintf(stderr,
+						"Empty item message\n");
+				} else if (seen >= count) {
+					rc = -E2BIG;
+					fprintf(stderr,
+						"Too many items!\n");
+				} else {
+					list[seen] = strdup(argv[0]);
+					if (!list[seen])
+						rc = -ENOMEM;
+					else
+						seen++;
+				}
+				break;
+
+		default:
+				rc = -EINVAL;
+				fprintf(stderr,
+					"Unexpected message %s from daemon\n",
+					message_to_string(message));
+				break;
+		}
+
+		if (rc)
+			done = 1;
+	}
+
+	if (!rc) {
+		if (ret_list)
+			*ret_list = list;
+	} else if (list) {
+		for (seen = 0; list[seen]; seen++)
+			free(list[seen]);
+		free(list);
+	}
+	return rc;
+}
+
+void free_received_list(char **list)
+{
+	int i;
+
+	for (i = 0; list[i]; i++)
+		free(list[i]);
+	free(list);
+}
+
 int client_listen(const char *path)
 {
 	struct sockaddr_un addr;
diff --git a/ocfs2_controld/cman.c b/ocfs2_controld/cman.c
index c5950e1..f2eb54f 100644
--- a/ocfs2_controld/cman.c
+++ b/ocfs2_controld/cman.c
@@ -37,9 +37,9 @@
 #include "ocfs2_controld.h"
 
 int			our_nodeid;
-int			cman_ci;
-char *			clustername;
-cman_cluster_t		cluster;
+static int		cman_ci;
+static char *		clustername;
+static cman_cluster_t	cluster;
 static cman_handle_t	ch;
 static cman_handle_t	ch_admin;
 extern struct list_head mounts;
@@ -118,6 +118,23 @@ int validate_cluster(const char *cluster)
 	return !strcmp(cluster, clustername);
 }
 
+int get_clustername(const char **cluster)
+{
+	if (!clustername) {
+		log_error("Trying to validate before cman is alive");
+		return -EIO;
+	}
+
+	if (!cluster) {
+		log_error("NULL passed!");
+		return -EINVAL;
+	}
+
+	*cluster = clustername;
+	return 0;
+}
+
+
 /* keep track of the nodes */
 static void statechange(void)
 {
diff --git a/ocfs2_controld/main.c b/ocfs2_controld/main.c
index 2cc8d01..246af07 100644
--- a/ocfs2_controld/main.c
+++ b/ocfs2_controld/main.c
@@ -374,6 +374,72 @@ static int dump_debug(int ci)
 	return 0;
 }
 
+static int send_filesystems(int ci, int fd, const char *fstype,
+			    const char *cluster)
+{
+	char *error_msg;
+
+	if (!fstype || strcmp(fstype, OCFS2_FS_NAME)) {
+		error_msg = "Invalid filesystem type";
+		goto fail;
+	}
+
+	if (!validate_cluster(cluster)) {
+		error_msg = "Invalid cluster name";
+		goto fail;
+	}
+
+	return send_mountgroups(ci, fd);
+
+fail:
+	return send_message(fd, CM_STATUS, EINVAL, error_msg);
+}
+
+static int send_clustername(int ci, int fd)
+{
+	int rc = 0, rctmp;
+	char error_msg[100];  /* Arbitrary size smaller than a message */
+	const char *cluster;
+
+	rc = get_clustername(&cluster);
+	if (rc) {
+		snprintf(error_msg, sizeof(error_msg),
+			 "Unable to query cluster name: %s",
+			 strerror(-rc));
+		goto out_status;
+	}
+
+	/* Cman only supports one cluster */
+	rc = send_message(fd, CM_ITEMCOUNT, 1);
+	if (rc) {
+		snprintf(error_msg, sizeof(error_msg),
+			 "Unable to send ITEMCOUNT: %s",
+			 strerror(-rc));
+		goto out_status;
+	}
+
+	rc = send_message(fd, CM_ITEM, cluster);
+	if (rc) {
+		snprintf(error_msg, sizeof(error_msg),
+			 "Unable to send ITEM: %s",
+			 strerror(-rc));
+		goto out_status;
+	}
+
+	strcpy(error_msg, "OK");
+
+out_status:
+	rctmp = send_message(fd, CM_STATUS, -rc, error_msg);
+	if (rctmp) {
+		log_error("Error sending STATUS message: %s",
+			  strerror(-rc));
+		if (!rc)
+			rc = rctmp;
+	}
+
+	return rc;
+}
+
 static void dead_client(int ci)
 {
 	dead_mounter(ci, client[ci].fd);
@@ -420,6 +486,14 @@ static void process_client(int ci)
 		rv = do_unmount(ci, fd, argv[0], argv[1], argv[2]);
 		break;
 
+		case CM_LISTCLUSTERS:
+		rv = send_clustername(ci, fd);
+		break;
+
+		case CM_LISTFS:
+		rv = send_filesystems(ci, fd, argv[0], argv[1]);
+		break;
+
 		case CM_STATUS:
 		log_error("Someone sent us cm_status!");
 		break;
diff --git a/ocfs2_controld/mount.c b/ocfs2_controld/mount.c
index 04617f9..7f0ece2 100644
--- a/ocfs2_controld/mount.c
+++ b/ocfs2_controld/mount.c
@@ -785,6 +785,52 @@ void dead_mounter(int ci, int fd)
 	 */
 }
 
+int send_mountgroups(int ci, int fd)
+{
+	unsigned int count = 0;
+	int rc = 0, rctmp;
+	char error_msg[100];  /* Arbitrary size smaller than a message */
+	struct list_head *p;
+	struct mountgroup *mg;
+
+	list_for_each(p, &mounts) {
+		count++;
+	}
+
+	rc = send_message(fd, CM_ITEMCOUNT, count);
+	if (rc) {
+		snprintf(error_msg, sizeof(error_msg),
+			 "Unable to send ITEMCOUNT: %s",
+			 strerror(-rc));
+		goto out_status;
+	}
+
+	list_for_each(p, &mounts) {
+		mg = list_entry(p, struct mountgroup, mg_list);
+		rc = send_message(fd, CM_ITEM, mg->mg_uuid);
+		if (rc) {
+			snprintf(error_msg, sizeof(error_msg),
+				 "Unable to send ITEM: %s",
+				 strerror(-rc));
+			goto out_status;
+		}
+	}
+
+	strcpy(error_msg, "OK");
+
+out_status:
+	log_debug("Sending status %d \"%s\"", -rc, error_msg);
+	rctmp = send_message(fd, CM_STATUS, -rc, error_msg);
+	if (rctmp) {
+		log_error("Error sending STATUS message: %s",
+			  strerror(-rc));
+		if (!rc)
+			rc = rctmp;
+	}
+
+	return rc;
+}
+
 void init_mounts(void)
 {
 	INIT_LIST_HEAD(&mounts);
diff --git a/ocfs2_controld/ocfs2_controld.h b/ocfs2_controld/ocfs2_controld.h
index be27490..6c6e77d 100644
--- a/ocfs2_controld/ocfs2_controld.h
+++ b/ocfs2_controld/ocfs2_controld.h
@@ -64,6 +64,7 @@ void shutdown_daemon(void);
 int setup_cman(void);
 char *nodeid2name(int nodeid);
 int validate_cluster(const char *cluster);
+int get_clustername(const char **cluster);
 int kill_cman(int nodeid);
 void exit_cman(void);
 
@@ -90,5 +91,6 @@ int complete_mount(int ci, int fd, const char *uuid, const char *errcode,
 int remove_mount(int ci, int fd, const char *uuid, const char *mountpoint);
 void dead_mounter(int ci, int fd);
 void bail_on_mounts(void);
+int send_mountgroups(int ci, int fd);
 
 #endif
diff --git a/ocfs2_controld/test_client.c b/ocfs2_controld/test_client.c
index 33147a9..aaa5eed 100644
--- a/ocfs2_controld/test_client.c
+++ b/ocfs2_controld/test_client.c
@@ -21,29 +21,6 @@
 #include "o2cb/o2cb_client_proto.h"
 
 
-
-static int parse_status(char **args, int *error, char **error_msg)
-{
-	int rc = 0;
-	long err;
-	char *ptr = NULL;
-
-	err = strtol(args[0], &ptr, 10);
-	if (ptr && *ptr != '\0') {
-		fprintf(stderr, "Invalid error code string: %s", args[0]);
-		rc = -EINVAL;
-	} else if ((err == LONG_MIN) || (err == LONG_MAX) ||
-		   (err < INT_MIN) || (err > INT_MAX)) {
-		fprintf(stderr, "Error code %ld out of range", err);
-		rc = -ERANGE;
-	} else {
-		*error_msg = args[1];
-		*error = err;
-	}
-
-	return rc;
-}
-
 static errcode_t fill_uuid(const char *device, char *uuid)
 {
 	errcode_t err;
@@ -255,9 +232,67 @@ out:
 	return rc;
 }
 
+static int call_listclusters(int fd)
+{
+	int rc, i;
+	char **list;
+	char buf[OCFS2_CONTROLD_MAXLINE];
+
+	rc = send_message(fd, CM_LISTCLUSTERS);
+	if (rc) {
+		fprintf(stderr, "Unable to send LISTCLUSTERS message: %s\n",
+			strerror(-rc));
+		goto out;
+	}
+
+	rc = receive_list(fd, buf, &list);
+	if (rc < 0) {
+		fprintf(stderr, "Error reading from daemon: %s\n",
+			strerror(-rc));
+		goto out;
+	}
+
+	for (i = 0; list[i]; i++)
+		fprintf(stderr, "%s\n", list[i]);
+	free_received_list(list);
+
+out:
+	return rc;
+}
+
+static int call_listfs(int fd, const char *cluster)
+{
+	int rc, i;
+	char **list;
+	char buf[OCFS2_CONTROLD_MAXLINE];
+
+	rc = send_message(fd, CM_LISTFS, OCFS2_FS_NAME, cluster);
+	if (rc) {
+		fprintf(stderr, "Unable to send LISTFS message: %s\n",
+			strerror(-rc));
+		goto out;
+	}
+
+	rc = receive_list(fd, buf, &list);
+	if (rc < 0) {
+		fprintf(stderr, "Error reading from daemon: %s\n",
+			strerror(-rc));
+		goto out;
+	}
+
+	for (i = 0; list[i]; i++)
+		fprintf(stderr, "%s\n", list[i]);
+	free_received_list(list);
+
+out:
+	return rc;
+}
+
 enum {
 	OP_MOUNT,
 	OP_UMOUNT,
+	OP_LISTCLUSTERS,
+	OP_LISTFS,
 };
 static int parse_options(int argc, char **argv, int *op, char ***args)
 {
@@ -284,6 +319,22 @@ static int parse_options(int argc, char **argv, int *op, char ***args)
 			fprintf(stderr, "Invalid number of arguments\n");
 			rc = -EINVAL;
 		}
+	} else if (!strcmp(argv[1], "listclusters")) {
+		if (argc == 2) {
+			*op = OP_LISTCLUSTERS;
+			*args = argv + 2;
+		} else {
+			fprintf(stderr, "Invalid number of arguments\n");
+			rc = -EINVAL;
+		}
+	} else if (!strcmp(argv[1], "listfs")) {
+		if (argc == 3) {
+			*op = OP_LISTFS;
+			*args = argv + 2;
+		} else {
+			fprintf(stderr, "Invalid number of arguments\n");
+			rc = -EINVAL;
+		}
 	} else {
 		fprintf(stderr, "Invalid operation: %s\n", argv[1]);
 		rc = -EINVAL;
@@ -319,6 +370,14 @@ int main(int argc, char **argv)
 			rc = call_unmount(fd, args[0], args[1]);
 			break;
 
+		case OP_LISTCLUSTERS:
+			rc = call_listclusters(fd);
+			break;
+
+		case OP_LISTFS:
+			rc = call_listfs(fd, args[0]);
+			break;
+
 		default:
 			fprintf(stderr, "Can't get here!\n");
 			rc = -ENOTSUP;
-- 
1.5.3.8




More information about the Ocfs2-tools-devel mailing list