[Sheepdog] [PATCH] shepherd: refine command syntax

FUJITA Tomonori fujita.tomonori at lab.ntt.co.jp
Sat May 8 18:09:43 CEST 2010


As discussed, this makes the command syntax saner.

=
From: FUJITA Tomonori <fujita.tomonori at lab.ntt.co.jp>
Subject: [PATCH] shepherd: refine command syntax

fujita at rose:~/git/sheepdog$ ./shepherd/shepherd --help
Usage: shepherd command subcommand [options]
Sheepdog Administrator Utilty

Command syntax:
  cluster (info|format|shutdown)
  node (info|list)
  vdi (list|delete|object|lock|release)
  vm list

Common parameters:
  -p, --port              specify the daemon port
  -h, --help              display this help and exit

Signed-off-by: FUJITA Tomonori <fujita.tomonori at lab.ntt.co.jp>
---
 shepherd/shepherd.c | 1187 ++++++++++++++++++++++-----------------------------
 1 files changed, 518 insertions(+), 669 deletions(-)

diff --git a/shepherd/shepherd.c b/shepherd/shepherd.c
index 85a77a6..a63788e 100644
--- a/shepherd/shepherd.c
+++ b/shepherd/shepherd.c
@@ -34,61 +34,30 @@
 
 static char program_name[] = "shepherd";
 static int sdport = SD_LISTEN_PORT;
+static int highlight = 1;
 
-static struct option const long_options[] =
-{
-	{"port", required_argument, NULL, 'p'},
-	{"copies", required_argument, NULL, 'c'},
-	{"epoch", required_argument, NULL, 'e'},
-	{"index", required_argument, NULL, 'i'},
-	{"format", required_argument, NULL, 'f'},
-	{"type", required_argument, NULL, 't'},
-	{"highlight", required_argument, NULL, 'H'},
-	{"resident", required_argument, NULL, 'R'},
-	{"op", required_argument, NULL, 'o'},
-	{"help", no_argument, NULL, 'h'},
-	{NULL, 0, NULL, 0},
-};
+#define COMMON_LONG_OPTIONS				\
+	{"port", required_argument, NULL, 'p'},		\
+	{"help", no_argument, NULL, 'h'},		\
 
-static char *short_options = "p:f:rR:t:H:o:i:e:h";
-
-enum info_type {
-	INFO_VDI,
-	INFO_DOG,
-	INFO_SHEEP,
-	INFO_OBJ,
-	INFO_VM,
-	INFO_CLUSTER,
-	INFO_NONE,
-};
-
-enum format_type {
-	FORMAT_LIST,
-	FORMAT_TREE,
-	FORMAT_GRAPH,
-	FORMAT_NONE,
-};
+#define COMMON_SHORT_OPTIONS "p:h"
 
 static void usage(int status)
 {
 	if (status)
 		fprintf(stderr, "Try `%s --help' for more information.\n", program_name);
 	else {
-		printf("Usage: %s command [command options]\n", program_name);
+		printf("Usage: %s command subcommand [options]\n", program_name);
 		printf("Sheepdog Administrator Utilty\n\
 \n\
 Command syntax:\n\
-  mkfs [--copies=N]\n\
-  delete [-i snapshot_id] vdiname\n\
-  info -t (vdi|dog|sheep|obj|cluster) [-f (list|tree|graph)] [-H (on|off)] [-R (on|off)] [-i N] [-e N] [vdiname]\n\
-  debug -o node_version\n\
-  shutdown\n\
+  cluster (info|format|shutdown)\n\
+  node (info|list)\n\
+  vdi (list|delete|object|lock|release)\n\
+  vm list\n\
 \n\
-Command parameters:\n\
-  -f, --format            specify the output format\n\
-  -R, --resient           show in a dynamic real-time view\n\
-  -t, --type              specify the type of information\n\
-  -H, --highlight         highlight an important infomation\n\
+Common parameters:\n\
+  -p, --port              specify the daemon port\n\
   -h, --help              display this help and exit\n\
 ");
 	}
@@ -97,7 +66,7 @@ Command parameters:\n\
 
 static uint64_t node_list_version;
 
-static struct sheepdog_node_list_entry *node_list_entries;
+static struct sheepdog_node_list_entry node_list_entries[SD_MAX_NODES];
 static int nr_nodes;
 static unsigned master_idx;
 
@@ -214,13 +183,18 @@ out:
 	return ret;
 }
 
-static int mkfs(int copies)
+struct cluster_cmd_data {
+	int copies;
+} cluster_cmd_data;
+
+static int cluster_format(int argc, char **argv)
 {
 	int fd, ret;
 	struct sd_so_req hdr;
 	struct sd_so_rsp *rsp = (struct sd_so_rsp *)&hdr;
 	unsigned rlen, wlen;
 	struct timeval tv;
+	int copies = cluster_cmd_data.copies ? cluster_cmd_data.copies : 3;
 
 	fd = connect_to("localhost", sdport);
 	if (fd < 0)
@@ -262,179 +236,6 @@ static int mkfs(int copies)
 	return 0;
 }
 
-static int delete(char *data, uint32_t id)
-{
-	int fd, ret;
-	struct sd_vdi_req hdr;
-	struct sd_vdi_rsp *rsp = (struct sd_vdi_rsp *)&hdr;
-	unsigned rlen, wlen;
-	char vdiname[SD_MAX_VDI_LEN];
-
-	fd = connect_to("localhost", sdport);
-	if (fd < 0)
-		return -1;
-
-	memset(&hdr, 0, sizeof(hdr));
-
-	rlen = 0;
-	wlen = sizeof(vdiname);
-
-	hdr.opcode = SD_OP_DEL_VDI;
-	if (id != ~0)
-		hdr.snapid = id;
-	hdr.epoch = node_list_version;
-	hdr.flags = SD_FLAG_CMD_WRITE;
-	hdr.data_length = wlen;
-	strncpy(vdiname, data, sizeof(vdiname));
-
-	ret = exec_req(fd, (struct sd_req *)&hdr, vdiname, &wlen, &rlen);
-	close(fd);
-
-	if (ret != SD_RES_SUCCESS) {
-		fprintf(stderr, "failed to connect the dog\n");
-		return ret;
-	}
-
-	if (rsp->result != SD_RES_SUCCESS) {
-		switch (rsp->result) {
-		case SD_RES_VDI_LOCKED:
-			fprintf(stderr, "the vdi is locked\n");
-			break;
-		case SD_RES_NO_VDI:
-			fprintf(stderr, "no such vdi\n");
-			break;
-		default:
-			fprintf(stderr, "error, %d\n", rsp->result);
-			break;
-		}
-	}
-
-	return 0;
-}
-
-static int debug(char *op, char *arg)
-{
-	struct sd_req hdr;
-	struct sd_rsp *rsp = (struct sd_rsp *)&hdr;
-	int fd, ret;
-	char name[128];
-	unsigned rlen, wlen;
-	unsigned opcode, flags;
-	uint32_t vid = 0;
-	char vdiname[SD_MAX_VDI_LEN];
-
-	if (!op)
-		return 1;
-
-	memset(vdiname, 0, sizeof(vdiname));
-
-	strcpy(name, "localhost");
-
-	if (!strcasecmp(op, "node_version")) {
-		rlen = 0;
-		wlen = 0;
-		opcode = SD_OP_DEBUG_INC_NVER;
-		flags = 0;
-	} else if (!strcasecmp(op, "node")) {
-		if (!arg)
-			return 1;
-		rlen = 0;
-		wlen = strlen(arg);
-		opcode = SD_OP_DEBUG_SET_NODE;
-		flags = SD_FLAG_CMD_WRITE;
-	} else if (!strcasecmp(op, "lock_vdi")) {
-		if (!arg)
-			return 1;
-		rlen = 0;
-		strncpy(vdiname, arg, sizeof(vdiname));
-		wlen = sizeof(vdiname);
-		opcode = SD_OP_LOCK_VDI;
-		flags = SD_FLAG_CMD_WRITE;
-		arg = vdiname;
-	} else if (!strcasecmp(op, "release_vdi")) {
-		if (!arg)
-			return 1;
-		rlen = 0;
-		strncpy(vdiname, arg, sizeof(vdiname));
-		wlen = sizeof(vdiname);
-		opcode = SD_OP_RELEASE_VDI;
-		flags = SD_FLAG_CMD_WRITE;
-		arg = vdiname;
-	} else if (!strcasecmp(op, "vdi_info")) {
-		if (!arg)
-			return 1;
-		rlen = 0;
-		vid = strtoul(arg, NULL, 10);
-		if (vid == 0) {
-			wlen = strlen(arg) + 1;
-			opcode = SD_OP_GET_VDI_INFO;
-			flags = SD_FLAG_CMD_WRITE;
-		} else {
-			wlen = 0;
-			opcode = SD_OP_GET_EPOCH;
-			flags = 0;
-		}
-	} else if (!strcasecmp(op, "kill")) {
-		if (!arg) {
-			fprintf(stderr, "specify hostname\n");
-			return 1;
-		}
-		strcpy(name, arg);
-		rlen = 0;
-		wlen = 0;
-		opcode = SD_OP_DEBUG_KILL;
-		flags = 0;
-	} else
-		return 1;
-
-	fd = connect_to(name, sdport);
-	if (fd < 0)
-		return -1;
-
-	memset(&hdr, 0, sizeof(hdr));
-
-	hdr.opcode = opcode;
-	hdr.data_length = wlen;
-	hdr.flags = flags;
-	hdr.epoch = node_list_version;
-	if (vid > 0) {
-		((struct sd_vdi_req *)&hdr)->base_vdi_id = vid;
-	}
-
-	ret = exec_req(fd, &hdr, arg, &wlen, &rlen);
-	close(fd);
-
-	if (ret) {
-		fprintf(stderr, "communication error\n");
-		return ret;
-	}
-
-	if (rsp->result != SD_RES_SUCCESS) {
-		switch(rsp->result) {
-		case SD_RES_VDI_LOCKED:
-			fprintf(stderr, "%s is already locked\n", arg);
-			break;
-		case SD_RES_VDI_NOT_LOCKED:
-			fprintf(stderr, "%s is not locked\n", arg);
-			break;
-		case SD_RES_NO_VDI:
-			fprintf(stderr, "%s: no such vdi\n", arg);
-			break;
-		default:
-			fprintf(stderr, "error %d\n", rsp->result);
-			break;
-		}
-		return -1;
-	}
-
-	if (!strcasecmp(op, "vdi_info")) {
-		struct sd_vdi_rsp *vdi_rsp = (struct sd_vdi_rsp *)rsp;
-		printf("name = %s, vid = %"PRIu32", epoch = %d\n",
-		       arg, vdi_rsp->vdi_id, vdi_rsp->vdi_epoch);
-	}
-	return ret;
-}
-
 static int shutdown_sheepdog(void)
 {
 	int fd, ret;
@@ -475,13 +276,9 @@ static int shutdown_sheepdog(void)
 	return 0;
 }
 
-#define DIR_BUF_LEN (UINT64_C(1) << 20)
-
 typedef void (*vdi_parser_func_t)(uint32_t vid, char *name, uint32_t tag, uint32_t flags,
 				  struct sheepdog_inode *i, void *data);
 
-
-
 static int parse_vdi(vdi_parser_func_t func, void *data)
 {
 	int ret, fd;
@@ -528,127 +325,6 @@ static int parse_vdi(vdi_parser_func_t func, void *data)
 	return 0;
 }
 
-struct graph_info {
-	int64_t root;
-	char *name;
-	int highlight;
-};
-
-static void print_graph_tree(uint32_t vid, char *name, uint32_t tag,
-			     uint32_t flags, struct sheepdog_inode *i, void *data)
-{
-	struct graph_info *info = (struct graph_info *)data;
-	time_t ti;
-	struct tm tm;
-	char date[128];
-	char time[128];
-	char size_str[8];
-
-	if (info->name && strcmp(info->name, name) != 0)
-		return;
-
-	if (info->root < 0)
-		info->root = vid_to_vdi_oid(i->parent_vdi_id);
-
-	ti = i->ctime >> 32;
-	localtime_r(&ti, &tm);
-
-	strftime(date, sizeof(date), "%y-%m-%d", &tm);
-	strftime(time, sizeof(time), "%H:%M:%S", &tm);
-	size_to_str(i->vdi_size, size_str, sizeof(size_str));
-
-	printf("  \"%" PRIu32 "\" [shape = \"box\","
-	       "fontname = \"Courier\","
-	       "fontsize = \"12\","
-	       "group = \"%s\","
-	       "label = \"",
-	       vid, name);
-	printf("name: %8s\\n"
-	       "tag : %8x\\n"
-	       "size: %8s\\n"
-	       "date: %8s\\n"
-	       "time: %8s",
-	       name, tag, size_str, date, time);
-
-	if (info->highlight && is_current(i))
-		printf("\", color=\"red\"];\n");
-	else
-		printf("\"];\n");
-
-	printf("  \"%" PRIu32 "\" -> \"%" PRIu32 "\";\n", i->parent_vdi_id, vid);
-}
-
-static int graphview_vdi(char *vdiname, int highlight)
-{
-	struct graph_info i;
-
-	i.name = vdiname;
-	i.highlight = highlight;
-	i.root = -1;
-
-	/* print a header */
-	printf("digraph G {\n");
-
-	parse_vdi(print_graph_tree, &i);
-
-	if (i.root == 0)
-		printf("  \"0\" [shape = \"ellipse\", label = \"root\"];\n");
-	else if (i.root > 0)
-		printf("  \"%" PRIu64 "\" [shape = \"ellipse\", label = \"%s\"];\n",
-		       i.root, vdiname);
-
-	/* print a footer */
-	printf("}\n");
-
-	return 0;
-}
-
-struct tree_info {
-	int highlight;
-	char *name;
-};
-
-static void print_vdi_tree(uint32_t vid, char *name, uint32_t tag,
-			   uint32_t flags, struct sheepdog_inode *i, void *data)
-{
-	struct tree_info *info = (struct tree_info *)data;
-	time_t ti;
-	struct tm tm;
-	char buf[128];
-
-	if (info->name && strcmp(name, info->name))
-		return;
-
-	if (is_current(i))
-		strcpy(buf, "(You Are Here)");
-	else {
-		ti = i->ctime >> 32;
-		localtime_r(&ti, &tm);
-
-		strftime(buf, sizeof(buf),
-			 "[%y-%m-%d %H:%M]", &tm);
-	}
-
-	add_vdi_tree(name, buf, vid, i->parent_vdi_id,
-		     info->highlight && is_current(i));
-}
-
-static int treeview_vdi(char *vdiname, int highlight)
-{
-	struct tree_info i;
-
-	i.name = vdiname;
-	i.highlight = highlight;
-
-	init_tree();
-
-	parse_vdi(print_vdi_tree, &i);
-
-	dump_tree();
-
-	return 0;
-}
-
 static void print_vdi_list(uint32_t vid, char *name, uint32_t tag,
 			   uint32_t flags, struct sheepdog_inode *i, void *data)
 {
@@ -878,8 +554,216 @@ static void parse_objs(uint64_t oid, obj_parser_func_t func, void *data)
 	free(buf);
 }
 
-static void print_obj(char *vdiname, unsigned index)
+#define SUBCMD_FLAG_NEED_NOEDLIST (1 << 0)
+#define SUBCMD_FLAG_NEED_THIRD_ARG (1 << 1)
+
+struct subcommand {
+	char *name;
+	unsigned long flags;
+	int (*fn)(int, char **);
+};
+
+static int node_list(int argc, char **argv)
+{
+	int i;
+
+	printf("  Idx\tNode id (FNV-1a) - Host:Port\n");
+	printf("------------------------------------------------\n");
+	for (i = 0; i < nr_nodes; i++) {
+		char data[128];
+
+		print_node_list_entry(&node_list_entries[i], data, sizeof(data));
+
+		if (i == master_idx) {
+			const char *tmp;
+
+			if (highlight && (tmp = tgetstr("md", NULL)))
+				tputs(tmp, 1, putchar);
+			printf("* %d\t%s\n", i, data);
+			if (highlight && (tmp = tgetstr("me", NULL)))
+				tputs(tmp, 1, putchar);
+		} else
+			printf("  %d\t%s\n", i, data);
+	}
+
+	return 0;
+}
+
+static int node_info(int argc, char **argv)
 {
+	int i, ret, success = 0;
+	uint64_t total_size = 0, total_avail = 0, total_vdi_size = 0;
+	char total_str[8], avail_str[8], vdi_size_str[8];
+
+	printf("Id\tSize\tUsed\tUse%%\n");
+
+	for (i = 0; i < nr_nodes; i++) {
+		char name[128];
+		int fd;
+		unsigned wlen, rlen;
+		struct sd_node_req req;
+		struct sd_node_rsp *rsp = (struct sd_node_rsp *)&req;
+		char store_str[8], free_str[8];
+
+		addr_to_str(name, sizeof(name), node_list_entries[i].addr, 0);
+
+		fd = connect_to(name, node_list_entries[i].port);
+		if (fd < 0)
+			return 1;
+
+		memset(&req, 0, sizeof(req));
+
+		req.opcode = SD_OP_STAT_SHEEP;
+		req.epoch = node_list_version;
+
+		wlen = 0;
+		rlen = 0;
+		ret = exec_req(fd, (struct sd_req *)&req, NULL, &wlen, &rlen);
+		close(fd);
+
+		size_to_str(rsp->store_size, store_str, sizeof(store_str));
+		size_to_str(rsp->store_size - rsp->store_free, free_str,
+			    sizeof(free_str));
+		if (!ret && rsp->result == SD_RES_SUCCESS) {
+			printf("%2d\t%s\t%s\t%3d%%\n", i, store_str, free_str,
+			       (int)(((double)(rsp->store_size - rsp->store_free) / rsp->store_size) * 100));
+			success++;
+		}
+
+		total_size += rsp->store_size;
+		total_avail += rsp->store_free;
+	}
+
+	printf("\n");
+
+	if (success == 0) {
+		fprintf(stderr, "cannot get information from any nodes\n");
+		return 1;
+	}
+
+	parse_vdi(cal_total_vdi_size, &total_vdi_size);
+
+	size_to_str(total_size, total_str, sizeof(total_str));
+	size_to_str(total_size - total_avail, avail_str, sizeof(avail_str));
+	size_to_str(total_vdi_size, vdi_size_str, sizeof(vdi_size_str));
+	printf("Total\t%s\t%s\t%3d%%, total virtual VDI Size\t%s\n",
+	       total_str, avail_str,
+	       (int)(((double)(total_size - total_avail) / total_size) * 100),
+	       vdi_size_str);
+
+	return 0;
+}
+
+static struct subcommand node_cmd[] = {
+	{"list", SUBCMD_FLAG_NEED_NOEDLIST, node_list},
+	{"info", SUBCMD_FLAG_NEED_NOEDLIST, node_info},
+	{NULL,},
+};
+
+static int vm_list(int argc, char **argv)
+{
+	int fd, ret;
+	struct sd_req hdr;
+	unsigned rlen, wlen;
+	char *data;
+	struct vm_list_info vli;
+
+	fd = connect_to("localhost", sdport);
+	if (fd < 0)
+		return 1;
+
+	memset(&hdr, 0, sizeof(hdr));
+
+	hdr.opcode = SD_OP_GET_VM_LIST;
+	hdr.data_length = sizeof(struct sheepdog_vm_list_entry) * SD_MAX_VMS;
+	hdr.epoch = node_list_version;
+	data = zalloc(hdr.data_length);
+
+	rlen = hdr.data_length;
+	wlen = 0;
+	ret = exec_req(fd, &hdr, data, &wlen, &rlen);
+	close(fd);
+
+	if (ret != SD_RES_SUCCESS)
+		return 1;
+	vli.vm_list_entries = (struct sheepdog_vm_list_entry *)data;
+	vli.nr_vms = rlen / sizeof(struct sheepdog_vm_list_entry);
+	vli.highlight = highlight;
+
+	printf("Name            |Vdi size |Allocated| Shared  | Status\n");
+	printf("----------------+---------+---------+---------+------------\n");
+	ret = parse_vdi(print_vm_list, &vli);
+
+	return 0;
+}
+
+static struct subcommand vm_cmd[] = {
+	{"list", SUBCMD_FLAG_NEED_NOEDLIST, vm_list},
+	{NULL,},
+};
+
+static int vdi_list(int argc, char **argv)
+{
+	parse_vdi(print_vdi_list, NULL);
+	return 0;
+}
+
+static int vdi_delete(int argc, char **argv)
+{
+	char *data = argv[optind];
+	int fd, ret;
+	struct sd_vdi_req hdr;
+	struct sd_vdi_rsp *rsp = (struct sd_vdi_rsp *)&hdr;
+	unsigned rlen, wlen;
+	char vdiname[SD_MAX_VDI_LEN];
+	uint32_t id = ~0;
+
+	fd = connect_to("localhost", sdport);
+	if (fd < 0)
+		return -1;
+
+	memset(&hdr, 0, sizeof(hdr));
+
+	rlen = 0;
+	wlen = sizeof(vdiname);
+
+	hdr.opcode = SD_OP_DEL_VDI;
+	if (id != ~0)
+		hdr.snapid = id;
+	hdr.epoch = node_list_version;
+	hdr.flags = SD_FLAG_CMD_WRITE;
+	hdr.data_length = wlen;
+	strncpy(vdiname, data, sizeof(vdiname));
+
+	ret = exec_req(fd, (struct sd_req *)&hdr, vdiname, &wlen, &rlen);
+	close(fd);
+
+	if (ret != SD_RES_SUCCESS) {
+		fprintf(stderr, "failed to connect the dog\n");
+		return ret;
+	}
+
+	if (rsp->result != SD_RES_SUCCESS) {
+		switch (rsp->result) {
+		case SD_RES_VDI_LOCKED:
+			fprintf(stderr, "the vdi is locked\n");
+			break;
+		case SD_RES_NO_VDI:
+			fprintf(stderr, "no such vdi\n");
+			break;
+		default:
+			fprintf(stderr, "error, %d\n", rsp->result);
+			break;
+		}
+	}
+
+	return 0;
+}
+
+static int vdi_object(int argc, char **argv)
+{
+	char *vdiname = argv[optind];
+	unsigned index = ~0;
 	int ret;
 	struct get_vid_info info;
 	uint32_t vid;
@@ -892,7 +776,7 @@ static void print_obj(char *vdiname, unsigned index)
 	vid = info.vid;
 	if (vid == 0) {
 		printf("No such vdi\n");
-		return;
+		return 1;
 	}
 
 	if (index == ~0) {
@@ -925,396 +809,361 @@ static void print_obj(char *vdiname, unsigned index)
 		} else
 			printf("failed to read the inode object 0x%" PRIx32 "\n", vid);
 	}
+
+	return 0;
 }
 
-static int info(enum info_type type, enum format_type format, char *name,
-	 int highlight, int real_time, unsigned index)
+static int vdi_lock(int argc, char **argv)
 {
-	int i, ret = -1;
-	uint64_t total_size = 0, total_avail = 0, total_vdi_size = 0;
-	char total_str[8], avail_str[8], vdi_size_str[8];
-	int success;
+	struct sd_req hdr;
+	struct sd_rsp *rsp = (struct sd_rsp *)&hdr;
+	int ret;
+	char vdiname[SD_MAX_VDI_LEN];
+	unsigned rlen = 0, wlen = 0;
+	unsigned opcode, flags;
+	int fd;
 
-	if (real_time) {
-		setupterm(NULL, 1, (int *)0);
-		fflush(stderr);
-		fflush(stdout);
-		clear();
-	}
-rerun:
-	if (real_time) {
-		if (clear_screen == NULL)
-			return -2;
-		putp(clear_screen);
+	memset(vdiname, 0, sizeof(vdiname));
+
+	strncpy(vdiname, argv[optind], sizeof(vdiname));
+	wlen = sizeof(vdiname);
+	opcode = SD_OP_LOCK_VDI;
+	flags = SD_FLAG_CMD_WRITE;
+
+	fd = connect_to("localhost", sdport);
+	if (fd < 0)
+		return 1;
+
+	memset(&hdr, 0, sizeof(hdr));
+
+	hdr.opcode = opcode;
+	hdr.data_length = wlen;
+	hdr.flags = flags;
+	hdr.epoch = node_list_version;
+
+	ret = exec_req(fd, &hdr, vdiname, &wlen, &rlen);
+	close(fd);
+
+	if (ret) {
+		fprintf(stderr, "communication error\n");
+		return 1;
 	}
 
-	switch (type) {
-	case INFO_VDI:
-		switch (format) {
-		case FORMAT_LIST:
-			printf("  name        id    size    used  shared    creation time   vdi id\n");
-			printf("------------------------------------------------------------------\n");
-			ret = parse_vdi(print_vdi_list, name);
+	if (rsp->result != SD_RES_SUCCESS) {
+		switch(rsp->result) {
+		case SD_RES_VDI_LOCKED:
+			fprintf(stderr, "%s is already locked\n", vdiname);
 			break;
-		case FORMAT_TREE:
-			ret = treeview_vdi(name, highlight);
+		case SD_RES_VDI_NOT_LOCKED:
+			fprintf(stderr, "%s is not locked\n", vdiname);
 			break;
-		case FORMAT_GRAPH:
-			ret = graphview_vdi(name, highlight);
+		case SD_RES_NO_VDI:
+			fprintf(stderr, "%s: no such vdi\n", vdiname);
 			break;
 		default:
-			ret = -1;
+			fprintf(stderr, "error %d\n", rsp->result);
 			break;
 		}
-		break;
-	case INFO_DOG:
-		printf("  Idx\tNode id (FNV-1a) - Host:Port\n");
-		printf("------------------------------------------------\n");
-		for (i = 0; i < nr_nodes; i++) {
-			char data[128];
-
-			print_node_list_entry(&node_list_entries[i], data, sizeof(data));
-
-			if (i == master_idx) {
-				const char *tmp;
-
-				if (highlight && (tmp = tgetstr("md", NULL)))
-					tputs(tmp, 1, putchar);
-				printf("* %d\t%s\n", i, data);
-				if (highlight && (tmp = tgetstr("me", NULL)))
-					tputs(tmp, 1, putchar);
-			} else
-				printf("  %d\t%s\n", i, data);
-		}
-		ret = 0;
-		break;
-	case INFO_SHEEP:
-		printf("Id\tSize\tUsed\tUse%%\n");
-
-		success = 0;
-		for (i = 0; i < nr_nodes; i++) {
-			char name[128];
-			int fd;
-			unsigned wlen, rlen;
-			struct sd_node_req req;
-			struct sd_node_rsp *rsp = (struct sd_node_rsp *)&req;
-			char store_str[8], free_str[8];
-
-			addr_to_str(name, sizeof(name), node_list_entries[i].addr, 0);
-
-			fd = connect_to(name, node_list_entries[i].port);
-			if (fd < 0)
-				continue;
+		return 1;
+	}
 
-			memset(&req, 0, sizeof(req));
+	return 0;
+}
 
-			req.opcode = SD_OP_STAT_SHEEP;
-			req.epoch = node_list_version;
+static int vdi_release(int argc, char **argv)
+{
+	struct sd_req hdr;
+	struct sd_rsp *rsp = (struct sd_rsp *)&hdr;
+	int ret;
+	char vdiname[SD_MAX_VDI_LEN];
+	unsigned rlen = 0, wlen = 0;
+	unsigned opcode, flags;
+	int fd;
+	char *data = NULL;
 
-			wlen = 0;
-			rlen = 0;
-			ret = exec_req(fd, (struct sd_req *)&req, NULL, &wlen, &rlen);
-			close(fd);
+	memset(vdiname, 0, sizeof(vdiname));
 
-			size_to_str(rsp->store_size, store_str, sizeof(store_str));
-			size_to_str(rsp->store_size - rsp->store_free, free_str,
-				    sizeof(free_str));
-			if (!ret && rsp->result == SD_RES_SUCCESS) {
-				printf("%2d\t%s\t%s\t%3d%%\n", i, store_str, free_str,
-				       (int)(((double)(rsp->store_size - rsp->store_free) / rsp->store_size) * 100));
-				success++;
-			}
+	strncpy(vdiname, argv[optind], sizeof(vdiname));
+	wlen = sizeof(vdiname);
+	data = vdiname;
+	opcode = SD_OP_RELEASE_VDI;
+	flags = SD_FLAG_CMD_WRITE;
 
-			total_size += rsp->store_size;
-			total_avail += rsp->store_free;
-		}
+	fd = connect_to("localhost", sdport);
+	if (fd < 0)
+		return 1;
 
-		printf("\n");
+	memset(&hdr, 0, sizeof(hdr));
 
-		if (success == 0) {
-			fprintf(stderr, "cannot get information from any nodes\n");
-			ret = -1;
-			break;
-		}
+	hdr.opcode = opcode;
+	hdr.data_length = wlen;
+	hdr.flags = flags;
+	hdr.epoch = node_list_version;
 
-		parse_vdi(cal_total_vdi_size, &total_vdi_size);
+	ret = exec_req(fd, &hdr, data, &wlen, &rlen);
+	close(fd);
 
-		size_to_str(total_size, total_str, sizeof(total_str));
-		size_to_str(total_size - total_avail, avail_str, sizeof(avail_str));
-		size_to_str(total_vdi_size, vdi_size_str, sizeof(vdi_size_str));
-		printf("Total\t%s\t%s\t%3d%%, total virtual VDI Size\t%s\n",
-		       total_str, avail_str,
-		       (int)(((double)(total_size - total_avail) / total_size) * 100),
-		       vdi_size_str);
+	if (ret) {
+		fprintf(stderr, "communication error\n");
+		return 1;
+	}
 
-		ret = 0;
-		break;
-	case INFO_OBJ:
-		if (!name) {
-			printf("Please specify the vdiname\n");
+	if (rsp->result != SD_RES_SUCCESS) {
+		switch(rsp->result) {
+		case SD_RES_VDI_LOCKED:
+			fprintf(stderr, "%s is already locked\n", vdiname);
+			break;
+		case SD_RES_VDI_NOT_LOCKED:
+			fprintf(stderr, "%s is not locked\n", vdiname);
+			break;
+		case SD_RES_NO_VDI:
+			fprintf(stderr, "%s: no such vdi\n", vdiname);
+			break;
+		default:
+			fprintf(stderr, "error %d\n", rsp->result);
 			break;
 		}
-		print_obj(name, index);
-		ret = 0;
-		break;
-	case INFO_VM:
-	{
-		int fd;
-		struct sd_req hdr;
-		unsigned rlen, wlen;
-		char *data;
-		struct vm_list_info vli;
+		return 1;
+	}
 
-		fd = connect_to("localhost", sdport);
-		if (fd < 0)
-			break;
+	return 0;
+}
 
-		memset(&hdr, 0, sizeof(hdr));
+static struct subcommand vdi_cmd[] = {
+	{"delete", SUBCMD_FLAG_NEED_NOEDLIST|SUBCMD_FLAG_NEED_THIRD_ARG, vdi_delete},
+	{"list", SUBCMD_FLAG_NEED_NOEDLIST, vdi_list},
+	{"object", SUBCMD_FLAG_NEED_NOEDLIST|SUBCMD_FLAG_NEED_THIRD_ARG, vdi_object},
+	{"lock", SUBCMD_FLAG_NEED_THIRD_ARG, vdi_lock},
+	{"release", SUBCMD_FLAG_NEED_THIRD_ARG, vdi_release},
+	{NULL,},
+};
 
-		hdr.opcode = SD_OP_GET_VM_LIST;
-		hdr.data_length = sizeof(struct sheepdog_vm_list_entry) * SD_MAX_VMS;
-		hdr.epoch = node_list_version;
-		data = zalloc(hdr.data_length);
+static int cluster_info(int argc, char **argv)
+{
+	int i, fd, ret;
+	struct sd_vdi_req hdr;
+	struct sd_vdi_rsp *rsp = (struct sd_vdi_rsp *)&hdr;
+	unsigned rlen, wlen;
+	struct epoch_log logs[8];
+	int nr_logs;
+	time_t ti;
+	struct tm tm;
+	char time[128];
 
-		rlen = hdr.data_length;
-		wlen = 0;
-		ret = exec_req(fd, &hdr, data, &wlen, &rlen);
-		close(fd);
+	fd = connect_to("localhost", sdport);
+	if (fd < 0)
+		return 1;
 
-		if (ret != SD_RES_SUCCESS)
-			break;
-		vli.vm_list_entries = (struct sheepdog_vm_list_entry *)data;
-		vli.nr_vms = rlen / sizeof(struct sheepdog_vm_list_entry);
-		vli.highlight = highlight;
+	memset(&hdr, 0, sizeof(hdr));
+
+	hdr.opcode = SD_OP_STAT_CLUSTER;
+	hdr.epoch = node_list_version;
+	hdr.data_length = sizeof(logs);
+
+	rlen = hdr.data_length;
+	wlen = 0;
+	ret = exec_req(fd, (struct sd_req *)&hdr, logs, &wlen, &rlen);
+	close(fd);
+
+	if (ret != 0)
+		return 1;
+
+	if (rsp->result != SD_RES_SUCCESS) {
+		fprintf(stderr, "failed to get cluster status, %x\n", rsp->result);
+		return 1;
+	}
+	switch (rsp->rsvd) {
+	case SD_STATUS_OK:
+		printf("running\n");
+		break;
+	case SD_STATUS_WAIT_FOR_FORMAT:
+		printf("sheepdog is not formatted yet\n");
+		break;
+	case SD_STATUS_WAIT_FOR_JOIN:
+		printf("sheepdog is waiting for other nodes joining\n");
+		break;
+	case SD_STATUS_INCONSISTENT_EPOCHS:
+		printf("there is inconsistency between epochs\n");
+		break;
+	case SD_STATUS_SHUTDOWN:
+		printf("shutdown\n");
+		break;
+	default:
+		printf("%d\n", rsp->rsvd);
+		break;
+	}
+	printf("\n");
+	printf("Ctime              Epoch Nodes\n");
+	nr_logs = rsp->data_length / sizeof(struct epoch_log);
+	for (i = 0; i < nr_logs; i++) {
+		int j;
+		char name[128];
+		struct sheepdog_node_list_entry *entry;
+
+		ti = logs[i].ctime >> 32;
+		localtime_r(&ti, &tm);
+		strftime(time, sizeof(time), "%y-%m-%d %H:%M:%S", &tm);
+
+		printf("%s %6d", time, logs[i].epoch);
+		printf(" [");
+		for (j = 0; j < logs[i].nr_nodes; j++) {
+			entry = logs[i].nodes + j;
+			printf("%s%s",
+			       (j == 0) ? "" : ", ",
+			       addr_to_str(name, sizeof(name),
+					   entry->addr, entry->port));
+		}
+		printf("]\n");
+	}
+
+	return 0;
+}
 
-		printf("Name            |Vdi size |Allocated| Shared  | Status\n");
-		printf("----------------+---------+---------+---------+------------\n");
-		ret = parse_vdi(print_vm_list, &vli);
+static int cluster_parser(int ch, char *opt)
+{
+	switch (ch) {
+	case 'c':
+		cluster_cmd_data.copies = atoi(opt);
 		break;
 	}
-	case INFO_CLUSTER:
-	{
-		int fd;
-		struct sd_vdi_req hdr;
-		struct sd_vdi_rsp *rsp = (struct sd_vdi_rsp *)&hdr;
-		unsigned rlen, wlen;
-		struct epoch_log logs[8];
-		int nr_logs;
-		time_t ti;
-		struct tm tm;
-		char time[128];
-
-		fd = connect_to("localhost", sdport);
-		if (fd < 0)
-			break;
 
-		memset(&hdr, 0, sizeof(hdr));
+	return 0;
+}
 
-		hdr.opcode = SD_OP_STAT_CLUSTER;
-		hdr.epoch = node_list_version;
-		hdr.data_length = sizeof(logs);
+static int cluster_shoutdown(int argc, char **argv)
+{
+	shutdown_sheepdog();
+	return 0;
+}
 
-		rlen = hdr.data_length;
-		wlen = 0;
-		ret = exec_req(fd, (struct sd_req *)&hdr, logs, &wlen, &rlen);
-		close(fd);
+static struct subcommand cluster_cmd[] = {
+	{"info", 0, cluster_info},
+	{"format", 0, cluster_format},
+	{"shutdown", SUBCMD_FLAG_NEED_NOEDLIST, cluster_shoutdown},
+	{NULL,},
+};
 
-		if (ret != 0)
-			break;
+static struct option cluster_long_options[] =
+{
+	COMMON_LONG_OPTIONS
+	{"copies", required_argument, NULL, 'c'},
+	{NULL, 0, NULL, 0},
+};
 
-		if (rsp->result != SD_RES_SUCCESS) {
-			fprintf(stderr, "failed to get cluster status, %x\n", rsp->result);
+static struct {
+	char *name;
+	struct subcommand *sub;
+	struct option *lopts;
+	char *sopts;
+	int (*parser)(int, char *);
+	void (*help)(void);
+} commands[] = {
+	{"vdi", vdi_cmd,},
+	{"node", node_cmd,},
+	{"vm", vm_cmd,},
+	{"cluster", cluster_cmd,
+	 cluster_long_options,
+	 COMMON_SHORT_OPTIONS "c:",
+	 cluster_parser,},
+};
+
+static struct option common_long_options[] =
+{
+	COMMON_LONG_OPTIONS
+	{NULL, 0, NULL, 0},
+};
+
+static struct option *long_options = common_long_options;
+static char *short_options = COMMON_SHORT_OPTIONS;
+static int (*command_parser)(int, char *);
+static int (*command_fn)(int, char **);
+static void (*command_help)(void);
+
+static void setup_command(char *cmd, char *subcmd)
+{
+	int i, found = 0;
+	struct subcommand *s;
+	unsigned long flags;
+
+	for (i = 0; i < ARRAY_SIZE(commands); i++) {
+		if (!strncmp(commands[i].name, cmd, strlen(commands[i].name))) {
+			found = 1;
+			if (commands[i].parser) {
+				command_parser = commands[i].parser;
+				long_options = commands[i].lopts;
+				short_options = commands[i].sopts;
+			}
 			break;
 		}
-		switch (rsp->rsvd) {
-		case SD_STATUS_OK:
-			printf("running\n");
-			break;
-		case SD_STATUS_WAIT_FOR_FORMAT:
-			printf("sheepdog is not formatted yet\n");
-			break;
-		case SD_STATUS_WAIT_FOR_JOIN:
-			printf("sheepdog is waiting for other nodes joining\n");
-			break;
-		case SD_STATUS_INCONSISTENT_EPOCHS:
-			printf("there is inconsistency between epochs\n");
-			break;
-		case SD_STATUS_SHUTDOWN:
-			printf("shutdown\n");
-			break;
-		default:
-			printf("%d\n", rsp->rsvd);
+	}
+
+	if (!found) {
+		fprintf(stderr, "'%s' is not a valid command\n", cmd);
+		usage(1);
+	}
+
+	for (s = commands[i].sub; s->name; s++) {
+		if (!strncmp(s->name, subcmd, strlen(s->name))) {
+			command_fn = s->fn;
+			flags = s->flags;
 			break;
 		}
-		printf("\n");
-		printf("Ctime              Epoch Nodes\n");
-		nr_logs = rsp->data_length / sizeof(struct epoch_log);
-		for (i = 0; i < nr_logs; i++) {
-			int j;
-			char name[128];
-			struct sheepdog_node_list_entry *entry;
-
-			ti = logs[i].ctime >> 32;
-			localtime_r(&ti, &tm);
-			strftime(time, sizeof(time), "%y-%m-%d %H:%M:%S", &tm);
-
-			printf("%s %6d", time, logs[i].epoch);
-			printf(" [");
-			for (j = 0; j < logs[i].nr_nodes; j++) {
-				entry = logs[i].nodes + j;
-				printf("%s%s",
-				       (j == 0) ? "" : ", ",
-				       addr_to_str(name, sizeof(name),
-						   entry->addr, entry->port));
-			}
-			printf("]\n");
-		}
-		break;
 	}
-	default:
-		ret = -1;
-		break;
+
+	if (!command_fn) {
+		fprintf(stderr, "'%s' is not a valid subcommand\n", subcmd);
+		fprintf(stderr, "'%s' supports the following subcommand:\n", cmd);
+		for (s = commands[i].sub; s->name; s++)
+			fprintf(stderr, "%s\n", s->name);
+		exit(1);
 	}
 
-	if (real_time && ret == 0) {
-		fflush(stdout);
-		sleep(1);
-		goto rerun;
+	if (flags & SUBCMD_FLAG_NEED_THIRD_ARG) {
+		fprintf(stderr, "'%s %s' needs the third argument\n", cmd, subcmd);
+		exit(1);
 	}
-	return ret;
+
+	if (flags & SUBCMD_FLAG_NEED_NOEDLIST)
+		update_node_list(SD_MAX_NODES, 0);
 }
 
 int main(int argc, char **argv)
 {
 	int ch, longindex;
-	int ret = 0;
-	char *command;
-	enum info_type type = INFO_NONE;
-	enum format_type format = FORMAT_LIST;
-	int reboot = 0;
-	int highlight = 1;
 	char termcap_area[1024];
-	int copies = DEAFAULT_NR_COPIES;
-	char *op = NULL;
-	unsigned index = ~0;
-	int real_time = 0;
-	int epoch = 0;
 
 	if (getenv("TERM"))
 		tgetent(termcap_area, getenv("TERM"));
 
+	if (argc < 3)
+		usage(0);
+
+	setup_command(argv[1], argv[2]);
+
+	optind = 3;
+
 	while ((ch = getopt_long(argc, argv, short_options, long_options,
-				 &longindex)) >= 0) {
+				&longindex)) >= 0) {
+
 		switch (ch) {
 		case 'p':
 			sdport = atoi(optarg);
 			break;
-		case 'c':
-			copies = atoi(optarg);
-			break;
-		case 'f':
-			if (strcasecmp(optarg, "list") == 0)
-				format = FORMAT_LIST;
-			else if (strcasecmp(optarg, "tree") == 0)
-				format = FORMAT_TREE;
-			else if (strcasecmp(optarg, "graph") == 0)
-				format = FORMAT_GRAPH;
-			else
-				usage(1);
-			break;
-		case 'H':
-			if (strcasecmp(optarg, "on") == 0)
-				highlight = 1;
-			else if (strcasecmp(optarg, "off") == 0)
-				highlight = 0;
-			else
-				usage(1);
-			break;
-		case 'R':
-			if (strcasecmp(optarg, "on") == 0)
-				real_time = 1;
-			else if (strcasecmp(optarg, "off") == 0)
-				real_time = 0;
-			else
-				usage(1);
-			break;
 		case 'h':
-			usage(0);
-		case 'r':
-			reboot = 1;
-			break;
-		case 't':
-			if (!strcasecmp(optarg, "vdi"))
-				type = INFO_VDI;
-			else if (!strcasecmp(optarg, "dog"))
-				type = INFO_DOG;
-			else if (!strcasecmp(optarg, "sheep"))
-				type = INFO_SHEEP;
-			else if (!strcasecmp(optarg, "obj"))
-				type = INFO_OBJ;
-			else if (!strcasecmp(optarg, "vm"))
-				type = INFO_VM;
-			else if (!strcasecmp(optarg, "cluster"))
-				type = INFO_CLUSTER;
-			else
-				usage(1);
-			break;
-		case 'o':
-			op = optarg;
+			if (command_help)
+				command_help();
 			break;
-		case 'i':
-			index = strtoul(optarg, NULL, 10);
-			break;
-		case 'e':
-			epoch = strtoul(optarg, NULL, 10);
-			if (epoch <= 0) {
-				fprintf(stderr, "epoch must be larger than 0\n");
-				usage(1);
-			}
+		case '?':
+			usage(1);
 			break;
 		default:
-			usage(1);
+			if (command_parser)
+				command_parser(ch, optarg);
+			else
+				usage(1);
 			break;
 		}
 	}
-	if (optind >= argc)
-		usage(0);
-
-	node_list_entries = zalloc(SD_MAX_NODES * sizeof(struct sheepdog_node_list_entry));
-	command = argv[optind++];
-
-	/* TODO: cleanup */
-	if (strcasecmp(command, "mkfs") == 0)
-		;
-	else if (strcasecmp(command, "info") == 0 && type == INFO_CLUSTER)
-		;
-	else {
-		ret = update_node_list(SD_MAX_NODES, epoch);
-		if (ret < 0)
-			return 1;
-	}
-
-	if (!strcasecmp(command, "info")) {
-		char *name = NULL;
-
-		if (type == INFO_NONE)
-			usage(0);
-		if (optind != argc)
-			name = argv[optind];
-
-		info(type, format, name, highlight, real_time, index);
-	} else if (!strcasecmp(command, "mkfs"))
-		ret = mkfs(copies);
-	else if (!strcasecmp(command, "delete"))
-		ret = delete(argv[optind], index);
-	else if (!strcasecmp(command, "debug"))
-		ret = debug(op, argv[optind]);
-	else if (!strcasecmp(command, "shutdown"))
-		ret = shutdown_sheepdog();
-	else {
-		fprintf(stderr, "'%s' is not a valid command\n", command);
-		usage(1);
-	}
 
-	return ret;
+	return command_fn(argc, argv);
 }
-- 
1.6.5




More information about the sheepdog mailing list