diff options
Diffstat (limited to 'cli/src')
| -rw-r--r-- | cli/src/Makefile.am | 17 | ||||
| -rw-r--r-- | cli/src/cli-cmd-misc.c | 63 | ||||
| -rw-r--r-- | cli/src/cli-cmd-parser.c | 3422 | ||||
| -rw-r--r-- | cli/src/cli-cmd-peer.c | 191 | ||||
| -rw-r--r-- | cli/src/cli-cmd-snapshot.c | 146 | ||||
| -rw-r--r-- | cli/src/cli-cmd-system.c | 485 | ||||
| -rw-r--r-- | cli/src/cli-cmd-volume.c | 1574 | ||||
| -rw-r--r-- | cli/src/cli-cmd.c | 145 | ||||
| -rw-r--r-- | cli/src/cli-cmd.h | 87 | ||||
| -rw-r--r-- | cli/src/cli-mem-types.h | 21 | ||||
| -rw-r--r-- | cli/src/cli-rl.c | 75 | ||||
| -rw-r--r-- | cli/src/cli-rpc-ops.c | 8673 | ||||
| -rw-r--r-- | cli/src/cli-xml-output.c | 3772 | ||||
| -rw-r--r-- | cli/src/cli.c | 411 | ||||
| -rw-r--r-- | cli/src/cli.h | 302 | ||||
| -rw-r--r-- | cli/src/cli3_1-cops.c | 2260 | ||||
| -rw-r--r-- | cli/src/input.c | 32 | ||||
| -rw-r--r-- | cli/src/registry.c | 115 |
18 files changed, 18300 insertions, 3491 deletions
diff --git a/cli/src/Makefile.am b/cli/src/Makefile.am index 595cfad9d..216d1bb55 100644 --- a/cli/src/Makefile.am +++ b/cli/src/Makefile.am @@ -1,22 +1,27 @@ sbin_PROGRAMS = gluster gluster_SOURCES = cli.c registry.c input.c cli-cmd.c cli-rl.c \ - cli-cmd-volume.c cli-cmd-peer.c cli3_1-cops.c cli-cmd-parser.c\ - cli-cmd-system.c cli-cmd-misc.c + cli-cmd-volume.c cli-cmd-peer.c cli-rpc-ops.c cli-cmd-parser.c\ + cli-cmd-system.c cli-cmd-misc.c cli-xml-output.c cli-cmd-snapshot.c gluster_LDADD = $(top_builddir)/libglusterfs/src/libglusterfs.la $(GF_LDADD)\ $(RLLIBS) $(top_builddir)/rpc/xdr/src/libgfxdr.la \ - $(top_builddir)/rpc/rpc-lib/src/libgfrpc.la + $(top_builddir)/rpc/rpc-lib/src/libgfrpc.la \ + $(GF_GLUSTERFS_LIBS) $(XML_LIBS) -gluster_LDFLAGS = $(GF_LDFLAGS) $(GF_GLUSTERFS_LDFLAGS) +gluster_LDFLAGS = $(GF_LDFLAGS) noinst_HEADERS = cli.h cli-mem-types.h cli-cmd.h -AM_CFLAGS = -fPIC -Wall -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -D$(GF_HOST_OS)\ +AM_CPPFLAGS = $(GF_CPPFLAGS) \ -I$(top_srcdir)/libglusterfs/src -I$(top_srcdir)/rpc/rpc-lib/src\ -I$(top_srcdir)/rpc/xdr/src\ -DDATADIR=\"$(localstatedir)\" \ - -DCONFDIR=\"$(sysconfdir)/glusterfs\" $(GF_GLUSTERFS_CFLAGS) + -DCONFDIR=\"$(sysconfdir)/glusterfs\" \ + -DGSYNCD_PREFIX=\"$(libexecdir)/glusterfs\"\ + -DSYNCDAEMON_COMPILE=$(SYNCDAEMON_COMPILE) -DSBIN_DIR=\"$(sbindir)\"\ + $(XML_CPPFLAGS) +AM_CFLAGS = -Wall $(GF_GLUSTERFS_CFLAGS) CLEANFILES = diff --git a/cli/src/cli-cmd-misc.c b/cli/src/cli-cmd-misc.c index 1e356c63b..566d7c978 100644 --- a/cli/src/cli-cmd-misc.c +++ b/cli/src/cli-cmd-misc.c @@ -1,22 +1,12 @@ /* - Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. - - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ + Copyright (c) 2010-2012 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ #include <stdio.h> #include <string.h> #include <stdlib.h> @@ -41,6 +31,8 @@ extern struct cli_cmd volume_cmds[]; extern struct cli_cmd cli_probe_cmds[]; extern struct cli_cmd cli_log_cmds[]; extern struct cli_cmd cli_system_cmds[]; +extern struct cli_cmd cli_bd_cmds[]; +extern struct cli_cmd snapshot_cmds[]; struct cli_cmd cli_misc_cmds[]; int @@ -54,23 +46,20 @@ int cli_cmd_display_help (struct cli_state *state, struct cli_cmd_word *in_word, const char **words, int wordcount) { - struct cli_cmd *cmd = NULL; - - for (cmd = volume_cmds; cmd->pattern; cmd++) - cli_out ("%s - %s", cmd->pattern, cmd->desc); - - for (cmd = cli_probe_cmds; cmd->pattern; cmd++) - cli_out ("%s - %s", cmd->pattern, cmd->desc); - - /* - * commands for internal usage, don't expose - - for (cmd = cli_system_cmds; cmd->pattern; cmd++) - cli_out ("%s - %s", cmd->pattern, cmd->desc); + struct cli_cmd *cmd[] = {volume_cmds, cli_probe_cmds, + cli_misc_cmds, snapshot_cmds, + NULL}; + struct cli_cmd *cmd_ind = NULL; + int i = 0; + + /* cli_system_cmds commands for internal usage + they are not exposed */ - - for (cmd = cli_misc_cmds; cmd->pattern; cmd++) - cli_out ("%s - %s", cmd->pattern, cmd->desc); + for (i=0; cmd[i]!=NULL; i++) + for (cmd_ind = cmd[i]; cmd_ind->pattern; cmd_ind++) + if (_gf_false == cmd_ind->disable) + cli_out ("%s - %s", cmd_ind->pattern, + cmd_ind->desc); return 0; } @@ -84,6 +73,10 @@ struct cli_cmd cli_misc_cmds[] = { cli_cmd_display_help, "display command options"}, + { "exit", + cli_cmd_quit_cbk, + "exit"}, + { NULL, NULL, NULL } }; @@ -95,8 +88,8 @@ cli_cmd_misc_register (struct cli_state *state) struct cli_cmd *cmd = NULL; for (cmd = cli_misc_cmds; cmd->pattern; cmd++) { - ret = cli_cmd_register (&state->tree, cmd->pattern, cmd->cbk, - cmd->desc); + + ret = cli_cmd_register (&state->tree, cmd); if (ret) goto out; } diff --git a/cli/src/cli-cmd-parser.c b/cli/src/cli-cmd-parser.c index 1381e0fec..5ab208b8f 100644 --- a/cli/src/cli-cmd-parser.c +++ b/cli/src/cli-cmd-parser.c @@ -1,22 +1,12 @@ /* - Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. - - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ + Copyright (c) 2010-2013 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ #include <stdio.h> #include <string.h> #include <stdlib.h> @@ -36,34 +26,188 @@ #include "protocol-common.h" #include "cli1-xdr.h" +#define MAX_SNAP_DESCRIPTION_LEN 1024 + +struct snap_config_opt_vals_ snap_confopt_vals[] = { + {.op_name = "snap-max-hard-limit", + .question = "Changing snapshot-max-hard-limit " + "will lead to deletion of snapshots " + "if they exceed the new limit.\n" + "Do you want to continue?" + }, + {.op_name = "snap-max-soft-limit", + .question = "Changing snapshot-max-soft-limit " + "will lead to deletion of snapshots " + "if they exceed the new limit.\n" + "Do you want to continue?" + }, + {.op_name = "both", + .question = "Changing snapshot-max-hard-limit & " + "snapshot-max-soft-limit will lead to " + "deletion of snapshots if they exceed " + "the new limit.\nDo you want to continue?" + }, + {.op_name = NULL, + } +}; + +enum cli_snap_config_set_types { + GF_SNAP_CONFIG_SET_HARD = 0, + GF_SNAP_CONFIG_SET_SOFT = 1, + GF_SNAP_CONFIG_SET_BOTH = 2, +}; +typedef enum cli_snap_config_set_types cli_snap_config_set_types; + +static const char * +id_sel (void *wcon) +{ + return (const char *)wcon; +} + +static char * +str_getunamb (const char *tok, char **opwords) +{ + return (char *)cli_getunamb (tok, (void **)opwords, id_sel); +} + +int32_t +cli_cmd_bricks_parse (const char **words, int wordcount, int brick_index, + char **bricks, int *brick_count) +{ + int ret = 0; + char *tmp_list = NULL; + char brick_list[120000] = {0,}; + char *space = " "; + char *delimiter = NULL; + char *host_name = NULL; + char *free_list_ptr = NULL; + char *tmpptr = NULL; + int j = 0; + int brick_list_len = 0; + char *tmp_host = NULL; + + GF_ASSERT (words); + GF_ASSERT (wordcount); + GF_ASSERT (bricks); + GF_ASSERT (brick_index > 0); + GF_ASSERT (brick_index < wordcount); + + strncpy (brick_list, space, strlen (space)); + brick_list_len++; + while (brick_index < wordcount) { + if (validate_brick_name ((char *)words[brick_index])) { + cli_err ("Wrong brick type: %s, use <HOSTNAME>:" + "<export-dir-abs-path>", words[brick_index]); + ret = -1; + goto out; + } else { + delimiter = strrchr (words[brick_index], ':'); + ret = gf_canonicalize_path (delimiter + 1); + if (ret) + goto out; + } + + if ((brick_list_len + strlen (words[brick_index]) + 1) > sizeof (brick_list)) { + cli_err ("Total brick list is larger than a request. " + "Can take (brick_count %d)", *brick_count); + ret = -1; + goto out; + } + + tmp_host = gf_strdup ((char *)words[brick_index]); + if (!tmp_host) { + gf_log ("cli", GF_LOG_ERROR, "Out of memory"); + ret = -1; + goto out; + } + get_host_name (tmp_host, &host_name); + if (!host_name) { + ret = -1; + gf_log("cli",GF_LOG_ERROR, "Unable to allocate " + "memory"); + goto out; + } + + if (!(strcmp (host_name, "localhost") && + strcmp (host_name, "127.0.0.1") && + strncmp (host_name, "0.", 2))) { + cli_err ("Please provide a valid hostname/ip other " + "than localhost, 127.0.0.1 or loopback " + "address (0.0.0.0 to 0.255.255.255)."); + ret = -1; + GF_FREE (tmp_host); + goto out; + } + if (!valid_internet_address (host_name, _gf_false)) { + cli_err ("internet address '%s' does not conform to " + "standards", host_name); + } + GF_FREE (tmp_host); + tmp_list = gf_strdup (brick_list + 1); + if (free_list_ptr) { + GF_FREE (free_list_ptr); + free_list_ptr = NULL; + } + free_list_ptr = tmp_list; + j = 0; + while(j < *brick_count) { + strtok_r (tmp_list, " ", &tmpptr); + if (!(strcmp (tmp_list, words[brick_index]))) { + ret = -1; + cli_err ("Found duplicate" + " exports %s",words[brick_index]); + goto out; + } + tmp_list = tmpptr; + j++; + } + strcat (brick_list, words[brick_index]); + strcat (brick_list, " "); + brick_list_len += (strlen (words[brick_index]) + 1); + ++(*brick_count); + ++brick_index; + } + + *bricks = gf_strdup (brick_list); + if (!*bricks) + ret = -1; +out: + GF_FREE (free_list_ptr); + return ret; +} + int32_t cli_cmd_volume_create_parse (const char **words, int wordcount, dict_t **options) { dict_t *dict = NULL; char *volname = NULL; - char *delimiter = NULL; int ret = -1; gf1_cluster_type type = GF_CLUSTER_TYPE_NONE; int count = 1; - int brick_count = 0, brick_index = 0; - int brick_list_size = 1; - char brick_list[120000] = {0,}; + int sub_count = 1; + int brick_index = 0; int i = 0; - char *tmp_list = NULL; - char *tmpptr = NULL; - int j = 0; - char *host_name = NULL; - char *tmp = NULL; - char *freeptr = NULL; char *trans_type = NULL; int32_t index = 0; + char *bricks = NULL; + int32_t brick_count = 0; + char *opwords[] = { "replica", "stripe", "transport", NULL }; + + char *invalid_volnames[] = {"volume", "type", "subvolumes", "option", + "end-volume", "all", "volume_not_in_ring", + "description", "force", + "snap-max-hard-limit", + "snap-max-soft-limit", NULL}; + char *w = NULL; + int op_count = 0; + int32_t replica_count = 1; + int32_t stripe_count = 1; + gf_boolean_t is_force = _gf_false; + int wc = wordcount; GF_ASSERT (words); GF_ASSERT (options); - GF_ASSERT ((strcmp (words[0], "volume")) == 0); - GF_ASSERT ((strcmp (words[1], "create")) == 0); - dict = dict_new (); if (!dict) @@ -81,8 +225,13 @@ cli_cmd_volume_create_parse (const char **words, int wordcount, dict_t **options if (volname[0] == '-') goto out; - if (!strcmp (volname, "all")) - goto out; + for (i = 0; invalid_volnames[i]; i++) { + if (!strcmp (volname, invalid_volnames[i])) { + cli_err ("\"%s\" cannot be the name of a volume.", + volname); + goto out; + } + } if (strchr (volname, '/')) goto out; @@ -95,178 +244,171 @@ cli_cmd_volume_create_parse (const char **words, int wordcount, dict_t **options goto out; } - - ret = dict_set_str (dict, "volname", volname); - if (ret) - goto out; - if (wordcount < 4) { ret = -1; goto out; } - if ((strcasecmp (words[3], "replica")) == 0) { - type = GF_CLUSTER_TYPE_REPLICATE; - if (wordcount < 5) { - ret = -1; - goto out; - } - count = strtol (words[4], NULL, 0); - if (!count || (count < 2)) { - cli_out ("replica count should be greater than 1"); - ret = -1; - goto out; - } - ret = dict_set_int32 (dict, "replica-count", count); - if (ret) - goto out; - brick_index = 5; - } else if ((strcasecmp (words[3], "stripe")) == 0) { - type = GF_CLUSTER_TYPE_STRIPE; - if (wordcount < 5) { - ret = -1; - goto out; - } - count = strtol (words[4], NULL, 0); - if (!count || (count < 2)) { - cli_out ("stripe count should be greater than 1"); + + type = GF_CLUSTER_TYPE_NONE; + index = 3; + + while (op_count < 3) { + ret = -1; + w = str_getunamb (words[index], opwords); + if (!w) { + break; + } else if ((strcmp (w, "replica")) == 0) { + switch (type) { + case GF_CLUSTER_TYPE_STRIPE_REPLICATE: + case GF_CLUSTER_TYPE_REPLICATE: + cli_err ("replica option given twice"); + goto out; + case GF_CLUSTER_TYPE_NONE: + type = GF_CLUSTER_TYPE_REPLICATE; + break; + case GF_CLUSTER_TYPE_STRIPE: + type = GF_CLUSTER_TYPE_STRIPE_REPLICATE; + break; + } + + if (wordcount < (index+2)) { + ret = -1; + goto out; + } + replica_count = strtol (words[index+1], NULL, 0); + if (replica_count < 2) { + cli_err ("replica count should be greater" + " than 1"); + ret = -1; + goto out; + } + ret = dict_set_int32 (dict, "replica-count", replica_count); + if (ret) + goto out; + + index += 2; + + } else if ((strcmp (w, "stripe")) == 0) { + switch (type) { + case GF_CLUSTER_TYPE_STRIPE_REPLICATE: + case GF_CLUSTER_TYPE_STRIPE: + cli_err ("stripe option given twice"); + goto out; + case GF_CLUSTER_TYPE_NONE: + type = GF_CLUSTER_TYPE_STRIPE; + break; + case GF_CLUSTER_TYPE_REPLICATE: + type = GF_CLUSTER_TYPE_STRIPE_REPLICATE; + break; + } + if (wordcount < (index + 2)) { + ret = -1; + goto out; + } + stripe_count = strtol (words[index+1], NULL, 0); + if (stripe_count < 2) { + cli_err ("stripe count should be greater" + " than 1"); + ret = -1; + goto out; + } + ret = dict_set_int32 (dict, "stripe-count", stripe_count); + if (ret) + goto out; + + index += 2; + + } else if ((strcmp (w, "transport")) == 0) { + if (trans_type) { + cli_err ("'transport' option given more" + " than one time"); + goto out; + } + if ((strcasecmp (words[index+1], "tcp") == 0)) { + trans_type = gf_strdup ("tcp"); + } else if ((strcasecmp (words[index+1], "rdma") == 0)) { + trans_type = gf_strdup ("rdma"); + } else if ((strcasecmp (words[index+1], "tcp,rdma") == 0) || + (strcasecmp (words[index+1], "rdma,tcp") == 0)) { + trans_type = gf_strdup ("tcp,rdma"); + } else { + gf_log ("", GF_LOG_ERROR, "incorrect transport" + " protocol specified"); + ret = -1; + goto out; + } + index += 2; + } else { + GF_ASSERT (!"opword mismatch"); ret = -1; goto out; } - ret = dict_set_int32 (dict, "stripe-count", count); - if (ret) - goto out; - brick_index = 5; - } else { - type = GF_CLUSTER_TYPE_NONE; - brick_index = 3; + op_count++; } - ret = dict_set_int32 (dict, "type", type); - if (ret) - goto out; + if (!trans_type) + trans_type = gf_strdup ("tcp"); - if (type) - index = 5; - else - index = 3; + sub_count = stripe_count * replica_count; + + /* reset the count value now */ + count = 1; - if (wordcount < (index + 1)) { + if (index >= wordcount) { ret = -1; goto out; } - if (strcasecmp(words[index], "transport") == 0) { - brick_index = index+2; - if (wordcount < (index + 2)) { - ret = -1; - goto out; - } + brick_index = index; - if ((strcasecmp (words[index+1], "tcp") == 0)) { - trans_type = gf_strdup ("tcp"); - } else if ((strcasecmp (words[index+1], "rdma") == 0)) { - trans_type = gf_strdup ("rdma"); - } else { - gf_log ("", GF_LOG_ERROR, "incorrect transport" - " protocol specified"); - ret = -1; - goto out; - } - } else { - trans_type = gf_strdup ("tcp"); + if (strcmp (words[wordcount - 1], "force") == 0) { + is_force = _gf_true; + wc = wordcount - 1; } - ret = dict_set_str (dict, "transport", trans_type); + ret = cli_cmd_bricks_parse (words, wc, brick_index, &bricks, + &brick_count); if (ret) goto out; - strcpy (brick_list, " "); - while (brick_index < wordcount) { - delimiter = strchr (words[brick_index], ':'); - if (!delimiter || delimiter == words[brick_index] - || *(delimiter+1) != '/') { - cli_out ("wrong brick type: %s, use <HOSTNAME>:" - "<export-dir-abs-path>", words[brick_index]); - ret = -1; - goto out; - } else { - cli_path_strip_trailing_slashes (delimiter + 1); - } - if ((brick_list_size + strlen (words[brick_index]) + 1) > 120000) { - gf_log ("cli", GF_LOG_ERROR, - "total brick list is larger than a request " - "can take (brick_count %d)", brick_count); - ret = -1; - goto out; - } - - host_name = gf_strdup(words[brick_index]); - if (!host_name) { - ret = -1; - gf_log("cli",GF_LOG_ERROR, "Unable to allocate " - "memory"); - goto out; - } - freeptr = host_name; - - strtok_r(host_name, ":", &tmp); - if (!(strcmp(host_name, "localhost") && - strcmp (host_name, "127.0.0.1"))) { - cli_out ("Please provide a valid hostname/ip other " - "than localhost or 127.0.0.1"); - ret = -1; - GF_FREE(freeptr); - goto out; - } - GF_FREE (freeptr); - tmp_list = strdup(brick_list+1); - j = 0; - while(( brick_count != 0) && (j < brick_count)) { - strtok_r (tmp_list, " ", &tmpptr); - if (!(strcmp (tmp_list, words[brick_index]))) { - ret = -1; - cli_out ("Found duplicate" - " exports %s",words[brick_index]); - goto out; - } - tmp_list = tmpptr; - j++; - } - strcat (brick_list, words[brick_index]); - strcat (brick_list, " "); - brick_list_size += (strlen (words[brick_index]) + 1); - ++brick_count; - ++brick_index; - /* - char key[50]; - snprintf (key, 50, "brick%d", ++brick_count); - ret = dict_set_str (dict, key, (char *)words[brick_index++]); - - if (ret) - goto out; - */ - } - /* If brick-count is not valid when replica or stripe is given, exit here */ if (!brick_count) { - cli_out ("No bricks specified"); + cli_err ("No bricks specified"); ret = -1; goto out; } - if (brick_count % count) { + if (brick_count % sub_count) { if (type == GF_CLUSTER_TYPE_STRIPE) - cli_out ("number of bricks is not a multiple of " + cli_err ("number of bricks is not a multiple of " "stripe count"); else if (type == GF_CLUSTER_TYPE_REPLICATE) - cli_out ("number of bricks is not a multiple of " + cli_err ("number of bricks is not a multiple of " "replica count"); + else + cli_err ("number of bricks given doesn't match " + "required count"); + ret = -1; goto out; } - ret = dict_set_str (dict, "bricks", brick_list); + /* Everything if parsed fine. start setting info in dict */ + ret = dict_set_str (dict, "volname", volname); + if (ret) + goto out; + + ret = dict_set_int32 (dict, "type", type); + if (ret) + goto out; + + ret = dict_set_dynstr (dict, "transport", trans_type); + if (ret) + goto out; + trans_type = NULL; + + ret = dict_set_dynstr (dict, "bricks", bricks); if (ret) goto out; @@ -274,6 +416,10 @@ cli_cmd_volume_create_parse (const char **words, int wordcount, dict_t **options if (ret) goto out; + ret = dict_set_int32 (dict, "force", is_force); + if (ret) + goto out; + *options = dict; out: @@ -282,8 +428,8 @@ out: if (dict) dict_destroy (dict); } - if (trans_type) - GF_FREE (trans_type); + + GF_FREE (trans_type); return ret; } @@ -298,9 +444,6 @@ cli_cmd_volume_reset_parse (const char **words, int wordcount, dict_t **options) GF_ASSERT (words); GF_ASSERT (options); - GF_ASSERT ((strcmp (words[0], "volume")) == 0); - GF_ASSERT ((strcmp (words[1], "reset")) == 0); - dict = dict_new (); if (!dict) @@ -309,6 +452,9 @@ cli_cmd_volume_reset_parse (const char **words, int wordcount, dict_t **options) if (wordcount < 3) goto out; + if (wordcount > 5) + goto out; + volname = (char *)words[2]; if (!volname) { @@ -317,45 +463,355 @@ cli_cmd_volume_reset_parse (const char **words, int wordcount, dict_t **options) } ret = dict_set_str (dict, "volname", volname); - if (ret) goto out; + if (wordcount == 3) { + ret = dict_set_str (dict, "key", "all"); + if (ret) + goto out; + } + + if (wordcount >= 4) { + if (!strcmp ("force", (char*)words[3])) { + ret = dict_set_int32 (dict, "force", 1); + if (ret) + goto out; + ret = dict_set_str (dict, "key", "all"); + if (ret) + goto out; + } else { + ret = dict_set_str (dict, "key", (char *)words[3]); + if (ret) + goto out; + } + } + + if (wordcount == 5) { + if (strcmp ("force", (char*)words[4])) { + ret = -1; + goto out; + } else { + ret = dict_set_int32 (dict, "force", 1); + if (ret) + goto out; + } + } + *options = dict; out: - if (ret) { - if (dict) + if (ret && dict) { dict_destroy (dict); - } + } return ret; } int32_t -cli_cmd_volume_set_parse (const char **words, int wordcount, dict_t **options) +cli_cmd_quota_parse (const char **words, int wordcount, dict_t **options) { - dict_t *dict = NULL; - char *volname = NULL; - int ret = -1; - int count = 0; - char *key = NULL; - char *value = NULL; - int i = 0; - char str[50] = {0,}; + dict_t *dict = NULL; + char *volname = NULL; + int ret = -1; + int i = 0; + char key[20] = {0, }; + uint64_t value = 0; + gf_quota_type type = GF_QUOTA_OPTION_TYPE_NONE; + char *opwords[] = { "enable", "disable", "limit-usage", + "remove", "list", "version", NULL }; + char *w = NULL; GF_ASSERT (words); GF_ASSERT (options); - GF_ASSERT ((strcmp (words[0], "volume")) == 0); - GF_ASSERT ((strcmp (words[1], "set")) == 0); + dict = dict_new (); + if (!dict) + goto out; + + if (wordcount < 4) + goto out; + + volname = (char *)words[2]; + if (!volname) { + ret = -1; + goto out; + } + + /* Validate the volume name here itself */ + { + if (volname[0] == '-') + goto out; + + if (!strcmp (volname, "all")) { + cli_err ("\"all\" cannot be the name of a volume."); + goto out; + } + + if (strchr (volname, '/')) + goto out; + + if (strlen (volname) > 512) + goto out; + + for (i = 0; i < strlen (volname); i++) + if (!isalnum (volname[i]) && (volname[i] != '_') && (volname[i] != '-')) + goto out; + } + + ret = dict_set_str (dict, "volname", volname); + if (ret < 0) + goto out; + + w = str_getunamb (words[3], opwords); + if (!w) { + ret = - 1; + goto out; + } + + if (strcmp (w, "enable") == 0) { + if (wordcount == 4) { + type = GF_QUOTA_OPTION_TYPE_ENABLE; + ret = 0; + goto set_type; + } else { + ret = -1; + goto out; + } + } + + if (strcmp (w, "disable") == 0) { + if (wordcount == 4) { + type = GF_QUOTA_OPTION_TYPE_DISABLE; + ret = 0; + goto set_type; + } else { + ret = -1; + goto out; + } + } + + if (strcmp (w, "limit-usage") == 0) { + if (wordcount != 6) { + ret = -1; + goto out; + } + + type = GF_QUOTA_OPTION_TYPE_LIMIT_USAGE; + + if (words[4][0] != '/') { + cli_err ("Please enter absolute path"); + + return -2; + } + ret = dict_set_str (dict, "path", (char *) words[4]); + if (ret) + goto out; + + if (!words[5]) { + cli_err ("Please enter the limit value to be set"); + + return -2; + } + + ret = gf_string2bytesize (words[5], &value); + if (ret != 0) { + cli_err ("Please enter a correct value"); + return -1; + } + + ret = dict_set_str (dict, "limit", (char *) words[5]); + if (ret < 0) + goto out; + + goto set_type; + } + if (strcmp (w, "remove") == 0) { + if (wordcount != 5) { + ret = -1; + goto out; + } + + type = GF_QUOTA_OPTION_TYPE_REMOVE; + + if (words[4][0] != '/') { + cli_err ("Please enter absolute path"); + + return -2; + } + + ret = dict_set_str (dict, "path", (char *) words[4]); + if (ret < 0) + goto out; + goto set_type; + } + + if (strcmp (w, "list") == 0) { + if (wordcount < 4) { + ret = -1; + goto out; + } + + type = GF_QUOTA_OPTION_TYPE_LIST; + + i = 4; + while (i < wordcount) { + snprintf (key, 20, "path%d", i-4); + + ret = dict_set_str (dict, key, (char *) words [i++]); + if (ret < 0) + goto out; + } + + ret = dict_set_int32 (dict, "count", i - 4); + if (ret < 0) + goto out; + + goto set_type; + } + + if (strcmp (w, "version") == 0) { + type = GF_QUOTA_OPTION_TYPE_VERSION; + } else { + GF_ASSERT (!"opword mismatch"); + } + +set_type: + ret = dict_set_int32 (dict, "type", type); + if (ret < 0) + goto out; + + *options = dict; +out: + if (ret < 0) { + if (dict) + dict_destroy (dict); + } + + return ret; +} + +static inline gf_boolean_t +cli_is_key_spl (char *key) +{ + return (strcmp (key, "group") == 0); +} + +#define GLUSTERD_DEFAULT_WORKDIR "/var/lib/glusterd" +static int +cli_add_key_group (dict_t *dict, char *key, char *value, char **op_errstr) +{ + int ret = -1; + int opt_count = 0; + char iter_key[1024] = {0,}; + char iter_val[1024] = {0,}; + char *saveptr = NULL; + char *tok_key = NULL; + char *tok_val = NULL; + char *dkey = NULL; + char *dval = NULL; + char *tagpath = NULL; + char *buf = NULL; + char line[PATH_MAX + 256] = {0,}; + char errstr[2048] = ""; + FILE *fp = NULL; + + ret = gf_asprintf (&tagpath, "%s/groups/%s", + GLUSTERD_DEFAULT_WORKDIR, value); + if (ret == -1) { + tagpath = NULL; + goto out; + } + + fp = fopen (tagpath, "r"); + if (!fp) { + ret = -1; + snprintf(errstr, sizeof(errstr), "Unable to open file '%s'." + " Error: %s", tagpath, strerror (errno)); + if (op_errstr) + *op_errstr = gf_strdup(errstr); + goto out; + } + + opt_count = 0; + buf = line; + while (fscanf (fp, "%s", buf) != EOF) { + + opt_count++; + tok_key = strtok_r (line, "=", &saveptr); + tok_val = strtok_r (NULL, "=", &saveptr); + if (!tok_key || !tok_val) { + ret = -1; + snprintf(errstr, sizeof(errstr), "'%s' file format " + "not valid.", tagpath); + if (op_errstr) + *op_errstr = gf_strdup(errstr); + goto out; + } + + snprintf (iter_key, sizeof (iter_key), "key%d", opt_count); + dkey = gf_strdup (tok_key); + ret = dict_set_dynstr (dict, iter_key, dkey); + if (ret) + goto out; + dkey = NULL; + + snprintf (iter_val, sizeof (iter_val), "value%d", opt_count); + dval = gf_strdup (tok_val); + ret = dict_set_dynstr (dict, iter_val, dval); + if (ret) + goto out; + dval = NULL; + + } + + if (!opt_count) { + ret = -1; + snprintf(errstr, sizeof(errstr), "'%s' file format " + "not valid.", tagpath); + if (op_errstr) + *op_errstr = gf_strdup(errstr); + goto out; + } + ret = dict_set_int32 (dict, "count", opt_count); +out: + + GF_FREE (tagpath); + + if (ret) { + GF_FREE (dkey); + GF_FREE (dval); + } + + if (fp) + fclose (fp); + + return ret; +} +#undef GLUSTERD_DEFAULT_WORKDIR + +int32_t +cli_cmd_volume_set_parse (const char **words, int wordcount, dict_t **options, + char **op_errstr) +{ + dict_t *dict = NULL; + char *volname = NULL; + int ret = -1; + int count = 0; + char *key = NULL; + char *value = NULL; + int i = 0; + char str[50] = {0,}; + + GF_ASSERT (words); + GF_ASSERT (options); dict = dict_new (); if (!dict) goto out; - if (wordcount < 4) + if (wordcount < 3) goto out; volname = (char *)words[2]; @@ -367,32 +823,65 @@ cli_cmd_volume_set_parse (const char **words, int wordcount, dict_t **options) if (ret) goto out; + if ((!strcmp (volname, "help") || !strcmp (volname, "help-xml")) + && wordcount == 3 ) { + ret = dict_set_str (dict, volname, volname); + if (ret) + goto out; - for (i = 3; i < wordcount; i+=2) { + } else if (wordcount < 5) { + ret = -1; + goto out; - key = (char *) words[i]; - value = (char *) words[i+1]; + } else if (wordcount == 5 && cli_is_key_spl ((char *)words[3])) { + key = (char *) words[3]; + value = (char *) words[4]; + if ( !key || !value) { + ret = -1; + goto out; + } - if ( key && !value ) { - if ( !strcmp (key, "history")) { - ret = dict_set_str (dict, key, "history"); - if (ret) - goto out; - ret = dict_set_int32 (dict, "count", 1); - if (ret) - goto out; - *options = dict; - goto out; - } + ret = gf_strip_whitespace (value, strlen (value)); + if (ret == -1) + goto out; + + if (strlen (value) == 0) { + ret = -1; + goto out; } - if ( !key || !value) { - ret = -1; - goto out; - } + ret = cli_add_key_group (dict, key, value, op_errstr); + if (ret == 0) + *options = dict; + goto out; + } + + for (i = 3; i < wordcount; i+=2) { + + key = (char *) words[i]; + value = (char *) words[i+1]; + + if ( !key || !value) { + ret = -1; + goto out; + } count++; + ret = gf_strip_whitespace (value, strlen (value)); + if (ret == -1) + goto out; + + if (strlen (value) == 0) { + ret = -1; + goto out; + } + + if (cli_is_key_spl (key)) { + ret = -1; + goto out; + } + sprintf (str, "key%d", count); ret = dict_set_str (dict, str, key); if (ret) @@ -413,10 +902,8 @@ cli_cmd_volume_set_parse (const char **words, int wordcount, dict_t **options) *options = dict; out: - if (ret) { - if (dict) - dict_destroy (dict); - } + if (ret) + dict_destroy (dict); return ret; } @@ -427,27 +914,20 @@ cli_cmd_volume_add_brick_parse (const char **words, int wordcount, { dict_t *dict = NULL; char *volname = NULL; - char *delimiter = NULL; int ret = -1; - gf1_cluster_type type = GF_CLUSTER_TYPE_NONE; - int count = 0; - //char key[50] = {0,}; int brick_count = 0, brick_index = 0; - int brick_list_size = 1; - char brick_list[120000] = {0,}; - int j = 0; - char *tmp_list = NULL; - char *tmpptr = NULL; - char *host_name = NULL; - char *tmp = NULL; - char *freeptr = NULL; + char *bricks = NULL; + char *opwords_cl[] = { "replica", "stripe", NULL }; + gf1_cluster_type type = GF_CLUSTER_TYPE_NONE; + int count = 1; + char *w = NULL; + int index; + gf_boolean_t is_force = _gf_false; + int wc = wordcount; GF_ASSERT (words); GF_ASSERT (options); - GF_ASSERT ((strcmp (words[0], "volume")) == 0); - GF_ASSERT ((strcmp (words[1], "add-brick")) == 0); - dict = dict_new (); if (!dict) @@ -469,106 +949,70 @@ cli_cmd_volume_add_brick_parse (const char **words, int wordcount, ret = -1; goto out; } + if (wordcount < 6) { + /* seems no options are given, go directly to the parse_brick */ + brick_index = 3; + type = GF_CLUSTER_TYPE_NONE; + goto parse_bricks; + } - if ((strcasecmp (words[3], "replica")) == 0) { + w = str_getunamb (words[3], opwords_cl); + if (!w) { + type = GF_CLUSTER_TYPE_NONE; + index = 3; + } else if ((strcmp (w, "replica")) == 0) { type = GF_CLUSTER_TYPE_REPLICATE; if (wordcount < 5) { ret = -1; goto out; } - - errno = 0; count = strtol (words[4], NULL, 0); - if (errno == ERANGE && (count == LONG_MAX || count == LONG_MIN)) - goto out; - - brick_index = 5; - } else if ((strcasecmp (words[3], "stripe")) == 0) { - type = GF_CLUSTER_TYPE_STRIPE; - if (wordcount < 5) { + if (!count || (count < 2)) { + cli_err ("replica count should be greater than 1"); ret = -1; goto out; } - - errno = 0; - count = strtol (words[4], NULL, 0); - if (errno == ERANGE && (count == LONG_MAX || count == LONG_MIN)) - goto out; - - brick_index = 5; - } else { - brick_index = 3; - } - - strcpy (brick_list, " "); - while (brick_index < wordcount) { - delimiter = strchr (words[brick_index], ':'); - if (!delimiter || delimiter == words[brick_index] - || *(delimiter+1) != '/') { - cli_out ("wrong brick type: %s, use <HOSTNAME>:" - "<export-dir-abs-path>", words[brick_index]); - ret = -1; + ret = dict_set_int32 (dict, "replica-count", count); + if (ret) goto out; - } else { - cli_path_strip_trailing_slashes (delimiter + 1); - } - - if ((brick_list_size + strlen (words[brick_index]) + 1) > 120000) { - gf_log ("cli", GF_LOG_ERROR, - "total brick list is larger than a request " - "can take (brick_count %d)", brick_count); + index = 5; + } else if ((strcmp (w, "stripe")) == 0) { + type = GF_CLUSTER_TYPE_STRIPE; + if (wordcount < 5) { ret = -1; goto out; } - - host_name = gf_strdup(words[brick_index]); - if (!host_name) { + count = strtol (words[4], NULL, 0); + if (!count || (count < 2)) { + cli_err ("stripe count should be greater than 1"); ret = -1; - gf_log ("cli", GF_LOG_ERROR, "unable to allocate " - "memory"); goto out; } - freeptr = host_name; - strtok_r(host_name, ":", &tmp); - if (!(strcmp(host_name, "localhost") && - strcmp (host_name, "127.0.0.1"))) { - cli_out ("Please provide a valid hostname/ip other " - "localhost or 127.0.0.1"); - ret = -1; - GF_FREE (freeptr); + ret = dict_set_int32 (dict, "stripe-count", count); + if (ret) goto out; - } - GF_FREE (freeptr); + index = 5; + } else { + GF_ASSERT (!"opword mismatch"); + ret = -1; + goto out; + } - tmp_list = strdup(brick_list+1); - j = 0; - while(( brick_count != 0) && (j < brick_count)) { - strtok_r (tmp_list, " ", &tmpptr); - if (!(strcmp (tmp_list, words[brick_index]))) { - ret = -1; - cli_out ("Found duplicate" - " exports %s",words[brick_index]); - goto out; - } - tmp_list = tmpptr; - j++; - } + brick_index = index; - strcat (brick_list, words[brick_index]); - strcat (brick_list, " "); - brick_list_size += (strlen (words[brick_index]) + 1); - ++brick_count; - ++brick_index; - /* - char key[50]; - snprintf (key, 50, "brick%d", ++brick_count); - ret = dict_set_str (dict, key, (char *)words[brick_index++]); +parse_bricks: - if (ret) - goto out; - */ + if (strcmp (words[wordcount - 1], "force") == 0) { + is_force = _gf_true; + wc = wordcount - 1; } - ret = dict_set_str (dict, "bricks", brick_list); + + ret = cli_cmd_bricks_parse (words, wc, brick_index, &bricks, + &brick_count); + if (ret) + goto out; + + ret = dict_set_dynstr (dict, "bricks", bricks); if (ret) goto out; @@ -577,6 +1021,10 @@ cli_cmd_volume_add_brick_parse (const char **words, int wordcount, if (ret) goto out; + ret = dict_set_int32 (dict, "force", is_force); + if (ret) + goto out; + *options = dict; out: @@ -592,82 +1040,106 @@ out: int32_t cli_cmd_volume_remove_brick_parse (const char **words, int wordcount, - dict_t **options) + dict_t **options, int *question) { dict_t *dict = NULL; char *volname = NULL; char *delimiter = NULL; int ret = -1; - gf1_cluster_type type = GF_CLUSTER_TYPE_NONE; - int count = 0; char key[50]; int brick_count = 0, brick_index = 0; int32_t tmp_index = 0; int32_t j = 0; char *tmp_brick = NULL; char *tmp_brick1 = NULL; + char *type_opword[] = { "replica", NULL }; + char *opwords[] = { "start", "commit", "stop", "status", + "force", NULL }; + char *w = NULL; + int32_t command = GF_OP_CMD_NONE; + long count = 0; GF_ASSERT (words); GF_ASSERT (options); - GF_ASSERT ((strcmp (words[0], "volume")) == 0); - GF_ASSERT ((strcmp (words[1], "remove-brick")) == 0); + if (wordcount < 4) + goto out; dict = dict_new (); - if (!dict) goto out; - if (wordcount < 3) - goto out; - volname = (char *)words[2]; GF_ASSERT (volname); ret = dict_set_str (dict, "volname", volname); - if (ret) goto out; - if (wordcount < 4) { - ret = -1; - goto out; - } - - if ((strcasecmp (words[3], "replica")) == 0) { - type = GF_CLUSTER_TYPE_REPLICATE; + brick_index = 3; + w = str_getunamb (words[3], type_opword); + if (w && !strcmp ("replica", w)) { if (wordcount < 5) { ret = -1; goto out; } - errno = 0; count = strtol (words[4], NULL, 0); - if (errno == ERANGE && (count == LONG_MAX || count == LONG_MIN)) - goto out; - - brick_index = 5; - } else if ((strcasecmp (words[3], "stripe")) == 0) { - type = GF_CLUSTER_TYPE_STRIPE; - if (wordcount < 5) { + if (count < 1) { + cli_err ("replica count should be greater than 0 in " + "case of remove-brick"); ret = -1; goto out; } - errno = 0; - count = strtol (words[4], NULL, 0); - if (errno == ERANGE && (count == LONG_MAX || count == LONG_MIN)) + ret = dict_set_int32 (dict, "replica-count", count); + if (ret) goto out; - brick_index = 5; + } else if (w) { + GF_ASSERT (!"opword mismatch"); + } + + w = str_getunamb (words[wordcount - 1], opwords); + if (!w) { + /* Should be default 'force' */ + command = GF_OP_CMD_COMMIT_FORCE; + if (question) + *question = 1; } else { - brick_index = 3; + /* handled this option */ + wordcount--; + if (!strcmp ("start", w)) { + command = GF_OP_CMD_START; + } else if (!strcmp ("commit", w)) { + command = GF_OP_CMD_COMMIT; + if (question) + *question = 1; + } else if (!strcmp ("stop", w)) { + command = GF_OP_CMD_STOP; + } else if (!strcmp ("status", w)) { + command = GF_OP_CMD_STATUS; + } else if (!strcmp ("force", w)) { + command = GF_OP_CMD_COMMIT_FORCE; + if (question) + *question = 1; + } else { + GF_ASSERT (!"opword mismatch"); + ret = -1; + goto out; + } } - ret = dict_set_int32 (dict, "type", type); + if (wordcount < 4) { + ret = -1; + goto out; + } + ret = dict_set_int32 (dict, "command", command); if (ret) - goto out; + gf_log ("cli", GF_LOG_INFO, "failed to set 'command' %d", + command); + tmp_index = brick_index; tmp_brick = GF_MALLOC(2048 * sizeof(*tmp_brick), gf_common_mt_char); @@ -678,7 +1150,7 @@ cli_cmd_volume_remove_brick_parse (const char **words, int wordcount, ret = -1; goto out; } - + tmp_brick1 = GF_MALLOC(2048 * sizeof(*tmp_brick1), gf_common_mt_char); if (!tmp_brick1) { @@ -689,15 +1161,16 @@ cli_cmd_volume_remove_brick_parse (const char **words, int wordcount, } while (brick_index < wordcount) { - delimiter = strchr(words[brick_index], ':'); - if (!delimiter || delimiter == words[brick_index] - || *(delimiter+1) != '/') { - cli_out ("wrong brick type: %s, use <HOSTNAME>:" + if (validate_brick_name ((char *)words[brick_index])) { + cli_err ("wrong brick type: %s, use <HOSTNAME>:" "<export-dir-abs-path>", words[brick_index]); ret = -1; goto out; } else { - cli_path_strip_trailing_slashes (delimiter + 1); + delimiter = strrchr(words[brick_index], ':'); + ret = gf_canonicalize_path (delimiter + 1); + if (ret) + goto out; } j = tmp_index; @@ -707,7 +1180,7 @@ cli_cmd_volume_remove_brick_parse (const char **words, int wordcount, if (!(strcmp (tmp_brick, tmp_brick1))) { gf_log("",GF_LOG_ERROR, "Duplicate bricks" " found %s", words[brick_index]); - cli_out("Duplicate bricks found %s", + cli_err("Duplicate bricks found %s", words[brick_index]); ret = -1; goto out; @@ -722,7 +1195,6 @@ cli_cmd_volume_remove_brick_parse (const char **words, int wordcount, } ret = dict_set_int32 (dict, "count", brick_count); - if (ret) goto out; @@ -735,10 +1207,8 @@ out: dict_destroy (dict); } - if (tmp_brick) - GF_FREE (tmp_brick); - if (tmp_brick1) - GF_FREE (tmp_brick1); + GF_FREE (tmp_brick); + GF_FREE (tmp_brick1); return ret; } @@ -751,17 +1221,17 @@ cli_cmd_volume_replace_brick_parse (const char **words, int wordcount, dict_t *dict = NULL; char *volname = NULL; int ret = -1; - char *op = NULL; int op_index = 0; char *delimiter = NULL; gf1_cli_replace_op replace_op = GF_REPLACE_OP_NONE; + char *opwords[] = { "start", "commit", "pause", "abort", "status", + NULL }; + char *w = NULL; + gf_boolean_t is_force = _gf_false; GF_ASSERT (words); GF_ASSERT (options); - GF_ASSERT ((strcmp (words[0], "volume")) == 0); - GF_ASSERT ((strcmp (words[1], "replace-brick")) == 0); - dict = dict_new (); if (!dict) @@ -784,15 +1254,16 @@ cli_cmd_volume_replace_brick_parse (const char **words, int wordcount, goto out; } - delimiter = strchr ((char *)words[3], ':'); - if (!delimiter || delimiter == words[3] - || *(delimiter+1) != '/') { - cli_out ("wrong brick type: %s, use " - "<HOSTNAME>:<export-dir-abs-path>", words[3]); + if (validate_brick_name ((char *)words[3])) { + cli_err ("wrong brick type: %s, use " + "<HOSTNAME>:<export-dir-abs-path>", words[3]); ret = -1; goto out; } else { - cli_path_strip_trailing_slashes (delimiter + 1); + delimiter = strrchr ((char *)words[3], ':'); + ret = gf_canonicalize_path (delimiter + 1); + if (ret) + goto out; } ret = dict_set_str (dict, "src-brick", (char *)words[3]); @@ -804,15 +1275,16 @@ cli_cmd_volume_replace_brick_parse (const char **words, int wordcount, goto out; } - delimiter = strchr ((char *)words[4], ':'); - if (!delimiter || delimiter == words[4] - || *(delimiter+1) != '/') { - cli_out ("wrong brick type: %s, use " - "<HOSTNAME>:<export-dir-abs-path>", words[4]); + if (validate_brick_name ((char *)words[4])) { + cli_err ("wrong brick type: %s, use " + "<HOSTNAME>:<export-dir-abs-path>", words[4]); ret = -1; goto out; } else { - cli_path_strip_trailing_slashes (delimiter + 1); + delimiter = strrchr ((char *)words[4], ':'); + ret = gf_canonicalize_path (delimiter + 1); + if (ret) + goto out; } @@ -827,21 +1299,24 @@ cli_cmd_volume_replace_brick_parse (const char **words, int wordcount, goto out; } - op = (char *) words[op_index]; + w = str_getunamb (words[op_index], opwords); - if (!strcasecmp ("start", op)) { + if (!w) { + } else if (!strcmp ("start", w)) { replace_op = GF_REPLACE_OP_START; - } else if (!strcasecmp ("commit", op)) { + } else if (!strcmp ("commit", w)) { replace_op = GF_REPLACE_OP_COMMIT; - } else if (!strcasecmp ("pause", op)) { + } else if (!strcmp ("pause", w)) { replace_op = GF_REPLACE_OP_PAUSE; - } else if (!strcasecmp ("abort", op)) { + } else if (!strcmp ("abort", w)) { replace_op = GF_REPLACE_OP_ABORT; - } else if (!strcasecmp ("status", op)) { + } else if (!strcmp ("status", w)) { replace_op = GF_REPLACE_OP_STATUS; - } + } else + GF_ASSERT (!"opword mismatch"); /* commit force option */ + op_index = 6; if (wordcount > (op_index + 1)) { @@ -850,9 +1325,17 @@ cli_cmd_volume_replace_brick_parse (const char **words, int wordcount, } if (wordcount == (op_index + 1)) { - op = (char *) words[op_index]; - if (!strcasecmp ("force", op)) { - replace_op = GF_REPLACE_OP_COMMIT_FORCE; + if ((replace_op != GF_REPLACE_OP_COMMIT) && + (replace_op != GF_REPLACE_OP_START)) { + ret = -1; + goto out; + } + if (!strcmp ("force", words[op_index])) { + if (replace_op == GF_REPLACE_OP_COMMIT) + replace_op = GF_REPLACE_OP_COMMIT_FORCE; + + else if (replace_op == GF_REPLACE_OP_START) + is_force = _gf_true; } } @@ -866,14 +1349,15 @@ cli_cmd_volume_replace_brick_parse (const char **words, int wordcount, if (ret) goto out; - - + ret = dict_set_int32 (dict, "force", is_force); + if (ret) + goto out; *options = dict; out: if (ret) { - gf_log ("cli", GF_LOG_ERROR, "Unable to parse remove-brick CLI"); + gf_log ("cli", GF_LOG_ERROR, "Unable to parse replace-brick CLI"); if (dict) dict_destroy (dict); } @@ -893,10 +1377,6 @@ cli_cmd_log_filename_parse (const char **words, int wordcount, dict_t **options) GF_ASSERT (words); GF_ASSERT (options); - GF_ASSERT ((strcmp (words[0], "volume")) == 0); - GF_ASSERT ((strcmp (words[1], "log")) == 0); - GF_ASSERT ((strcmp (words[2], "filename")) == 0); - dict = dict_new (); if (!dict) goto out; @@ -913,12 +1393,14 @@ cli_cmd_log_filename_parse (const char **words, int wordcount, dict_t **options) delimiter = strchr (words[4], ':'); if (!delimiter || delimiter == words[4] || *(delimiter+1) != '/') { - cli_out ("wrong brick type: %s, use <HOSTNAME>:" + cli_err ("wrong brick type: %s, use <HOSTNAME>:" "<export-dir-abs-path>", words[4]); ret = -1; goto out; } else { - cli_path_strip_trailing_slashes (delimiter + 1); + ret = gf_canonicalize_path (delimiter + 1); + if (ret) + goto out; } ret = dict_set_str (dict, "brick", str); if (ret) @@ -944,6 +1426,63 @@ out: } int32_t +cli_cmd_log_level_parse (const char **words, int worcount, dict_t **options) +{ + dict_t *dict = NULL; + int ret = -1; + + GF_ASSERT (words); + GF_ASSERT (options); + + /* + * loglevel command format: + * > volume log level <VOL> <XLATOR[*]> <LOGLEVEL> + * > volume log level colon-o posix WARNING + * > volume log level colon-o replicate* DEBUG + * > volume log level coon-o * TRACE + */ + + GF_ASSERT ((strncmp(words[0], "volume", 6) == 0)); + GF_ASSERT ((strncmp(words[1], "log", 3) == 0)); + GF_ASSERT ((strncmp(words[2], "level", 5) == 0)); + + ret = glusterd_check_log_level(words[5]); + if (ret == -1) { + cli_err("Invalid log level [%s] specified", words[5]); + cli_err("Valid values for loglevel: (DEBUG|WARNING|ERROR" + "|CRITICAL|NONE|TRACE)"); + goto out; + } + + dict = dict_new (); + if (!dict) + goto out; + + GF_ASSERT(words[3]); + GF_ASSERT(words[4]); + + ret = dict_set_str (dict, "volname", (char *)words[3]); + if (ret) + goto out; + + ret = dict_set_str (dict, "xlator", (char *)words[4]); + if (ret) + goto out; + + ret = dict_set_str (dict, "loglevel", (char *)words[5]); + if (ret) + goto out; + + *options = dict; + + out: + if (ret && dict) + dict_destroy (dict); + + return ret; +} + +int32_t cli_cmd_log_locate_parse (const char **words, int wordcount, dict_t **options) { dict_t *dict = NULL; @@ -955,10 +1494,6 @@ cli_cmd_log_locate_parse (const char **words, int wordcount, dict_t **options) GF_ASSERT (words); GF_ASSERT (options); - GF_ASSERT ((strcmp (words[0], "volume")) == 0); - GF_ASSERT ((strcmp (words[1], "log")) == 0); - GF_ASSERT ((strcmp (words[2], "locate")) == 0); - dict = dict_new (); if (!dict) goto out; @@ -974,12 +1509,14 @@ cli_cmd_log_locate_parse (const char **words, int wordcount, dict_t **options) delimiter = strchr (words[4], ':'); if (!delimiter || delimiter == words[4] || *(delimiter+1) != '/') { - cli_out ("wrong brick type: %s, use <HOSTNAME>:" + cli_err ("wrong brick type: %s, use <HOSTNAME>:" "<export-dir-abs-path>", words[4]); ret = -1; goto out; } else { - cli_path_strip_trailing_slashes (delimiter + 1); + ret = gf_canonicalize_path (delimiter + 1); + if (ret) + goto out; } str = (char *)words[4]; ret = dict_set_str (dict, "brick", str); @@ -1008,10 +1545,6 @@ cli_cmd_log_rotate_parse (const char **words, int wordcount, dict_t **options) GF_ASSERT (words); GF_ASSERT (options); - GF_ASSERT ((strcmp (words[0], "volume")) == 0); - GF_ASSERT ((strcmp (words[1], "log")) == 0); - GF_ASSERT ((strcmp (words[2], "rotate")) == 0); - dict = dict_new (); if (!dict) goto out; @@ -1027,12 +1560,14 @@ cli_cmd_log_rotate_parse (const char **words, int wordcount, dict_t **options) delimiter = strchr (words[4], ':'); if (!delimiter || delimiter == words[4] || *(delimiter+1) != '/') { - cli_out ("wrong brick type: %s, use <HOSTNAME>:" + cli_err ("wrong brick type: %s, use <HOSTNAME>:" "<export-dir-abs-path>", words[4]); ret = -1; goto out; } else { - cli_path_strip_trailing_slashes (delimiter + 1); + ret = gf_canonicalize_path (delimiter + 1); + if (ret) + goto out; } str = (char *)words[4]; ret = dict_set_str (dict, "brick", str); @@ -1048,3 +1583,2100 @@ out: return ret; } + +static gf_boolean_t +gsyncd_url_check (const char *w) +{ + return !!strpbrk (w, ":/"); +} + +static gf_boolean_t +gsyncd_glob_check (const char *w) +{ + return !!strpbrk (w, "*?["); +} + +static int +config_parse (const char **words, int wordcount, dict_t *dict, + unsigned cmdi, unsigned glob) +{ + int32_t ret = -1; + int32_t i = -1; + char *append_str = NULL; + size_t append_len = 0; + char *subop = NULL; + + switch ((wordcount - 1) - cmdi) { + case 0: + subop = gf_strdup ("get-all"); + break; + case 1: + if (words[cmdi + 1][0] == '!') { + (words[cmdi + 1])++; + if (gf_asprintf (&subop, "del%s", + glob ? "-glob" : "") == -1) + subop = NULL; + } else + subop = gf_strdup ("get"); + + ret = dict_set_str (dict, "op_name", ((char *)words[cmdi + 1])); + if (ret < 0) + goto out; + break; + default: + if (gf_asprintf (&subop, "set%s", glob ? "-glob" : "") == -1) + subop = NULL; + + ret = dict_set_str (dict, "op_name", ((char *)words[cmdi + 1])); + if (ret < 0) + goto out; + + /* join the varargs by spaces to get the op_value */ + + for (i = cmdi + 2; i < wordcount; i++) + append_len += (strlen (words[i]) + 1); + /* trailing strcat will add two bytes, make space for that */ + append_len++; + + append_str = GF_CALLOC (1, append_len, cli_mt_append_str); + if (!append_str) { + ret = -1; + goto out; + } + + for (i = cmdi + 2; i < wordcount; i++) { + strcat (append_str, words[i]); + strcat (append_str, " "); + } + append_str[append_len - 2] = '\0'; + /* "checkpoint now" is special: we resolve that "now" */ + if (strcmp (words[cmdi + 1], "checkpoint") == 0 && + strcmp (append_str, "now") == 0) { + struct timeval tv = {0,}; + + ret = gettimeofday (&tv, NULL); + if (ret == -1) + goto out; /* FIXME: free append_str? */ + + GF_FREE (append_str); + append_str = GF_CALLOC (1, 300, cli_mt_append_str); + if (!append_str) { + ret = -1; + goto out; + } + strcpy (append_str, "as of "); + gf_time_fmt (append_str + strlen ("as of "), + 300 - strlen ("as of "), + tv.tv_sec, gf_timefmt_FT); + } + + ret = dict_set_dynstr (dict, "op_value", append_str); + } + + ret = -1; + if (subop) { + ret = dict_set_dynstr (dict, "subop", subop); + if (!ret) + subop = NULL; + } + +out: + if (ret && append_str) + GF_FREE (append_str); + + GF_FREE (subop); + + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +static int32_t +force_push_pem_parse (const char **words, int wordcount, + dict_t *dict, unsigned *cmdi) +{ + int32_t ret = 0; + + if (!strcmp ((char *)words[wordcount-1], "force")) { + if ((strcmp ((char *)words[wordcount-2], "start")) && + (strcmp ((char *)words[wordcount-2], "stop")) && + (strcmp ((char *)words[wordcount-2], "create")) && + (strcmp ((char *)words[wordcount-2], "push-pem"))) { + ret = -1; + goto out; + } + ret = dict_set_uint32 (dict, "force", + _gf_true); + if (ret) + goto out; + (*cmdi)++; + + if (!strcmp ((char *)words[wordcount-2], "push-pem")) { + if (strcmp ((char *)words[wordcount-3], "create")) { + ret = -1; + goto out; + } + ret = dict_set_int32 (dict, "push_pem", 1); + if (ret) + goto out; + (*cmdi)++; + } + } else if (!strcmp ((char *)words[wordcount-1], "push-pem")) { + if (strcmp ((char *)words[wordcount-2], "create")) { + ret = -1; + goto out; + } + ret = dict_set_int32 (dict, "push_pem", 1); + if (ret) + goto out; + (*cmdi)++; + } + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + + +int32_t +cli_cmd_gsync_set_parse (const char **words, int wordcount, dict_t **options) +{ + int32_t ret = -1; + dict_t *dict = NULL; + gf1_cli_gsync_set type = GF_GSYNC_OPTION_TYPE_NONE; + int i = 0; + unsigned masteri = 0; + unsigned slavei = 0; + unsigned glob = 0; + unsigned cmdi = 0; + char *opwords[] = { "create", "status", "start", "stop", + "config", "force", "delete", + "push-pem", "detail", NULL }; + char *w = NULL; + + GF_ASSERT (words); + GF_ASSERT (options); + + dict = dict_new (); + if (!dict) + goto out; + + /* new syntax: + * + * volume geo-replication $m $s create [push-pem] [force] + * volume geo-replication [$m [$s]] status [detail] + * volume geo-replication [$m] $s config [[!]$opt [$val]] + * volume geo-replication $m $s start|stop [force] + * volume geo-replication $m $s delete + */ + + if (wordcount < 3) + goto out; + + for (i = 2; i <= 3 && i < wordcount - 1; i++) { + if (gsyncd_glob_check (words[i])) + glob = i; + if (gsyncd_url_check (words[i])) { + slavei = i; + break; + } + } + + if (glob && !slavei) + /* glob is allowed only for config, thus it implies there is a + * slave argument; but that might have not been recognized on + * the first scan as it's url characteristics has been covered + * by the glob syntax. + * + * In this case, the slave is perforce the last glob-word -- the + * upcoming one is neither glob, nor url, so it's definitely not + * the slave. + */ + slavei = glob; + if (slavei) { + cmdi = slavei + 1; + if (slavei == 3) + masteri = 2; + } else if (i <= 3) { + if (!strcmp ((char *)words[wordcount-1], "detail")) { + /* For status detail it is mandatory to provide + * both master and slave */ + ret = -1; + goto out; + } + + /* no $s, can only be status cmd + * (with either a single $m before it or nothing) + * -- these conditions imply that i <= 3 after + * the iteration and that i is the successor of + * the (0 or 1 length) sequence of $m-s. + */ + cmdi = i; + if (i == 3) + masteri = 2; + } else + goto out; + + /* now check if input really complies syntax + * (in a somewhat redundant way, in favor + * transparent soundness) + */ + + if (masteri && gsyncd_url_check (words[masteri])) + goto out; + if (slavei && !glob && !gsyncd_url_check (words[slavei])) + goto out; + + w = str_getunamb (words[cmdi], opwords); + if (!w) + goto out; + + if (strcmp (w, "create") == 0) { + type = GF_GSYNC_OPTION_TYPE_CREATE; + + if (!masteri || !slavei) + goto out; + } else if (strcmp (w, "status") == 0) { + type = GF_GSYNC_OPTION_TYPE_STATUS; + + if (slavei && !masteri) + goto out; + } else if (strcmp (w, "config") == 0) { + type = GF_GSYNC_OPTION_TYPE_CONFIG; + + if (!slavei) + goto out; + } else if (strcmp (w, "start") == 0) { + type = GF_GSYNC_OPTION_TYPE_START; + + if (!masteri || !slavei) + goto out; + } else if (strcmp (w, "stop") == 0) { + type = GF_GSYNC_OPTION_TYPE_STOP; + + if (!masteri || !slavei) + goto out; + } else if (strcmp (w, "delete") == 0) { + type = GF_GSYNC_OPTION_TYPE_DELETE; + + if (!masteri || !slavei) + goto out; + } else + GF_ASSERT (!"opword mismatch"); + + ret = force_push_pem_parse (words, wordcount, dict, &cmdi); + if (ret) + goto out; + + if (!strcmp ((char *)words[wordcount-1], "detail")) { + if (strcmp ((char *)words[wordcount-2], "status")) { + ret = -1; + goto out; + } + if (!slavei || !masteri) { + ret = -1; + goto out; + } + ret = dict_set_uint32 (dict, "status-detail", _gf_true); + if (ret) + goto out; + cmdi++; + } + + if (type != GF_GSYNC_OPTION_TYPE_CONFIG && + (cmdi < wordcount - 1 || glob)) + goto out; + + /* If got so far, input is valid, assemble the message */ + + ret = 0; + + if (masteri) { + ret = dict_set_str (dict, "master", (char *)words[masteri]); + if (!ret) + ret = dict_set_str (dict, "volname", + (char *)words[masteri]); + } + if (!ret && slavei) + ret = dict_set_str (dict, "slave", (char *)words[slavei]); + if (!ret) + ret = dict_set_int32 (dict, "type", type); + if (!ret && type == GF_GSYNC_OPTION_TYPE_CONFIG) + ret = config_parse (words, wordcount, dict, cmdi, glob); + +out: + if (ret) { + if (dict) + dict_destroy (dict); + } else + *options = dict; + + + return ret; +} + +int32_t +cli_cmd_volume_profile_parse (const char **words, int wordcount, + dict_t **options) +{ + dict_t *dict = NULL; + char *volname = NULL; + int ret = -1; + gf1_cli_stats_op op = GF_CLI_STATS_NONE; + char *opwords[] = { "start", "stop", "info", NULL }; + char *w = NULL; + + GF_ASSERT (words); + GF_ASSERT (options); + + dict = dict_new (); + if (!dict) + goto out; + + if (wordcount < 4 || wordcount >5) + goto out; + + volname = (char *)words[2]; + + ret = dict_set_str (dict, "volname", volname); + if (ret) + goto out; + + w = str_getunamb (words[3], opwords); + if (!w) { + ret = -1; + goto out; + } + if (strcmp (w, "start") == 0) { + op = GF_CLI_STATS_START; + } else if (strcmp (w, "stop") == 0) { + op = GF_CLI_STATS_STOP; + } else if (strcmp (w, "info") == 0) { + op = GF_CLI_STATS_INFO; + } else + GF_ASSERT (!"opword mismatch"); + + ret = dict_set_int32 (dict, "op", (int32_t)op); + if (ret) + goto out; + + if (wordcount == 5) { + if (!strcmp (words[4], "nfs")) { + ret = dict_set_int32 (dict, "nfs", _gf_true); + if (ret) + goto out; + } + } + + *options = dict; +out: + if (ret && dict) + dict_destroy (dict); + return ret; +} + +int32_t +cli_cmd_volume_top_parse (const char **words, int wordcount, + dict_t **options) +{ + dict_t *dict = NULL; + char *volname = NULL; + char *value = NULL; + char *key = NULL; + int ret = -1; + gf1_cli_stats_op op = GF_CLI_STATS_NONE; + gf1_cli_top_op top_op = GF_CLI_TOP_NONE; + int32_t list_cnt = -1; + int index = 0; + int perf = 0; + uint32_t blk_size = 0; + uint32_t count = 0; + gf_boolean_t nfs = _gf_false; + char *delimiter = NULL; + char *opwords[] = { "open", "read", "write", "opendir", + "readdir", "read-perf", "write-perf", + "clear", NULL }; + char *w = NULL; + + GF_ASSERT (words); + GF_ASSERT (options); + + dict = dict_new (); + if (!dict) + goto out; + + if (wordcount < 4) + goto out; + + volname = (char *)words[2]; + + ret = dict_set_str (dict, "volname", volname); + if (ret) + goto out; + + op = GF_CLI_STATS_TOP; + ret = dict_set_int32 (dict, "op", (int32_t)op); + if (ret) + goto out; + + w = str_getunamb (words[3], opwords); + if (!w) { + ret = -1; + goto out; + } + if (strcmp (w, "open") == 0) { + top_op = GF_CLI_TOP_OPEN; + } else if (strcmp (w, "read") == 0) { + top_op = GF_CLI_TOP_READ; + } else if (strcmp (w, "write") == 0) { + top_op = GF_CLI_TOP_WRITE; + } else if (strcmp (w, "opendir") == 0) { + top_op = GF_CLI_TOP_OPENDIR; + } else if (strcmp (w, "readdir") == 0) { + top_op = GF_CLI_TOP_READDIR; + } else if (strcmp (w, "read-perf") == 0) { + top_op = GF_CLI_TOP_READ_PERF; + perf = 1; + } else if (strcmp (w, "write-perf") == 0) { + top_op = GF_CLI_TOP_WRITE_PERF; + perf = 1; + } else if (strcmp (w, "clear") == 0) { + ret = dict_set_int32 (dict, "clear-stats", 1); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, + "Could not set clear-stats in dict"); + goto out; + } + } else + GF_ASSERT (!"opword mismatch"); + ret = dict_set_int32 (dict, "top-op", (int32_t)top_op); + if (ret) + goto out; + + if ((wordcount > 4) && !strcmp (words[4], "nfs")) { + nfs = _gf_true; + ret = dict_set_int32 (dict, "nfs", nfs); + if (ret) + goto out; + index = 5; + } else { + index = 4; + } + + for (; index < wordcount; index+=2) { + + key = (char *) words[index]; + value = (char *) words[index+1]; + + if ( key && !value ) { + ret = -1; + goto out; + } + if (!strcmp (key, "brick")) { + delimiter = strchr (value, ':'); + if (!delimiter || delimiter == value + || *(delimiter+1) != '/') { + cli_err ("wrong brick type: %s, use <HOSTNAME>:" + "<export-dir-abs-path>", value); + ret = -1; + goto out; + } else { + ret = gf_canonicalize_path (delimiter + 1); + if (ret) + goto out; + } + ret = dict_set_str (dict, "brick", value); + + } else if (!strcmp (key, "list-cnt")) { + ret = gf_is_str_int (value); + if (!ret) + list_cnt = atoi (value); + if (ret || (list_cnt < 0) || (list_cnt > 100)) { + cli_err ("list-cnt should be between 0 to 100"); + ret = -1; + goto out; + } + } else if (perf && !nfs && !strcmp (key, "bs")) { + ret = gf_is_str_int (value); + if (!ret) + blk_size = atoi (value); + if (ret || (blk_size <= 0)) { + if (blk_size < 0) + cli_err ("block size is an invalid" + " number"); + else + cli_err ("block size should be an " + "integer greater than zero"); + ret = -1; + goto out; + } + ret = dict_set_uint32 (dict, "blk-size", blk_size); + } else if (perf && !nfs && !strcmp (key, "count")) { + ret = gf_is_str_int (value); + if (!ret) + count = atoi(value); + if (ret || (count <= 0)) { + if (count < 0) + cli_err ("count is an invalid number"); + else + cli_err ("count should be an integer " + "greater than zero"); + + ret = -1; + goto out; + } + ret = dict_set_uint32 (dict, "blk-cnt", count); + } else { + ret = -1; + goto out; + } + if (ret) { + gf_log ("", GF_LOG_WARNING, "Dict set failed for " + "key %s", key); + goto out; + } + } + if (list_cnt == -1) + list_cnt = 100; + ret = dict_set_int32 (dict, "list-cnt", list_cnt); + if (ret) { + gf_log ("", GF_LOG_WARNING, "Dict set failed for list_cnt"); + goto out; + } + + if ((blk_size > 0) ^ (count > 0)) { + cli_err ("Need to give both 'bs' and 'count'"); + ret = -1; + goto out; + } else if (((uint64_t)blk_size * count) > (10 * GF_UNIT_GB)) { + cli_err ("'bs * count' value %"PRIu64" is greater than " + "maximum allowed value of 10GB", + ((uint64_t)blk_size * count)); + ret = -1; + goto out; + } + + *options = dict; +out: + if (ret && dict) + dict_destroy (dict); + return ret; +} + +uint32_t +cli_cmd_get_statusop (const char *arg) +{ + int i = 0; + uint32_t ret = GF_CLI_STATUS_NONE; + char *w = NULL; + char *opwords[] = {"detail", "mem", "clients", "fd", + "inode", "callpool", "tasks", NULL}; + struct { + char *opname; + uint32_t opcode; + } optable[] = { + { "detail", GF_CLI_STATUS_DETAIL }, + { "mem", GF_CLI_STATUS_MEM }, + { "clients", GF_CLI_STATUS_CLIENTS }, + { "fd", GF_CLI_STATUS_FD }, + { "inode", GF_CLI_STATUS_INODE }, + { "callpool", GF_CLI_STATUS_CALLPOOL }, + { "tasks", GF_CLI_STATUS_TASKS }, + { NULL } + }; + + w = str_getunamb (arg, opwords); + if (!w) { + gf_log ("cli", GF_LOG_DEBUG, + "Not a status op %s", arg); + goto out; + } + + for (i = 0; optable[i].opname; i++) { + if (!strcmp (w, optable[i].opname)) { + ret = optable[i].opcode; + break; + } + } + + out: + return ret; +} + +int +cli_cmd_volume_status_parse (const char **words, int wordcount, + dict_t **options) +{ + dict_t *dict = NULL; + int ret = -1; + uint32_t cmd = 0; + + GF_ASSERT (options); + + dict = dict_new (); + if (!dict) + goto out; + + switch (wordcount) { + + case 2: + cmd = GF_CLI_STATUS_ALL; + ret = 0; + break; + + case 3: + if (!strcmp (words[2], "all")) { + cmd = GF_CLI_STATUS_ALL; + ret = 0; + + } else { + cmd = GF_CLI_STATUS_VOL; + ret = dict_set_str (dict, "volname", (char *)words[2]); + } + + break; + + case 4: + cmd = cli_cmd_get_statusop (words[3]); + + if (!strcmp (words[2], "all")) { + if (cmd == GF_CLI_STATUS_NONE) { + cli_err ("%s is not a valid status option", + words[3]); + ret = -1; + goto out; + } + cmd |= GF_CLI_STATUS_ALL; + ret = 0; + + } else { + ret = dict_set_str (dict, "volname", + (char *)words[2]); + if (ret) + goto out; + + if (cmd == GF_CLI_STATUS_NONE) { + if (!strcmp (words[3], "nfs")) { + cmd |= GF_CLI_STATUS_NFS; + } else if (!strcmp (words[3], "shd")) { + cmd |= GF_CLI_STATUS_SHD; + } else { + cmd = GF_CLI_STATUS_BRICK; + ret = dict_set_str (dict, "brick", + (char *)words[3]); + } + + } else { + cmd |= GF_CLI_STATUS_VOL; + ret = 0; + } + } + + break; + + case 5: + if (!strcmp (words[2], "all")) { + cli_err ("Cannot specify brick/nfs for \"all\""); + ret = -1; + goto out; + } + + cmd = cli_cmd_get_statusop (words[4]); + if (cmd == GF_CLI_STATUS_NONE) { + cli_err ("%s is not a valid status option", + words[4]); + ret = -1; + goto out; + } + + + ret = dict_set_str (dict, "volname", (char *)words[2]); + if (ret) + goto out; + + if (!strcmp (words[3], "nfs")) { + if (cmd == GF_CLI_STATUS_FD || + cmd == GF_CLI_STATUS_DETAIL || + cmd == GF_CLI_STATUS_TASKS) { + cli_err ("Detail/FD/Tasks status not available" + " for NFS Servers"); + ret = -1; + goto out; + } + cmd |= GF_CLI_STATUS_NFS; + } else if (!strcmp (words[3], "shd")){ + if (cmd == GF_CLI_STATUS_FD || + cmd == GF_CLI_STATUS_CLIENTS || + cmd == GF_CLI_STATUS_DETAIL || + cmd == GF_CLI_STATUS_TASKS) { + cli_err ("Detail/FD/Clients/Tasks status not " + "available for Self-heal Daemons"); + ret = -1; + goto out; + } + cmd |= GF_CLI_STATUS_SHD; + } else { + if (cmd == GF_CLI_STATUS_TASKS) { + cli_err ("Tasks status not available for " + "bricks"); + ret = -1; + goto out; + } + cmd |= GF_CLI_STATUS_BRICK; + ret = dict_set_str (dict, "brick", (char *)words[3]); + } + break; + + default: + goto out; + } + + if (ret) + goto out; + + ret = dict_set_int32 (dict, "cmd", cmd); + if (ret) + goto out; + + *options = dict; + + out: + if (ret && dict) + dict_destroy (dict); + + return ret; +} + +gf_boolean_t +cli_cmd_validate_dumpoption (const char *arg, char **option) +{ + char *opwords[] = {"all", "nfs", "mem", "iobuf", "callpool", "priv", + "fd", "inode", "history", "inodectx", "fdctx", + NULL}; + char *w = NULL; + + w = str_getunamb (arg, opwords); + if (!w) { + gf_log ("cli", GF_LOG_DEBUG, "Unknown statedump option %s", + arg); + return _gf_false; + } + *option = w; + return _gf_true; +} + +int +cli_cmd_volume_statedump_options_parse (const char **words, int wordcount, + dict_t **options) +{ + int ret = 0; + int i = 0; + dict_t *dict = NULL; + int option_cnt = 0; + char *option = NULL; + char option_str[100] = {0,}; + + for (i = 3; i < wordcount; i++, option_cnt++) { + if (!cli_cmd_validate_dumpoption (words[i], &option)) { + ret = -1; + goto out; + } + strncat (option_str, option, strlen (option)); + strncat (option_str, " ", 1); + } + + dict = dict_new (); + if (!dict) + goto out; + + ret = dict_set_dynstr (dict, "options", gf_strdup (option_str)); + if (ret) + goto out; + + ret = dict_set_int32 (dict, "option_cnt", option_cnt); + if (ret) + goto out; + + *options = dict; +out: + if (ret && dict) + dict_destroy (dict); + if (ret) + gf_log ("cli", GF_LOG_ERROR, "Error parsing dumpoptions"); + return ret; +} + +int +cli_cmd_volume_clrlks_opts_parse (const char **words, int wordcount, + dict_t **options) +{ + int ret = -1; + int i = 0; + dict_t *dict = NULL; + char *kind_opts[4] = {"blocked", "granted", "all", NULL}; + char *types[4] = {"inode", "entry", "posix", NULL}; + char *free_ptr = NULL; + + dict = dict_new (); + if (!dict) + goto out; + + if (strcmp (words[4], "kind")) + goto out; + + for (i = 0; kind_opts[i]; i++) { + if (!strcmp (words[5], kind_opts[i])) { + free_ptr = gf_strdup (words[5]); + ret = dict_set_dynstr (dict, "kind", free_ptr); + if (ret) + goto out; + free_ptr = NULL; + break; + } + } + if (i == 3) + goto out; + + ret = -1; + for (i = 0; types[i]; i++) { + if (!strcmp (words[6], types[i])) { + free_ptr = gf_strdup (words[6]); + ret = dict_set_dynstr (dict, "type", free_ptr); + if (ret) + goto out; + free_ptr = NULL; + break; + } + } + if (i == 3) + goto out; + + if (wordcount == 8) { + free_ptr = gf_strdup (words[7]); + ret = dict_set_dynstr (dict, "opts", free_ptr); + if (ret) + goto out; + free_ptr = NULL; + } + + ret = 0; + *options = dict; +out: + if (ret) { + GF_FREE (free_ptr); + dict_unref (dict); + } + + return ret; +} + +static int +extract_hostname_path_from_token (const char *tmp_words, char **hostname, + char **path) +{ + int ret = 0; + char *delimiter = NULL; + char *tmp_host = NULL; + char *host_name = NULL; + char *words = NULL; + + *hostname = NULL; + *path = NULL; + + words = GF_CALLOC (1, strlen (tmp_words) + 1, gf_common_mt_char); + if (!words){ + ret = -1; + goto out; + } + + strncpy (words, tmp_words, strlen (tmp_words) + 1); + + if (validate_brick_name (words)) { + cli_err ("Wrong brick type: %s, use <HOSTNAME>:" + "<export-dir-abs-path>", words); + ret = -1; + goto out; + } else { + delimiter = strrchr (words, ':'); + ret = gf_canonicalize_path (delimiter + 1); + if (ret) { + goto out; + } else { + *path = GF_CALLOC (1, strlen (delimiter+1) +1, + gf_common_mt_char); + if (!*path) { + ret = -1; + goto out; + + } + strncpy (*path, delimiter +1, + strlen(delimiter + 1) + 1); + } + } + + tmp_host = gf_strdup (words); + if (!tmp_host) { + gf_log ("cli", GF_LOG_ERROR, "Out of memory"); + ret = -1; + goto out; + } + get_host_name (tmp_host, &host_name); + if (!host_name) { + ret = -1; + gf_log("cli",GF_LOG_ERROR, "Unable to allocate " + "memory"); + goto out; + } + if (!(strcmp (host_name, "localhost") && + strcmp (host_name, "127.0.0.1") && + strncmp (host_name, "0.", 2))) { + cli_err ("Please provide a valid hostname/ip other " + "than localhost, 127.0.0.1 or loopback " + "address (0.0.0.0 to 0.255.255.255)."); + ret = -1; + goto out; + } + if (!valid_internet_address (host_name, _gf_false)) { + cli_err ("internet address '%s' does not conform to " + "standards", host_name); + ret = -1; + goto out; + } + + *hostname = GF_CALLOC (1, strlen (host_name) + 1, + gf_common_mt_char); + if (!*hostname) { + ret = -1; + goto out; + } + strncpy (*hostname, host_name, strlen (host_name) + 1); + ret = 0; + +out: + GF_FREE (words); + GF_FREE (tmp_host); + return ret; +} + + +int +cli_cmd_volume_heal_options_parse (const char **words, int wordcount, + dict_t **options) +{ + int ret = 0; + dict_t *dict = NULL; + char *hostname = NULL; + char *path = NULL; + + dict = dict_new (); + if (!dict) + goto out; + + ret = dict_set_str (dict, "volname", (char *) words[2]); + if (ret) { + gf_log (THIS->name, GF_LOG_ERROR, "failed to set volname"); + goto out; + } + + if (wordcount == 3) { + ret = dict_set_int32 (dict, "heal-op", GF_AFR_OP_HEAL_INDEX); + goto done; + } + + if (wordcount == 4) { + if (!strcmp (words[3], "full")) { + ret = dict_set_int32 (dict, "heal-op", + GF_AFR_OP_HEAL_FULL); + goto done; + } else if (!strcmp (words[3], "statistics")) { + ret = dict_set_int32 (dict, "heal-op", + GF_AFR_OP_STATISTICS); + goto done; + + } else if (!strcmp (words[3], "info")) { + ret = dict_set_int32 (dict, "heal-op", + GF_AFR_OP_INDEX_SUMMARY); + goto done; + } else { + ret = -1; + goto out; + } + } + if (wordcount == 5) { + if (strcmp (words[3], "info") && + strcmp (words[3], "statistics")) { + ret = -1; + goto out; + } + + if (!strcmp (words[3], "info")) { + if (!strcmp (words[4], "healed")) { + ret = dict_set_int32 (dict, "heal-op", + GF_AFR_OP_HEALED_FILES); + goto done; + } + if (!strcmp (words[4], "heal-failed")) { + ret = dict_set_int32 (dict, "heal-op", + GF_AFR_OP_HEAL_FAILED_FILES); + goto done; + } + if (!strcmp (words[4], "split-brain")) { + ret = dict_set_int32 (dict, "heal-op", + GF_AFR_OP_SPLIT_BRAIN_FILES); + goto done; + } + } + + if (!strcmp (words[3], "statistics")) { + if (!strcmp (words[4], "heal-count")) { + ret = dict_set_int32 (dict, "heal-op", + GF_AFR_OP_STATISTICS_HEAL_COUNT); + goto done; + } + } + ret = -1; + goto out; + } + if (wordcount == 7) { + if (!strcmp (words[3], "statistics") + && !strcmp (words[4], "heal-count") + && !strcmp (words[5], "replica")) { + + ret = dict_set_int32 (dict, "heal-op", + GF_AFR_OP_STATISTICS_HEAL_COUNT_PER_REPLICA); + if (ret) + goto out; + ret = extract_hostname_path_from_token (words[6], + &hostname, &path); + if (ret) + goto out; + ret = dict_set_dynstr (dict, "per-replica-cmd-hostname", + hostname); + if (ret) + goto out; + ret = dict_set_dynstr (dict, "per-replica-cmd-path", + path); + if (ret) + goto out; + else + goto done; + + } + } + ret = -1; + goto out; +done: + *options = dict; +out: + if (ret && dict) { + dict_unref (dict); + *options = NULL; + } + + return ret; +} + +int +cli_cmd_volume_defrag_parse (const char **words, int wordcount, + dict_t **options) +{ + dict_t *dict = NULL; + int ret = -1; + char *option = NULL; + char *volname = NULL; + char *command = NULL; + gf_cli_defrag_type cmd = 0; + + GF_ASSERT (words); + GF_ASSERT (options); + + dict = dict_new (); + if (!dict) + goto out; + + if (!((wordcount == 4) || (wordcount == 5))) + goto out; + + if (wordcount == 4) { + if (strcmp (words[3], "start") && strcmp (words[3], "stop") && + strcmp (words[3], "status")) + goto out; + } else { + if (strcmp (words[3], "fix-layout") && + strcmp (words[3], "start")) + goto out; + } + + volname = (char *) words[2]; + + if (wordcount == 4) { + command = (char *) words[3]; + } + if (wordcount == 5) { + if ((strcmp (words[3], "fix-layout") || + strcmp (words[4], "start")) && + (strcmp (words[3], "start") || + strcmp (words[4], "force"))) { + ret = -1; + goto out; + } + command = (char *) words[3]; + option = (char *) words[4]; + } + + if (strcmp (command, "start") == 0) { + cmd = GF_DEFRAG_CMD_START; + if (option && strcmp (option, "force") == 0) { + cmd = GF_DEFRAG_CMD_START_FORCE; + } + goto done; + } + + if (strcmp (command, "fix-layout") == 0) { + cmd = GF_DEFRAG_CMD_START_LAYOUT_FIX; + goto done; + } + if (strcmp (command, "stop") == 0) { + cmd = GF_DEFRAG_CMD_STOP; + goto done; + } + if (strcmp (command, "status") == 0) { + cmd = GF_DEFRAG_CMD_STATUS; + } + +done: + ret = dict_set_str (dict, "volname", volname); + + if (ret) { + gf_log (THIS->name, GF_LOG_ERROR, "failed to set dict"); + goto out; + } + + ret = dict_set_int32 (dict, "rebalance-command", (int32_t) cmd); + + if (ret) { + gf_log (THIS->name, GF_LOG_ERROR, "failed to set dict"); + goto out; + } + + *options = dict; + +out: + if (ret && dict) + dict_destroy (dict); + + return ret; +} + +int32_t +cli_snap_create_desc_parse (dict_t *dict, const char **words, + size_t wordcount, int32_t desc_opt_loc) +{ + int32_t ret = -1; + char *desc = NULL; + int32_t desc_len = 0; + + desc = GF_CALLOC (MAX_SNAP_DESCRIPTION_LEN + 1, sizeof(char), + gf_common_mt_char); + if (!desc) { + ret = -1; + goto out; + } + + + if (strlen (words[desc_opt_loc]) >= MAX_SNAP_DESCRIPTION_LEN) { + cli_out ("snapshot create: description truncated: " + "Description provided is longer than 1024 characters"); + desc_len = MAX_SNAP_DESCRIPTION_LEN; + } else { + desc_len = strlen (words[desc_opt_loc]); + } + + strncpy (desc, words[desc_opt_loc], desc_len); + desc[desc_len] = '\0'; + /* Calculating the size of the description as given by the user */ + + ret = dict_set_dynstr (dict, "description", desc); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Unable to save snap " + "description"); + goto out; + } + + ret = 0; +out: + if (ret && desc) + GF_FREE (desc); + + return ret; +} + +/* Function to check whether the Volume name is repeated */ +int +cli_check_if_volname_repeated (const char **words, unsigned int start_index, + uint64_t cur_index) { + uint64_t i = -1; + int ret = 0; + + GF_ASSERT (words); + + for (i = start_index ; i < cur_index ; i++) { + if (strcmp (words[i], words[cur_index]) == 0) { + ret = -1; + goto out; + } + } +out : + return ret; +} + +/* snapshot create <snapname> <vol-name(s)> [description <description>] + * [force] + * @arg-0, dict : Request Dictionary to be sent to server side. + * @arg-1, words : Contains individual words of CLI command. + * @arg-2, wordcount: Contains number of words present in the CLI command. + * + * return value : -1 on failure + * 0 on success + */ +int +cli_snap_create_parse (dict_t *dict, const char **words, int wordcount) { + uint64_t i = 0; + int ret = -1; + uint64_t volcount = 0; + char key[PATH_MAX] = ""; + char *snapname = NULL; + unsigned int cmdi = 2; + /* cmdi is command index, here cmdi is "2" (gluster snapshot create)*/ + + GF_ASSERT (words); + GF_ASSERT (dict); + + if (wordcount <= cmdi + 1) { + cli_err ("Invalid Syntax."); + gf_log ("cli", GF_LOG_ERROR, + "Too less words for snap create command"); + goto out; + } + + if (strlen(words[cmdi]) >= GLUSTERD_MAX_SNAP_NAME) { + cli_err ("snapshot create: failed: snapname cannot exceed " + "255 characters."); + gf_log ("cli", GF_LOG_ERROR, "Snapname too long"); + + goto out; + } + + snapname = (char *) words[cmdi]; + for (i = 0 ; i < strlen (snapname); i++) { + /* Following volume name convention */ + if (!isalnum (snapname[i]) && (snapname[i] != '_' + && (snapname[i] != '-'))) { + /* TODO : Is this message enough?? */ + cli_err ("Snapname can contain only alphanumeric, " + "\"-\" and \"_\" characters"); + goto out; + } + } + + ret = dict_set_str (dict, "snapname", (char *)words[cmdi]); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Could not save snap " + "name"); + goto out; + } + + /* Filling volume name in the dictionary */ + for (i = cmdi + 1 ; i < wordcount + && (strcmp (words[i], "description")) != 0 + && (strcmp (words[i], "force") != 0); i++) { + volcount++; + /* volume index starts from 1 */ + ret = snprintf (key, sizeof (key),"volname%ld", volcount); + if (ret < 0) { + goto out; + } + + ret = dict_set_str (dict, key, (char *)words[i]); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Could not " + "save volume name"); + goto out; + } + + if (i >= cmdi + 2) { + ret = -1; + cli_err("Creating multiple volume snapshot is not " + "supported as of now"); + goto out; + } + /* TODO : remove this above condition check once + * multiple volume snapshot is supported */ + } + + if (volcount == 0) { + ret = -1; + cli_err ("Please provide the volume name"); + gf_log ("cli", GF_LOG_ERROR, "Invalid Syntax"); + goto out; + } + + ret = dict_set_int32 (dict, "volcount", volcount); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Could not save volcount"); + goto out; + } + + /* Verify how we got out of "for" loop, + * if it is by reaching wordcount limit then goto "out", + * because we need not parse for "description" and "force" + * after this. + */ + if (i == wordcount) { + goto out; + } + + if ((strcmp (words[i], "description")) == 0) { + ++i; + if (i > (wordcount - 1)) { + ret = -1; + cli_err ("Please provide a description"); + gf_log ("cli", GF_LOG_ERROR, + "Description not provided"); + goto out; + } + + ret = cli_snap_create_desc_parse(dict, words, wordcount, i); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Could not save snap " + "description"); + goto out; + } + + if ( i == (wordcount - 1)) + goto out; + i++; + /* point the index to next word. + * As description might be follwed by force option. + * Before that, check if wordcount limit is reached + */ + } + + if ((strcmp (words[i], "force") != 0)) { + ret = -1; + cli_err ("Invalid Syntax."); + gf_log ("cli", GF_LOG_ERROR, "Invalid Syntax"); + goto out; + } + ret = dict_set_int8 (dict, "snap-force", 1); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Could not save " + "snap force option"); + goto out; + } + + /* Check if the command has anything after "force" keyword */ + if (++i < wordcount) { + ret = -1; + gf_log ("cli", GF_LOG_ERROR, "Invalid Syntax"); + goto out; + } + + ret = 0; + +out : + return ret; +} + +/* snapshot list [volname] + * @arg-0, dict : Request Dictionary to be sent to server side. + * @arg-1, words : Contains individual words of CLI command. + * @arg-2, wordcount: Contains number of words present in the CLI command. + * + * return value : -1 on failure + * 0 on success + */ +int +cli_snap_list_parse (dict_t *dict, const char **words, int wordcount) { + int ret = -1; + + GF_ASSERT (words); + GF_ASSERT (dict); + + if (wordcount < 2 || wordcount > 3) { + gf_log ("cli", GF_LOG_ERROR, "Invalid Syntax"); + goto out; + } + + if (wordcount == 2) { + ret = 0; + goto out; + } + + ret = dict_set_str (dict, "volname", (char *)words[2]); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, + "Failed to save volname in dictionary"); + goto out; + } +out : + return ret; +} + +/* snapshot info [(snapname | volume <volname>)] + * @arg-0, dict : Request Dictionary to be sent to server side. + * @arg-1, words : Contains individual words of CLI command. + * @arg-2, wordcount: Contains number of words present in the CLI command. + * + * return value : -1 on failure + * 0 on success + */ +int +cli_snap_info_parse (dict_t *dict, const char **words, int wordcount) +{ + + int ret = -1; + int32_t cmd = GF_SNAP_INFO_TYPE_ALL; + unsigned int cmdi = 2; + /* cmdi is command index, here cmdi is "2" (gluster snapshot info)*/ + + GF_ASSERT (words); + GF_ASSERT (dict); + + if (wordcount > 4 || wordcount < cmdi) { + gf_log ("", GF_LOG_ERROR, "Invalid syntax"); + goto out; + } + + if (wordcount == cmdi) { + ret = 0; + goto out; + } + + /* If 3rd word is not "volume", then it must + * be snapname. + */ + if (strcmp (words[cmdi], "volume") != 0) { + ret = dict_set_str (dict, "snapname", + (char *)words[cmdi]); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Unable to save " + "snapname %s", words[cmdi]); + goto out; + } + + /* Once snap name is parsed, if we encounter any other + * word then fail it. Invalid Syntax. + * example : snapshot info <snapname> word + */ + if ((cmdi + 1) != wordcount) { + ret = -1; + gf_log ("cli", GF_LOG_ERROR, "Invalid Syntax"); + goto out; + } + + cmd = GF_SNAP_INFO_TYPE_SNAP; + ret = 0; + goto out; + /* No need to continue the parsing once we + * get the snapname + */ + } + + /* If 3rd word is "volume", then check if next word + * is present. As, "snapshot info volume" is an + * invalid command. + */ + if ((cmdi + 1) == wordcount) { + ret = -1; + gf_log ("cli", GF_LOG_ERROR, "Invalid Syntax"); + goto out; + } + + ret = dict_set_str (dict, "volname", (char *)words[wordcount - 1]); + if (ret) { + gf_log ("", GF_LOG_ERROR, "Count not save " + "volume name %s", words[wordcount - 1]); + goto out; + } + cmd = GF_SNAP_INFO_TYPE_VOL; +out : + if (ret == 0) { + ret = dict_set_int32 (dict, "cmd", cmd); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Could not save " + "type of snapshot info"); + } + } + return ret; +} + + + +/* snapshot restore <snapname> + * @arg-0, dict : Request Dictionary to be sent to server side. + * @arg-1, words : Contains individual words of CLI command. + * @arg-2, wordcount: Contains number of words present in the CLI command. + * + * return value : -1 on failure + * 0 on success + */ +int +cli_snap_restore_parse (dict_t *dict, const char **words, int wordcount) +{ + + int ret = -1; + + GF_ASSERT (words); + GF_ASSERT (dict); + + if (wordcount != 3) { + gf_log ("cli", GF_LOG_ERROR, "Invalid Syntax"); + goto out; + } + + ret = dict_set_str (dict, "snapname", (char *)words[2]); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Unable to save snap-name %s", + words[2]); + goto out; + } +out : + return ret; +} + +/* snapshot delete <snapname> + * @arg-0, dict : Request Dictionary to be sent to server side. + * @arg-1, words : Contains individual words of CLI command. + * @arg-2, wordcount: Contains number of words present in the CLI command. + * + * return value : -1 on failure + * 0 on success + * 1 if user cancel the operation + */ +int +cli_snap_delete_parse (dict_t *dict, const char **words, int wordcount, + struct cli_state *state) { + + int ret = -1; + const char *question = NULL; + gf_answer_t answer = GF_ANSWER_NO; + + question = "Deleting snap will erase all the information about " + "the snap. Do you still want to continue?"; + + GF_ASSERT (words); + GF_ASSERT (dict); + + if (wordcount != 3) { + gf_log ("cli", GF_LOG_ERROR, "Invalid Syntax"); + goto out; + } + + ret = dict_set_str (dict, "snapname", (char *)words[2]); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Unable to save snapname %s", + words[2]); + goto out; + } + + answer = cli_cmd_get_confirmation (state, question); + if (GF_ANSWER_NO == answer) { + ret = 1; + gf_log ("cli", GF_LOG_DEBUG, "User cancelled " + "snapshot delete operation"); + goto out; + } +out : + return ret; +} + +/* snapshot status [(snapname | volume <volname>)] + * @arg-0, dict : Request Dictionary to be sent to server side. + * @arg-1, words : Contains individual words of CLI command. + * @arg-2, wordcount: Contains number of words present in the CLI command. + * + * return value : -1 on failure + * 0 on success + */ +int +cli_snap_status_parse (dict_t *dict, const char **words, int wordcount) +{ + + int ret = -1; + int32_t cmd = GF_SNAP_STATUS_TYPE_ALL; + unsigned int cmdi = 2; + /* cmdi is command index, here cmdi is "2" (gluster snapshot status)*/ + + GF_ASSERT (words); + GF_ASSERT (dict); + + if (wordcount > 4 || wordcount < cmdi) { + gf_log ("cli", GF_LOG_ERROR, "Invalid Syntax"); + goto out; + } + + if (wordcount == cmdi) { + ret = 0; + goto out; + } + + /* if 3rd word is not "volume", then it must be "snapname" + */ + if (strcmp (words[cmdi], "volume") != 0) { + ret = dict_set_str (dict, "snapname", + (char *)words[cmdi]); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Count not save " + "snap name %s", words[cmdi]); + goto out; + } + + if ((cmdi + 1) != wordcount) { + ret = -1; + gf_log ("cli", GF_LOG_ERROR, "Invalid Syntax"); + goto out; + } + + ret = 0; + cmd = GF_SNAP_STATUS_TYPE_SNAP; + goto out; + } + + /* If 3rd word is "volume", then check if next word is present. + * As, "snapshot info volume" is an invalid command + */ + if ((cmdi + 1) == wordcount) { + ret = -1; + gf_log ("cli", GF_LOG_ERROR, "Invalid Syntax"); + goto out; + } + + ret = dict_set_str (dict, "volname", (char *)words [wordcount - 1]); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Count not save " + "volume name %s", words[wordcount - 1]); + goto out; + } + cmd = GF_SNAP_STATUS_TYPE_VOL; + +out : + if (ret == 0) { + ret = dict_set_int32 (dict, "cmd", cmd); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Could not save cmd " + "of snapshot status"); + } + } + return ret; +} + + +int32_t +cli_snap_config_limit_parse (const char **words, dict_t *dict, + unsigned int wordcount, unsigned int index, + char *key) +{ + int ret = -1; + int limit = 0; + + GF_ASSERT (words); + GF_ASSERT (dict); + GF_ASSERT (key); + + if (index >= wordcount) { + ret = -1; + cli_err ("Please provide a value for %s.",key); + gf_log ("cli", GF_LOG_ERROR, "Value not provided for %s", key); + goto out; + } + + limit = strtol (words[index], NULL, 0); + if (limit <= 0) { + ret = -1; + cli_err ("%s should be greater than 0.", key); + goto out; + } + + ret = dict_set_int32 (dict, key, limit); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Could not set " + "%s in dictionary", key); + goto out; + } + +out : + return ret; +} + +/* function cli_snap_config_parse + * Config Syntax : gluster snapshot config [volname] + * [snap-max-hard-limit <count>] + * [snap-max-soft-limit <count>] + * + return value: <0 on failure + 1 if user cancels the operation + 0 on success + + NOTE : snap-max-soft-limit can only be set for system. +*/ +int32_t +cli_snap_config_parse (const char **words, int wordcount, dict_t *dict, + struct cli_state *state) +{ + int ret = -1; + gf_answer_t answer = GF_ANSWER_NO; + gf_boolean_t vol_presence = _gf_false; + struct snap_config_opt_vals_ *conf_vals = NULL; + int8_t hard_limit = 0; + int8_t soft_limit = 0; + int8_t config_type = -1; + const char *question = NULL; + unsigned int cmdi = 2; + /* cmdi is command index, here cmdi is "2" (gluster snapshot config)*/ + + GF_ASSERT (words); + GF_ASSERT (dict); + GF_ASSERT (state); + + if ((wordcount < 2) || (wordcount > 7)) { + gf_log ("cli", GF_LOG_ERROR, + "Invalid wordcount(%d)", wordcount); + goto out; + } + + if (wordcount == 2) { + config_type = GF_SNAP_CONFIG_DISPLAY; + ret = 0; + goto set; + } + + /* Check whether the 3rd word is volname */ + if (strcmp (words[cmdi], "snap-max-hard-limit") != 0 + && strcmp (words[cmdi], "snap-max-soft-limit") != 0) { + ret = dict_set_str (dict, "volname", (char *)words[cmdi]); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Failed to set volname"); + goto out; + } + cmdi++; + vol_presence = _gf_true; + + if (cmdi == wordcount) { + config_type = GF_SNAP_CONFIG_DISPLAY; + ret = 0; + goto set; + } + } + + config_type = GF_SNAP_CONFIG_TYPE_SET; + + if (strcmp (words[cmdi], "snap-max-hard-limit") == 0) { + ret = cli_snap_config_limit_parse (words, dict, wordcount, + ++cmdi, "snap-max-hard-limit"); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Failed to parse snap " + "config hard limit"); + goto out; + } + hard_limit = 1; + + if (++cmdi == wordcount) { + ret = 0; + goto set; + } + } + + if (strcmp (words[cmdi], "snap-max-soft-limit") == 0) { + if (vol_presence == 1) { + ret = -1; + cli_err ("Soft limit cannot be set to individual " + "volumes."); + gf_log ("cli", GF_LOG_ERROR, "Soft limit cannot be " + "set to volumes"); + goto out; + } + + ret = cli_snap_config_limit_parse (words, dict, wordcount, + ++cmdi, "snap-max-soft-limit"); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Failed to parse snap " + "config soft limit"); + goto out; + } + + if (++cmdi != wordcount) { + ret = -1; + gf_log ("cli", GF_LOG_ERROR, "Invalid Syntax"); + goto out; + } + soft_limit = 1; + } else { + ret = -1; + gf_log ("cli", GF_LOG_ERROR, "Invalid Syntax"); + goto out; + } + ret = 0; /* Success */ + +set: + ret = dict_set_int32 (dict, "config-command", config_type); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Unable to set " + "config-command"); + goto out; + } + + if (config_type == GF_SNAP_CONFIG_TYPE_SET) { + conf_vals = snap_confopt_vals; + if (hard_limit && soft_limit) { + question = conf_vals[GF_SNAP_CONFIG_SET_BOTH].question; + } else if (soft_limit) { + question = conf_vals[GF_SNAP_CONFIG_SET_SOFT].question; + } else if (hard_limit) { + question = conf_vals[GF_SNAP_CONFIG_SET_HARD].question; + } + + answer = cli_cmd_get_confirmation (state, question); + if (GF_ANSWER_NO == answer) { + ret = 1; + gf_log ("cli", GF_LOG_DEBUG, "User cancelled " + "snapshot config operation"); + } + } + +out: + return ret; +} + +int +validate_snapname (const char *snapname, char **opwords) { + int ret = -1; + int i = 0; + + GF_ASSERT (snapname); + GF_ASSERT (opwords); + + for (i = 0 ; opwords[i] != NULL; i++) { + if (strcmp (opwords[i], snapname) == 0) { + cli_out ("\"%s\" cannot be a snapname", snapname); + goto out; + } + } + ret = 0; +out : + return ret; +} + +int32_t +cli_cmd_snapshot_parse (const char **words, int wordcount, dict_t **options, + struct cli_state *state) +{ + int32_t ret = -1; + dict_t *dict = NULL; + gf1_cli_snapshot type = GF_SNAP_OPTION_TYPE_NONE; + char *w = NULL; + char *opwords[] = {"create", "delete", "restore", "start", + "stop", "list", "status", "config", + "info", NULL}; + char *invalid_snapnames[] = {"description", "force", + "volume", NULL}; + + GF_ASSERT (words); + GF_ASSERT (options); + GF_ASSERT (state); + + dict = dict_new (); + if (!dict) + goto out; + + /* Lowest wordcount possible */ + if (wordcount < 2) { + gf_log ("", GF_LOG_ERROR, + "Invalid command: Not enough arguments"); + goto out; + } + + w = str_getunamb (words[1], opwords); + if (!w) { + /* Checks if the operation is a valid operation */ + gf_log ("", GF_LOG_ERROR, "Opword Mismatch"); + goto out; + } + + if (!strcmp (w, "create")) { + type = GF_SNAP_OPTION_TYPE_CREATE; + } else if (!strcmp (w, "list")) { + type = GF_SNAP_OPTION_TYPE_LIST; + } else if (!strcmp (w, "info")) { + type = GF_SNAP_OPTION_TYPE_INFO; + } else if (!strcmp (w, "delete")) { + type = GF_SNAP_OPTION_TYPE_DELETE; + } else if (!strcmp (w, "config")) { + type = GF_SNAP_OPTION_TYPE_CONFIG; + } else if (!strcmp (w, "restore")) { + type = GF_SNAP_OPTION_TYPE_RESTORE; + } else if (!strcmp (w, "status")) { + type = GF_SNAP_OPTION_TYPE_STATUS; + } + + if (type != GF_SNAP_OPTION_TYPE_CONFIG) { + ret = dict_set_int32 (dict, "hold_snap_locks", _gf_true); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, + "Unable to set hold-snap-locks value " + "as _gf_true"); + goto out; + } + } + + /* Check which op is intended */ + switch (type) { + case GF_SNAP_OPTION_TYPE_CREATE: + { + /* Syntax : + * gluster snapshot create <snapname> <vol-name(s)> + * [description <description>] + * [force] + */ + + /* In cases where the snapname is not given then + * parsing fails & snapname cannot be "description", + * "force" and "volume", that check is made here + */ + if (wordcount == 2){ + ret = -1; + gf_log ("cli", GF_LOG_ERROR, + "Invalid Syntax"); + goto out; + } + + ret = validate_snapname (words[2], invalid_snapnames); + if (ret) { + goto out; + } + + ret = cli_snap_create_parse (dict, words, wordcount); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, + "create command parsing failed."); + goto out; + } + break; + } + case GF_SNAP_OPTION_TYPE_INFO: + { + /* Syntax : + * gluster snapshot info [(snapname] | [vol <volname>)] + */ + ret = cli_snap_info_parse (dict, words, wordcount); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Failed to parse " + "snapshot info command"); + goto out; + } + break; + } + + case GF_SNAP_OPTION_TYPE_LIST: + { + /* Syntax : + * gluster snaphsot list [volname] + */ + + ret = cli_snap_list_parse (dict, words, wordcount); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Failed to parse " + "snapshot list command"); + goto out; + } + break; + } + + case GF_SNAP_OPTION_TYPE_DELETE: + { + /* Syntax : + * gluster snapshot delete <snapname> + */ + ret = cli_snap_delete_parse (dict, words, wordcount, + state); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Failed to parse " + "snapshot delete command"); + goto out; + } + break; + } + + case GF_SNAP_OPTION_TYPE_CONFIG: + { + /* snapshot config [volname] [snap-max-hard-limit <count>] + * [snap-max-soft-limit <percent>] */ + ret = cli_snap_config_parse (words, wordcount, dict, + state); + if (ret) { + if (ret < 0) + gf_log ("cli", GF_LOG_ERROR, + "config command parsing failed."); + goto out; + } + + ret = dict_set_int32 (dict, "type", + GF_SNAP_OPTION_TYPE_CONFIG); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Unable to set " + "config type"); + ret = -1; + goto out; + } + break; + } + case GF_SNAP_OPTION_TYPE_STATUS: + { + /* Syntax : + * gluster snapshot status [(snapname | + * volume <volname>)] + */ + ret = cli_snap_status_parse (dict, words, wordcount); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Failed to parse " + "snapshot status command"); + goto out; + } + break; + } + + case GF_SNAP_OPTION_TYPE_RESTORE: + { + /* Syntax: + * snapshot restore <snapname> + */ + ret = cli_snap_restore_parse (dict, words, wordcount); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Failed to parse " + "restore command"); + goto out; + } + break; + } + default: + gf_log ("", GF_LOG_ERROR, "Opword Mismatch"); + goto out; + break; + } + + ret = dict_set_int32 (dict, "type", type); + if (ret) { + gf_log ("", GF_LOG_ERROR, + "Failed to set type."); + goto out; + } + /* If you got so far, input is valid */ + ret = 0; +out: + if (ret) { + if (dict) + dict_destroy (dict); + } else + *options = dict; + + return ret; +} diff --git a/cli/src/cli-cmd-peer.c b/cli/src/cli-cmd-peer.c index 5ae2007f3..551312411 100644 --- a/cli/src/cli-cmd-peer.c +++ b/cli/src/cli-cmd-peer.c @@ -1,22 +1,12 @@ /* - Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. - - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ + Copyright (c) 2010-2012 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ #include <stdio.h> #include <string.h> #include <stdlib.h> @@ -31,6 +21,7 @@ #include "cli.h" #include "cli-cmd.h" #include "cli-mem-types.h" +#include "cli1-xdr.h" #include "protocol-common.h" extern struct rpc_clnt *global_rpc; @@ -40,24 +31,6 @@ extern rpc_clnt_prog_t *cli_rpc_prog; int cli_cmd_peer_help_cbk (struct cli_state *state, struct cli_cmd_word *in_word, const char **words, int wordcount); -void -cli_cmd_probe_usage () -{ - cli_out ("Usage: probe <hostname>"); -} - -void -cli_cmd_deprobe_usage () -{ - cli_out ("Usage: detach <hostname>"); -} - -void -cli_cmd_peer_status_usage () -{ - cli_out ("Usage: peer status"); -} - int cli_cmd_peer_probe_cbk (struct cli_state *state, struct cli_cmd_word *word, const char **words, int wordcount) @@ -66,13 +39,17 @@ cli_cmd_peer_probe_cbk (struct cli_state *state, struct cli_cmd_word *word, rpc_clnt_procedure_t *proc = NULL; call_frame_t *frame = NULL; dict_t *dict = NULL; + int sent = 0; + int parse_error = 0; + cli_local_t *local = NULL; if (!(wordcount == 3)) { - cli_cmd_probe_usage (); + cli_usage_out (word->pattern); + parse_error = 1; goto out; } - proc = &cli_rpc_prog->proctable[GF1_CLI_PROBE]; + proc = &cli_rpc_prog->proctable[GLUSTER_CLI_PROBE]; frame = create_frame (THIS, THIS->ctx->pool); if (!frame) @@ -86,19 +63,38 @@ cli_cmd_peer_probe_cbk (struct cli_state *state, struct cli_cmd_word *word, if (ret) goto out; + ret = valid_internet_address ((char *) words[2], _gf_false); + if (ret == 1) { + ret = 0; + } else { + cli_out ("%s is an invalid address", words[2]); + cli_usage_out (word->pattern); + parse_error = 1; + ret = -1; + goto out; + } /* if (words[3]) { ret = dict_set_str (dict, "port", (char *)words[3]); if (ret) goto out; } */ + + CLI_LOCAL_INIT (local, words, frame, dict); + if (proc->fn) { ret = proc->fn (frame, THIS, dict); } out: - if (ret) - cli_out ("Probe failed"); + if (ret) { + cli_cmd_sent_status_get (&sent); + if ((sent == 0) && (parse_error == 0)) + cli_out ("Peer probe failed"); + } + + CLI_STACK_DESTROY (frame); + return ret; } @@ -111,13 +107,18 @@ cli_cmd_peer_deprobe_cbk (struct cli_state *state, struct cli_cmd_word *word, rpc_clnt_procedure_t *proc = NULL; call_frame_t *frame = NULL; dict_t *dict = NULL; - - if (!(wordcount == 3) ) { - cli_cmd_deprobe_usage (); + int flags = 0; + int sent = 0; + int parse_error = 0; + cli_local_t *local = NULL; + + if ((wordcount < 3) || (wordcount > 4)) { + cli_usage_out (word->pattern); + parse_error = 1; goto out; } - proc = &cli_rpc_prog->proctable[GF1_CLI_DEPROBE]; + proc = &cli_rpc_prog->proctable[GLUSTER_CLI_DEPROBE]; frame = create_frame (THIS, THIS->ctx->pool); if (!frame) @@ -135,11 +136,35 @@ cli_cmd_peer_deprobe_cbk (struct cli_state *state, struct cli_cmd_word *word, goto out; } */ + if (wordcount == 4) { + if (!strcmp("force", words[3])) + flags |= GF_CLI_FLAG_OP_FORCE; + else { + ret = -1; + cli_usage_out (word->pattern); + parse_error = 1; + goto out; + } + } + ret = dict_set_int32 (dict, "flags", flags); + if (ret) + goto out; + + CLI_LOCAL_INIT (local, words, frame, dict); + if (proc->fn) { ret = proc->fn (frame, THIS, dict); } out: + if (ret) { + cli_cmd_sent_status_get (&sent); + if ((sent == 0) && (parse_error == 0)) + cli_out ("Peer detach failed"); + } + + CLI_STACK_DESTROY (frame); + return ret; } @@ -150,25 +175,73 @@ cli_cmd_peer_status_cbk (struct cli_state *state, struct cli_cmd_word *word, int ret = -1; rpc_clnt_procedure_t *proc = NULL; call_frame_t *frame = NULL; + int sent = 0; + int parse_error = 0; if (wordcount != 2) { - cli_cmd_peer_status_usage (); + cli_usage_out (word->pattern); + parse_error = 1; goto out; } - proc = &cli_rpc_prog->proctable[GF1_CLI_LIST_FRIENDS]; + proc = &cli_rpc_prog->proctable[GLUSTER_CLI_LIST_FRIENDS]; frame = create_frame (THIS, THIS->ctx->pool); if (!frame) goto out; if (proc->fn) { - ret = proc->fn (frame, THIS, (char *)words[1] ); + ret = proc->fn (frame, THIS, (void *)GF_CLI_LIST_PEERS); } out: - if (ret) - cli_out ("Command Execution failed"); + if (ret) { + cli_cmd_sent_status_get (&sent); + if ((sent == 0) && (parse_error == 0)) + cli_out ("Peer status failed"); + } + + CLI_STACK_DESTROY (frame); + + return ret; +} + +int +cli_cmd_pool_list_cbk (struct cli_state *state, struct cli_cmd_word *word, + const char **words, int wordcount) +{ + int ret = -1; + rpc_clnt_procedure_t *proc = NULL; + call_frame_t *frame = NULL; + int sent = 0; + int parse_error = 0; + + if (wordcount != 2) { + cli_usage_out (word->pattern); + parse_error = 1; + goto out; + } + + proc = &cli_rpc_prog->proctable[GLUSTER_CLI_LIST_FRIENDS]; + + frame = create_frame (THIS, THIS->ctx->pool); + if (!frame) + goto out; + + if (proc->fn) { + ret = proc->fn (frame, THIS, + (void *)GF_CLI_LIST_POOL_NODES); + } + +out: + if (ret) { + cli_cmd_sent_status_get (&sent); + if ((sent == 0) && (parse_error == 0)) + cli_err ("pool list: command execution failed"); + } + + CLI_STACK_DESTROY (frame); + return ret; } @@ -177,18 +250,21 @@ struct cli_cmd cli_probe_cmds[] = { cli_cmd_peer_probe_cbk, "probe peer specified by <HOSTNAME>"}, - { "peer detach <HOSTNAME>", + { "peer detach <HOSTNAME> [force]", cli_cmd_peer_deprobe_cbk, "detach peer specified by <HOSTNAME>"}, { "peer status", cli_cmd_peer_status_cbk, "list status of peers"}, - - { "peer help", - cli_cmd_peer_help_cbk, + + { "peer help", + cli_cmd_peer_help_cbk, "Help command for peer "}, + { "pool list", + cli_cmd_pool_list_cbk, + "list all the nodes in the pool (including localhost)"}, { NULL, NULL, NULL } }; @@ -199,16 +275,11 @@ cli_cmd_peer_help_cbk (struct cli_state *state, struct cli_cmd_word *in_word, { struct cli_cmd *cmd = NULL; - + for (cmd = cli_probe_cmds; cmd->pattern; cmd++) cli_out ("%s - %s", cmd->pattern, cmd->desc); - - - if (!state->rl_enabled) - exit (0); - return 0; } @@ -219,8 +290,8 @@ cli_cmd_probe_register (struct cli_state *state) struct cli_cmd *cmd = NULL; for (cmd = cli_probe_cmds; cmd->pattern; cmd++) { - ret = cli_cmd_register (&state->tree, cmd->pattern, cmd->cbk, - cmd->desc); + + ret = cli_cmd_register (&state->tree, cmd); if (ret) goto out; } diff --git a/cli/src/cli-cmd-snapshot.c b/cli/src/cli-cmd-snapshot.c new file mode 100644 index 000000000..de492d683 --- /dev/null +++ b/cli/src/cli-cmd-snapshot.c @@ -0,0 +1,146 @@ +/* + Copyright (c) 2013-2014 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stdint.h> +#include <pthread.h> + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include "cli.h" +#include "cli-cmd.h" + +extern rpc_clnt_prog_t *cli_rpc_prog; + +int +cli_cmd_snapshot_help_cbk (struct cli_state *state, struct cli_cmd_word *in_word, + const char **words, int wordcount); + +int +cli_cmd_snapshot_cbk (struct cli_state *state, struct cli_cmd_word *word, + const char **words, int wordcount) +{ + int ret = 0; + int parse_err = 0; + dict_t *options = NULL; + rpc_clnt_procedure_t *proc = NULL; + call_frame_t *frame = NULL; + cli_local_t *local = NULL; + + proc = &cli_rpc_prog->proctable [GLUSTER_CLI_SNAP]; + if (proc == NULL) { + ret = -1; + goto out; + } + + frame = create_frame (THIS, THIS->ctx->pool); + if (frame == NULL) { + ret = -1; + goto out; + } + + /* Parses the command entered by the user */ + ret = cli_cmd_snapshot_parse (words, wordcount, &options, state); + if (ret) { + if (ret < 0) { + cli_usage_out (word->pattern); + parse_err = 1; + } + else { + /* User might have cancelled the snapshot operation */ + ret = 0; + } + goto out; + } + + CLI_LOCAL_INIT (local, words, frame, options); + + if (proc->fn) + ret = proc->fn (frame, THIS, options); + +out: + if (ret && parse_err == 0) + cli_out ("Snapshot command failed"); + + CLI_STACK_DESTROY (frame); + + return ret; +} + +struct cli_cmd snapshot_cmds[] = { + { "snapshot help", + cli_cmd_snapshot_help_cbk, + "display help for snapshot commands" + }, + { "snapshot create <snapname> <volname(s)> [description <description>] [force]", + cli_cmd_snapshot_cbk, + "Snapshot Create." + }, + { "snapshot restore <snapname>", + cli_cmd_snapshot_cbk, + "Snapshot Restore." + }, + { "snapshot status [(snapname | volume <volname>)]", + cli_cmd_snapshot_cbk, + "Snapshot Status." + }, + { "snapshot info [(snapname | volume <volname>)]", + cli_cmd_snapshot_cbk, + "Snapshot Info." + }, + { "snapshot list [volname]", + cli_cmd_snapshot_cbk, + "Snapshot List." + }, + {"snapshot config [volname] [snap-max-hard-limit <count>] [snap-max-soft-limit <percent>]", + cli_cmd_snapshot_cbk, + "Snapshot Config." + }, + {"snapshot delete <snapname>", + cli_cmd_snapshot_cbk, + "Snapshot Delete." + }, + { NULL, NULL, NULL } +}; + +int +cli_cmd_snapshot_help_cbk (struct cli_state *state, + struct cli_cmd_word *in_word, + const char **words, + int wordcount) +{ + struct cli_cmd *cmd = NULL; + + for (cmd = snapshot_cmds; cmd->pattern; cmd++) + if (_gf_false == cmd->disable) + cli_out ("%s - %s", cmd->pattern, cmd->desc); + + return 0; +} + +int +cli_cmd_snapshot_register (struct cli_state *state) +{ + int ret = 0; + struct cli_cmd *cmd = NULL; + + for (cmd = snapshot_cmds; cmd->pattern; cmd++) { + + ret = cli_cmd_register (&state->tree, cmd); + if (ret) + goto out; + } +out: + return ret; +} diff --git a/cli/src/cli-cmd-system.c b/cli/src/cli-cmd-system.c index 08fc44a37..8cfa5e70c 100644 --- a/cli/src/cli-cmd-system.c +++ b/cli/src/cli-cmd-system.c @@ -1,22 +1,12 @@ /* - Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. - - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ + Copyright (c) 2010-2012 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ #include <stdio.h> #include <string.h> #include <stdlib.h> @@ -33,8 +23,6 @@ #include "cli-mem-types.h" #include "protocol-common.h" -#define GETSPEC_SYNTAX "system:: getspec <VOLID>" -#define BRICKTOPORT_SYNTAX "system:: portmap brick2port <BRICK>" extern struct rpc_clnt *global_rpc; @@ -43,6 +31,12 @@ extern rpc_clnt_prog_t *cli_rpc_prog; int cli_cmd_system_help_cbk (struct cli_state *state, struct cli_cmd_word *in_word, const char **words, int wordcount); +int cli_cmd_copy_file_cbk (struct cli_state *state, struct cli_cmd_word *word, + const char **words, int wordcount); + +int cli_cmd_sys_exec_cbk (struct cli_state *state, struct cli_cmd_word *word, + const char **words, int wordcount); + int cli_cmd_getspec_cbk (struct cli_state *state, struct cli_cmd_word *word, const char **words, int wordcount) @@ -61,7 +55,7 @@ cli_cmd_getspec_cbk (struct cli_state *state, struct cli_cmd_word *word, goto out; if (wordcount != 3) { - cli_out ("Usage: " GETSPEC_SYNTAX); + cli_usage_out (word->pattern); goto out; } @@ -69,7 +63,7 @@ cli_cmd_getspec_cbk (struct cli_state *state, struct cli_cmd_word *word, if (ret) goto out; - proc = &cli_rpc_prog->proctable[GF1_CLI_GETSPEC]; + proc = &cli_rpc_prog->proctable[GLUSTER_CLI_GETSPEC]; if (proc->fn) { ret = proc->fn (frame, THIS, dict); } @@ -104,7 +98,7 @@ cli_cmd_pmap_b2p_cbk (struct cli_state *state, struct cli_cmd_word *word, goto out; if (wordcount != 4) { - cli_out ("Usage: " BRICKTOPORT_SYNTAX); + cli_usage_out (word->pattern); goto out; } @@ -112,7 +106,7 @@ cli_cmd_pmap_b2p_cbk (struct cli_state *state, struct cli_cmd_word *word, if (ret) goto out; - proc = &cli_rpc_prog->proctable[GF1_CLI_PMAP_PORTBYBRICK]; + proc = &cli_rpc_prog->proctable[GLUSTER_CLI_PMAP_PORTBYBRICK]; if (proc->fn) { ret = proc->fn (frame, THIS, dict); } @@ -129,23 +123,457 @@ out: return ret; } +int +cli_cmd_fsm_log_cbk (struct cli_state *state, struct cli_cmd_word *word, + const char **words, int wordcount) +{ + int ret = -1; + rpc_clnt_procedure_t *proc = NULL; + call_frame_t *frame = NULL; + char *name = ""; + + if ((wordcount != 4) && (wordcount != 3)) { + cli_usage_out (word->pattern); + goto out; + } + + if (wordcount == 4) + name = (char*)words[3]; + proc = &cli_rpc_prog->proctable[GLUSTER_CLI_FSM_LOG]; + if (proc && proc->fn) { + frame = create_frame (THIS, THIS->ctx->pool); + if (!frame) + goto out; + ret = proc->fn (frame, THIS, (void*)name); + } +out: + return ret; +} + +int +cli_cmd_getwd_cbk (struct cli_state *state, struct cli_cmd_word *word, + const char **words, int wordcount) +{ + int ret = -1; + rpc_clnt_procedure_t *proc = NULL; + call_frame_t *frame = NULL; + + if (wordcount != 2) { + cli_usage_out (word->pattern); + goto out; + } + + proc = &cli_rpc_prog->proctable[GLUSTER_CLI_GETWD]; + if (proc && proc->fn) { + frame = create_frame (THIS, THIS->ctx->pool); + if (!frame) + goto out; + ret = proc->fn (frame, THIS, NULL); + } +out: + return ret; +} + +static dict_t * +make_seq_dict (int argc, char **argv) +{ + char index[] = "4294967296"; // 1<<32 + int i = 0; + int ret = 0; + dict_t *dict = dict_new (); + + if (!dict) + return NULL; + + for (i = 0; i < argc; i++) { + snprintf(index, sizeof(index), "%d", i); + ret = dict_set_str (dict, index, argv[i]); + if (ret == -1) + break; + } + + if (ret) { + dict_destroy (dict); + dict = NULL; + } + + return dict; +} + +int +cli_cmd_mount_cbk (struct cli_state *state, struct cli_cmd_word *word, + const char **words, int wordcount) +{ + rpc_clnt_procedure_t *proc = NULL; + call_frame_t *frame = NULL; + int ret = -1; + dict_t *dict = NULL; + void *dataa[] = {NULL, NULL}; + + if (wordcount < 4) { + cli_usage_out (word->pattern); + goto out; + } + + dict = make_seq_dict (wordcount - 3, (char **)words + 3); + if (!dict) + goto out; + + dataa[0] = (void *)words[2]; + dataa[1] = dict; + + proc = &cli_rpc_prog->proctable[GLUSTER_CLI_MOUNT]; + if (proc && proc->fn) { + frame = create_frame (THIS, THIS->ctx->pool); + if (!frame) + goto out; + ret = proc->fn (frame, THIS, dataa); + } + + out: + if (dict) + dict_unref (dict); + + if (!proc && ret) + cli_out ("Mount command failed"); + + return ret; +} + +int +cli_cmd_umount_cbk (struct cli_state *state, struct cli_cmd_word *word, + const char **words, int wordcount) +{ + rpc_clnt_procedure_t *proc = NULL; + call_frame_t *frame = NULL; + int ret = -1; + dict_t *dict = NULL; + + if (!(wordcount == 3 || + (wordcount == 4 && strcmp (words[3], "lazy") == 0))) { + cli_usage_out (word->pattern); + goto out; + } + + dict = dict_new (); + if (!dict) + goto out; + + ret = dict_set_str (dict, "path", (char *)words[2]); + if (ret != 0) + goto out; + ret = dict_set_int32 (dict, "lazy", wordcount == 4); + if (ret != 0) + goto out; + + proc = &cli_rpc_prog->proctable[GLUSTER_CLI_UMOUNT]; + if (proc && proc->fn) { + frame = create_frame (THIS, THIS->ctx->pool); + if (!frame) + goto out; + ret = proc->fn (frame, THIS, dict); + } + + out: + if (dict) + dict_unref (dict); + + if (!proc && ret) + cli_out ("Umount command failed"); + + return ret; +} + +int +cli_cmd_uuid_get_cbk (struct cli_state *state, struct cli_cmd_word *word, + const char **words, int wordcount) +{ + int ret = -1; + int sent = 0; + int parse_error = 0; + dict_t *dict = NULL; + rpc_clnt_procedure_t *proc = NULL; + call_frame_t *frame = NULL; + cli_local_t *local = NULL; + xlator_t *this = NULL; + + this = THIS; + if (wordcount != 3) { + cli_usage_out (word->pattern); + parse_error = 1; + goto out; + } + + proc = &cli_rpc_prog->proctable[GLUSTER_CLI_UUID_GET]; + frame = create_frame (this, this->ctx->pool); + if (!frame) + goto out; + + dict = dict_new (); + if (!dict) + goto out; + + CLI_LOCAL_INIT (local, words, frame, dict); + if (proc->fn) + ret = proc->fn (frame, this, dict); + +out: + if (ret) { + cli_cmd_sent_status_get (&sent); + if ((sent == 0) && (parse_error == 0)) + cli_out ("uuid get failed"); + } + + if (dict) + dict_unref (dict); + + CLI_STACK_DESTROY (frame); + return ret; +} + +int +cli_cmd_uuid_reset_cbk (struct cli_state *state, struct cli_cmd_word *word, + const char **words, int wordcount) +{ + int ret = -1; + rpc_clnt_procedure_t *proc = NULL; + call_frame_t *frame = NULL; + int sent = 0; + int parse_error = 0; + gf_answer_t answer = GF_ANSWER_NO; + char *question = NULL; + cli_local_t *local = NULL; + dict_t *dict = NULL; + xlator_t *this = NULL; + + question = "Resetting uuid changes the uuid of local glusterd. " + "Do you want to continue?"; + + if (wordcount != 3) { + cli_usage_out (word->pattern); + parse_error = 1; + goto out; + } + + proc = &cli_rpc_prog->proctable[GLUSTER_CLI_UUID_RESET]; + + this = THIS; + frame = create_frame (this, this->ctx->pool); + if (!frame) + goto out; + + dict = dict_new (); + if (!dict) { + ret = -1; + goto out; + } + CLI_LOCAL_INIT (local, words, frame, dict); + answer = cli_cmd_get_confirmation (state, question); + + if (GF_ANSWER_NO == answer) { + ret = 0; + goto out; + } + + //send NULL as argument since no dictionary is sent to glusterd + if (proc->fn) { + ret = proc->fn (frame, this, dict); + } + +out: + if (ret) { + cli_cmd_sent_status_get (&sent); + if ((sent == 0) && (parse_error == 0)) + cli_out ("uuid reset failed"); + } + + CLI_STACK_DESTROY (frame); + + return ret; +} + struct cli_cmd cli_system_cmds[] = { - { GETSPEC_SYNTAX, + { "system:: getspec <VOLID>", cli_cmd_getspec_cbk, "fetch spec for volume <VOLID>"}, - { BRICKTOPORT_SYNTAX, + { "system:: portmap brick2port <BRICK>", cli_cmd_pmap_b2p_cbk, "query which port <BRICK> listens on"}, + { "system:: fsm log [<peer-name>]", + cli_cmd_fsm_log_cbk, + "display fsm transitions"}, + + { "system:: getwd", + cli_cmd_getwd_cbk, + "query glusterd work directory"}, + + { "system:: mount <label> <args...>", + cli_cmd_mount_cbk, + "request a mount"}, + + { "system:: umount <path> [lazy]", + cli_cmd_umount_cbk, + "request an umount"}, + + { "system:: uuid get", + cli_cmd_uuid_get_cbk, + "get uuid of glusterd"}, + + { "system:: uuid reset", + cli_cmd_uuid_reset_cbk, + "reset the uuid of glusterd"}, + { "system:: help", cli_cmd_system_help_cbk, "display help for system commands"}, + { "system:: copy file [<filename>]", + cli_cmd_copy_file_cbk, + "Copy file from current node's $working_dir to " + "$working_dir of all cluster nodes"}, + + { "system:: execute <command> <args>", + cli_cmd_sys_exec_cbk, + "Execute the command on all the nodes " + "in the cluster and display their output."}, + { NULL, NULL, NULL } }; int +cli_cmd_sys_exec_cbk (struct cli_state *state, struct cli_cmd_word *word, + const char **words, int wordcount) +{ + char cmd_arg_name[PATH_MAX] = ""; + char *command = NULL; + char *saveptr = NULL; + char *tmp = NULL; + int ret = -1; + int i = -1; + int cmd_args_count = 0; + int in_cmd_args_count = 0; + rpc_clnt_procedure_t *proc = NULL; + call_frame_t *frame = NULL; + dict_t *dict = NULL; + cli_local_t *local = NULL; + + if (wordcount < 3) { + cli_usage_out (word->pattern); + goto out; + } + + dict = dict_new (); + if (!dict) + goto out; + + command = strtok_r ((char *)words[2], " ", &saveptr); + do { + tmp = strtok_r (NULL, " ", &saveptr); + if (tmp) { + in_cmd_args_count++; + memset (cmd_arg_name, '\0', sizeof(cmd_arg_name)); + snprintf (cmd_arg_name, sizeof(cmd_arg_name), + "cmd_arg_%d", in_cmd_args_count); + ret = dict_set_str (dict, cmd_arg_name, tmp); + if (ret) { + gf_log ("", GF_LOG_ERROR, "Unable to set " + "%s in dict", cmd_arg_name); + goto out; + } + } + } while (tmp); + + cmd_args_count = wordcount - 3; + + ret = dict_set_str (dict, "command", command); + if (ret) { + gf_log ("", GF_LOG_ERROR, "Unable to set command in dict"); + goto out; + } + + for (i=1; i <= cmd_args_count; i++) { + in_cmd_args_count++; + memset (cmd_arg_name, '\0', sizeof(cmd_arg_name)); + snprintf (cmd_arg_name, sizeof(cmd_arg_name), + "cmd_arg_%d", in_cmd_args_count); + ret = dict_set_str (dict, cmd_arg_name, + (char *)words[2+i]); + if (ret) { + gf_log ("", GF_LOG_ERROR, "Unable to set %s in dict", + cmd_arg_name); + goto out; + } + } + + ret = dict_set_int32 (dict, "cmd_args_count", in_cmd_args_count); + if (ret) { + gf_log ("", GF_LOG_ERROR, + "Unable to set cmd_args_count in dict"); + goto out; + } + + ret = dict_set_str (dict, "volname", "N/A"); + if (ret) { + gf_log ("", GF_LOG_ERROR, "Unable to set volname in dict"); + goto out; + } + + proc = &cli_rpc_prog->proctable[GLUSTER_CLI_SYS_EXEC]; + if (proc && proc->fn) { + frame = create_frame (THIS, THIS->ctx->pool); + if (!frame) + goto out; + CLI_LOCAL_INIT (local, words, frame, dict); + ret = proc->fn (frame, THIS, (void*)dict); + } +out: + return ret; +} + +int +cli_cmd_copy_file_cbk (struct cli_state *state, struct cli_cmd_word *word, + const char **words, int wordcount) +{ + int ret = -1; + rpc_clnt_procedure_t *proc = NULL; + call_frame_t *frame = NULL; + char *filename = ""; + dict_t *dict = NULL; + cli_local_t *local = NULL; + + if (wordcount != 4) { + cli_usage_out (word->pattern); + goto out; + } + + dict = dict_new (); + if (!dict) + goto out; + + filename = (char*)words[3]; + ret = dict_set_str (dict, "source", filename); + if (ret) + gf_log ("", GF_LOG_ERROR, "Unable to set filename in dict"); + + ret = dict_set_str (dict, "volname", "N/A"); + if (ret) + gf_log ("", GF_LOG_ERROR, "Unable to set volname in dict"); + + proc = &cli_rpc_prog->proctable[GLUSTER_CLI_COPY_FILE]; + if (proc && proc->fn) { + frame = create_frame (THIS, THIS->ctx->pool); + if (!frame) + goto out; + CLI_LOCAL_INIT (local, words, frame, dict); + ret = proc->fn (frame, THIS, (void*)dict); + } +out: + return ret; +} + +int cli_cmd_system_help_cbk (struct cli_state *state, struct cli_cmd_word *in_word, const char **words, int wordcount) { @@ -154,9 +582,6 @@ cli_cmd_system_help_cbk (struct cli_state *state, struct cli_cmd_word *in_word, for (cmd = cli_system_cmds; cmd->pattern; cmd++) cli_out ("%s - %s", cmd->pattern, cmd->desc); - if (!state->rl_enabled) - exit (0); - return 0; } @@ -167,8 +592,8 @@ cli_cmd_system_register (struct cli_state *state) struct cli_cmd *cmd = NULL; for (cmd = cli_system_cmds; cmd->pattern; cmd++) { - ret = cli_cmd_register (&state->tree, cmd->pattern, cmd->cbk, - cmd->desc); + + ret = cli_cmd_register (&state->tree, cmd); if (ret) goto out; } diff --git a/cli/src/cli-cmd-volume.c b/cli/src/cli-cmd-volume.c index 8fb32f5de..100be0b73 100644 --- a/cli/src/cli-cmd-volume.c +++ b/cli/src/cli-cmd-volume.c @@ -1,28 +1,23 @@ /* - Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. - - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ + Copyright (c) 2010-2012 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ #include <stdio.h> #include <string.h> #include <stdlib.h> #include <stdint.h> #include <pthread.h> +#include <sys/socket.h> +#include <netdb.h> +#include <sys/types.h> +#include <netinet/in.h> + #ifndef _CONFIG_H #define _CONFIG_H #include "config.h" @@ -32,6 +27,7 @@ #include "cli-cmd.h" #include "cli-mem-types.h" #include "cli1-xdr.h" +#include "run.h" extern struct rpc_clnt *global_rpc; @@ -41,48 +37,6 @@ int cli_cmd_volume_help_cbk (struct cli_state *state, struct cli_cmd_word *in_word, const char **words, int wordcount); -void -cli_cmd_volume_start_usage () -{ - cli_out ("Usage: volume start <VOLNAME> [force]"); -} - -void -cli_cmd_volume_stop_usage () -{ - cli_out ("Usage: volume stop <VOLNAME> [force]"); -} - -void -cli_cmd_volume_rename_usage () -{ - cli_out ("Usage: volume rename <VOLNAME> <NEW-VOLNAME>"); -} - -void -cli_cmd_volume_delete_usage () -{ - cli_out ("Usage: volume delete <VOLNAME>"); -} - -void -cli_cmd_volume_info_usage () -{ - cli_out ("Usage: volume info [all|<VOLNAME>]"); -} - -void -cli_cmd_volume_reset_usage () -{ - cli_out ("Usage: volume reset <VOLNAME> "); -} - -void -cli_cmd_volume_set_usage () -{ - cli_out ("Usage: volume set <VOLNAME> <KEY> <VALUE>"); -} - int cli_cmd_volume_info_cbk (struct cli_state *state, struct cli_cmd_word *word, const char **words, int wordcount) @@ -92,8 +46,10 @@ cli_cmd_volume_info_cbk (struct cli_state *state, struct cli_cmd_word *word, call_frame_t *frame = NULL; cli_cmd_volume_get_ctx_t ctx = {0,}; cli_local_t *local = NULL; + int sent = 0; + int parse_error = 0; - proc = &cli_rpc_prog->proctable[GF1_CLI_GET_VOLUME]; + proc = &cli_rpc_prog->proctable[GLUSTER_CLI_GET_VOLUME]; frame = create_frame (THIS, THIS->ctx->pool); if (!frame) @@ -102,7 +58,7 @@ cli_cmd_volume_info_cbk (struct cli_state *state, struct cli_cmd_word *word, if ((wordcount == 2) || (wordcount == 3 && !strcmp (words[2], "all"))) { ctx.flags = GF_CLI_GET_NEXT_VOLUME; - proc = &cli_rpc_prog->proctable[GF1_CLI_GET_NEXT_VOLUME]; + proc = &cli_rpc_prog->proctable[GLUSTER_CLI_GET_NEXT_VOLUME]; } else if (wordcount == 3) { ctx.flags = GF_CLI_GET_VOLUME; ctx.volname = (char *)words[2]; @@ -110,9 +66,10 @@ cli_cmd_volume_info_cbk (struct cli_state *state, struct cli_cmd_word *word, cli_out ("Invalid volume name"); goto out; } - proc = &cli_rpc_prog->proctable[GF1_CLI_GET_VOLUME]; + proc = &cli_rpc_prog->proctable[GLUSTER_CLI_GET_VOLUME]; } else { - cli_cmd_volume_info_usage (); + cli_usage_out (word->pattern); + parse_error = 1; return -1; } @@ -121,9 +78,9 @@ cli_cmd_volume_info_cbk (struct cli_state *state, struct cli_cmd_word *word, if (!local) goto out; - local->u.get_vol.flags = ctx.flags; + local->get_vol.flags = ctx.flags; if (ctx.volname) - local->u.get_vol.volname = gf_strdup (ctx.volname); + local->get_vol.volname = gf_strdup (ctx.volname); frame->local = local; @@ -132,17 +89,16 @@ cli_cmd_volume_info_cbk (struct cli_state *state, struct cli_cmd_word *word, } out: - if (ret) - cli_out ("Getting Volume information failed!"); - return ret; + if (ret) { + cli_cmd_sent_status_get (&sent); + if ((sent == 0) && (parse_error == 0)) + cli_out ("Getting Volume information failed!"); + } -} + CLI_STACK_DESTROY (frame); + return ret; -void -cli_cmd_sync_volume_usage () -{ - cli_out ("Usage: volume sync <HOSTNAME> [all|<VOLNAME>]"); } int @@ -152,44 +108,227 @@ cli_cmd_sync_volume_cbk (struct cli_state *state, struct cli_cmd_word *word, int ret = -1; rpc_clnt_procedure_t *proc = NULL; call_frame_t *frame = NULL; - gf1_cli_sync_volume_req req = {0,}; + int sent = 0; + int parse_error = 0; + dict_t *dict = NULL; + cli_local_t *local = NULL; + gf_answer_t answer = GF_ANSWER_NO; + const char *question = "Sync volume may make data " + "inaccessible while the sync " + "is in progress. Do you want " + "to continue?"; if ((wordcount < 3) || (wordcount > 4)) { - cli_cmd_sync_volume_usage (); - goto out; + cli_usage_out (word->pattern); + parse_error = 1; + goto out; } + dict = dict_new (); + if (!dict) + goto out; + if ((wordcount == 3) || !strcmp(words[3], "all")) { - req.flags = GF_CLI_SYNC_ALL; - req.volname = ""; + ret = dict_set_int32 (dict, "flags", (int32_t) + GF_CLI_SYNC_ALL); + if (ret) { + gf_log (THIS->name, GF_LOG_ERROR, "failed to set" + "flag"); + goto out; + } } else { - req.volname = (char *)words[3]; + ret = dict_set_str (dict, "volname", (char *) words[3]); + if (ret) { + gf_log (THIS->name, GF_LOG_ERROR, "failed to set " + "volume"); + goto out; + } + } + + ret = dict_set_str (dict, "hostname", (char *) words[2]); + if (ret) { + gf_log (THIS->name, GF_LOG_ERROR, "failed to set hostname"); + goto out; } - req.hostname = (char *)words[2]; + if (!(state->mode & GLUSTER_MODE_SCRIPT)) { + answer = cli_cmd_get_confirmation (state, question); + if (GF_ANSWER_NO == answer) { + ret = 0; + goto out; + } + } - proc = &cli_rpc_prog->proctable[GF1_CLI_SYNC_VOLUME]; + proc = &cli_rpc_prog->proctable[GLUSTER_CLI_SYNC_VOLUME]; frame = create_frame (THIS, THIS->ctx->pool); if (!frame) goto out; + CLI_LOCAL_INIT (local, words, frame, dict); + if (proc->fn) { - ret = proc->fn (frame, THIS, &req); + ret = proc->fn (frame, THIS, dict); } out: - if (ret) - cli_out ("Volume sync failed"); + if (ret) { + cli_cmd_sent_status_get (&sent); + if ((sent == 0) && (parse_error == 0)) + cli_out ("Volume sync failed"); + } + + CLI_STACK_DESTROY (frame); return ret; } -void -cli_cmd_volume_create_usage () + +gf_ai_compare_t +cli_cmd_compare_addrinfo (struct addrinfo *first, struct addrinfo *next) { - cli_out ("Usage: volume create <NEW-VOLNAME> " - "[stripe <COUNT>] [replica <COUNT>] [transport <tcp|rdma>] " - "<NEW-BRICK> ..."); + int ret = -1; + struct addrinfo *tmp1 = NULL; + struct addrinfo *tmp2 = NULL; + char firstip[NI_MAXHOST] = {0.}; + char nextip[NI_MAXHOST] = {0,}; + + for (tmp1 = first; tmp1 != NULL; tmp1 = tmp1->ai_next) { + ret = getnameinfo (tmp1->ai_addr, tmp1->ai_addrlen, firstip, + NI_MAXHOST, NULL, 0, NI_NUMERICHOST); + if (ret) + return GF_AI_COMPARE_ERROR; + for (tmp2 = next; tmp2 != NULL; tmp2 = tmp2->ai_next) { + ret = getnameinfo (tmp2->ai_addr, tmp2->ai_addrlen, nextip, + NI_MAXHOST, NULL, 0, NI_NUMERICHOST); + if (ret) + return GF_AI_COMPARE_ERROR; + if (!strcmp (firstip, nextip)) { + return GF_AI_COMPARE_MATCH; + } + } + } + return GF_AI_COMPARE_NO_MATCH; +} + +/* Check for non optimal brick order for replicate : + * Checks if bricks belonging to a replicate volume + * are present on the same server + */ +int32_t +cli_cmd_check_brick_order (struct cli_state *state, const char *bricks, + int brick_count, int sub_count) +{ + int ret = -1; + int i = 0; + int j = 0; + int k = 0; + addrinfo_list_t *ai_list = NULL; + addrinfo_list_t *ai_list_tmp1 = NULL; + addrinfo_list_t *ai_list_tmp2 = NULL; + char *brick = NULL; + char *brick_list = NULL; + char *brick_list_dup = NULL; + char *tmpptr = NULL; + struct addrinfo *ai_info = NULL; + gf_answer_t answer = GF_ANSWER_NO; + const char *failed_question = NULL; + const char *found_question = NULL; + failed_question = "Failed to perform brick order check. " + "Do you want to continue creating the volume? "; + found_question = "Multiple bricks of a replicate volume are present" + " on the same server. This setup is not optimal.\n" + "Do you still want to continue creating the volume? "; + + GF_ASSERT (bricks); + GF_ASSERT (brick_count > 0); + GF_ASSERT (sub_count > 0); + + ai_list = malloc (sizeof (addrinfo_list_t)); + ai_list->info = NULL; + INIT_LIST_HEAD (&ai_list->list); + brick_list = gf_strdup (bricks); + if (brick_list == NULL) { + gf_log ("cli", GF_LOG_DEBUG, "failed to allocate memory"); + goto check_failed; + } + brick_list_dup = brick_list; + /* Resolve hostnames and get addrinfo */ + while (i < brick_count) { + ++i; + brick = strtok_r (brick_list, " \n", &tmpptr); + brick_list = tmpptr; + if (brick == NULL) + goto check_failed; + brick = strtok_r (brick, ":", &tmpptr); + if (brick == NULL) + goto check_failed; + ret = getaddrinfo (brick, NULL, NULL, &ai_info); + if (ret) + goto check_failed; + ai_list_tmp1 = malloc (sizeof (addrinfo_list_t)); + if (ai_list_tmp1 == NULL) + goto check_failed; + ai_list_tmp1->info = ai_info; + list_add_tail (&ai_list_tmp1->list, &ai_list->list); + ai_list_tmp1 = NULL; + } + + i = 0; + ai_list_tmp1 = list_entry (ai_list->list.next, addrinfo_list_t, list); + + /* Check for bad brick order */ + while (i < brick_count) { + ++i; + ai_info = ai_list_tmp1->info; + ai_list_tmp1 = list_entry (ai_list_tmp1->list.next, + addrinfo_list_t, list); + if ( 0 == i % sub_count) { + j = 0; + continue; + } + ai_list_tmp2 = ai_list_tmp1; + k = j; + while (k < sub_count - 1) { + ++k; + ret = cli_cmd_compare_addrinfo (ai_info, + ai_list_tmp2->info); + if (GF_AI_COMPARE_ERROR == ret) + goto check_failed; + if (GF_AI_COMPARE_MATCH == ret) + goto found_bad_brick_order; + ai_list_tmp2 = list_entry (ai_list_tmp2->list.next, + addrinfo_list_t, list); + } + ++j; + } + gf_log ("cli", GF_LOG_INFO, "Brick order okay"); + ret = 0; + goto out; + +check_failed: + gf_log ("cli", GF_LOG_INFO, "Failed bad brick order check"); + answer = cli_cmd_get_confirmation(state, failed_question); + if (GF_ANSWER_YES == answer) + ret = 0; + goto out; + +found_bad_brick_order: + gf_log ("cli", GF_LOG_INFO, "Bad brick order found"); + answer = cli_cmd_get_confirmation (state, found_question); + if (GF_ANSWER_YES == answer) + ret = 0; +out: + ai_list_tmp2 = NULL; + i = 0; + GF_FREE (brick_list_dup); + list_for_each_entry (ai_list_tmp1, &ai_list->list, list) { + if (ai_list_tmp1->info) + freeaddrinfo (ai_list_tmp1->info); + free (ai_list_tmp2); + ai_list_tmp2 = ai_list_tmp1; + } + free (ai_list_tmp2); + return ret; } int @@ -200,8 +339,15 @@ cli_cmd_volume_create_cbk (struct cli_state *state, struct cli_cmd_word *word, rpc_clnt_procedure_t *proc = NULL; call_frame_t *frame = NULL; dict_t *options = NULL; + int sent = 0; + int parse_error = 0; + char *brick_list = NULL; + int32_t brick_count = 0; + int32_t sub_count = 0; + int32_t type = GF_CLUSTER_TYPE_NONE; + cli_local_t *local = NULL; - proc = &cli_rpc_prog->proctable[GF1_CLI_CREATE_VOLUME]; + proc = &cli_rpc_prog->proctable[GLUSTER_CLI_CREATE_VOLUME]; frame = create_frame (THIS, THIS->ctx->pool); if (!frame) @@ -210,17 +356,65 @@ cli_cmd_volume_create_cbk (struct cli_state *state, struct cli_cmd_word *word, ret = cli_cmd_volume_create_parse (words, wordcount, &options); if (ret) { - cli_cmd_volume_create_usage (); + cli_usage_out (word->pattern); + parse_error = 1; + goto out; + } + /*Check brick order if type is replicate*/ + ret = dict_get_int32 (options, "type", &type); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Could not get brick type"); goto out; } + if ((type == GF_CLUSTER_TYPE_REPLICATE) || + (type == GF_CLUSTER_TYPE_STRIPE_REPLICATE)) { + if ((ret = dict_get_str (options, "bricks", &brick_list)) != 0) { + gf_log ("cli", GF_LOG_ERROR, "Replica bricks check : " + "Could not retrieve bricks list"); + goto out; + } + if ((ret = dict_get_int32 (options, "count", &brick_count)) != 0) { + gf_log ("cli", GF_LOG_ERROR, "Replica bricks check : " + "Could not retrieve brick count"); + goto out; + } + if ((ret = dict_get_int32 (options, "replica-count", &sub_count)) != 0) { + gf_log ("cli", GF_LOG_ERROR, "Replica bricks check : " + "Could not retrieve replica count"); + goto out; + } + gf_log ("cli", GF_LOG_INFO, "Replicate cluster type found." + " Checking brick order."); + ret = cli_cmd_check_brick_order (state, brick_list, brick_count, sub_count); + if (ret) { + gf_log("cli", GF_LOG_INFO, "Not creating volume because of bad brick order"); + goto out; + } + } + + if (state->mode & GLUSTER_MODE_SCRIPT) { + ret = dict_set_int32 (options, "force", _gf_true); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Failed to set force " + "option"); + goto out; + } + } + + CLI_LOCAL_INIT (local, words, frame, options); if (proc->fn) { ret = proc->fn (frame, THIS, options); } out: - if (options) - dict_unref (options); + if (ret) { + cli_cmd_sent_status_get (&sent); + if ((sent == 0) && (parse_error == 0)) + cli_out ("Volume create failed"); + } + + CLI_STACK_DESTROY (frame); return ret; } @@ -235,17 +429,27 @@ cli_cmd_volume_delete_cbk (struct cli_state *state, struct cli_cmd_word *word, call_frame_t *frame = NULL; char *volname = NULL; gf_answer_t answer = GF_ANSWER_NO; - const char *question = "Deleting volume will erase all information about the volume." - "Do you want to continue?"; + const char *question = NULL; + int sent = 0; + int parse_error = 0; + cli_local_t *local = NULL; + dict_t *dict = NULL; - proc = &cli_rpc_prog->proctable[GF1_CLI_DELETE_VOLUME]; + question = "Deleting volume will erase all information about the volume. " + "Do you want to continue?"; + proc = &cli_rpc_prog->proctable[GLUSTER_CLI_DELETE_VOLUME]; frame = create_frame (THIS, THIS->ctx->pool); if (!frame) goto out; + dict = dict_new (); + if (!dict) + goto out; + if (wordcount != 3) { - cli_cmd_volume_delete_usage (); + cli_usage_out (word->pattern); + parse_error = 1; goto out; } @@ -258,13 +462,27 @@ cli_cmd_volume_delete_cbk (struct cli_state *state, struct cli_cmd_word *word, volname = (char *)words[2]; + ret = dict_set_str (dict, "volname", volname); + + if (ret) { + gf_log (THIS->name, GF_LOG_WARNING, "dict set failed"); + goto out; + } + + CLI_LOCAL_INIT (local, words, frame, dict); + if (proc->fn) { - ret = proc->fn (frame, THIS, volname); + ret = proc->fn (frame, THIS, dict); } out: - if (ret && volname) - cli_out ("Deleting Volume %s failed", volname); + if (ret) { + cli_cmd_sent_status_get (&sent); + if ((sent == 0) && (parse_error == 0)) + cli_out ("Volume delete failed"); + } + + CLI_STACK_DESTROY (frame); return ret; } @@ -276,40 +494,75 @@ cli_cmd_volume_start_cbk (struct cli_state *state, struct cli_cmd_word *word, int ret = -1; rpc_clnt_procedure_t *proc = NULL; call_frame_t *frame = NULL; - gf1_cli_start_vol_req req = {0,}; + int sent = 0; + int parse_error = 0; + dict_t *dict = NULL; + int flags = 0; + cli_local_t *local = NULL; frame = create_frame (THIS, THIS->ctx->pool); if (!frame) goto out; if (wordcount < 3 || wordcount > 4) { - cli_cmd_volume_start_usage (); + cli_usage_out (word->pattern); + parse_error = 1; goto out; } - req.volname = (char *)words[2]; - if (!req.volname) + dict = dict_new (); + if (!dict) { + goto out; + } + + if (!words[2]) + goto out; + + ret = dict_set_str (dict, "volname", (char *)words[2]); + if (ret) { + gf_log (THIS->name, GF_LOG_ERROR, "dict set failed"); goto out; + } if (wordcount == 4) { if (!strcmp("force", words[3])) { - req.flags |= GF_CLI_FLAG_OP_FORCE; + flags |= GF_CLI_FLAG_OP_FORCE; } else { ret = -1; - cli_cmd_volume_start_usage (); + cli_usage_out (word->pattern); + parse_error = 1; goto out; } } + ret = dict_set_int32 (dict, "flags", flags); + if (ret) { + gf_log (THIS->name, GF_LOG_ERROR, + "dict set failed"); + goto out; + } + + if (ret < 0) { + gf_log (THIS->name, GF_LOG_ERROR, + "failed to serialize dict"); + goto out; + } + + proc = &cli_rpc_prog->proctable[GLUSTER_CLI_START_VOLUME]; - proc = &cli_rpc_prog->proctable[GF1_CLI_START_VOLUME]; + CLI_LOCAL_INIT (local, words, frame, dict); if (proc->fn) { - ret = proc->fn (frame, THIS, &req); + ret = proc->fn (frame, THIS, dict); } out: - if (!proc && ret && req.volname) - cli_out ("Starting Volume %s failed", req.volname); + if (ret) { + cli_cmd_sent_status_get (&sent); + if ((sent == 0) && (parse_error == 0)) + cli_out ("Volume start failed"); + } + + CLI_STACK_DESTROY (frame); return ret; } @@ -319,18 +572,21 @@ cli_cmd_get_confirmation (struct cli_state *state, const char *question) { char answer[5] = {'\0', }; char flush = '\0'; - int len = 0; + size_t len; if (state->mode & GLUSTER_MODE_SCRIPT) return GF_ANSWER_YES; printf ("%s (y/n) ", question); - fgets (answer, 4, stdin); + if (fgets (answer, 4, stdin) == NULL) { + cli_out("gluster cli read error"); + goto out; + } len = strlen (answer); - if (answer [len - 1] == '\n'){ + if (len && answer [len - 1] == '\n'){ answer [--len] = '\0'; } else { do{ @@ -361,34 +617,51 @@ cli_cmd_volume_stop_cbk (struct cli_state *state, struct cli_cmd_word *word, rpc_clnt_procedure_t *proc = NULL; call_frame_t *frame = NULL; int flags = 0; - gf1_cli_stop_vol_req req = {0,}; gf_answer_t answer = GF_ANSWER_NO; + int sent = 0; + int parse_error = 0; + dict_t *dict = NULL; + char *volname = NULL; + cli_local_t *local = NULL; const char *question = "Stopping volume will make its data inaccessible. " - "Do you want to Continue?"; + "Do you want to continue?"; frame = create_frame (THIS, THIS->ctx->pool); if (!frame) goto out; if (wordcount < 3 || wordcount > 4) { - cli_cmd_volume_stop_usage (); - goto out; + cli_usage_out (word->pattern); + parse_error = 1; + goto out; } - req.volname = (char *)words[2]; - if (!req.volname) + volname = (char*) words[2]; + + dict = dict_new (); + ret = dict_set_str (dict, "volname", volname); + if (ret) { + gf_log (THIS->name, GF_LOG_ERROR, "dict set failed"); goto out; + } if (wordcount == 4) { if (!strcmp("force", words[3])) { flags |= GF_CLI_FLAG_OP_FORCE; } else { ret = -1; - cli_cmd_volume_stop_usage (); + cli_usage_out (word->pattern); + parse_error = 1; goto out; } } + ret = dict_set_int32 (dict, "flags", flags); + if (ret) { + gf_log (THIS->name, GF_LOG_ERROR, + "dict set failed"); + goto out; + } answer = cli_cmd_get_confirmation (state, question); @@ -397,16 +670,22 @@ cli_cmd_volume_stop_cbk (struct cli_state *state, struct cli_cmd_word *word, goto out; } - req.flags = flags; - proc = &cli_rpc_prog->proctable[GF1_CLI_STOP_VOLUME]; + proc = &cli_rpc_prog->proctable[GLUSTER_CLI_STOP_VOLUME]; + + CLI_LOCAL_INIT (local, words, frame, dict); if (proc->fn) { - ret = proc->fn (frame, THIS, &req); + ret = proc->fn (frame, THIS, dict); } out: - if (!proc && ret && req.volname) - cli_out ("Stopping Volume %s failed", req.volname); + if (ret) { + cli_cmd_sent_status_get (&sent); + if ((sent == 0) && (parse_error == 0)) + cli_out ("Volume stop on '%s' failed", volname); + } + + CLI_STACK_DESTROY (frame); return ret; } @@ -420,6 +699,8 @@ cli_cmd_volume_rename_cbk (struct cli_state *state, struct cli_cmd_word *word, rpc_clnt_procedure_t *proc = NULL; call_frame_t *frame = NULL; dict_t *dict = NULL; + int sent = 0; + int parse_error = 0; frame = create_frame (THIS, THIS->ctx->pool); @@ -431,7 +712,8 @@ cli_cmd_volume_rename_cbk (struct cli_state *state, struct cli_cmd_word *word, goto out; if (wordcount != 4) { - cli_cmd_volume_rename_usage (); + cli_usage_out (word->pattern); + parse_error = 1; goto out; } @@ -445,27 +727,25 @@ cli_cmd_volume_rename_cbk (struct cli_state *state, struct cli_cmd_word *word, if (ret) goto out; - proc = &cli_rpc_prog->proctable[GF1_CLI_RENAME_VOLUME]; + proc = &cli_rpc_prog->proctable[GLUSTER_CLI_RENAME_VOLUME]; if (proc->fn) { ret = proc->fn (frame, THIS, dict); } out: - if (!proc && ret) { - if (dict) - dict_destroy (dict); - if (wordcount > 2) - cli_out ("Renaming Volume %s failed", (char *)words[2]); + if (dict) + dict_destroy (dict); + + if (ret) { + cli_cmd_sent_status_get (&sent); + if ((sent == 0) && (parse_error == 0)) + cli_out ("Volume rename on '%s' failed", (char *)words[2]); } - return ret; -} + CLI_STACK_DESTROY (frame); -void -cli_cmd_volume_defrag_usage () -{ - cli_out ("Usage: volume rebalance <VOLNAME> <start|stop|status>"); + return ret; } int @@ -476,123 +756,184 @@ cli_cmd_volume_defrag_cbk (struct cli_state *state, struct cli_cmd_word *word, rpc_clnt_procedure_t *proc = NULL; call_frame_t *frame = NULL; dict_t *dict = NULL; + int sent = 0; + int parse_error = 0; + cli_local_t *local = NULL; +#ifdef GF_SOLARIS_HOST_OS + cli_out ("Command not supported on Solaris"); + goto out; +#endif frame = create_frame (THIS, THIS->ctx->pool); if (!frame) goto out; - dict = dict_new (); - if (!dict) - goto out; + ret = cli_cmd_volume_defrag_parse (words, wordcount, &dict); - if (wordcount != 4) { - cli_cmd_volume_defrag_usage(); - goto out; + if (ret) { + cli_usage_out (word->pattern); + parse_error = 1; } - ret = dict_set_str (dict, "volname", (char *)words[2]); - if (ret) - goto out; + proc = &cli_rpc_prog->proctable[GLUSTER_CLI_DEFRAG_VOLUME]; - ret = dict_set_str (dict, "command", (char *)words[3]); - if (ret) - goto out; - - proc = &cli_rpc_prog->proctable[GF1_CLI_DEFRAG_VOLUME]; + CLI_LOCAL_INIT (local, words, frame, dict); if (proc->fn) { ret = proc->fn (frame, THIS, dict); } out: - if (!proc && ret) { - if (dict) - dict_destroy (dict); - - if (wordcount > 2) - cli_out ("Rebalance of Volume %s failed", - (char *)words[2]); + if (ret) { + cli_cmd_sent_status_get (&sent); + if ((sent == 0) && (parse_error == 0)) + cli_out ("Volume rebalance failed"); } - return 0; + CLI_STACK_DESTROY (frame); + + return ret; } int -cli_cmd_volume_reset_cbk (struct cli_state *state, struct cli_cmd_word *word, +cli_cmd_volume_reset_cbk (struct cli_state *state, struct cli_cmd_word *word, const char **words, int wordcount) { - + int sent = 0; + int parse_error = 0; int ret = -1; rpc_clnt_procedure_t *proc = NULL; call_frame_t *frame = NULL; dict_t *options = NULL; + cli_local_t *local = NULL; - proc = &cli_rpc_prog->proctable[GF1_CLI_RESET_VOLUME]; + proc = &cli_rpc_prog->proctable[GLUSTER_CLI_RESET_VOLUME]; frame = create_frame (THIS, THIS->ctx->pool); if (!frame) goto out; ret = cli_cmd_volume_reset_parse (words, wordcount, &options); - if (ret) { - cli_cmd_volume_reset_usage (); + cli_usage_out (word->pattern); + parse_error = 1; goto out; } + CLI_LOCAL_INIT (local, words, frame, options); + if (proc->fn) { ret = proc->fn (frame, THIS, options); } out: - if (options) - dict_unref (options); + if (ret) { + cli_cmd_sent_status_get (&sent); + if ((sent == 0) && (parse_error == 0)) + cli_out ("Volume reset failed"); + } + + CLI_STACK_DESTROY (frame); return ret; } +int +cli_cmd_volume_profile_cbk (struct cli_state *state, struct cli_cmd_word *word, + const char **words, int wordcount) +{ + int sent = 0; + int parse_error = 0; + + int ret = -1; + rpc_clnt_procedure_t *proc = NULL; + call_frame_t *frame = NULL; + dict_t *options = NULL; + cli_local_t *local = NULL; + + ret = cli_cmd_volume_profile_parse (words, wordcount, &options); + + if (ret) { + cli_usage_out (word->pattern); + parse_error = 1; + goto out; + } + + proc = &cli_rpc_prog->proctable[GLUSTER_CLI_PROFILE_VOLUME]; + + frame = create_frame (THIS, THIS->ctx->pool); + if (!frame) + goto out; + + CLI_LOCAL_INIT (local, words, frame, options); + + if (proc->fn) { + ret = proc->fn (frame, THIS, options); + } + +out: + if (ret) { + cli_cmd_sent_status_get (&sent); + if ((sent == 0) && (parse_error == 0)) + cli_out ("Volume profile failed"); + } + + CLI_STACK_DESTROY (frame); + + return ret; + +} int cli_cmd_volume_set_cbk (struct cli_state *state, struct cli_cmd_word *word, const char **words, int wordcount) { + int sent = 0; + int parse_error = 0; int ret = -1; rpc_clnt_procedure_t *proc = NULL; call_frame_t *frame = NULL; dict_t *options = NULL; + cli_local_t *local = NULL; + char *op_errstr = NULL; - proc = &cli_rpc_prog->proctable[GF1_CLI_SET_VOLUME]; + proc = &cli_rpc_prog->proctable[GLUSTER_CLI_SET_VOLUME]; frame = create_frame (THIS, THIS->ctx->pool); if (!frame) goto out; - ret = cli_cmd_volume_set_parse (words, wordcount, &options); - + ret = cli_cmd_volume_set_parse (words, wordcount, &options, &op_errstr); if (ret) { - cli_cmd_volume_set_usage (); + if (op_errstr) { + cli_err ("%s", op_errstr); + GF_FREE (op_errstr); + } else + cli_usage_out (word->pattern); + + parse_error = 1; goto out; } + CLI_LOCAL_INIT (local, words, frame, options); + if (proc->fn) { ret = proc->fn (frame, THIS, options); } out: - if (options) - dict_unref (options); + if (ret) { + cli_cmd_sent_status_get (&sent); + if ((sent == 0) && (parse_error == 0)) + cli_out ("Volume set failed"); + } - return ret; + CLI_STACK_DESTROY (frame); -} + return ret; -void -cli_cmd_volume_add_brick_usage () -{ - cli_out ("Usage: volume add-brick <VOLNAME> " - "<NEW-BRICK> ..."); } int @@ -604,40 +945,122 @@ cli_cmd_volume_add_brick_cbk (struct cli_state *state, rpc_clnt_procedure_t *proc = NULL; call_frame_t *frame = NULL; dict_t *options = NULL; + int sent = 0; + int parse_error = 0; + gf_answer_t answer = GF_ANSWER_NO; + cli_local_t *local = NULL; + + const char *question = "Changing the 'stripe count' of the volume is " + "not a supported feature. In some cases it may result in data " + "loss on the volume. Also there may be issues with regular " + "filesystem operations on the volume after the change. Do you " + "really want to continue with 'stripe' count option ? "; frame = create_frame (THIS, THIS->ctx->pool); if (!frame) goto out; ret = cli_cmd_volume_add_brick_parse (words, wordcount, &options); - if (ret) { - cli_cmd_volume_add_brick_usage (); + cli_usage_out (word->pattern); + parse_error = 1; goto out; } - proc = &cli_rpc_prog->proctable[GF1_CLI_ADD_BRICK]; + /* TODO: there are challenges in supporting changing of + stripe-count, untill it is properly supported give warning to user */ + if (dict_get (options, "stripe-count")) { + answer = cli_cmd_get_confirmation (state, question); + + if (GF_ANSWER_NO == answer) { + ret = 0; + goto out; + } + } + + if (state->mode & GLUSTER_MODE_SCRIPT) { + ret = dict_set_int32 (options, "force", _gf_true); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Failed to set force " + "option"); + goto out; + } + } + + proc = &cli_rpc_prog->proctable[GLUSTER_CLI_ADD_BRICK]; + + CLI_LOCAL_INIT (local, words, frame, options); if (proc->fn) { ret = proc->fn (frame, THIS, options); } out: - if (!proc && ret) { - if (wordcount > 2) { - char *volname = (char *) words[2]; - cli_out ("Adding brick to Volume %s failed",volname ); - } + if (ret) { + cli_cmd_sent_status_get (&sent); + if ((sent == 0) && (parse_error == 0)) + cli_out ("Volume add-brick failed"); } + + CLI_STACK_DESTROY (frame); + return ret; } - -void -cli_cmd_volume_remove_brick_usage () +int +cli_cmd_quota_cbk (struct cli_state *state, struct cli_cmd_word *word, + const char **words, int wordcount) { - cli_out ("Usage: volume remove-brick <VOLNAME> " - "<BRICK> ..."); + + int ret = 0; + int parse_err = 0; + int32_t type = 0; + rpc_clnt_procedure_t *proc = NULL; + call_frame_t *frame = NULL; + dict_t *options = NULL; + gf_answer_t answer = GF_ANSWER_NO; + cli_local_t *local = NULL; + const char *question = "Disabling quota will delete all the quota " + "configuration. Do you want to continue?"; + + proc = &cli_rpc_prog->proctable[GLUSTER_CLI_QUOTA]; + if (proc == NULL) { + ret = -1; + goto out; + } + + frame = create_frame (THIS, THIS->ctx->pool); + if (!frame) { + ret = -1; + goto out; + } + + ret = cli_cmd_quota_parse (words, wordcount, &options); + + if (ret < 0) { + cli_usage_out (word->pattern); + parse_err = 1; + goto out; + } else if (dict_get_int32 (options, "type", &type) == 0 && + type == GF_QUOTA_OPTION_TYPE_DISABLE) { + answer = cli_cmd_get_confirmation (state, question); + if (answer == GF_ANSWER_NO) + goto out; + } + + CLI_LOCAL_INIT (local, words, frame, options); + + if (proc->fn) + ret = proc->fn (frame, THIS, options); + +out: + if (ret && parse_err == 0) + cli_out ("Quota command failed"); + + CLI_STACK_DESTROY (frame); + + return ret; + } int @@ -650,6 +1073,10 @@ cli_cmd_volume_remove_brick_cbk (struct cli_state *state, call_frame_t *frame = NULL; dict_t *options = NULL; gf_answer_t answer = GF_ANSWER_NO; + int sent = 0; + int parse_error = 0; + int need_question = 0; + cli_local_t *local = NULL; const char *question = "Removing brick(s) can result in data loss. " "Do you want to Continue?"; @@ -658,44 +1085,43 @@ cli_cmd_volume_remove_brick_cbk (struct cli_state *state, if (!frame) goto out; - ret = cli_cmd_volume_remove_brick_parse (words, wordcount, &options); - + ret = cli_cmd_volume_remove_brick_parse (words, wordcount, &options, + &need_question); if (ret) { - cli_cmd_volume_remove_brick_usage (); + cli_usage_out (word->pattern); + parse_error = 1; goto out; } - answer = cli_cmd_get_confirmation (state, question); - - if (GF_ANSWER_NO == answer) { - ret = 0; - goto out; + if (!(state->mode & GLUSTER_MODE_SCRIPT) && need_question) { + /* we need to ask question only in case of 'commit or force' */ + answer = cli_cmd_get_confirmation (state, question); + if (GF_ANSWER_NO == answer) { + ret = 0; + goto out; + } } - proc = &cli_rpc_prog->proctable[GF1_CLI_REMOVE_BRICK]; + proc = &cli_rpc_prog->proctable[GLUSTER_CLI_REMOVE_BRICK]; + + CLI_LOCAL_INIT (local, words, frame, options); if (proc->fn) { ret = proc->fn (frame, THIS, options); } out: - if (!proc && ret) { - if (wordcount > 2) { - char *volname = (char *) words[2]; - cli_out ("Removing brick from Volume %s failed",volname ); - } + if (ret) { + cli_cmd_sent_status_get (&sent); + if ((sent == 0) && (parse_error == 0)) + cli_out ("Volume remove-brick failed"); } - return ret; -} + CLI_STACK_DESTROY (frame); -void -cli_cmd_volume_replace_brick_usage () -{ - cli_out("Usage: volume replace-brick <VOLNAME> " - "<BRICK> <NEW-BRICK> start|pause|abort|commit|status"); -} + return ret; +} int cli_cmd_volume_replace_brick_cbk (struct cli_state *state, @@ -707,8 +1133,15 @@ cli_cmd_volume_replace_brick_cbk (struct cli_state *state, rpc_clnt_procedure_t *proc = NULL; call_frame_t *frame = NULL; dict_t *options = NULL; + int sent = 0; + int parse_error = 0; + cli_local_t *local = NULL; - proc = &cli_rpc_prog->proctable[GF1_CLI_REPLACE_BRICK]; +#ifdef GF_SOLARIS_HOST_OS + cli_out ("Command not supported on Solaris"); + goto out; +#endif + proc = &cli_rpc_prog->proctable[GLUSTER_CLI_REPLACE_BRICK]; frame = create_frame (THIS, THIS->ctx->pool); if (!frame) @@ -717,23 +1150,36 @@ cli_cmd_volume_replace_brick_cbk (struct cli_state *state, ret = cli_cmd_volume_replace_brick_parse (words, wordcount, &options); if (ret) { - cli_cmd_volume_replace_brick_usage (); + cli_usage_out (word->pattern); + parse_error = 1; goto out; } + if (state->mode & GLUSTER_MODE_SCRIPT) { + ret = dict_set_int32 (options, "force", _gf_true); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Failed to set force" + "option"); + goto out; + } + } + + CLI_LOCAL_INIT (local, words, frame, options); + if (proc->fn) { ret = proc->fn (frame, THIS, options); } out: if (ret) { - if (wordcount > 2) { - char *volname = (char *) words[2]; - cli_out ("Replacing brick from Volume %s failed",volname ); - } + cli_cmd_sent_status_get (&sent); + if ((sent == 0) && (parse_error == 0)) + cli_out ("Volume replace-brick failed"); } - return ret; + CLI_STACK_DESTROY (frame); + + return ret; } @@ -746,147 +1192,649 @@ cli_cmd_volume_set_transport_cbk (struct cli_state *state, return 0; } -void -cli_cmd_log_filename_usage () +int +cli_cmd_volume_top_cbk (struct cli_state *state, struct cli_cmd_word *word, + const char **words, int wordcount) { - cli_out ("Usage: volume log filename <VOLNAME> [BRICK] <PATH>"); + + int ret = -1; + rpc_clnt_procedure_t *proc = NULL; + call_frame_t *frame = NULL; + dict_t *options = NULL; + int sent = 0; + int parse_error = 0; + cli_local_t *local = NULL; + + ret = cli_cmd_volume_top_parse (words, wordcount, &options); + + if (ret) { + parse_error = 1; + cli_usage_out (word->pattern); + goto out; + } + + proc = &cli_rpc_prog->proctable[GLUSTER_CLI_TOP_VOLUME]; + + frame = create_frame (THIS, THIS->ctx->pool); + if (!frame) + goto out; + + CLI_LOCAL_INIT (local, words, frame, options); + + if (proc->fn) { + ret = proc->fn (frame, THIS, options); + } + +out: + if (ret) { + cli_cmd_sent_status_get (&sent); + if ((sent == 0) && (parse_error == 0)) + cli_out ("Volume top failed"); + } + + CLI_STACK_DESTROY (frame); + + return ret; + } + int -cli_cmd_log_filename_cbk (struct cli_state *state, struct cli_cmd_word *word, - const char **words, int wordcount) +cli_cmd_log_rotate_cbk (struct cli_state *state, struct cli_cmd_word *word, + const char **words, int wordcount) { int ret = -1; rpc_clnt_procedure_t *proc = NULL; call_frame_t *frame = NULL; dict_t *options = NULL; + int sent = 0; + int parse_error = 0; + cli_local_t *local = NULL; - if (!((wordcount == 5) || (wordcount == 6))) { - cli_cmd_log_filename_usage (); - goto out; + if (!((wordcount == 4) || (wordcount == 5))) { + cli_usage_out (word->pattern); + parse_error = 1; + goto out; } - proc = &cli_rpc_prog->proctable[GF1_CLI_LOG_FILENAME]; + proc = &cli_rpc_prog->proctable[GLUSTER_CLI_LOG_ROTATE]; frame = create_frame (THIS, THIS->ctx->pool); if (!frame) goto out; - ret = cli_cmd_log_filename_parse (words, wordcount, &options); + ret = cli_cmd_log_rotate_parse (words, wordcount, &options); if (ret) goto out; + CLI_LOCAL_INIT (local, words, frame, options); + if (proc->fn) { ret = proc->fn (frame, THIS, options); } out: - if (ret) - cli_out ("setting log filename failed"); - - if (options) - dict_destroy (options); + if (ret) { + cli_cmd_sent_status_get (&sent); + if ((sent == 0) && (parse_error == 0)) + cli_out ("Volume log rotate failed"); + } + CLI_STACK_DESTROY (frame); return ret; } +#if (SYNCDAEMON_COMPILE) +static int +cli_check_gsync_present () +{ + char buff[PATH_MAX] = {0, }; + runner_t runner = {0,}; + char *ptr = NULL; + int ret = 0; + + ret = setenv ("_GLUSTERD_CALLED_", "1", 1); + if (-1 == ret) { + gf_log ("", GF_LOG_WARNING, "setenv syscall failed, hence could" + "not assert if geo-replication is installed"); + goto out; + } + + runinit (&runner); + runner_add_args (&runner, GSYNCD_PREFIX"/gsyncd", "--version", NULL); + runner_redir (&runner, STDOUT_FILENO, RUN_PIPE); + ret = runner_start (&runner); + if (ret == -1) { + gf_log ("", GF_LOG_INFO, "geo-replication not installed"); + goto out; + } + + ptr = fgets(buff, sizeof(buff), runner_chio (&runner, STDOUT_FILENO)); + if (ptr) { + if (!strstr (buff, "gsyncd")) { + ret = -1; + goto out; + } + } else { + ret = -1; + goto out; + } + + ret = runner_end (&runner); + + if (ret) + gf_log ("", GF_LOG_ERROR, "geo-replication not installed"); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret ? -1 : 0; + +} void -cli_cmd_log_locate_usage () +cli_cmd_check_gsync_exists_cbk (struct cli_cmd *this) { - cli_out ("Usage: volume log locate <VOLNAME> [BRICK]"); + + int ret = 0; + + ret = cli_check_gsync_present (); + if (ret) + this->disable = _gf_true; + } +#endif int -cli_cmd_log_locate_cbk (struct cli_state *state, struct cli_cmd_word *word, - const char **words, int wordcount) +cli_cmd_volume_gsync_set_cbk (struct cli_state *state, struct cli_cmd_word *word, + const char **words, int wordcount) { - int ret = -1; - rpc_clnt_procedure_t *proc = NULL; - call_frame_t *frame = NULL; + int ret = 0; + int parse_err = 0; dict_t *options = NULL; + rpc_clnt_procedure_t *proc = NULL; + call_frame_t *frame = NULL; + cli_local_t *local = NULL; - if (!((wordcount == 4) || (wordcount == 5))) { - cli_cmd_log_locate_usage (); - goto out; + proc = &cli_rpc_prog->proctable [GLUSTER_CLI_GSYNC_SET]; + if (proc == NULL) { + ret = -1; + goto out; } - proc = &cli_rpc_prog->proctable[GF1_CLI_LOG_LOCATE]; - frame = create_frame (THIS, THIS->ctx->pool); - if (!frame) + if (frame == NULL) { + ret = -1; goto out; + } - ret = cli_cmd_log_locate_parse (words, wordcount, &options); - if (ret) + ret = cli_cmd_gsync_set_parse (words, wordcount, &options); + if (ret) { + cli_usage_out (word->pattern); + parse_err = 1; goto out; + } - if (proc->fn) { + CLI_LOCAL_INIT (local, words, frame, options); + + if (proc->fn) ret = proc->fn (frame, THIS, options); + +out: + if (ret && parse_err == 0) + cli_out (GEOREP" command failed"); + + CLI_STACK_DESTROY (frame); + + return ret; +} + +int +cli_cmd_volume_status_cbk (struct cli_state *state, + struct cli_cmd_word *word, + const char **words, int wordcount) +{ + int ret = -1; + rpc_clnt_procedure_t *proc = NULL; + call_frame_t *frame = NULL; + dict_t *dict = NULL; + uint32_t cmd = 0; + cli_local_t *local = NULL; + + ret = cli_cmd_volume_status_parse (words, wordcount, &dict); + + if (ret) { + cli_usage_out (word->pattern); + goto out; } + ret = dict_get_uint32 (dict, "cmd", &cmd); + if (ret) + goto out; + + if (!(cmd & GF_CLI_STATUS_ALL)) { + /* for one volume or brick */ + proc = &cli_rpc_prog->proctable[GLUSTER_CLI_STATUS_VOLUME]; + } else { + /* volume status all or all detail */ + proc = &cli_rpc_prog->proctable[GLUSTER_CLI_STATUS_ALL]; + } + + if (!proc->fn) + goto out; + + frame = create_frame (THIS, THIS->ctx->pool); + if (!frame) + goto out; + + CLI_LOCAL_INIT (local, words, frame, dict); + + ret = proc->fn (frame, THIS, dict); + out: + CLI_STACK_DESTROY (frame); + + return ret; +} + + +int +cli_get_detail_status (dict_t *dict, int i, cli_volume_status_t *status) +{ + uint64_t free = 0; + uint64_t total = 0; + char key[1024] = {0}; + int ret = 0; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.free", i); + ret = dict_get_uint64 (dict, key, &free); + + status->free = gf_uint64_2human_readable (free); + if (!status->free) + goto out; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.total", i); + ret = dict_get_uint64 (dict, key, &total); + + status->total = gf_uint64_2human_readable (total); + if (!status->total) + goto out; + +#ifdef GF_LINUX_HOST_OS + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.device", i); + ret = dict_get_str (dict, key, &(status->device)); + if (ret) + status->device = NULL; +#endif + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.block_size", i); + ret = dict_get_uint64 (dict, key, &(status->block_size)); + if (ret) { + ret = 0; + status->block_size = 0; + } + +#ifdef GF_LINUX_HOST_OS + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.mnt_options", i); + ret = dict_get_str (dict, key, &(status->mount_options)); + if (ret) + status->mount_options = NULL; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.fs_name", i); + ret = dict_get_str (dict, key, &(status->fs_name)); + if (ret) { + ret = 0; + status->fs_name = NULL; + } + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.inode_size", i); + ret = dict_get_str (dict, key, &(status->inode_size)); + if (ret) + status->inode_size = NULL; +#endif /* GF_LINUX_HOST_OS */ + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.total_inodes", i); + ret = dict_get_uint64 (dict, key, + &(status->total_inodes)); if (ret) - cli_out ("getting log file location information failed"); + status->total_inodes = 0; - if (options) - dict_destroy (options); + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.free_inodes", i); + ret = dict_get_uint64 (dict, key, &(status->free_inodes)); + if (ret) { + ret = 0; + status->free_inodes = 0; + } + out: return ret; } void -cli_cmd_log_rotate_usage () +cli_print_detailed_status (cli_volume_status_t *status) { - cli_out ("Usage: volume log rotate <VOLNAME> [BRICK]"); + cli_out ("%-20s : %-20s", "Brick", status->brick); + if (status->online) + cli_out ("%-20s : %-20d", "Port", status->port); + else + cli_out ("%-20s : %-20s", "Port", "N/A"); + cli_out ("%-20s : %-20c", "Online", (status->online) ? 'Y' : 'N'); + cli_out ("%-20s : %-20s", "Pid", status->pid_str); + +#ifdef GF_LINUX_HOST_OS + if (status->fs_name) + cli_out ("%-20s : %-20s", "File System", status->fs_name); + else + cli_out ("%-20s : %-20s", "File System", "N/A"); + + if (status->device) + cli_out ("%-20s : %-20s", "Device", status->device); + else + cli_out ("%-20s : %-20s", "Device", "N/A"); + + if (status->mount_options) { + cli_out ("%-20s : %-20s", "Mount Options", + status->mount_options); + } else { + cli_out ("%-20s : %-20s", "Mount Options", "N/A"); + } + + if (status->inode_size) { + cli_out ("%-20s : %-20s", "Inode Size", + status->inode_size); + } else { + cli_out ("%-20s : %-20s", "Inode Size", "N/A"); + } +#endif + if (status->free) + cli_out ("%-20s : %-20s", "Disk Space Free", status->free); + else + cli_out ("%-20s : %-20s", "Disk Space Free", "N/A"); + + if (status->total) + cli_out ("%-20s : %-20s", "Total Disk Space", status->total); + else + cli_out ("%-20s : %-20s", "Total Disk Space", "N/A"); + + + if (status->total_inodes) { + cli_out ("%-20s : %-20ld", "Inode Count", + status->total_inodes); + } else { + cli_out ("%-20s : %-20s", "Inode Count", "N/A"); + } + + if (status->free_inodes) { + cli_out ("%-20s : %-20ld", "Free Inodes", + status->free_inodes); + } else { + cli_out ("%-20s : %-20s", "Free Inodes", "N/A"); + } } int -cli_cmd_log_rotate_cbk (struct cli_state *state, struct cli_cmd_word *word, - const char **words, int wordcount) +cli_print_brick_status (cli_volume_status_t *status) +{ + int fieldlen = CLI_VOL_STATUS_BRICK_LEN; + int bricklen = 0; + char *p = NULL; + int num_tabs = 0; + + p = status->brick; + bricklen = strlen (p); + while (bricklen > 0) { + if (bricklen > fieldlen) { + cli_out ("%.*s", fieldlen, p); + p += fieldlen; + bricklen -= fieldlen; + } else { + num_tabs = (fieldlen - bricklen) / CLI_TAB_LENGTH + 1; + printf ("%s", p); + while (num_tabs-- != 0) + printf ("\t"); + if (status->port) { + if (status->online) + cli_out ("%d\t%c\t%s", + status->port, + status->online?'Y':'N', + status->pid_str); + else + cli_out ("%s\t%c\t%s", + "N/A", + status->online?'Y':'N', + status->pid_str); + } + else + cli_out ("%s\t%c\t%s", + "N/A", status->online?'Y':'N', + status->pid_str); + bricklen = 0; + } + } + + return 0; +} + +int +cli_cmd_volume_heal_cbk (struct cli_state *state, struct cli_cmd_word *word, + const char **words, int wordcount) { int ret = -1; rpc_clnt_procedure_t *proc = NULL; call_frame_t *frame = NULL; + int sent = 0; + int parse_error = 0; dict_t *options = NULL; + xlator_t *this = NULL; + cli_local_t *local = NULL; - if (!((wordcount == 4) || (wordcount == 5))) { - cli_cmd_log_rotate_usage (); + this = THIS; + frame = create_frame (this, this->ctx->pool); + if (!frame) + goto out; + + if (wordcount < 3) { + cli_usage_out (word->pattern); + parse_error = 1; goto out; } - proc = &cli_rpc_prog->proctable[GF1_CLI_LOG_ROTATE]; + ret = cli_cmd_volume_heal_options_parse (words, wordcount, &options); + if (ret) { + cli_usage_out (word->pattern); + parse_error = 1; + goto out; + } + + proc = &cli_rpc_prog->proctable[GLUSTER_CLI_HEAL_VOLUME]; + + CLI_LOCAL_INIT (local, words, frame, options); + + if (proc->fn) { + ret = proc->fn (frame, THIS, options); + } + +out: + if (ret) { + cli_cmd_sent_status_get (&sent); + if ((sent == 0) && (parse_error == 0)) + cli_out ("Volume heal failed"); + } + + CLI_STACK_DESTROY (frame); + + return ret; +} + +int +cli_cmd_volume_statedump_cbk (struct cli_state *state, struct cli_cmd_word *word, + const char **words, int wordcount) +{ + int ret = -1; + rpc_clnt_procedure_t *proc = NULL; + call_frame_t *frame = NULL; + dict_t *options = NULL; + int sent = 0; + int parse_error = 0; + cli_local_t *local = NULL; frame = create_frame (THIS, THIS->ctx->pool); if (!frame) goto out; - ret = cli_cmd_log_rotate_parse (words, wordcount, &options); + if (wordcount < 3) { + cli_usage_out (word->pattern); + parse_error = 1; + goto out; + } + + if (wordcount >= 3) { + ret = cli_cmd_volume_statedump_options_parse (words, wordcount, + &options); + if (ret) { + parse_error = 1; + gf_log ("cli", GF_LOG_ERROR, "Error parsing " + "statedump options"); + cli_out ("Error parsing options"); + cli_usage_out (word->pattern); + } + } + + ret = dict_set_str (options, "volname", (char *)words[2]); if (ret) goto out; + proc = &cli_rpc_prog->proctable[GLUSTER_CLI_STATEDUMP_VOLUME]; + + CLI_LOCAL_INIT (local, words, frame, options); + if (proc->fn) { ret = proc->fn (frame, THIS, options); } out: - if (ret) - cli_out ("log rotate failed"); + if (ret) { + cli_cmd_sent_status_get (&sent); + if ((sent == 0) && (parse_error = 0)) + cli_out ("Volume statedump failed"); + } - if (options) - dict_destroy (options); + CLI_STACK_DESTROY (frame); return ret; } +int +cli_cmd_volume_list_cbk (struct cli_state *state, struct cli_cmd_word *word, + const char **words, int wordcount) +{ + int ret = -1; + call_frame_t *frame = NULL; + rpc_clnt_procedure_t *proc = NULL; + int sent = 0; + + frame = create_frame (THIS, THIS->ctx->pool); + if (!frame) + goto out; + + proc = &cli_rpc_prog->proctable[GLUSTER_CLI_LIST_VOLUME]; + if (proc->fn) { + ret = proc->fn (frame, THIS, NULL); + } + +out: + if (ret) { + cli_cmd_sent_status_get (&sent); + if (sent == 0) + cli_out ("Volume list failed"); + } + + CLI_STACK_DESTROY (frame); + + return ret; +} + +int +cli_cmd_volume_clearlocks_cbk (struct cli_state *state, + struct cli_cmd_word *word, + const char **words, int wordcount) +{ + int ret = -1; + rpc_clnt_procedure_t *proc = NULL; + call_frame_t *frame = NULL; + dict_t *options = NULL; + int sent = 0; + int parse_error = 0; + cli_local_t *local = NULL; + + frame = create_frame (THIS, THIS->ctx->pool); + if (!frame) + goto out; + + if (wordcount < 7 || wordcount > 8) { + cli_usage_out (word->pattern); + parse_error = 1; + goto out; + } + + ret = cli_cmd_volume_clrlks_opts_parse (words, wordcount, &options); + if (ret) { + parse_error = 1; + gf_log ("cli", GF_LOG_ERROR, "Error parsing " + "clear-locks options"); + cli_out ("Error parsing options"); + cli_usage_out (word->pattern); + } + + ret = dict_set_str (options, "volname", (char *)words[2]); + if (ret) + goto out; + + ret = dict_set_str (options, "path", (char *)words[3]); + if (ret) + goto out; + + proc = &cli_rpc_prog->proctable[GLUSTER_CLI_CLRLOCKS_VOLUME]; + + CLI_LOCAL_INIT (local, words, frame, options); + + if (proc->fn) { + ret = proc->fn (frame, THIS, options); + } + +out: + if (ret) { + cli_cmd_sent_status_get (&sent); + if ((sent == 0) && (parse_error = 0)) + cli_out ("Volume clear-locks failed"); + } + + CLI_STACK_DESTROY (frame); + + return ret; +} struct cli_cmd volume_cmds[] = { { "volume info [all|<VOLNAME>]", cli_cmd_volume_info_cbk, "list information of all volumes"}, - { "volume create <NEW-VOLNAME> [stripe <COUNT>] [replica <COUNT>] [transport <tcp|rdma>] <NEW-BRICK> ...", + { "volume create <NEW-VOLNAME> [stripe <COUNT>] [replica <COUNT>] " + "[transport <tcp|rdma|tcp,rdma>] <NEW-BRICK>" +#ifdef HAVE_BD_XLATOR + "?<vg_name>" +#endif + "... [force]", + cli_cmd_volume_create_cbk, "create a new volume of specified type with mentioned bricks"}, @@ -906,27 +1854,19 @@ struct cli_cmd volume_cmds[] = { cli_cmd_volume_rename_cbk, "rename volume <VOLNAME> to <NEW-VOLNAME>"},*/ - { "volume add-brick <VOLNAME> [(replica <COUNT>)|(stripe <COUNT>)] <NEW-BRICK> ...", + { "volume add-brick <VOLNAME> [<stripe|replica> <COUNT>] <NEW-BRICK> ... [force]", cli_cmd_volume_add_brick_cbk, "add brick to volume <VOLNAME>"}, - { "volume remove-brick <VOLNAME> [(replica <COUNT>)|(stripe <COUNT>)] <BRICK> ...", + { "volume remove-brick <VOLNAME> [replica <COUNT>] <BRICK> ... [start|stop|status|commit|force]", cli_cmd_volume_remove_brick_cbk, "remove brick from volume <VOLNAME>"}, - { "volume rebalance <VOLNAME> start", - cli_cmd_volume_defrag_cbk, - "start rebalance of volume <VOLNAME>"}, - - { "volume rebalance <VOLNAME> stop", - cli_cmd_volume_defrag_cbk, - "stop rebalance of volume <VOLNAME>"}, - - { "volume rebalance <VOLNAME> status", + { "volume rebalance <VOLNAME> [fix-layout] {start|stop|status} [force]", cli_cmd_volume_defrag_cbk, - "rebalance status of volume <VOLNAME>"}, + "rebalance operations"}, - { "volume replace-brick <VOLNAME> (<BRICK> <NEW-BRICK>) start|pause|abort|status", + { "volume replace-brick <VOLNAME> <BRICK> <NEW-BRICK> {start [force]|pause|abort|status|commit [force]}", cli_cmd_volume_replace_brick_cbk, "replace-brick operations"}, @@ -942,14 +1882,6 @@ struct cli_cmd volume_cmds[] = { cli_cmd_volume_help_cbk, "display help for the volume command"}, - { "volume log filename <VOLNAME> [BRICK] <PATH>", - cli_cmd_log_filename_cbk, - "set the log file for corresponding volume/brick"}, - - { "volume log locate <VOLNAME> [BRICK]", - cli_cmd_log_locate_cbk, - "locate the log file for corresponding volume/brick"}, - { "volume log rotate <VOLNAME> [BRICK]", cli_cmd_log_rotate_cbk, "rotate the log file for corresponding volume/brick"}, @@ -957,10 +1889,55 @@ struct cli_cmd volume_cmds[] = { { "volume sync <HOSTNAME> [all|<VOLNAME>]", cli_cmd_sync_volume_cbk, "sync the volume information from a peer"}, - - { "volume reset <VOLNAME> ", + + { "volume reset <VOLNAME> [option] [force]", cli_cmd_volume_reset_cbk, - "reset all the reconfigured options"}, + "reset all the reconfigured options"}, + +#if (SYNCDAEMON_COMPILE) + {"volume "GEOREP" [<VOLNAME>] [<SLAVE-URL>] {create [push-pem] [force]" + "|start [force]|stop [force]|config|status [detail]|delete} [options...]", + cli_cmd_volume_gsync_set_cbk, + "Geo-sync operations", + cli_cmd_check_gsync_exists_cbk}, +#endif + + { "volume profile <VOLNAME> {start|stop|info [nfs]}", + cli_cmd_volume_profile_cbk, + "volume profile operations"}, + + { "volume quota <VOLNAME> <enable|disable|limit-usage|list|remove> [path] [value]", + cli_cmd_quota_cbk, + "quota translator specific operations"}, + + { "volume top <VOLNAME> {open|read|write|opendir|readdir|clear} [nfs|brick <brick>] [list-cnt <value>] |\n" + "volume top <VOLNAME> {read-perf|write-perf} [bs <size> count <count>] [brick <brick>] [list-cnt <value>]", + cli_cmd_volume_top_cbk, + "volume top operations"}, + + { "volume status [all | <VOLNAME> [nfs|shd|<BRICK>]]" + " [detail|clients|mem|inode|fd|callpool|tasks]", + cli_cmd_volume_status_cbk, + "display status of all or specified volume(s)/brick"}, + + { "volume heal <VOLNAME> [{full | statistics {heal-count {replica <hostname:brickname>}} |info {healed | heal-failed | split-brain}}]", + cli_cmd_volume_heal_cbk, + "self-heal commands on volume specified by <VOLNAME>"}, + + {"volume statedump <VOLNAME> [nfs] [all|mem|iobuf|callpool|priv|fd|" + "inode|history]...", + cli_cmd_volume_statedump_cbk, + "perform statedump on bricks"}, + + {"volume list", + cli_cmd_volume_list_cbk, + "list all volumes in cluster"}, + + {"volume clear-locks <VOLNAME> <path> kind {blocked|granted|all}" + "{inode [range]|entry [basename]|posix [range]}", + cli_cmd_volume_clearlocks_cbk, + "Clear locks held on path" + }, { NULL, NULL, NULL } }; @@ -972,11 +1949,8 @@ cli_cmd_volume_help_cbk (struct cli_state *state, struct cli_cmd_word *in_word, struct cli_cmd *cmd = NULL; for (cmd = volume_cmds; cmd->pattern; cmd++) - cli_out ("%s - %s", cmd->pattern, cmd->desc); - - - if (!state->rl_enabled) - exit (0); + if (_gf_false == cmd->disable) + cli_out ("%s - %s", cmd->pattern, cmd->desc); return 0; } @@ -988,8 +1962,8 @@ cli_cmd_volume_register (struct cli_state *state) struct cli_cmd *cmd = NULL; for (cmd = volume_cmds; cmd->pattern; cmd++) { - ret = cli_cmd_register (&state->tree, cmd->pattern, cmd->cbk, - cmd->desc); + + ret = cli_cmd_register (&state->tree, cmd); if (ret) goto out; } diff --git a/cli/src/cli-cmd.c b/cli/src/cli-cmd.c index f09c62106..b81f75b5b 100644 --- a/cli/src/cli-cmd.c +++ b/cli/src/cli-cmd.c @@ -1,22 +1,12 @@ /* - Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. - - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ + Copyright (c) 2010-2012 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ #include <stdio.h> #include <string.h> #include <stdlib.h> @@ -31,6 +21,7 @@ #include "cli.h" #include "cli-cmd.h" #include "cli-mem-types.h" +#include "protocol-common.h" #include <fnmatch.h> @@ -47,16 +38,54 @@ int connected = 0; int cli_cmd_log_help_cbk (struct cli_state *state, struct cli_cmd_word *in_word, const char **words, int wordcount); -static gf_boolean_t +static unsigned cli_cmd_needs_connection (struct cli_cmd_word *word) { if (!strcasecmp ("quit", word->word)) - return _gf_false; + return 0; if (!strcasecmp ("help", word->word)) - return _gf_false; + return 0; + + if (!strcasecmp ("getwd", word->word)) + return 1; + + if (!strcasecmp ("exit", word->word)) + return 0; + + return CLI_DEFAULT_CONN_TIMEOUT; +} + +int +cli_cmd_status_reset (void) +{ + int ret = 0; + + ret = cli_cmd_lock (); + { + if (ret == 0) { + cmd_sent = 0; + cmd_done = 0; + } + } + ret = cli_cmd_unlock (); + return ret; + +} + +int +cli_cmd_sent_status_get (int *status) +{ + int ret = 0; + GF_ASSERT (status); - return _gf_true; + ret = cli_cmd_lock (); + { + if (ret == 0) + *status = cmd_sent; + } + ret = cli_cmd_unlock (); + return ret; } int @@ -66,7 +95,6 @@ cli_cmd_process (struct cli_state *state, int argc, char **argv) struct cli_cmd_word *word = NULL; struct cli_cmd_word *next = NULL; int i = 0; - gf_boolean_t await_conn = _gf_false; word = &state->tree.root; @@ -98,25 +126,22 @@ cli_cmd_process (struct cli_state *state, int argc, char **argv) if ( strcmp (word->word,"help")==0 ) goto callback; - await_conn = cli_cmd_needs_connection (word); + state->await_connected = cli_cmd_needs_connection (word); - if (await_conn) { - ret = cli_cmd_await_connected (); - if (ret) { - cli_out ("Connection failed. Please check if gluster " - "daemon is operational."); - gf_log ("", GF_LOG_NORMAL, "Exiting with: %d", ret); - exit (ret); - } + ret = cli_cmd_await_connected (state->await_connected); + if (ret) { + cli_out ("Connection failed. Please check if gluster " + "daemon is operational."); + gf_log ("", GF_LOG_INFO, "Exiting with: %d", ret); + exit (ret); } callback: ret = word->cbkfn (state, word, (const char **)argv, argc); - + (void) cli_cmd_status_reset (); return ret; } - int cli_cmd_input_token_count (const char *text) { @@ -176,8 +201,7 @@ cli_cmd_process_line (struct cli_state *state, const char *text) ret = cli_cmd_process (state, count, tokens); out: - if (copy) - free (copy); + free (copy); if (tokens) cli_cmd_tokens_destroy (tokens); @@ -207,6 +231,9 @@ cli_cmds_register (struct cli_state *state) if (ret) goto out; + ret = cli_cmd_snapshot_register (state); + if (ret) + goto out; out: return ret; } @@ -238,16 +265,26 @@ cli_cmd_unlock () return 0; } +static void +seconds_from_now (unsigned secs, struct timespec *ts) +{ + struct timeval tv = {0,}; + + gettimeofday (&tv, NULL); + + ts->tv_sec = tv.tv_sec + secs; + ts->tv_nsec = tv.tv_usec * 1000; +} + int -cli_cmd_await_response () +cli_cmd_await_response (unsigned time) { struct timespec ts = {0,}; int ret = 0; cli_op_ret = -1; - time (&ts.tv_sec); - ts.tv_sec += CLI_DEFAULT_CMD_TIMEOUT; + seconds_from_now (time, &ts); while (!cmd_done && !ret) { ret = pthread_cond_timedwait (&cond, &cond_mutex, &ts); @@ -255,8 +292,6 @@ cli_cmd_await_response () cmd_done = 0; - cli_cmd_unlock (); - if (ret) return ret; @@ -283,15 +318,17 @@ out: } int32_t -cli_cmd_await_connected () +cli_cmd_await_connected (unsigned conn_timo) { int32_t ret = 0; struct timespec ts = {0,}; + if (!conn_timo) + return 0; + pthread_mutex_lock (&conn_mutex); { - time (&ts.tv_sec); - ts.tv_sec += CLI_DEFAULT_CONN_TIMEOUT; + seconds_from_now (conn_timo, &ts); while (!connected && !ret) { ret = pthread_cond_timedwait (&conn, &conn_mutex, &ts); @@ -321,22 +358,28 @@ int cli_cmd_submit (void *req, call_frame_t *frame, rpc_clnt_prog_t *prog, int procnum, struct iobref *iobref, - cli_serialize_t sfunc, xlator_t *this, - fop_cbk_fn_t cbkfn) + xlator_t *this, fop_cbk_fn_t cbkfn, xdrproc_t xdrproc) { - int ret = -1; + int ret = -1; + unsigned timeout = 0; + + if ((GLUSTER_CLI_PROFILE_VOLUME == procnum) || + (GLUSTER_CLI_HEAL_VOLUME == procnum)) + timeout = CLI_TEN_MINUTES_TIMEOUT; + else + timeout = CLI_DEFAULT_CMD_TIMEOUT; cli_cmd_lock (); cmd_sent = 0; ret = cli_submit_request (req, frame, prog, - procnum, NULL, sfunc, - this, cbkfn); + procnum, NULL, this, cbkfn, xdrproc); if (!ret) { cmd_sent = 1; - ret = cli_cmd_await_response (); - } else - cli_cmd_unlock (); + ret = cli_cmd_await_response (timeout); + } + + cli_cmd_unlock (); gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); return ret; diff --git a/cli/src/cli-cmd.h b/cli/src/cli-cmd.h index 1655c3a31..041729276 100644 --- a/cli/src/cli-cmd.h +++ b/cli/src/cli-cmd.h @@ -1,22 +1,12 @@ /* - Copyright (c) 2006-2010 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2006-2012 Red Hat, Inc. <http://www.redhat.com> This file is part of GlusterFS. - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. */ - #ifndef __CLI_CMD_H__ #define __CLI_CMD_H__ @@ -25,7 +15,36 @@ #include "config.h" #endif +#include <netdb.h> + #include "cli.h" +#include "list.h" + +#define CLI_LOCAL_INIT(local, words, frame, dictionary) \ + do { \ + local = cli_local_get (); \ + \ + if (local) { \ + local->words = words; \ + if (dictionary) \ + local->dict = dictionary; \ + if (frame) \ + frame->local = local; \ + } \ + } while (0) + +#define CLI_STACK_DESTROY(_frame) \ + do { \ + if (_frame) { \ + if (_frame->local) { \ + gf_log ("cli", GF_LOG_DEBUG, "frame->local " \ + "is not NULL (%p)", _frame->local); \ + cli_local_wipe (_frame->local); \ + _frame->local = NULL; \ + } \ + STACK_DESTROY (_frame->root); \ + } \ + } while (0); typedef enum { GF_ANSWER_YES = 1, @@ -33,9 +52,12 @@ typedef enum { } gf_answer_t; struct cli_cmd { - const char *pattern; - cli_cmd_cbk_t *cbk; - const char *desc; + const char *pattern; + cli_cmd_cbk_t *cbk; + const char *desc; + cli_cmd_reg_cbk_t *reg_cbk; /* callback to check in runtime if the * + * command should be enabled or disabled */ + gf_boolean_t disable; }; struct cli_cmd_volume_get_ctx_ { @@ -43,6 +65,26 @@ struct cli_cmd_volume_get_ctx_ { int flags; }; +typedef struct cli_profile_info_ { + uint64_t fop_hits; + double min_latency; + double max_latency; + double avg_latency; + char *fop_name; + double percentage_avg_latency; +} cli_profile_info_t; + +typedef struct addrinfo_list { + struct list_head list; + struct addrinfo *info; +} addrinfo_list_t; + +typedef enum { + GF_AI_COMPARE_NO_MATCH = 0, + GF_AI_COMPARE_MATCH = 1, + GF_AI_COMPARE_ERROR = 2 +} gf_ai_compare_t; + typedef struct cli_cmd_volume_get_ctx_ cli_cmd_volume_get_ctx_t; int cli_cmd_volume_register (struct cli_state *state); @@ -51,13 +93,15 @@ int cli_cmd_probe_register (struct cli_state *state); int cli_cmd_system_register (struct cli_state *state); +int cli_cmd_snapshot_register (struct cli_state *state); + int cli_cmd_misc_register (struct cli_state *state); struct cli_cmd_word *cli_cmd_nextword (struct cli_cmd_word *word, const char *text); void cli_cmd_tokens_destroy (char **tokens); -int cli_cmd_await_response (); +int cli_cmd_await_response (unsigned time); int cli_cmd_broadcast_response (int32_t status); @@ -71,9 +115,10 @@ int cli_cmd_submit (void *req, call_frame_t *frame, rpc_clnt_prog_t *prog, int procnum, struct iobref *iobref, - cli_serialize_t sfunc, xlator_t *this, - fop_cbk_fn_t cbkfn); + xlator_t *this, fop_cbk_fn_t cbkfn, xdrproc_t xdrproc); gf_answer_t cli_cmd_get_confirmation (struct cli_state *state, const char *question); +int cli_cmd_sent_status_get (int *status); + #endif /* __CLI_CMD_H__ */ diff --git a/cli/src/cli-mem-types.h b/cli/src/cli-mem-types.h index 86e346641..09fcb639b 100644 --- a/cli/src/cli-mem-types.h +++ b/cli/src/cli-mem-types.h @@ -1,22 +1,12 @@ /* - Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2010-2012 Red Hat, Inc. <http://www.redhat.com> This file is part of GlusterFS. - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. */ - #ifndef __CLI_MEM_TYPES_H__ #define __CLI_MEM_TYPES_H__ @@ -32,6 +22,7 @@ enum cli_mem_types_ { cli_mt_call_pool_t, cli_mt_cli_local_t, cli_mt_cli_get_vol_ctx_t, + cli_mt_append_str, cli_mt_end }; diff --git a/cli/src/cli-rl.c b/cli/src/cli-rl.c index 5d1310858..ade1c8ebb 100644 --- a/cli/src/cli-rl.c +++ b/cli/src/cli-rl.c @@ -1,22 +1,12 @@ /* - Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. - - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ + Copyright (c) 2010-2012 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ #include <stdio.h> #include <string.h> #include <stdlib.h> @@ -48,7 +38,6 @@ cli_rl_out (struct cli_state *state, const char *fmt, va_list ap) { int tmp_rl_point = rl_point; int n = rl_end; - int i = 0; int ret = 0; if (rl_end >= 0 ) { @@ -56,12 +45,7 @@ cli_rl_out (struct cli_state *state, const char *fmt, va_list ap) rl_redisplay (); } - printf ("\r"); - - for (i = 0; i <= strlen (state->prompt); i++) - printf (" "); - - printf ("\r"); + printf ("\r%*s\r", (int)strlen (state->prompt), ""); ret = vprintf (fmt, ap); @@ -77,6 +61,34 @@ cli_rl_out (struct cli_state *state, const char *fmt, va_list ap) return ret; } +int +cli_rl_err (struct cli_state *state, const char *fmt, va_list ap) +{ + int tmp_rl_point = rl_point; + int n = rl_end; + int ret = 0; + + if (rl_end >= 0 ) { + rl_kill_text (0, rl_end); + rl_redisplay (); + } + + fprintf (stderr, "\r%*s\r", (int)strlen (state->prompt), ""); + + ret = vfprintf (stderr, fmt, ap); + + fprintf (stderr, "\n"); + fflush(stderr); + + if (n) { + rl_do_undo (); + rl_point = tmp_rl_point; + rl_reset_line_state (); + } + + return ret; +} + void cli_rl_process_line (char *line) @@ -89,9 +101,14 @@ cli_rl_process_line (char *line) state->rl_processing = 1; { ret = cli_cmd_process_line (state, line); + if (ret) + gf_log (THIS->name, GF_LOG_WARNING, + "failed to process line"); + add_history (line); } state->rl_processing = 0; + } @@ -187,7 +204,7 @@ cli_rl_tokenize (const char *text) } if (i < count) { - /* symoblize that what needs to be autocompleted is + /* symbolize that what needs to be autocompleted is the full set of possible nextwords, and not extend the last word */ @@ -199,8 +216,7 @@ cli_rl_tokenize (const char *text) } out: - if (copy) - free (copy); + free (copy); if (i < count) { cli_cmd_tokens_destroy (tokens); @@ -347,9 +363,10 @@ cli_rl_input (void *_data) for (;;) { line = readline (state->prompt); if (!line) - break; + exit(0); //break; - cli_rl_process_line (line); + if (*line) + cli_rl_process_line (line); free (line); } diff --git a/cli/src/cli-rpc-ops.c b/cli/src/cli-rpc-ops.c new file mode 100644 index 000000000..bfeb854ad --- /dev/null +++ b/cli/src/cli-rpc-ops.c @@ -0,0 +1,8673 @@ +/* + Copyright (c) 2010-2012 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +/* Widths of various columns in top read/write-perf output + * Total width of top read/write-perf should be 80 chars + * including one space between column + */ +#define VOL_TOP_PERF_FILENAME_DEF_WIDTH 47 +#define VOL_TOP_PERF_FILENAME_ALT_WIDTH 44 +#define VOL_TOP_PERF_SPEED_WIDTH 4 +#define VOL_TOP_PERF_TIME_WIDTH 26 + +#define INDENT_MAIN_HEAD "%-25s %s " + +#include "cli.h" +#include "compat-errno.h" +#include "cli-cmd.h" +#include <sys/uio.h> +#include <stdlib.h> +#include <sys/mount.h> +#include "cli1-xdr.h" +#include "xdr-generic.h" +#include "protocol-common.h" +#include "cli-mem-types.h" +#include "compat.h" + +#include "syscall.h" +#include "glusterfs3.h" +#include "portmap-xdr.h" + +#include "run.h" + +extern rpc_clnt_prog_t *cli_rpc_prog; +extern int cli_op_ret; +extern int connected; + +char *cli_vol_type_str[] = {"Distribute", + "Stripe", + "Replicate", + "Striped-Replicate", + "Distributed-Stripe", + "Distributed-Replicate", + "Distributed-Striped-Replicate", + }; + +char *cli_vol_status_str[] = {"Created", + "Started", + "Stopped", + }; + +char *cli_vol_task_status_str[] = {"not started", + "in progress", + "stopped", + "completed", + "failed", + "fix-layout in progress", + "fix-layout stopped", + "fix-layout completed", + "fix-layout failed", +}; + +int32_t +gf_cli_get_volume (call_frame_t *frame, xlator_t *this, + void *data); + +int +cli_to_glusterd (gf_cli_req *req, call_frame_t *frame, fop_cbk_fn_t cbkfn, + xdrproc_t xdrproc, dict_t *dict, int procnum, xlator_t *this, + rpc_clnt_prog_t *prog, struct iobref *iobref); + +rpc_clnt_prog_t cli_handshake_prog = { + .progname = "cli handshake", + .prognum = GLUSTER_HNDSK_PROGRAM, + .progver = GLUSTER_HNDSK_VERSION, +}; + +rpc_clnt_prog_t cli_pmap_prog = { + .progname = "cli portmap", + .prognum = GLUSTER_PMAP_PROGRAM, + .progver = GLUSTER_PMAP_VERSION, +}; + +int +gf_cli_probe_cbk (struct rpc_req *req, struct iovec *iov, + int count, void *myframe) +{ + gf_cli_rsp rsp = {0,}; + int ret = -1; + char msg[1024] = {0,}; + + if (-1 == req->rpc_status) { + goto out; + } + + ret = xdr_to_generic (*iov, &rsp, (xdrproc_t)xdr_gf_cli_rsp); + if (ret < 0) { + gf_log (((call_frame_t *) myframe)->this->name, GF_LOG_ERROR, + "Failed to decode xdr response"); + //rsp.op_ret = -1; + //rsp.op_errno = EINVAL; + goto out; + } + + gf_log ("cli", GF_LOG_INFO, "Received resp to probe"); + + if (rsp.op_errstr && (strlen (rsp.op_errstr) > 0)) { + snprintf (msg, sizeof (msg), "%s", rsp.op_errstr); + if (rsp.op_ret) + gf_log ("cli", GF_LOG_ERROR, "%s", msg); + } + + if (global_state->mode & GLUSTER_MODE_XML) { + ret = cli_xml_output_str (NULL, + (rsp.op_ret)? NULL : msg, + rsp.op_ret, rsp.op_errno, + (rsp.op_ret)? msg : NULL); + if (ret) + gf_log ("cli", GF_LOG_ERROR, + "Error outputting to xml"); + goto out; + } + + if (!rsp.op_ret) + cli_out ("peer probe: success. %s", msg); + else + cli_err ("peer probe: failed: %s", msg); + + ret = rsp.op_ret; + +out: + cli_cmd_broadcast_response (ret); + return ret; +} + +int +gf_cli_deprobe_cbk (struct rpc_req *req, struct iovec *iov, + int count, void *myframe) +{ + gf_cli_rsp rsp = {0,}; + int ret = -1; + char msg[1024] = {0,}; + + if (-1 == req->rpc_status) { + goto out; + } + + ret = xdr_to_generic (*iov, &rsp, (xdrproc_t)xdr_gf_cli_rsp); + if (ret < 0) { + gf_log (((call_frame_t *) myframe)->this->name, GF_LOG_ERROR, + "Failed to decode xdr response"); + //rsp.op_ret = -1; + //rsp.op_errno = EINVAL; + goto out; + } + + gf_log ("cli", GF_LOG_INFO, "Received resp to deprobe"); + + if (rsp.op_ret) { + if (strlen (rsp.op_errstr) > 0) { + snprintf (msg, sizeof (msg), "%s", rsp.op_errstr); + gf_log ("cli", GF_LOG_ERROR, "%s", rsp.op_errstr); + } + } else { + snprintf (msg, sizeof (msg), "success"); + } + + if (global_state->mode & GLUSTER_MODE_XML) { + ret = cli_xml_output_str (NULL, + (rsp.op_ret)? NULL : msg, + rsp.op_ret, rsp.op_errno, + (rsp.op_ret)? msg : NULL); + if (ret) + gf_log ("cli", GF_LOG_ERROR, + "Error outputting to xml"); + goto out; + } + + if (!rsp.op_ret) + cli_out ("peer detach: %s", msg); + else + cli_err ("peer detach: failed: %s", msg); + + ret = rsp.op_ret; + +out: + cli_cmd_broadcast_response (ret); + return ret; +} + +int +gf_cli_output_peer_status (dict_t *dict, int count) +{ + int ret = -1; + char *uuid_buf = NULL; + char *hostname_buf = NULL; + int32_t i = 1; + char key[256] = {0,}; + char *state = NULL; + int32_t connected = 0; + char *connected_str = NULL; + + cli_out ("Number of Peers: %d", count); + i = 1; + while ( i <= count) { + snprintf (key, 256, "friend%d.uuid", i); + ret = dict_get_str (dict, key, &uuid_buf); + if (ret) + goto out; + + snprintf (key, 256, "friend%d.hostname", i); + ret = dict_get_str (dict, key, &hostname_buf); + if (ret) + goto out; + + snprintf (key, 256, "friend%d.connected", i); + ret = dict_get_int32 (dict, key, &connected); + if (ret) + goto out; + if (connected) + connected_str = "Connected"; + else + connected_str = "Disconnected"; + + + snprintf (key, 256, "friend%d.state", i); + ret = dict_get_str (dict, key, &state); + if (ret) + goto out; + + cli_out ("\nHostname: %s\nUuid: %s\nState: %s (%s)", + hostname_buf, uuid_buf, state, connected_str); + i++; + } + + ret = 0; +out: + return ret; +} + +int +gf_cli_output_pool_list (dict_t *dict, int count) +{ + int ret = -1; + char *uuid_buf = NULL; + char *hostname_buf = NULL; + int32_t i = 1; + char key[256] = {0,}; + int32_t connected = 0; + char *connected_str = NULL; + + if (count >= 1) + cli_out ("UUID\t\t\t\t\tHostname\tState"); + + while ( i <= count) { + snprintf (key, 256, "friend%d.uuid", i); + ret = dict_get_str (dict, key, &uuid_buf); + if (ret) + goto out; + + snprintf (key, 256, "friend%d.hostname", i); + ret = dict_get_str (dict, key, &hostname_buf); + if (ret) + goto out; + + snprintf (key, 256, "friend%d.connected", i); + ret = dict_get_int32 (dict, key, &connected); + if (ret) + goto out; + if (connected) + connected_str = "Connected"; + else + connected_str = "Disconnected"; + + cli_out ("%s\t%-9s\t%s ", uuid_buf, hostname_buf, + connected_str); + i++; + } + + ret = 0; +out: + return ret; +} + +/* function pointer for gf_cli_output_{pool_list,peer_status} */ +typedef int (*cli_friend_output_fn) (dict_t*, int); + +int +gf_cli_list_friends_cbk (struct rpc_req *req, struct iovec *iov, + int count, void *myframe) +{ + gf1_cli_peer_list_rsp rsp = {0,}; + int ret = -1; + dict_t *dict = NULL; + char msg[1024] = {0,}; + char *cmd = NULL; + cli_friend_output_fn friend_output_fn; + call_frame_t *frame = NULL; + unsigned long flags = 0; + + frame = myframe; + flags = (long)frame->local; + + if (flags == GF_CLI_LIST_POOL_NODES) { + cmd = "pool list"; + friend_output_fn = &gf_cli_output_pool_list; + } else { + cmd = "peer status"; + friend_output_fn = &gf_cli_output_peer_status; + } + + /* 'free' the flags set by gf_cli_list_friends */ + frame->local = NULL; + + if (-1 == req->rpc_status) { + goto out; + } + + ret = xdr_to_generic (*iov, &rsp, (xdrproc_t)xdr_gf1_cli_peer_list_rsp); + if (ret < 0) { + gf_log (((call_frame_t *) myframe)->this->name, GF_LOG_ERROR, + "Failed to decode xdr response"); + //rsp.op_ret = -1; + //rsp.op_errno = EINVAL; + goto out; + } + + gf_log ("cli", GF_LOG_DEBUG, "Received resp to list: %d", + rsp.op_ret); + + ret = rsp.op_ret; + + if (!rsp.op_ret) { + + if (!rsp.friends.friends_len) { + snprintf (msg, sizeof (msg), + "%s: No peers present", cmd); + if (global_state->mode & GLUSTER_MODE_XML) { + ret = cli_xml_output_peer_status (dict, + rsp.op_ret, + rsp.op_errno, + msg); + if (ret) + gf_log ("cli", GF_LOG_ERROR, + "Error outputting to xml"); + goto out; + } + cli_err ("%s", msg); + ret = 0; + goto out; + } + + dict = dict_new (); + + if (!dict) { + ret = -1; + goto out; + } + + ret = dict_unserialize (rsp.friends.friends_val, + rsp.friends.friends_len, + &dict); + + if (ret) { + gf_log ("", GF_LOG_ERROR, + "Unable to allocate memory"); + goto out; + } + + if (global_state->mode & GLUSTER_MODE_XML) { + ret = cli_xml_output_peer_status (dict, rsp.op_ret, + rsp.op_errno, msg); + if (ret) + gf_log ("cli", GF_LOG_ERROR, + "Error outputting to xml"); + goto out; + } + + ret = dict_get_int32 (dict, "count", &count); + if (ret) { + goto out; + } + + ret = friend_output_fn (dict, count); + if (ret) { + goto out; + } + } else { + if (global_state->mode & GLUSTER_MODE_XML) { + ret = cli_xml_output_peer_status (dict, rsp.op_ret, + rsp.op_errno, NULL); + if (ret) + gf_log ("cli", GF_LOG_ERROR, + "Error outputting to xml"); + } else { + ret = -1; + } + goto out; + } + + + ret = 0; + +out: + cli_cmd_broadcast_response (ret); + if (ret) + cli_err ("%s: failed", cmd); + + if (dict) + dict_destroy (dict); + + return ret; +} + +void +cli_out_options ( char *substr, char *optstr, char *valstr) +{ + char *ptr1 = NULL; + char *ptr2 = NULL; + + ptr1 = substr; + ptr2 = optstr; + + while (ptr1) + { + if (*ptr1 != *ptr2) + break; + ptr1++; + ptr2++; + if (!ptr1) + return; + if (!ptr2) + return; + } + + if (*ptr2 == '\0') + return; + cli_out ("%s: %s",ptr2 , valstr); +} + +static int +_gf_cli_output_volinfo_opts (dict_t *d, char *k, + data_t *v, void *tmp) +{ + int ret = 0; + char *key = NULL; + char *ptr = NULL; + data_t *value = NULL; + + key = tmp; + + ptr = strstr (k, "option."); + if (ptr) { + value = v; + if (!value) { + ret = -1; + goto out; + } + cli_out_options (key, k, v->data); + } +out: + return ret; +} + + +int +gf_cli_get_volume_cbk (struct rpc_req *req, struct iovec *iov, + int count, void *myframe) +{ + int ret = -1; + int opt_count = 0; + int32_t i = 0; + int32_t j = 1; + int32_t status = 0; + int32_t type = 0; + int32_t brick_count = 0; + int32_t dist_count = 0; + int32_t stripe_count = 0; + int32_t replica_count = 0; + int32_t vol_type = 0; + int32_t transport = 0; + char *volume_id_str = NULL; + char *brick = NULL; + char *volname = NULL; + dict_t *dict = NULL; + cli_local_t *local = NULL; + char key[1024] = {0}; + char err_str[2048] = {0}; + gf_cli_rsp rsp = {0}; + char *caps = NULL; + int k __attribute__((unused)) = 0; + // snap_volume variable helps in showing whether a volume is a normal + //volume or a volume for the snapshot + int32_t snap_volume = 0; + + if (-1 == req->rpc_status) + goto out; + + ret = xdr_to_generic (*iov, &rsp, (xdrproc_t)xdr_gf_cli_rsp); + if (ret < 0) { + gf_log (((call_frame_t *) myframe)->this->name, GF_LOG_ERROR, + "Failed to decode xdr response"); + goto out; + } + + gf_log ("cli", GF_LOG_INFO, "Received resp to get vol: %d", + rsp.op_ret); + + if (rsp.op_ret) { + ret = -1; + goto out; + } + + if (!rsp.dict.dict_len) { + if (global_state->mode & GLUSTER_MODE_XML) + goto xml_output; + cli_err ("No volumes present"); + ret = 0; + goto out; + } + + dict = dict_new (); + + if (!dict) { + ret = -1; + goto out; + } + + ret = dict_unserialize (rsp.dict.dict_val, + rsp.dict.dict_len, + &dict); + + if (ret) { + gf_log ("cli", GF_LOG_ERROR, + "Unable to allocate memory"); + goto out; + } + + ret = dict_get_int32 (dict, "count", &count); + if (ret) + goto out; + + local = ((call_frame_t *)myframe)->local; + + if (!count) { + switch (local->get_vol.flags) { + + case GF_CLI_GET_NEXT_VOLUME: + GF_FREE (local->get_vol.volname); + local->get_vol.volname = NULL; + ret = 0; + goto out; + + case GF_CLI_GET_VOLUME: + memset (err_str, 0, sizeof (err_str)); + snprintf (err_str, sizeof (err_str), + "Volume %s does not exist", + local->get_vol.volname); + ret = -1; + if (!(global_state->mode & GLUSTER_MODE_XML)) + goto out; + } + } + +xml_output: + if (global_state->mode & GLUSTER_MODE_XML) { + /* For GET_NEXT_VOLUME output is already begun in + * and will also end in gf_cli_get_next_volume() + */ + if (local->get_vol.flags == GF_CLI_GET_VOLUME) { + ret = cli_xml_output_vol_info_begin + (local, rsp.op_ret, rsp.op_errno, + rsp.op_errstr); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, + "Error outputting to xml"); + goto out; + } + } + + if (dict) { + ret = cli_xml_output_vol_info (local, dict); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, + "Error outputting to xml"); + goto out; + } + } + + if (local->get_vol.flags == GF_CLI_GET_VOLUME) { + ret = cli_xml_output_vol_info_end (local); + if (ret) + gf_log ("cli", GF_LOG_ERROR, + "Error outputting to xml"); + } + goto out; + } + + while ( i < count) { + cli_out (" "); + snprintf (key, 256, "volume%d.name", i); + ret = dict_get_str (dict, key, &volname); + if (ret) + goto out; + + snprintf (key, 256, "volume%d.type", i); + ret = dict_get_int32 (dict, key, &type); + if (ret) + goto out; + + snprintf (key, 256, "volume%d.status", i); + ret = dict_get_int32 (dict, key, &status); + if (ret) + goto out; + + snprintf (key, sizeof (key), "volume%d.snap_volume", i); + ret = dict_get_int32 (dict, key, &snap_volume); + if (ret) + goto out; + + snprintf (key, 256, "volume%d.brick_count", i); + ret = dict_get_int32 (dict, key, &brick_count); + if (ret) + goto out; + + snprintf (key, 256, "volume%d.dist_count", i); + ret = dict_get_int32 (dict, key, &dist_count); + if (ret) + goto out; + + snprintf (key, 256, "volume%d.stripe_count", i); + ret = dict_get_int32 (dict, key, &stripe_count); + if (ret) + goto out; + + snprintf (key, 256, "volume%d.replica_count", i); + ret = dict_get_int32 (dict, key, &replica_count); + if (ret) + goto out; + + snprintf (key, 256, "volume%d.transport", i); + ret = dict_get_int32 (dict, key, &transport); + if (ret) + goto out; + + snprintf (key, 256, "volume%d.volume_id", i); + ret = dict_get_str (dict, key, &volume_id_str); + if (ret) + goto out; + + vol_type = type; + + // Distributed (stripe/replicate/stripe-replica) setups + if ((type > 0) && ( dist_count < brick_count)) + vol_type = type + 3; + + cli_out ("Volume Name: %s", volname); + cli_out ("Type: %s", cli_vol_type_str[vol_type]); + cli_out ("Volume ID: %s", volume_id_str); + cli_out ("Status: %s", cli_vol_status_str[status]); + if (snap_volume) + cli_out ("Snap Volume: %s", "yes"); + else + cli_out ("Snap Volume: %s", "no"); + +#ifdef HAVE_BD_XLATOR + k = 0; + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "volume%d.xlator%d", i, k); + ret = dict_get_str (dict, key, &caps); + if (ret) + goto next; + do { + j = 0; + cli_out ("Xlator %d: %s", k + 1, caps); + do { + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), + "volume%d.xlator%d.caps%d", + i, k, j++); + ret = dict_get_str (dict, key, &caps); + if (ret) + break; + cli_out ("Capability %d: %s", j, caps); + } while (1); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), + "volume%d.xlator%d", i, ++k); + ret = dict_get_str (dict, key, &caps); + if (ret) + break; + } while (1); + +next: +#else + caps = 0; /* Avoid compiler warnings when BD not enabled */ +#endif + + if (type == GF_CLUSTER_TYPE_STRIPE_REPLICATE) { + cli_out ("Number of Bricks: %d x %d x %d = %d", + (brick_count / dist_count), + stripe_count, + replica_count, + brick_count); + } else if (type == GF_CLUSTER_TYPE_NONE) { + cli_out ("Number of Bricks: %d", brick_count); + } else { + /* For both replicate and stripe, dist_count is + good enough */ + cli_out ("Number of Bricks: %d x %d = %d", + (brick_count / dist_count), + dist_count, brick_count); + } + + cli_out ("Transport-type: %s", + ((transport == 0)?"tcp": + (transport == 1)?"rdma": + "tcp,rdma")); + j = 1; + + GF_FREE (local->get_vol.volname); + local->get_vol.volname = gf_strdup (volname); + + if (brick_count) + cli_out ("Bricks:"); + + while (j <= brick_count) { + snprintf (key, 1024, "volume%d.brick%d", i, j); + ret = dict_get_str (dict, key, &brick); + if (ret) + goto out; + + cli_out ("Brick%d: %s", j, brick); +#ifdef HAVE_BD_XLATOR + snprintf (key, 256, "volume%d.vg%d", i, j); + ret = dict_get_str (dict, key, &caps); + if (!ret) + cli_out ("Brick%d VG: %s", j, caps); +#endif + j++; + } + + snprintf (key, 256, "volume%d.opt_count",i); + ret = dict_get_int32 (dict, key, &opt_count); + if (ret) + goto out; + + if (!opt_count) + goto out; + + cli_out ("Options Reconfigured:"); + + snprintf (key, 256, "volume%d.option.",i); + + ret = dict_foreach (dict, _gf_cli_output_volinfo_opts, key); + if (ret) + goto out; + + i++; + } + + + ret = 0; +out: + cli_cmd_broadcast_response (ret); + if (ret) + cli_err ("%s", err_str); + + if (dict) + dict_destroy (dict); + + free (rsp.dict.dict_val); + + free (rsp.op_errstr); + + gf_log ("cli", GF_LOG_INFO, "Returning: %d", ret); + return ret; +} + +int +gf_cli_create_volume_cbk (struct rpc_req *req, struct iovec *iov, + int count, void *myframe) +{ + gf_cli_rsp rsp = {0,}; + int ret = -1; + cli_local_t *local = NULL; + char *volname = NULL; + dict_t *dict = NULL; + dict_t *rsp_dict = NULL; + + if (-1 == req->rpc_status) { + goto out; + } + + local = ((call_frame_t *) (myframe))->local; + + ret = xdr_to_generic (*iov, &rsp, (xdrproc_t)xdr_gf_cli_rsp); + if (ret < 0) { + gf_log (((call_frame_t *) myframe)->this->name, GF_LOG_ERROR, + "Failed to decode xdr response"); + goto out; + } + + gf_log ("cli", GF_LOG_INFO, "Received resp to create volume"); + + dict = local->dict; + + ret = dict_get_str (dict, "volname", &volname); + if (ret) + goto out; + + if (global_state->mode & GLUSTER_MODE_XML) { + if (rsp.op_ret == 0) { + rsp_dict = dict_new (); + ret = dict_unserialize (rsp.dict.dict_val, + rsp.dict.dict_len, + &rsp_dict); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, + "Failed rsp_dict unserialization"); + goto out; + } + } + + ret = cli_xml_output_vol_create (rsp_dict, rsp.op_ret, + rsp.op_errno, rsp.op_errstr); + if (ret) + gf_log ("cli", GF_LOG_ERROR, + "Error outputting to xml"); + goto out; + } + + if (rsp.op_ret && strcmp (rsp.op_errstr, "")) + cli_err ("volume create: %s: failed: %s", volname, + rsp.op_errstr); + else if (rsp.op_ret) + cli_err ("volume create: %s: failed", volname); + else + cli_out ("volume create: %s: success: " + "please start the volume to access data", volname); + + ret = rsp.op_ret; + +out: + cli_cmd_broadcast_response (ret); + free (rsp.dict.dict_val); + free (rsp.op_errstr); + return ret; +} + +int +gf_cli_delete_volume_cbk (struct rpc_req *req, struct iovec *iov, + int count, void *myframe) +{ + gf_cli_rsp rsp = {0,}; + int ret = -1; + cli_local_t *local = NULL; + char *volname = NULL; + call_frame_t *frame = NULL; + dict_t *dict = NULL; + dict_t *rsp_dict = NULL; + + if (-1 == req->rpc_status) { + goto out; + } + + frame = myframe; + + ret = xdr_to_generic (*iov, &rsp, (xdrproc_t)xdr_gf_cli_rsp); + if (ret < 0) { + gf_log (frame->this->name, GF_LOG_ERROR, + "Failed to decode xdr response"); + goto out; + } + + local = frame->local; + + if (local) + dict = local->dict; + ret = dict_get_str (dict, "volname", &volname); + if (ret) { + gf_log (frame->this->name, GF_LOG_ERROR, + "dict get failed"); + goto out; + } + + gf_log ("cli", GF_LOG_INFO, "Received resp to delete volume"); + + if (global_state->mode & GLUSTER_MODE_XML) { + if (rsp.op_ret == 0) { + rsp_dict = dict_new (); + ret = dict_unserialize (rsp.dict.dict_val, + rsp.dict.dict_len, + &rsp_dict); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, + "Failed rsp_dict unserialization"); + goto out; + } + } + + ret = cli_xml_output_generic_volume ("volDelete", rsp_dict, + rsp.op_ret, rsp.op_errno, + rsp.op_errstr); + if (ret) + gf_log ("cli", GF_LOG_ERROR, + "Error outputting to xml"); + goto out; + } + + if (rsp.op_ret && strcmp (rsp.op_errstr, "")) + cli_err ("volume delete: %s: failed: %s", volname, + rsp.op_errstr); + else if (rsp.op_ret) + cli_err ("volume delete: %s: failed", volname); + else + cli_out ("volume delete: %s: success", volname); + + ret = rsp.op_ret; + +out: + cli_cmd_broadcast_response (ret); + free (rsp.dict.dict_val); + + gf_log ("", GF_LOG_INFO, "Returning with %d", ret); + return ret; +} + +int +gf_cli3_1_uuid_get_cbk (struct rpc_req *req, struct iovec *iov, + int count, void *myframe) +{ + char *uuid_str = NULL; + gf_cli_rsp rsp = {0,}; + int ret = -1; + cli_local_t *local = NULL; + call_frame_t *frame = NULL; + dict_t *dict = NULL; + + if (-1 == req->rpc_status) + goto out; + + frame = myframe; + + ret = xdr_to_generic (*iov, &rsp, (xdrproc_t)xdr_gf_cli_rsp); + if (ret < 0) { + gf_log (frame->this->name, GF_LOG_ERROR, + "Failed to decode xdr response"); + goto out; + } + + local = frame->local; + frame->local = NULL; + + gf_log ("cli", GF_LOG_INFO, "Received resp to uuid get"); + + dict = dict_new (); + if (!dict) { + ret = -1; + goto out; + } + + ret = dict_unserialize (rsp.dict.dict_val, rsp.dict.dict_len, + &dict); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Failed to unserialize " + "response for uuid get"); + goto out; + } + + ret = dict_get_str (dict, "uuid", &uuid_str); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Failed to get uuid " + "from dictionary"); + goto out; + } + + if (global_state->mode & GLUSTER_MODE_XML) { + ret = cli_xml_output_dict ("uuidGenerate", dict, rsp.op_ret, + rsp.op_errno, rsp.op_errstr); + if (ret) + gf_log ("cli", GF_LOG_ERROR, + "Error outputting to xml"); + goto out; + } + + if (rsp.op_ret) { + if (strcmp (rsp.op_errstr, "") == 0) + cli_err ("Get uuid was unsuccessful"); + else + cli_err ("%s", rsp.op_errstr); + + } else { + cli_out ("UUID: %s", uuid_str); + + } + ret = rsp.op_ret; + +out: + cli_cmd_broadcast_response (ret); + cli_local_wipe (local); + if (rsp.dict.dict_val) + free (rsp.dict.dict_val); + if (dict) + dict_unref (dict); + + gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret); + return ret; +} + +int +gf_cli3_1_uuid_reset_cbk (struct rpc_req *req, struct iovec *iov, + int count, void *myframe) +{ + gf_cli_rsp rsp = {0,}; + int ret = -1; + cli_local_t *local = NULL; + call_frame_t *frame = NULL; + dict_t *dict = NULL; + + if (-1 == req->rpc_status) { + goto out; + } + + frame = myframe; + + ret = xdr_to_generic (*iov, &rsp, (xdrproc_t)xdr_gf_cli_rsp); + if (ret < 0) { + gf_log (frame->this->name, GF_LOG_ERROR, + "Failed to decode xdr response"); + goto out; + } + + local = frame->local; + frame->local = NULL; + + gf_log ("cli", GF_LOG_INFO, "Received resp to uuid reset"); + + if (global_state->mode & GLUSTER_MODE_XML) { + ret = cli_xml_output_dict ("uuidReset", dict, rsp.op_ret, + rsp.op_errno, rsp.op_errstr); + if (ret) + gf_log ("cli", GF_LOG_ERROR, + "Error outputting to xml"); + goto out; + } + + if (rsp.op_ret && strcmp (rsp.op_errstr, "")) + cli_err ("%s", rsp.op_errstr); + else + cli_out ("resetting the peer uuid has been %s", + (rsp.op_ret) ? "unsuccessful": "successful"); + ret = rsp.op_ret; + +out: + cli_cmd_broadcast_response (ret); + cli_local_wipe (local); + if (rsp.dict.dict_val) + free (rsp.dict.dict_val); + if (dict) + dict_unref (dict); + + gf_log ("", GF_LOG_INFO, "Returning with %d", ret); + return ret; +} + +int +gf_cli_start_volume_cbk (struct rpc_req *req, struct iovec *iov, + int count, void *myframe) +{ + gf_cli_rsp rsp = {0,}; + int ret = -1; + cli_local_t *local = NULL; + char *volname = NULL; + call_frame_t *frame = NULL; + dict_t *dict = NULL; + dict_t *rsp_dict = NULL; + + if (-1 == req->rpc_status) { + goto out; + } + + frame = myframe; + + ret = xdr_to_generic (*iov, &rsp, (xdrproc_t)xdr_gf_cli_rsp); + if (ret < 0) { + gf_log (frame->this->name, GF_LOG_ERROR, + "Failed to decode xdr response"); + goto out; + } + + if (frame) + local = frame->local; + + if (local) + dict = local->dict; + + ret = dict_get_str (dict, "volname", &volname); + if (ret) { + gf_log (frame->this->name, GF_LOG_ERROR, "dict get failed"); + goto out; + } + + gf_log ("cli", GF_LOG_INFO, "Received resp to start volume"); + + if (global_state->mode & GLUSTER_MODE_XML) { + if (rsp.op_ret == 0) { + rsp_dict = dict_new (); + ret = dict_unserialize (rsp.dict.dict_val, + rsp.dict.dict_len, + &rsp_dict); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, + "Failed rsp_dict unserialization"); + goto out; + } + } + + ret = cli_xml_output_generic_volume ("volStart", rsp_dict, + rsp.op_ret, rsp.op_errno, + rsp.op_errstr); + if (ret) + gf_log ("cli", GF_LOG_ERROR, + "Error outputting to xml"); + goto out; + } + + if (rsp.op_ret && strcmp (rsp.op_errstr, "")) + cli_err ("volume start: %s: failed: %s", volname, + rsp.op_errstr); + else if (rsp.op_ret) + cli_err ("volume start: %s: failed", volname); + else + cli_out ("volume start: %s: success", volname); + + ret = rsp.op_ret; + +out: + cli_cmd_broadcast_response (ret); + free (rsp.dict.dict_val); + free (rsp.op_errstr); + return ret; +} + +int +gf_cli_stop_volume_cbk (struct rpc_req *req, struct iovec *iov, + int count, void *myframe) +{ + gf_cli_rsp rsp = {0,}; + int ret = -1; + cli_local_t *local = NULL; + char *volname = NULL; + call_frame_t *frame = NULL; + dict_t *dict = NULL; + dict_t *rsp_dict = NULL; + + if (-1 == req->rpc_status) { + goto out; + } + + frame = myframe; + + ret = xdr_to_generic (*iov, &rsp, (xdrproc_t)xdr_gf_cli_rsp); + if (ret < 0) { + gf_log (frame->this->name, GF_LOG_ERROR, + "Failed to decode xdr response"); + goto out; + } + + if (frame) + local = frame->local; + + if (local) { + dict = local->dict; + ret = dict_get_str (dict, "volname", &volname); + if (ret) { + gf_log (frame->this->name, GF_LOG_ERROR, + "Unable to get volname from dict"); + goto out; + } + } + + gf_log ("cli", GF_LOG_INFO, "Received resp to stop volume"); + + if (global_state->mode & GLUSTER_MODE_XML) { + if (rsp.op_ret == 0) { + rsp_dict = dict_new (); + ret = dict_unserialize (rsp.dict.dict_val, + rsp.dict.dict_len, + &rsp_dict); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, + "Failed rsp_dict unserialization"); + goto out; + } + } + + ret = cli_xml_output_generic_volume ("volStop", rsp_dict, + rsp.op_ret, rsp.op_errno, + rsp.op_errstr); + if (ret) + gf_log ("cli", GF_LOG_ERROR, + "Error outputting to xml"); + goto out; + } + + if (rsp.op_ret && strcmp (rsp.op_errstr, "")) + cli_err ("volume stop: %s: failed: %s", volname, rsp.op_errstr); + else if (rsp.op_ret) + cli_err ("volume stop: %s: failed", volname); + else + cli_out ("volume stop: %s: success", volname); + + ret = rsp.op_ret; + +out: + cli_cmd_broadcast_response (ret); + free (rsp.op_errstr); + free (rsp.dict.dict_val); + + return ret; +} + +int +gf_cli_defrag_volume_cbk (struct rpc_req *req, struct iovec *iov, + int count, void *myframe) +{ + gf_cli_rsp rsp = {0,}; + cli_local_t *local = NULL; + char *volname = NULL; + call_frame_t *frame = NULL; + char *status = "unknown"; + int cmd = 0; + int ret = -1; + dict_t *dict = NULL; + dict_t *local_dict = NULL; + uint64_t files = 0; + uint64_t size = 0; + uint64_t lookup = 0; + char msg[1024] = {0,}; + gf_defrag_status_t status_rcd = GF_DEFRAG_STATUS_NOT_STARTED; + int32_t counter = 0; + char *node_name = NULL; + char key[256] = {0,}; + int32_t i = 1; + uint64_t failures = 0; + uint64_t skipped = 0; + double elapsed = 0; + char *size_str = NULL; + char *task_id_str = NULL; + + if (-1 == req->rpc_status) { + goto out; + } + + frame = myframe; + + ret = xdr_to_generic (*iov, &rsp, + (xdrproc_t)xdr_gf_cli_rsp); + if (ret < 0) { + gf_log (frame->this->name, GF_LOG_ERROR, + "Failed to decode xdr response"); + goto out; + } + + if (frame) + local = frame->local; + + if (local) + local_dict = local->dict; + + ret = dict_get_str (local_dict, "volname", &volname); + if (ret) { + gf_log (frame->this->name, GF_LOG_ERROR, + "Failed to get volname"); + goto out; + } + + ret = dict_get_int32 (local_dict, "rebalance-command", (int32_t*)&cmd); + if (ret) { + gf_log (frame->this->name, GF_LOG_ERROR, + "Failed to get command"); + goto out; + } + + if (rsp.dict.dict_len) { + /* Unserialize the dictionary */ + dict = dict_new (); + + ret = dict_unserialize (rsp.dict.dict_val, + rsp.dict.dict_len, + &dict); + if (ret < 0) { + gf_log ("glusterd", GF_LOG_ERROR, + "failed to " + "unserialize req-buffer to dictionary"); + goto out; + } + } + + if (!((cmd == GF_DEFRAG_CMD_STOP) || (cmd == GF_DEFRAG_CMD_STATUS)) && + !(global_state->mode & GLUSTER_MODE_XML)) { + /* All other possibilites are about starting a rebalance */ + ret = dict_get_str (dict, GF_REBALANCE_TID_KEY, &task_id_str); + if (rsp.op_ret && strcmp (rsp.op_errstr, "")) { + snprintf (msg, sizeof (msg), "%s", rsp.op_errstr); + } else { + if (!rsp.op_ret) { + snprintf (msg, sizeof (msg), + "Starting rebalance on volume %s has " + "been successful.\nID: %s", volname, + task_id_str); + } else { + snprintf (msg, sizeof (msg), + "Starting rebalance on volume %s has " + "been unsuccessful.", volname); + } + } + goto done; + } + + if (cmd == GF_DEFRAG_CMD_STOP) { + if (rsp.op_ret == -1) { + if (strcmp (rsp.op_errstr, "")) + snprintf (msg, sizeof (msg), + "%s", rsp.op_errstr); + else + snprintf (msg, sizeof (msg), + "rebalance volume %s stop failed", + volname); + goto done; + } else { + snprintf (msg, sizeof (msg), + "rebalance process may be in the middle of a " + "file migration.\nThe process will be fully " + "stopped once the migration of the file is " + "complete.\nPlease check rebalance process " + "for completion before doing any further " + "brick related tasks on the volume."); + } + } + if (cmd == GF_DEFRAG_CMD_STATUS) { + if (rsp.op_ret == -1) { + if (strcmp (rsp.op_errstr, "")) + snprintf (msg, sizeof (msg), + "%s", rsp.op_errstr); + else + snprintf (msg, sizeof (msg), + "Failed to get the status of " + "rebalance process"); + goto done; + } + } + + if (global_state->mode & GLUSTER_MODE_XML) { + ret = cli_xml_output_vol_rebalance (cmd, dict, rsp.op_ret, + rsp.op_errno, + rsp.op_errstr); + goto out; + } + + ret = dict_get_int32 (dict, "count", &counter); + if (ret) { + gf_log (frame->this->name, GF_LOG_ERROR, "count not set"); + goto out; + } + + cli_out ("%40s %16s %13s %13s %13s %13s %20s %18s", "Node", + "Rebalanced-files", "size", "scanned", "failures", "skipped", + "status", "run time in secs"); + cli_out ("%40s %16s %13s %13s %13s %13s %20s %18s", "---------", + "-----------", "-----------", "-----------", "-----------", + "-----------", "------------", "--------------"); + do { + snprintf (key, 256, "node-name-%d", i); + ret = dict_get_str (dict, key, &node_name); + if (ret) + gf_log (frame->this->name, GF_LOG_TRACE, + "failed to get node-name"); + + memset (key, 0, 256); + snprintf (key, 256, "files-%d", i); + ret = dict_get_uint64 (dict, key, &files); + if (ret) + gf_log (frame->this->name, GF_LOG_TRACE, + "failed to get file count"); + + memset (key, 0, 256); + snprintf (key, 256, "size-%d", i); + ret = dict_get_uint64 (dict, key, &size); + if (ret) + gf_log (frame->this->name, GF_LOG_TRACE, + "failed to get size of xfer"); + + memset (key, 0, 256); + snprintf (key, 256, "lookups-%d", i); + ret = dict_get_uint64 (dict, key, &lookup); + if (ret) + gf_log (frame->this->name, GF_LOG_TRACE, + "failed to get lookedup file count"); + + memset (key, 0, 256); + snprintf (key, 256, "status-%d", i); + ret = dict_get_int32 (dict, key, (int32_t *)&status_rcd); + if (ret) + gf_log (frame->this->name, GF_LOG_TRACE, + "failed to get status"); + + memset (key, 0, 256); + snprintf (key, 256, "failures-%d", i); + ret = dict_get_uint64 (dict, key, &failures); + if (ret) + gf_log (frame->this->name, GF_LOG_TRACE, + "failed to get failures count"); + + memset (key, 0, 256); + snprintf (key, 256, "skipped-%d", i); + ret = dict_get_uint64 (dict, key, &skipped); + if (ret) + gf_log (frame->this->name, GF_LOG_TRACE, + "failed to get skipped count"); + memset (key, 0, 256); + snprintf (key, 256, "run-time-%d", i); + ret = dict_get_double (dict, key, &elapsed); + if (ret) + gf_log (frame->this->name, GF_LOG_TRACE, + "failed to get run-time"); + + status = cli_vol_task_status_str[status_rcd]; + size_str = gf_uint64_2human_readable(size); + cli_out ("%40s %16"PRIu64 " %13s" " %13"PRIu64 " %13"PRIu64 + " %13"PRIu64 " %20s %18.2f", node_name, files, + size_str, lookup, failures, skipped, status, elapsed); + GF_FREE(size_str); + + i++; + } while (i <= counter); + + +done: + if (global_state->mode & GLUSTER_MODE_XML) + cli_xml_output_str ("volRebalance", msg, + rsp.op_ret, rsp.op_errno, + rsp.op_errstr); + else { + if (rsp.op_ret) + cli_err ("volume rebalance: %s: failed: %s", volname, + msg); + else + cli_out ("volume rebalance: %s: success: %s", volname, + msg); + } + ret = rsp.op_ret; + +out: + free (rsp.op_errstr); //malloced by xdr + free (rsp.dict.dict_val); //malloced by xdr + if (dict) + dict_unref (dict); + cli_cmd_broadcast_response (ret); + return ret; +} + +int +gf_cli_rename_volume_cbk (struct rpc_req *req, struct iovec *iov, + int count, void *myframe) +{ + gf_cli_rsp rsp = {0,}; + int ret = -1; + char msg[1024] = {0,}; + + if (-1 == req->rpc_status) { + goto out; + } + + ret = xdr_to_generic (*iov, &rsp, (xdrproc_t)xdr_gf_cli_rsp); + if (ret < 0) { + gf_log (((call_frame_t *) myframe)->this->name, GF_LOG_ERROR, + "Failed to decode xdr response"); + goto out; + } + + + gf_log ("cli", GF_LOG_INFO, "Received resp to probe"); + snprintf (msg, sizeof (msg), "Rename volume %s", + (rsp.op_ret) ? "unsuccessful": "successful"); + + if (global_state->mode & GLUSTER_MODE_XML) { + ret = cli_xml_output_str ("volRename", msg, rsp.op_ret, + rsp.op_errno, rsp.op_errstr); + if (ret) + gf_log ("cli", GF_LOG_ERROR, + "Error outputting to xml"); + goto out; + } + + if (rsp.op_ret) + cli_err ("volume rename: failed"); + else + cli_out ("volume rename: success"); + + ret = rsp.op_ret; + +out: + cli_cmd_broadcast_response (ret); + return ret; +} + +int +gf_cli_reset_volume_cbk (struct rpc_req *req, struct iovec *iov, + int count, void *myframe) +{ + gf_cli_rsp rsp = {0,}; + int ret = -1; + char msg[1024] = {0,}; + + if (-1 == req->rpc_status) { + goto out; + } + + ret = xdr_to_generic (*iov, &rsp, (xdrproc_t)xdr_gf_cli_rsp); + if (ret < 0) { + gf_log (((call_frame_t *) myframe)->this->name, GF_LOG_ERROR, + "Failed to decode xdr response"); + goto out; + } + + gf_log ("cli", GF_LOG_INFO, "Received resp to reset"); + + if (strcmp (rsp.op_errstr, "")) + snprintf (msg, sizeof (msg), "%s", rsp.op_errstr); + else + snprintf (msg, sizeof (msg), "reset volume %s", + (rsp.op_ret) ? "unsuccessful": "successful"); + + if (global_state->mode & GLUSTER_MODE_XML) { + ret = cli_xml_output_str ("volReset", msg, rsp.op_ret, + rsp.op_errno, rsp.op_errstr); + if (ret) + gf_log ("cli", GF_LOG_ERROR, + "Error outputting to xml"); + goto out; + } + + if (rsp.op_ret) + cli_err ("volume reset: failed: %s", msg); + else + cli_out ("volume reset: success: %s", msg); + + ret = rsp.op_ret; + +out: + cli_cmd_broadcast_response (ret); + return ret; +} + +char * +is_server_debug_xlator (void *myframe) +{ + call_frame_t *frame = NULL; + cli_local_t *local = NULL; + char **words = NULL; + char *key = NULL; + char *value = NULL; + char *debug_xlator = NULL; + + frame = myframe; + local = frame->local; + words = (char **)local->words; + + while (*words != NULL) { + if (strstr (*words, "trace") == NULL && + strstr (*words, "error-gen") == NULL) { + words++; + continue; + } + + key = *words; + words++; + value = *words; + if (value == NULL) + break; + if (strstr (value, "client")) { + words++; + continue; + } else { + if (!(strstr (value, "posix") || strstr (value, "acl") + || strstr (value, "locks") || + strstr (value, "io-threads") || + strstr (value, "marker") || + strstr (value, "index"))) { + words++; + continue; + } else { + debug_xlator = gf_strdup (key); + break; + } + } + } + + return debug_xlator; +} + +int +gf_cli_set_volume_cbk (struct rpc_req *req, struct iovec *iov, + int count, void *myframe) +{ + gf_cli_rsp rsp = {0,}; + int ret = -1; + dict_t *dict = NULL; + char *help_str = NULL; + char msg[1024] = {0,}; + char *debug_xlator = _gf_false; + char tmp_str[512] = {0,}; + + if (-1 == req->rpc_status) { + goto out; + } + + ret = xdr_to_generic (*iov, &rsp, (xdrproc_t)xdr_gf_cli_rsp); + if (ret < 0) { + gf_log (((call_frame_t *) myframe)->this->name, GF_LOG_ERROR, + "Failed to decode xdr response"); + goto out; + } + + gf_log ("cli", GF_LOG_INFO, "Received resp to set"); + + dict = dict_new (); + + if (!dict) { + ret = -1; + goto out; + } + + ret = dict_unserialize (rsp.dict.dict_val, rsp.dict.dict_len, &dict); + + /* For brick processes graph change does not happen on the fly. + * The proces has to be restarted. So this is a check from the + * volume set option such that if debug xlators such as trace/errorgen + * are provided in the set command, warn the user. + */ + debug_xlator = is_server_debug_xlator (myframe); + + if (dict_get_str (dict, "help-str", &help_str) && !msg[0]) + snprintf (msg, sizeof (msg), "Set volume %s", + (rsp.op_ret) ? "unsuccessful": "successful"); + if (rsp.op_ret == 0 && debug_xlator) { + snprintf (tmp_str, sizeof (tmp_str), "\n%s translator has been " + "added to the server volume file. Please restart the" + " volume for enabling the translator", debug_xlator); + } + + if ((global_state->mode & GLUSTER_MODE_XML) && (help_str == NULL)) { + ret = cli_xml_output_str ("volSet", msg, rsp.op_ret, + rsp.op_errno, rsp.op_errstr); + if (ret) + gf_log ("cli", GF_LOG_ERROR, + "Error outputting to xml"); + goto out; + } + + if (rsp.op_ret) { + if (strcmp (rsp.op_errstr, "")) + cli_err ("volume set: failed: %s", rsp.op_errstr); + else + cli_err ("volume set: failed"); + } else { + if (help_str == NULL) { + if (debug_xlator == NULL) + cli_out ("volume set: success"); + else + cli_out ("volume set: success%s", tmp_str); + }else { + cli_out ("%s", help_str); + } + } + + ret = rsp.op_ret; + +out: + if (dict) + dict_unref (dict); + GF_FREE (debug_xlator); + cli_cmd_broadcast_response (ret); + return ret; +} + +int +gf_cli_add_brick_cbk (struct rpc_req *req, struct iovec *iov, + int count, void *myframe) +{ + gf_cli_rsp rsp = {0,}; + int ret = -1; + char msg[1024] = {0,}; + + if (-1 == req->rpc_status) { + goto out; + } + + ret = xdr_to_generic (*iov, &rsp, (xdrproc_t)xdr_gf_cli_rsp); + if (ret < 0) { + gf_log (((call_frame_t *) myframe)->this->name, GF_LOG_ERROR, + "Failed to decode xdr response"); + goto out; + } + + + gf_log ("cli", GF_LOG_INFO, "Received resp to add brick"); + + if (rsp.op_ret && strcmp (rsp.op_errstr, "")) + snprintf (msg, sizeof (msg), "%s", rsp.op_errstr); + else + snprintf (msg, sizeof (msg), "Add Brick %s", + (rsp.op_ret) ? "unsuccessful": "successful"); + + if (global_state->mode & GLUSTER_MODE_XML) { + ret = cli_xml_output_str ("volAddBrick", msg, rsp.op_ret, + rsp.op_errno, rsp.op_errstr); + if (ret) + gf_log ("cli", GF_LOG_ERROR, + "Error outputting to xml"); + goto out; + } + + if (rsp.op_ret) + cli_err ("volume add-brick: failed: %s", rsp.op_errstr); + else + cli_out ("volume add-brick: success"); + ret = rsp.op_ret; + +out: + cli_cmd_broadcast_response (ret); + free (rsp.dict.dict_val); + free (rsp.op_errstr); + return ret; +} + +int +gf_cli3_remove_brick_status_cbk (struct rpc_req *req, struct iovec *iov, + int count, void *myframe) +{ + gf_cli_rsp rsp = {0,}; + char *status = "unknown"; + int ret = -1; + uint64_t files = 0; + uint64_t size = 0; + uint64_t lookup = 0; + dict_t *dict = NULL; + char msg[1024] = {0,}; + char key[256] = {0,}; + int32_t i = 1; + int32_t counter = 0; + char *node_name = 0; + gf_defrag_status_t status_rcd = GF_DEFRAG_STATUS_NOT_STARTED; + uint64_t failures = 0; + uint64_t skipped = 0; + double elapsed = 0; + char *size_str = NULL; + int32_t command = 0; + gf1_op_commands cmd = GF_OP_CMD_NONE; + cli_local_t *local = NULL; + call_frame_t *frame = NULL; + char *cmd_str = "unknown"; + + if (-1 == req->rpc_status) { + goto out; + } + + frame = myframe; + + ret = xdr_to_generic (*iov, &rsp, + (xdrproc_t)xdr_gf_cli_rsp); + if (ret < 0) { + gf_log (frame->this->name, GF_LOG_ERROR, + "Failed to decode xdr response"); + goto out; + } + + if (frame) + local = frame->local; + ret = dict_get_int32 (local->dict, "command", &command); + if (ret) + goto out; + cmd = command; + + switch (cmd) { + case GF_OP_CMD_STOP: + cmd_str = "stop"; + break; + case GF_OP_CMD_STATUS: + cmd_str = "status"; + break; + default: + break; + } + + ret = rsp.op_ret; + if (rsp.op_ret == -1) { + if (strcmp (rsp.op_errstr, "")) + snprintf (msg, sizeof (msg), "volume remove-brick %s: " + "failed: %s", cmd_str, rsp.op_errstr); + else + snprintf (msg, sizeof (msg), "volume remove-brick %s: " + "failed", cmd_str); + + if (global_state->mode & GLUSTER_MODE_XML) + goto xml_output; + + cli_err ("%s", msg); + goto out; + } + + if (rsp.dict.dict_len) { + /* Unserialize the dictionary */ + dict = dict_new (); + + ret = dict_unserialize (rsp.dict.dict_val, + rsp.dict.dict_len, + &dict); + if (ret < 0) { + strncpy (msg, "failed to unserialize req-buffer to " + "dictionary", sizeof (msg)); + + if (global_state->mode & GLUSTER_MODE_XML) { + rsp.op_ret = -1; + goto xml_output; + } + + gf_log ("cli", GF_LOG_ERROR, "%s", msg); + goto out; + } + } + +xml_output: + if (global_state->mode & GLUSTER_MODE_XML) { + if (strcmp (rsp.op_errstr, "")) { + ret = cli_xml_output_vol_remove_brick (_gf_true, dict, + rsp.op_ret, + rsp.op_errno, + rsp.op_errstr); + } else { + ret = cli_xml_output_vol_remove_brick (_gf_true, dict, + rsp.op_ret, + rsp.op_errno, + msg); + } + goto out; + } + + ret = dict_get_int32 (dict, "count", &counter); + if (ret) { + gf_log (frame->this->name, GF_LOG_ERROR, "count not set"); + goto out; + } + + + cli_out ("%40s %16s %13s %13s %13s %13s %14s %s", "Node", + "Rebalanced-files", "size", "scanned", "failures", "skipped", + "status", "run-time in secs"); + cli_out ("%40s %16s %13s %13s %13s %13s %14s %16s", "---------", + "-----------", "-----------", "-----------", "-----------", + "-----------","------------", "--------------"); + + do { + snprintf (key, 256, "node-name-%d", i); + ret = dict_get_str (dict, key, &node_name); + if (ret) + gf_log (frame->this->name, GF_LOG_TRACE, + "failed to get node-name"); + + memset (key, 0, 256); + snprintf (key, 256, "files-%d", i); + ret = dict_get_uint64 (dict, key, &files); + if (ret) + gf_log (frame->this->name, GF_LOG_TRACE, + "failed to get file count"); + + memset (key, 0, 256); + snprintf (key, 256, "size-%d", i); + ret = dict_get_uint64 (dict, key, &size); + if (ret) + gf_log (frame->this->name, GF_LOG_TRACE, + "failed to get size of xfer"); + + memset (key, 0, 256); + snprintf (key, 256, "lookups-%d", i); + ret = dict_get_uint64 (dict, key, &lookup); + if (ret) + gf_log (frame->this->name, GF_LOG_TRACE, + "failed to get lookedup file count"); + + memset (key, 0, 256); + snprintf (key, 256, "status-%d", i); + ret = dict_get_int32 (dict, key, (int32_t *)&status_rcd); + if (ret) + gf_log (frame->this->name, GF_LOG_TRACE, + "failed to get status"); + + snprintf (key, 256, "failures-%d", i); + ret = dict_get_uint64 (dict, key, &failures); + if (ret) + gf_log (frame->this->name, GF_LOG_TRACE, + "Failed to get failure on files"); + + snprintf (key, 256, "failures-%d", i); + ret = dict_get_uint64 (dict, key, &skipped); + if (ret) + gf_log (frame->this->name, GF_LOG_TRACE, + "Failed to get skipped files"); + memset (key, 0, 256); + snprintf (key, 256, "run-time-%d", i); + ret = dict_get_double (dict, key, &elapsed); + if (ret) + gf_log (frame->this->name, GF_LOG_TRACE, + "Failed to get run-time"); + + switch (status_rcd) { + case GF_DEFRAG_STATUS_NOT_STARTED: + status = "not started"; + break; + case GF_DEFRAG_STATUS_STARTED: + status = "in progress"; + break; + case GF_DEFRAG_STATUS_STOPPED: + status = "stopped"; + break; + case GF_DEFRAG_STATUS_COMPLETE: + status = "completed"; + break; + case GF_DEFRAG_STATUS_FAILED: + status = "failed"; + break; + default: + break; + } + + size_str = gf_uint64_2human_readable(size); + + if (strcmp (status, "not started")) { + cli_out ("%40s %16"PRIu64 " %13s" " %13"PRIu64 " %13" + PRIu64 " %13"PRIu64 " %14s %16.2f", node_name, + files, size_str, lookup, failures, skipped, + status, elapsed); + } + GF_FREE(size_str); + + i++; + } while (i <= counter); + + if ((cmd == GF_OP_CMD_STOP) && (rsp.op_ret == 0)) { + cli_out ("'remove-brick' process may be in the middle of a " + "file migration.\nThe process will be fully stopped " + "once the migration of the file is complete.\nPlease " + "check remove-brick process for completion before " + "doing any further brick related tasks on the " + "volume."); + } + +out: + free (rsp.dict.dict_val); //malloced by xdr + if (dict) + dict_unref (dict); + cli_cmd_broadcast_response (ret); + return ret; +} + + +int +gf_cli_remove_brick_cbk (struct rpc_req *req, struct iovec *iov, + int count, void *myframe) +{ + gf_cli_rsp rsp = {0,}; + int ret = -1; + char msg[1024] = {0,}; + gf1_op_commands cmd = GF_OP_CMD_NONE; + char *cmd_str = "unknown"; + cli_local_t *local = NULL; + call_frame_t *frame = NULL; + char *task_id_str = NULL; + dict_t *rsp_dict = NULL; + + if (-1 == req->rpc_status) { + goto out; + } + + frame = myframe; + local = frame->local; + + ret = xdr_to_generic (*iov, &rsp, (xdrproc_t)xdr_gf_cli_rsp); + if (ret < 0) { + gf_log (frame->this->name, GF_LOG_ERROR, + "Failed to decode xdr response"); + goto out; + } + + ret = dict_get_int32 (local->dict, "command", (int32_t *)&cmd); + if (ret) { + gf_log ("", GF_LOG_ERROR, "failed to get command"); + goto out; + } + + if (rsp.dict.dict_len) { + rsp_dict = dict_new (); + if (!rsp_dict) { + ret = -1; + goto out; + } + + ret = dict_unserialize (rsp.dict.dict_val, rsp.dict.dict_len, + &rsp_dict); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, + "Failed to unserialize rsp_dict"); + goto out; + } + } + + switch (cmd) { + case GF_OP_CMD_START: + cmd_str = "start"; + + ret = dict_get_str (rsp_dict, GF_REMOVE_BRICK_TID_KEY, &task_id_str); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, + "remove-brick-id is not present in dict"); + } + break; + case GF_OP_CMD_COMMIT: + cmd_str = "commit"; + break; + case GF_OP_CMD_COMMIT_FORCE: + cmd_str = "commit force"; + break; + default: + cmd_str = "unknown"; + break; + } + + gf_log ("cli", GF_LOG_INFO, "Received resp to remove brick"); + + if (rsp.op_ret && strcmp (rsp.op_errstr, "")) + snprintf (msg, sizeof (msg), "%s", rsp.op_errstr); + else + snprintf (msg, sizeof (msg), "Remove Brick %s %s", cmd_str, + (rsp.op_ret) ? "unsuccessful": "successful"); + + if (global_state->mode & GLUSTER_MODE_XML) { + ret = cli_xml_output_vol_remove_brick (_gf_false, rsp_dict, + rsp.op_ret, rsp.op_errno, + msg); + if (ret) + gf_log ("cli", GF_LOG_ERROR, + "Error outputting to xml"); + goto out; + } + + if (rsp.op_ret) { + cli_err ("volume remove-brick %s: failed: %s", cmd_str, + msg); + } else { + cli_out ("volume remove-brick %s: success", cmd_str); + if (GF_OP_CMD_START == cmd && task_id_str != NULL) + cli_out ("ID: %s", task_id_str); + } + + ret = rsp.op_ret; + +out: + cli_cmd_broadcast_response (ret); + free (rsp.dict.dict_val); + free (rsp.op_errstr); + + return ret; +} + + + +int +gf_cli_replace_brick_cbk (struct rpc_req *req, struct iovec *iov, + int count, void *myframe) +{ + gf_cli_rsp rsp = {0,}; + int ret = -1; + cli_local_t *local = NULL; + call_frame_t *frame = NULL; + dict_t *dict = NULL; + char *src_brick = NULL; + char *dst_brick = NULL; + char *status_reply = NULL; + gf1_cli_replace_op replace_op = 0; + char *rb_operation_str = NULL; + dict_t *rsp_dict = NULL; + char msg[1024] = {0,}; + char *task_id_str = NULL; + + if (-1 == req->rpc_status) { + goto out; + } + + frame = (call_frame_t *) myframe; + + ret = xdr_to_generic (*iov, &rsp, (xdrproc_t)xdr_gf_cli_rsp); + if (ret < 0) { + gf_log (frame->this->name, GF_LOG_ERROR, + "Failed to decode xdr response"); + goto out; + } + + local = frame->local; + GF_ASSERT (local); + dict = local->dict; + + ret = dict_get_int32 (dict, "operation", (int32_t *)&replace_op); + if (ret) { + gf_log ("", GF_LOG_DEBUG, + "dict_get on operation failed"); + goto out; + } + + if (rsp.dict.dict_len) { + /* Unserialize the dictionary */ + rsp_dict = dict_new (); + + ret = dict_unserialize (rsp.dict.dict_val, + rsp.dict.dict_len, + &rsp_dict); + if (ret < 0) { + gf_log ("glusterd", GF_LOG_ERROR, + "failed to " + "unserialize rsp buffer to dictionary"); + goto out; + } + } + + switch (replace_op) { + case GF_REPLACE_OP_START: + if (rsp.op_ret) { + rb_operation_str = gf_strdup ("replace-brick failed to" + " start"); + } else { + ret = dict_get_str (rsp_dict, GF_REPLACE_BRICK_TID_KEY, + &task_id_str); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Failed to get " + "\"replace-brick-id\" from dict"); + goto out; + } + ret = gf_asprintf (&rb_operation_str, + "replace-brick started successfully" + "\nID: %s", task_id_str); + if (ret < 0) + goto out; + } + break; + + case GF_REPLACE_OP_STATUS: + + if (rsp.op_ret || ret) { + rb_operation_str = gf_strdup ("replace-brick status " + "unknown"); + } else { + ret = dict_get_str (rsp_dict, "status-reply", + &status_reply); + if (ret) { + gf_log (frame->this->name, GF_LOG_ERROR, "failed to" + "get status"); + goto out; + } + + rb_operation_str = gf_strdup (status_reply); + } + + break; + + case GF_REPLACE_OP_PAUSE: + if (rsp.op_ret) + rb_operation_str = gf_strdup ("replace-brick pause " + "failed"); + else + rb_operation_str = gf_strdup ("replace-brick paused " + "successfully"); + break; + + case GF_REPLACE_OP_ABORT: + if (rsp.op_ret) + rb_operation_str = gf_strdup ("replace-brick abort " + "failed"); + else + rb_operation_str = gf_strdup ("replace-brick aborted " + "successfully"); + break; + + case GF_REPLACE_OP_COMMIT: + case GF_REPLACE_OP_COMMIT_FORCE: + ret = dict_get_str (dict, "src-brick", &src_brick); + if (ret) { + gf_log ("", GF_LOG_DEBUG, + "dict_get on src-brick failed"); + goto out; + } + + ret = dict_get_str (dict, "dst-brick", &dst_brick); + if (ret) { + gf_log ("", GF_LOG_DEBUG, + "dict_get on dst-brick failed"); + goto out; + } + + + if (rsp.op_ret || ret) + rb_operation_str = gf_strdup ("replace-brick commit " + "failed"); + else + rb_operation_str = gf_strdup ("replace-brick commit " + "successful"); + + break; + + default: + gf_log ("", GF_LOG_DEBUG, + "Unknown operation"); + break; + } + + if (rsp.op_ret && (strcmp (rsp.op_errstr, ""))) { + rb_operation_str = gf_strdup (rsp.op_errstr); + } + + gf_log ("cli", GF_LOG_INFO, "Received resp to replace brick"); + snprintf (msg, sizeof (msg), "%s", + rb_operation_str ? rb_operation_str : "Unknown operation"); + + if (global_state->mode & GLUSTER_MODE_XML) { + ret = cli_xml_output_vol_replace_brick (replace_op, rsp_dict, + rsp.op_ret, + rsp.op_errno, msg); + if (ret) + gf_log ("cli", GF_LOG_ERROR, + "Error outputting to xml"); + goto out; + } + + if (rsp.op_ret) + cli_err ("volume replace-brick: failed: %s", msg); + else + cli_out ("volume replace-brick: success: %s", msg); + ret = rsp.op_ret; + +out: + if (frame) + frame->local = NULL; + + if (local) { + dict_unref (local->dict); + cli_local_wipe (local); + } + + if (rb_operation_str) + GF_FREE (rb_operation_str); + + cli_cmd_broadcast_response (ret); + free (rsp.dict.dict_val); + if (rsp_dict) + dict_unref (rsp_dict); + + return ret; +} + + +static int +gf_cli_log_rotate_cbk (struct rpc_req *req, struct iovec *iov, + int count, void *myframe) +{ + gf_cli_rsp rsp = {0,}; + int ret = -1; + char msg[1024] = {0,}; + + if (-1 == req->rpc_status) { + goto out; + } + + ret = xdr_to_generic (*iov, &rsp, (xdrproc_t)xdr_gf_cli_rsp); + if (ret < 0) { + gf_log (((call_frame_t *) myframe)->this->name, GF_LOG_ERROR, + "Failed to decode xdr response"); + goto out; + } + + gf_log ("cli", GF_LOG_DEBUG, "Received resp to log rotate"); + + if (rsp.op_ret && strcmp (rsp.op_errstr, "")) + snprintf (msg, sizeof (msg), "%s", rsp.op_errstr); + else + snprintf (msg, sizeof (msg), "log rotate %s", + (rsp.op_ret) ? "unsuccessful": "successful"); + + if (global_state->mode & GLUSTER_MODE_XML) { + ret = cli_xml_output_str ("volLogRotate", msg, rsp.op_ret, + rsp.op_errno, rsp.op_errstr); + if (ret) + gf_log ("cli", GF_LOG_ERROR, + "Error outputting to xml"); + goto out; + } + + if (rsp.op_ret) + cli_err ("volume log-rotate: failed: %s", msg); + else + cli_out ("volume log-rotate: success"); + ret = rsp.op_ret; + +out: + cli_cmd_broadcast_response (ret); + free (rsp.dict.dict_val); + + return ret; +} + +static int +gf_cli_sync_volume_cbk (struct rpc_req *req, struct iovec *iov, + int count, void *myframe) +{ + gf_cli_rsp rsp = {0,}; + int ret = -1; + char msg[1024] = {0,}; + + if (-1 == req->rpc_status) { + goto out; + } + + ret = xdr_to_generic (*iov, &rsp, (xdrproc_t)xdr_gf_cli_rsp); + if (ret < 0) { + gf_log (((call_frame_t *) myframe)->this->name, GF_LOG_ERROR, + "Failed to decode xdr response"); + goto out; + } + + gf_log ("cli", GF_LOG_DEBUG, "Received resp to sync"); + + if (rsp.op_ret && strcmp (rsp.op_errstr, "")) + snprintf (msg, sizeof (msg), "volume sync: failed: %s", + rsp.op_errstr); + else + snprintf (msg, sizeof (msg), "volume sync: %s", + (rsp.op_ret) ? "failed": "success"); + + if (global_state->mode & GLUSTER_MODE_XML) { + ret = cli_xml_output_str ("volSync", msg, rsp.op_ret, + rsp.op_errno, rsp.op_errstr); + if (ret) + gf_log ("cli", GF_LOG_ERROR, + "Error outputting to xml"); + goto out; + } + + if (rsp.op_ret) + cli_err ("%s", msg); + else + cli_out ("%s", msg); + ret = rsp.op_ret; + +out: + cli_cmd_broadcast_response (ret); + return ret; +} + +int32_t +gf_cli_print_limit_list (char *volname, char *limit_list, + char *op_errstr) +{ + int64_t size = 0; + int64_t limit_value = 0; + int32_t i, j; + int32_t len = 0, ret = -1; + char *size_str = NULL; + char path [PATH_MAX] = {0, }; + char ret_str [1024] = {0, }; + char value [1024] = {0, }; + char mountdir [] = "/tmp/mntXXXXXX"; + char abspath [PATH_MAX] = {0, }; + char *colon_ptr = NULL; + runner_t runner = {0,}; + + GF_VALIDATE_OR_GOTO ("cli", volname, out); + GF_VALIDATE_OR_GOTO ("cli", limit_list, out); + + if (!connected) + goto out; + + len = strlen (limit_list); + if (len == 0) { + cli_err ("%s", op_errstr?op_errstr:"quota limit not set "); + goto out; + } + + if (mkdtemp (mountdir) == NULL) { + gf_log ("cli", GF_LOG_WARNING, "failed to create a temporary " + "mount directory"); + ret = -1; + goto out; + } + + /* Mount a temporary client to fetch the disk usage + * of the directory on which the limit is set. + */ + ret = runcmd (SBIN_DIR"/glusterfs", "-s", + "localhost", "--volfile-id", volname, "-l", + DEFAULT_LOG_FILE_DIRECTORY"/quota-list.log", + mountdir, NULL); + if (ret) { + gf_log ("cli", GF_LOG_WARNING, "failed to mount glusterfs client"); + ret = -1; + goto rm_dir; + } + + len = strlen (limit_list); + if (len == 0) { + cli_err ("quota limit not set "); + goto unmount; + } + + i = 0; + + cli_out ("\tpath\t\t limit_set\t size"); + cli_out ("-----------------------------------------------------------" + "-----------------------"); + while (i < len) { + j = 0; + + while (limit_list [i] != ',' && limit_list [i] != '\0') { + path [j++] = limit_list[i++]; + } + path [j] = '\0'; + //here path[] contains both path and limit value + + colon_ptr = strrchr (path, ':'); + *colon_ptr = '\0'; + strcpy (value, ++colon_ptr); + + snprintf (abspath, sizeof (abspath), "%s/%s", mountdir, path); + + ret = sys_lgetxattr (abspath, "trusted.limit.list", (void *) ret_str, 4096); + if (ret < 0) { + cli_out ("%-20s %10s", path, value); + } else { + sscanf (ret_str, "%"PRId64",%"PRId64, &size, + &limit_value); + size_str = gf_uint64_2human_readable ((uint64_t) size); + if (size_str == NULL) { + cli_out ("%-20s %10s %20"PRId64, path, + value, size); + } else { + cli_out ("%-20s %10s %20s", path, + value, size_str); + GF_FREE (size_str); + } + } + i++; + } + +unmount: + + runinit (&runner); + runner_add_args (&runner, "umount", +#if GF_LINUX_HOST_OS + "-l", +#endif + mountdir, NULL); + ret = runner_run_reuse (&runner); + if (ret) + runner_log (&runner, "cli", GF_LOG_WARNING, "error executing"); + runner_end (&runner); + +rm_dir: + rmdir (mountdir); +out: + return ret; +} + +int +gf_cli_quota_cbk (struct rpc_req *req, struct iovec *iov, + int count, void *myframe) +{ + gf_cli_rsp rsp = {0,}; + int ret = -1; + dict_t *dict = NULL; + char *volname = NULL; + char *limit_list = NULL; + int32_t type = 0; + char msg[1024] = {0,}; + call_frame_t *frame = NULL; + + if (-1 == req->rpc_status) { + goto out; + } + + frame = myframe; + + ret = xdr_to_generic (*iov, &rsp, (xdrproc_t)xdr_gf_cli_rsp); + if (ret < 0) { + gf_log (frame->this->name, GF_LOG_ERROR, + "Failed to decode xdr response"); + goto out; + } + + if (rsp.op_ret && + strcmp (rsp.op_errstr, "") == 0) { + snprintf (msg, sizeof (msg), "command unsuccessful %s", + rsp.op_errstr); + + if (global_state->mode & GLUSTER_MODE_XML) + goto xml_output; + goto out; + } + + if (rsp.dict.dict_len) { + /* Unserialize the dictionary */ + dict = dict_new (); + + ret = dict_unserialize (rsp.dict.dict_val, + rsp.dict.dict_len, + &dict); + if (ret < 0) { + gf_log ("glusterd", GF_LOG_ERROR, + "failed to " + "unserialize req-buffer to dictionary"); + goto out; + } + } + + ret = dict_get_str (dict, "volname", &volname); + if (ret) + gf_log (frame->this->name, GF_LOG_TRACE, + "failed to get volname"); + + ret = dict_get_str (dict, "limit_list", &limit_list); + if (ret) + gf_log (frame->this->name, GF_LOG_TRACE, + "failed to get limit_list"); + + ret = dict_get_int32 (dict, "type", &type); + if (ret) + gf_log (frame->this->name, GF_LOG_TRACE, + "failed to get type"); + + if (type == GF_QUOTA_OPTION_TYPE_LIST) { + if (global_state->mode & GLUSTER_MODE_XML) { + ret = cli_xml_output_vol_quota_limit_list + (volname, limit_list, rsp.op_ret, + rsp.op_errno, rsp.op_errstr); + if (ret) + gf_log ("cli", GF_LOG_ERROR, + "Error outputting to xml"); + goto out; + + } + + if (limit_list) { + gf_cli_print_limit_list (volname, + limit_list, + rsp.op_errstr); + } else { + gf_log ("cli", GF_LOG_INFO, "Received resp to quota " + "command "); + if (rsp.op_errstr) + snprintf (msg, sizeof (msg), "%s", + rsp.op_errstr); + } + } else { + gf_log ("cli", GF_LOG_INFO, "Received resp to quota command "); + if (rsp.op_errstr) + snprintf (msg, sizeof (msg), "%s", rsp.op_errstr); + else + snprintf (msg, sizeof (msg), "successful"); + } + +xml_output: + if (global_state->mode & GLUSTER_MODE_XML) { + ret = cli_xml_output_str ("volQuota", msg, rsp.op_ret, + rsp.op_errno, rsp.op_errstr); + if (ret) + gf_log ("cli", GF_LOG_ERROR, + "Error outputting to xml"); + goto out; + } + + if (strlen (msg) > 0) { + if (rsp.op_ret) + cli_err ("%s", msg); + else + cli_out ("%s", msg); + } + + ret = rsp.op_ret; +out: + cli_cmd_broadcast_response (ret); + if (dict) + dict_unref (dict); + + free (rsp.dict.dict_val); + + return ret; +} + +int +gf_cli_getspec_cbk (struct rpc_req *req, struct iovec *iov, + int count, void *myframe) +{ + gf_getspec_rsp rsp = {0,}; + int ret = -1; + char *spec = NULL; + call_frame_t *frame = NULL; + + if (-1 == req->rpc_status) { + goto out; + } + + frame = myframe; + + ret = xdr_to_generic (*iov, &rsp, (xdrproc_t)xdr_gf_getspec_rsp); + if (ret < 0) { + gf_log (frame->this->name, GF_LOG_ERROR, + "Failed to decode xdr response"); + goto out; + } + + if (rsp.op_ret == -1) { + gf_log (frame->this->name, GF_LOG_ERROR, + "getspec failed"); + goto out; + } + + gf_log ("cli", GF_LOG_INFO, "Received resp to getspec"); + + spec = GF_MALLOC (rsp.op_ret + 1, cli_mt_char); + if (!spec) { + gf_log("", GF_LOG_ERROR, "out of memory"); + goto out; + } + memcpy (spec, rsp.spec, rsp.op_ret); + spec[rsp.op_ret] = '\0'; + cli_out ("%s", spec); + GF_FREE (spec); + + ret = 0; + +out: + cli_cmd_broadcast_response (ret); + return ret; +} + +int +gf_cli_pmap_b2p_cbk (struct rpc_req *req, struct iovec *iov, + int count, void *myframe) +{ + pmap_port_by_brick_rsp rsp = {0,}; + int ret = -1; + char *spec = NULL; + call_frame_t *frame = NULL; + + if (-1 == req->rpc_status) { + goto out; + } + + frame = myframe; + + ret = xdr_to_generic (*iov, &rsp, (xdrproc_t)xdr_pmap_port_by_brick_rsp); + if (ret < 0) { + gf_log (frame->this->name, GF_LOG_ERROR, + "Failed to decode xdr response"); + goto out; + } + + if (rsp.op_ret == -1) { + gf_log (frame->this->name, GF_LOG_ERROR, + "pump_b2p failed"); + goto out; + } + + gf_log ("cli", GF_LOG_INFO, "Received resp to pmap b2p"); + + cli_out ("%d", rsp.port); + GF_FREE (spec); + + ret = rsp.op_ret; + +out: + cli_cmd_broadcast_response (ret); + return ret; +} + + +int32_t +gf_cli_probe (call_frame_t *frame, xlator_t *this, + void *data) +{ + gf_cli_req req = {{0,},}; + int ret = 0; + dict_t *dict = NULL; + int port = 0; + + if (!frame || !this || !data) { + ret = -1; + goto out; + } + + dict = data; + + ret = dict_get_int32 (dict, "port", &port); + if (ret) { + ret = dict_set_int32 (dict, "port", CLI_GLUSTERD_PORT); + if (ret) + goto out; + } + + ret = cli_to_glusterd (&req, frame, gf_cli_probe_cbk, + (xdrproc_t) xdr_gf_cli_req, dict, + GLUSTER_CLI_PROBE, this, cli_rpc_prog, NULL); + +out: + GF_FREE (req.dict.dict_val); + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + + return ret; +} + +int32_t +gf_cli_deprobe (call_frame_t *frame, xlator_t *this, + void *data) +{ + gf_cli_req req = {{0,},}; + int ret = 0; + dict_t *dict = NULL; + int port = 0; + int flags = 0; + + if (!frame || !this || !data) { + ret = -1; + goto out; + } + + dict = data; + ret = dict_get_int32 (dict, "port", &port); + if (ret) { + ret = dict_set_int32 (dict, "port", CLI_GLUSTERD_PORT); + if (ret) + goto out; + } + + ret = dict_get_int32 (dict, "flags", &flags); + if (ret) { + ret = dict_set_int32 (dict, "flags", 0); + if (ret) + goto out; + } + + ret = cli_to_glusterd (&req, frame, gf_cli_deprobe_cbk, + (xdrproc_t)xdr_gf_cli_req, dict, + GLUSTER_CLI_DEPROBE, this, cli_rpc_prog, NULL); + +out: + GF_FREE (req.dict.dict_val); + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + + return ret; +} + +int32_t +gf_cli_list_friends (call_frame_t *frame, xlator_t *this, + void *data) +{ + gf1_cli_peer_list_req req = {0,}; + int ret = 0; + unsigned long flags = 0; + + if (!frame || !this) { + ret = -1; + goto out; + } + + GF_ASSERT (frame->local == NULL); + + flags = (long)data; + req.flags = flags; + frame->local = (void*)flags; + ret = cli_cmd_submit (&req, frame, cli_rpc_prog, + GLUSTER_CLI_LIST_FRIENDS, NULL, + this, gf_cli_list_friends_cbk, + (xdrproc_t) xdr_gf1_cli_peer_list_req); + +out: + if (ret) { + /* + * If everything goes fine, gf_cli_list_friends_cbk() + * [invoked through cli_cmd_submit()]resets the + * frame->local to NULL. In case cli_cmd_submit() + * fails in between, RESET frame->local here. + */ + frame->local = NULL; + } + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int32_t +gf_cli_get_next_volume (call_frame_t *frame, xlator_t *this, + void *data) +{ + + int ret = 0; + cli_cmd_volume_get_ctx_t *ctx = NULL; + cli_local_t *local = NULL; + + if (!frame || !this || !data) { + ret = -1; + goto out; + } + + ctx = data; + local = frame->local; + + if (global_state->mode & GLUSTER_MODE_XML) { + ret = cli_xml_output_vol_info_begin (local, 0, 0, ""); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Error outputting to xml"); + goto out; + } + } + + ret = gf_cli_get_volume (frame, this, data); + + + if (!local || !local->get_vol.volname) { + if ((global_state->mode & GLUSTER_MODE_XML)) + goto end_xml; + + cli_err ("No volumes present"); + goto out; + } + + + ctx->volname = local->get_vol.volname; + + while (ctx->volname) { + ret = gf_cli_get_volume (frame, this, ctx); + if (ret) + goto out; + ctx->volname = local->get_vol.volname; + } + +end_xml: + if (global_state->mode & GLUSTER_MODE_XML) { + ret = cli_xml_output_vol_info_end (local); + if (ret) + gf_log ("cli", GF_LOG_ERROR, "Error outputting to xml"); + } + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int32_t +gf_cli_get_volume (call_frame_t *frame, xlator_t *this, + void *data) +{ + gf_cli_req req = {{0,}}; + int ret = 0; + cli_cmd_volume_get_ctx_t *ctx = NULL; + dict_t *dict = NULL; + int32_t flags = 0; + + if (!frame || !this || !data) { + ret = -1; + goto out; + } + + ctx = data; + + dict = dict_new (); + if (!dict) + goto out; + + if (ctx->volname) { + ret = dict_set_str (dict, "volname", ctx->volname); + if (ret) + goto out; + } + + flags = ctx->flags; + ret = dict_set_int32 (dict, "flags", flags); + if (ret) { + gf_log (frame->this->name, GF_LOG_ERROR, "failed to set flags"); + goto out; + } + + ret = dict_allocate_and_serialize (dict, &req.dict.dict_val, + &req.dict.dict_len); + + ret = cli_cmd_submit (&req, frame, cli_rpc_prog, + GLUSTER_CLI_GET_VOLUME, NULL, + this, gf_cli_get_volume_cbk, + (xdrproc_t) xdr_gf_cli_req); + +out: + if (dict) + dict_unref (dict); + + GF_FREE (req.dict.dict_val); + + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int32_t +gf_cli3_1_uuid_get (call_frame_t *frame, xlator_t *this, + void *data) +{ + gf_cli_req req = {{0,}}; + int ret = 0; + dict_t *dict = NULL; + + if (!frame || !this || !data) { + ret = -1; + goto out; + } + + dict = data; + ret = cli_to_glusterd (&req, frame, gf_cli3_1_uuid_get_cbk, + (xdrproc_t)xdr_gf_cli_req, dict, + GLUSTER_CLI_UUID_GET, this, cli_rpc_prog, + NULL); +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int32_t +gf_cli3_1_uuid_reset (call_frame_t *frame, xlator_t *this, + void *data) +{ + gf_cli_req req = {{0,}}; + int ret = 0; + dict_t *dict = NULL; + + if (!frame || !this || !data) { + ret = -1; + goto out; + } + + dict = data; + ret = cli_to_glusterd (&req, frame, gf_cli3_1_uuid_reset_cbk, + (xdrproc_t)xdr_gf_cli_req, dict, + GLUSTER_CLI_UUID_RESET, this, cli_rpc_prog, + NULL); +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int32_t +gf_cli_create_volume (call_frame_t *frame, xlator_t *this, + void *data) +{ + gf_cli_req req = {{0,}}; + int ret = 0; + dict_t *dict = NULL; + + if (!frame || !this || !data) { + ret = -1; + goto out; + } + + dict = data; + + ret = cli_to_glusterd (&req, frame, gf_cli_create_volume_cbk, + (xdrproc_t) xdr_gf_cli_req, dict, + GLUSTER_CLI_CREATE_VOLUME, this, cli_rpc_prog, + NULL); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + + GF_FREE (req.dict.dict_val); + + return ret; +} + +int32_t +gf_cli_delete_volume (call_frame_t *frame, xlator_t *this, + void *data) +{ + gf_cli_req req = {{0,}}; + int ret = 0; + dict_t *dict = NULL; + + if (!frame || !this || !data) { + ret = -1; + goto out; + } + + dict = data; + + ret = cli_to_glusterd (&req, frame, gf_cli_delete_volume_cbk, + (xdrproc_t) xdr_gf_cli_req, dict, + GLUSTER_CLI_DELETE_VOLUME, this, cli_rpc_prog, + NULL); + +out: + GF_FREE (req.dict.dict_val); + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + + return ret; +} + +int32_t +gf_cli_start_volume (call_frame_t *frame, xlator_t *this, + void *data) +{ + gf_cli_req req = {{0,}}; + int ret = 0; + dict_t *dict = NULL; + + if (!frame || !this || !data) { + ret = -1; + goto out; + } + + dict = data; + + ret = cli_to_glusterd (&req, frame, gf_cli_start_volume_cbk, + (xdrproc_t) xdr_gf_cli_req, dict, + GLUSTER_CLI_START_VOLUME, this, cli_rpc_prog, + NULL); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + + return ret; +} + +int32_t +gf_cli_stop_volume (call_frame_t *frame, xlator_t *this, + void *data) +{ + gf_cli_req req = {{0,}}; + int ret = 0; + dict_t *dict = data; + + if (!frame || !this || !data) { + ret = -1; + goto out; + } + + dict = data; + + ret = cli_to_glusterd (&req, frame, gf_cli_stop_volume_cbk, + (xdrproc_t) xdr_gf_cli_req, dict, + GLUSTER_CLI_STOP_VOLUME, this, cli_rpc_prog, + NULL); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + + return ret; +} + +int32_t +gf_cli_defrag_volume (call_frame_t *frame, xlator_t *this, + void *data) +{ + gf_cli_req req = {{0,}}; + int ret = 0; + dict_t *dict = NULL; + + if (!frame || !this || !data) { + ret = -1; + goto out; + } + + dict = data; + + ret = cli_to_glusterd (&req, frame, gf_cli_defrag_volume_cbk, + (xdrproc_t) xdr_gf_cli_req, dict, + GLUSTER_CLI_DEFRAG_VOLUME, this, cli_rpc_prog, + NULL); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + + return ret; +} + +int32_t +gf_cli_rename_volume (call_frame_t *frame, xlator_t *this, + void *data) +{ + gf_cli_req req = {{0,}}; + int ret = 0; + dict_t *dict = NULL; + + if (!frame || !this || !data) { + ret = -1; + goto out; + } + + dict = data; + + ret = dict_allocate_and_serialize (dict, &req.dict.dict_val, + &req.dict.dict_len); + if (ret < 0) { + gf_log (this->name, GF_LOG_ERROR, + "failed to serialize the data"); + + goto out; + } + + + ret = cli_cmd_submit (&req, frame, cli_rpc_prog, + GLUSTER_CLI_RENAME_VOLUME, NULL, + this, gf_cli_rename_volume_cbk, + (xdrproc_t) xdr_gf_cli_req); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + + return ret; +} + +int32_t +gf_cli_reset_volume (call_frame_t *frame, xlator_t *this, + void *data) +{ + gf_cli_req req = {{0,}}; + int ret = 0; + dict_t *dict = NULL; + + if (!frame || !this || !data) { + ret = -1; + goto out; + } + + dict = data; + + ret = cli_to_glusterd (&req, frame, gf_cli_reset_volume_cbk, + (xdrproc_t) xdr_gf_cli_req, dict, + GLUSTER_CLI_RESET_VOLUME, this, cli_rpc_prog, + NULL); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int32_t +gf_cli_set_volume (call_frame_t *frame, xlator_t *this, + void *data) +{ + gf_cli_req req = {{0,}}; + int ret = 0; + dict_t *dict = NULL; + + if (!frame || !this || !data) { + ret = -1; + goto out; + } + + dict = data; + + ret = cli_to_glusterd (&req, frame, gf_cli_set_volume_cbk, + (xdrproc_t) xdr_gf_cli_req, dict, + GLUSTER_CLI_SET_VOLUME, this, cli_rpc_prog, + NULL); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + + return ret; +} + +int32_t +gf_cli_add_brick (call_frame_t *frame, xlator_t *this, + void *data) +{ + gf_cli_req req = {{0,}}; + int ret = 0; + dict_t *dict = NULL; + char *volname = NULL; + int32_t count = 0; + + if (!frame || !this || !data) { + ret = -1; + goto out; + } + + dict = data; + + ret = dict_get_str (dict, "volname", &volname); + + if (ret) + goto out; + + ret = dict_get_int32 (dict, "count", &count); + if (ret) + goto out; + + ret = cli_to_glusterd (&req, frame, gf_cli_add_brick_cbk, + (xdrproc_t) xdr_gf_cli_req, dict, + GLUSTER_CLI_ADD_BRICK, this, cli_rpc_prog, NULL); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + + GF_FREE (req.dict.dict_val); + + return ret; +} + +int32_t +gf_cli_remove_brick (call_frame_t *frame, xlator_t *this, + void *data) +{ + gf_cli_req req = {{0,}};; + gf_cli_req status_req = {{0,}};; + int ret = 0; + dict_t *dict = NULL; + int32_t command = 0; + char *volname = NULL; + dict_t *req_dict = NULL; + int32_t cmd = 0; + + if (!frame || !this || !data) { + ret = -1; + goto out; + } + + dict = data; + + ret = dict_get_str (dict, "volname", &volname); + if (ret) + goto out; + + ret = dict_get_int32 (dict, "command", &command); + if (ret) + goto out; + + if ((command != GF_OP_CMD_STATUS) && + (command != GF_OP_CMD_STOP)) { + + + ret = cli_to_glusterd (&req, frame, gf_cli_remove_brick_cbk, + (xdrproc_t) xdr_gf_cli_req, dict, + GLUSTER_CLI_REMOVE_BRICK, this, + cli_rpc_prog, NULL); + } else { + /* Need rebalance status to be sent :-) */ + req_dict = dict_new (); + if (!req_dict) { + ret = -1; + goto out; + } + + ret = dict_set_str (req_dict, "volname", volname); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Failed to set dict"); + goto out; + } + + if (command == GF_OP_CMD_STATUS) + cmd |= GF_DEFRAG_CMD_STATUS; + else + cmd |= GF_DEFRAG_CMD_STOP; + + ret = dict_set_int32 (req_dict, "rebalance-command", (int32_t) cmd); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Failed to set dict"); + goto out; + } + + ret = cli_to_glusterd (&status_req, frame, + gf_cli3_remove_brick_status_cbk, + (xdrproc_t) xdr_gf_cli_req, req_dict, + GLUSTER_CLI_DEFRAG_VOLUME, this, + cli_rpc_prog, NULL); + + } + +out: + if (req_dict) + dict_unref (req_dict); + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + + GF_FREE (req.dict.dict_val); + + GF_FREE (status_req.dict.dict_val); + + return ret; +} + +int32_t +gf_cli_replace_brick (call_frame_t *frame, xlator_t *this, + void *data) +{ + gf_cli_req req = {{0,}}; + int ret = 0; + dict_t *dict = NULL; + char *src_brick = NULL; + char *dst_brick = NULL; + char *volname = NULL; + int32_t op = 0; + + if (!frame || !this || !data) { + ret = -1; + goto out; + } + + dict = data; + + ret = dict_get_int32 (dict, "operation", &op); + if (ret) { + gf_log (this->name, GF_LOG_DEBUG, + "dict_get on operation failed"); + goto out; + } + ret = dict_get_str (dict, "volname", &volname); + if (ret) { + gf_log (this->name, GF_LOG_DEBUG, + "dict_get on volname failed"); + goto out; + } + + ret = dict_get_str (dict, "src-brick", &src_brick); + if (ret) { + gf_log (this->name, GF_LOG_DEBUG, + "dict_get on src-brick failed"); + goto out; + } + + ret = dict_get_str (dict, "dst-brick", &dst_brick); + if (ret) { + gf_log (this->name, GF_LOG_DEBUG, + "dict_get on dst-brick failed"); + goto out; + } + + gf_log (this->name, GF_LOG_DEBUG, + "Received command replace-brick %s with " + "%s with operation=%d", src_brick, + dst_brick, op); + + ret = cli_to_glusterd (&req, frame, gf_cli_replace_brick_cbk, + (xdrproc_t) xdr_gf_cli_req, dict, + GLUSTER_CLI_REPLACE_BRICK, this, cli_rpc_prog, + NULL); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + + GF_FREE (req.dict.dict_val); + + return ret; +} + + +int32_t +gf_cli_log_rotate (call_frame_t *frame, xlator_t *this, + void *data) +{ + gf_cli_req req = {{0,}}; + int ret = 0; + dict_t *dict = NULL; + + if (!frame || !this || !data) { + ret = -1; + goto out; + } + + dict = data; + + ret = cli_to_glusterd (&req, frame, gf_cli_log_rotate_cbk, + (xdrproc_t) xdr_gf_cli_req, dict, + GLUSTER_CLI_LOG_ROTATE, this, cli_rpc_prog, + NULL); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + + GF_FREE (req.dict.dict_val); + return ret; +} + +int32_t +gf_cli_sync_volume (call_frame_t *frame, xlator_t *this, + void *data) +{ + int ret = 0; + gf_cli_req req = {{0,}}; + dict_t *dict = NULL; + + if (!frame || !this || !data) { + ret = -1; + goto out; + } + + dict = data; + + ret = cli_to_glusterd (&req, frame, gf_cli_sync_volume_cbk, + (xdrproc_t) xdr_gf_cli_req, dict, + GLUSTER_CLI_SYNC_VOLUME, this, cli_rpc_prog, + NULL); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + GF_FREE (req.dict.dict_val); + + return ret; +} + +int32_t +gf_cli_getspec (call_frame_t *frame, xlator_t *this, + void *data) +{ + gf_getspec_req req = {0,}; + int ret = 0; + dict_t *dict = NULL; + dict_t *op_dict = NULL; + + if (!frame || !this || !data) { + ret = -1; + goto out; + } + + dict = data; + + ret = dict_get_str (dict, "volid", &req.key); + if (ret) + goto out; + + op_dict = dict_new (); + if (!dict) { + ret = -1; + goto out; + } + + // Set the supported min and max op-versions, so glusterd can make a + // decision + ret = dict_set_int32 (op_dict, "min-op-version", GD_OP_VERSION_MIN); + if (ret) { + gf_log (THIS->name, GF_LOG_ERROR, "Failed to set min-op-version" + " in request dict"); + goto out; + } + + ret = dict_set_int32 (op_dict, "max-op-version", GD_OP_VERSION_MAX); + if (ret) { + gf_log (THIS->name, GF_LOG_ERROR, "Failed to set max-op-version" + " in request dict"); + goto out; + } + + ret = dict_allocate_and_serialize (op_dict, &req.xdata.xdata_val, + &req.xdata.xdata_len); + if (ret < 0) { + gf_log (THIS->name, GF_LOG_ERROR, + "Failed to serialize dictionary"); + goto out; + } + + ret = cli_cmd_submit (&req, frame, &cli_handshake_prog, + GF_HNDSK_GETSPEC, NULL, + this, gf_cli_getspec_cbk, + (xdrproc_t) xdr_gf_getspec_req); + +out: + if (op_dict) { + dict_unref(op_dict); + } + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + + return ret; +} + +int32_t +gf_cli_quota (call_frame_t *frame, xlator_t *this, + void *data) +{ + gf_cli_req req = {{0,}}; + int ret = 0; + dict_t *dict = NULL; + + if (!frame || !this || !data) { + ret = -1; + goto out; + } + + dict = data; + + ret = cli_to_glusterd (&req, frame, gf_cli_quota_cbk, + (xdrproc_t) xdr_gf_cli_req, dict, + GLUSTER_CLI_QUOTA, this, cli_rpc_prog, NULL); + +out: + GF_FREE (req.dict.dict_val); + + return ret; +} + +int32_t +gf_cli_pmap_b2p (call_frame_t *frame, xlator_t *this, void *data) +{ + pmap_port_by_brick_req req = {0,}; + int ret = 0; + dict_t *dict = NULL; + + if (!frame || !this || !data) { + ret = -1; + goto out; + } + + dict = data; + + ret = dict_get_str (dict, "brick", &req.brick); + if (ret) + goto out; + + ret = cli_cmd_submit (&req, frame, &cli_pmap_prog, + GF_PMAP_PORTBYBRICK, NULL, + this, gf_cli_pmap_b2p_cbk, + (xdrproc_t) xdr_pmap_port_by_brick_req); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + + return ret; +} + +static int +gf_cli_fsm_log_cbk (struct rpc_req *req, struct iovec *iov, + int count, void *myframe) +{ + gf1_cli_fsm_log_rsp rsp = {0,}; + int ret = -1; + dict_t *dict = NULL; + int tr_count = 0; + char key[256] = {0}; + int i = 0; + char *old_state = NULL; + char *new_state = NULL; + char *event = NULL; + char *time = NULL; + + if (-1 == req->rpc_status) { + goto out; + } + + ret = xdr_to_generic (*iov, &rsp, (xdrproc_t)xdr_gf1_cli_fsm_log_rsp); + if (ret < 0) { + gf_log (((call_frame_t *) myframe)->this->name, GF_LOG_ERROR, + "Failed to decode xdr response"); + goto out; + } + + if (rsp.op_ret) { + if (strcmp (rsp.op_errstr, "")) + cli_err ("%s", rsp.op_errstr); + cli_err ("fsm log unsuccessful"); + ret = rsp.op_ret; + goto out; + } + + dict = dict_new (); + if (!dict) { + ret = -1; + goto out; + } + + ret = dict_unserialize (rsp.fsm_log.fsm_log_val, + rsp.fsm_log.fsm_log_len, + &dict); + + if (ret) { + cli_err ("bad response"); + goto out; + } + + ret = dict_get_int32 (dict, "count", &tr_count); + if (tr_count) + cli_out("number of transitions: %d", tr_count); + else + cli_err("No transitions"); + for (i = 0; i < tr_count; i++) { + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "log%d-old-state", i); + ret = dict_get_str (dict, key, &old_state); + if (ret) + goto out; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "log%d-event", i); + ret = dict_get_str (dict, key, &event); + if (ret) + goto out; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "log%d-new-state", i); + ret = dict_get_str (dict, key, &new_state); + if (ret) + goto out; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "log%d-time", i); + ret = dict_get_str (dict, key, &time); + if (ret) + goto out; + cli_out ("Old State: [%s]\n" + "New State: [%s]\n" + "Event : [%s]\n" + "timestamp: [%s]\n", old_state, new_state, event, time); + } + + ret = rsp.op_ret; + +out: + cli_cmd_broadcast_response (ret); + return ret; +} + +int32_t +gf_cli_fsm_log (call_frame_t *frame, xlator_t *this, void *data) +{ + int ret = -1; + gf1_cli_fsm_log_req req = {0,}; + + GF_ASSERT (frame); + GF_ASSERT (this); + GF_ASSERT (data); + + if (!frame || !this || !data) + goto out; + req.name = data; + ret = cli_cmd_submit (&req, frame, cli_rpc_prog, + GLUSTER_CLI_FSM_LOG, NULL, + this, gf_cli_fsm_log_cbk, + (xdrproc_t) xdr_gf1_cli_fsm_log_req); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + + return ret; +} + +int +gf_cli_gsync_config_command (dict_t *dict) +{ + runner_t runner = {0,}; + char *subop = NULL; + char *gwd = NULL; + char *slave = NULL; + char *confpath = NULL; + char *master = NULL; + char *op_name = NULL; + int ret = -1; + char conf_path[PATH_MAX] = ""; + + if (dict_get_str (dict, "subop", &subop) != 0) + return -1; + + if (strcmp (subop, "get") != 0 && strcmp (subop, "get-all") != 0) { + cli_out (GEOREP" config updated successfully"); + return 0; + } + + if (dict_get_str (dict, "glusterd_workdir", &gwd) != 0 || + dict_get_str (dict, "slave", &slave) != 0) + return -1; + + if (dict_get_str (dict, "master", &master) != 0) + master = NULL; + if (dict_get_str (dict, "op_name", &op_name) != 0) + op_name = NULL; + + ret = dict_get_str (dict, "conf_path", &confpath); + if (!confpath) { + ret = snprintf (conf_path, sizeof(conf_path) - 1, + "%s/"GEOREP"/gsyncd_template.conf", gwd); + conf_path[ret] = '\0'; + confpath = conf_path; + } + + runinit (&runner); + runner_add_args (&runner, GSYNCD_PREFIX"/gsyncd", "-c", NULL); + runner_argprintf (&runner, "%s", confpath); + if (master) + runner_argprintf (&runner, ":%s", master); + runner_add_arg (&runner, slave); + runner_argprintf (&runner, "--config-%s", subop); + if (op_name) + runner_add_arg (&runner, op_name); + + return runner_run (&runner); +} + +int +gf_cli_fetch_gsyncd_status_values (char *status, + gf_cli_gsync_status_t *sts_val) +{ + int32_t ret = -1; + char *tmp = NULL; + char *save_ptr = NULL; + char *key = NULL; + char *value = NULL; + + if (!status || !sts_val) { + gf_log ("", GF_LOG_ERROR, "status or sts_val is null"); + goto out; + } + + tmp = strtok_r (status, "\n", &save_ptr); + + if (tmp) + sts_val->health = gf_strdup (tmp); + + while (tmp) { + key = strtok_r (tmp, "=", &value); + + if ((key) && (!strcmp(key, "Uptime"))) + sts_val->uptime = gf_strdup (value); + + if ((key) && (!strcmp(key, "FilesSyncd"))) + sts_val->files_syncd = gf_strdup (value); + + if ((key) && (!strcmp(key, "FilesPending"))) + sts_val->files_pending = gf_strdup (value); + + if ((key) && (!strcmp(key, "BytesPending"))) { + value = gf_uint64_2human_readable(atol(value)); + sts_val->bytes_pending = gf_strdup (value); + } + + if ((key) && (!strcmp(key, "DeletesPending"))) + sts_val->deletes_pending = gf_strdup (value); + + tmp = strtok_r (NULL, ";", &save_ptr); + } + + if (sts_val->health) + ret = 0; + + if (!sts_val->uptime) + sts_val->uptime = gf_strdup ("N/A"); + + if (!sts_val->files_syncd) + sts_val->files_syncd = gf_strdup ("N/A"); + + if (!sts_val->files_pending) + sts_val->files_pending = gf_strdup ("N/A"); + + if (!sts_val->bytes_pending) + sts_val->bytes_pending = gf_strdup ("N/A"); + + if (!sts_val->deletes_pending) + sts_val->deletes_pending = gf_strdup ("N/A"); + +out: + gf_log ("", GF_LOG_DEBUG, "Returning %d.", ret); + return ret; +} + +char* +get_struct_variable (int mem_num, gf_cli_gsync_status_t *sts_val) +{ + switch (mem_num) { + case 0: return (sts_val->node); + case 1: return (sts_val->master); + case 2: return (sts_val->slave); + case 3: return (sts_val->health); + case 4: return (sts_val->uptime); + case 5: return (sts_val->files_syncd); + case 6: return (sts_val->files_pending); + case 7: return (sts_val->bytes_pending); + case 8: return (sts_val->deletes_pending); + default: + goto out; + } + +out: + return NULL; +} + +int +gf_cli_print_status (char **title_values, + gf_cli_gsync_status_t **sts_vals, + int *spacing, int gsync_count, + int number_of_fields, int is_detail) +{ + int indents = 0; + int i = 0; + int j = 0; + int ret = 0; + int total_spacing = 0; + char **output_values = NULL; + char *tmp = NULL; + char *hyphens = NULL; + char heading[PATH_MAX] = {0, }; + char indent_spaces[PATH_MAX] = {0, }; + + /* calculating spacing for hyphens */ + for (i = 0; i < number_of_fields; i++) { + /* Suppressing master and slave output for status detail */ + if ((is_detail) && ((i == 1) || (i == 2))) { + total_spacing++; + continue; + } else if ((!is_detail) && (i > 4)) { + /* Suppressing detailed output for + * status */ + continue; + } + spacing[i] += 3; /* Adding extra space to + distinguish between fields */ + total_spacing += spacing[i]; + } + total_spacing += 4; /* For the spacing between the fields */ + + /* char pointers for each field */ + output_values = GF_CALLOC (number_of_fields, sizeof (char *), + gf_common_mt_char); + if (!output_values) { + ret = -1; + goto out; + } + for (i = 0; i < number_of_fields; i++) { + output_values[i] = GF_CALLOC (spacing[i] + 1, sizeof (char), + gf_common_mt_char); + if (!output_values[i]) { + ret = -1; + goto out; + } + } + + hyphens = GF_CALLOC (total_spacing + 1, sizeof (char), + gf_common_mt_char); + if (!hyphens) { + ret = -1; + goto out; + } + + ret = snprintf(heading, sizeof(heading), "MASTER: %s SLAVE: %s", + sts_vals[0]->master, sts_vals[0]->slave); + if (ret) { + if (ret < sizeof(heading)) + heading[ret] = '\0'; + else + heading[sizeof(heading) - 1] = '\0'; + ret = 0; + } else { + ret = -1; + goto out; + } + + if (is_detail) { + cli_out (" "); + if (strlen(heading) > total_spacing) + cli_out ("%s", heading); + else { + /* Printing the heading with centre justification */ + indents = (total_spacing - strlen(heading)) / 2; + memset (indent_spaces, ' ', indents); + indent_spaces[indents] = '\0'; + ret = snprintf (hyphens, total_spacing, "%s%s", + indent_spaces, heading); + if (ret) { + hyphens[ret] = '\0'; + cli_out ("%s", hyphens); + ret = 0; + } else { + ret = -1; + goto out; + } + } + cli_out (" "); + } + + /* setting the title "NODE", "MASTER", etc. from title_values[] + and printing the same */ + for (j = 0; j < number_of_fields; j++) { + /* Suppressing master and slave output for status detail */ + if ((is_detail) && ((j == 1) || (j == 2))) { + output_values[j][0] = '\0'; + continue; + } else if ((!is_detail) && (j > 4)) { + /* Suppressing detailed output for + * status */ + output_values[j][0] = '\0'; + continue; + } + memset (output_values[j], ' ', spacing[j]); + memcpy (output_values[j], title_values[j], + strlen(title_values[j])); + output_values[j][spacing[j]] = '\0'; + } + cli_out ("%s %s %s %s %s %s %s %s %s", output_values[0], + output_values[1], output_values[2], output_values[3], + output_values[4], output_values[5], output_values[6], + output_values[7], output_values[8]); + + /* setting and printing the hyphens */ + memset (hyphens, '-', total_spacing); + hyphens[total_spacing] = '\0'; + cli_out ("%s", hyphens); + + for (i = 0; i < gsync_count; i++) { + for (j = 0; j < number_of_fields; j++) { + /* Suppressing master and slave output for + * status detail */ + if ((is_detail) && ((j == 1) || (j == 2))) { + output_values[j][0] = '\0'; + continue; + } else if ((!is_detail) && (j > 4)) { + /* Suppressing detailed output for + * status */ + output_values[j][0] = '\0'; + continue; + } + tmp = get_struct_variable(j, sts_vals[i]); + if (!tmp) { + gf_log ("", GF_LOG_ERROR, + "struct member empty."); + ret = -1; + goto out; + } + memset (output_values[j], ' ', spacing[j]); + memcpy (output_values[j], tmp, strlen (tmp)); + output_values[j][spacing[j]] = '\0'; + } + + cli_out ("%s %s %s %s %s %s %s %s %s", output_values[0], + output_values[1], output_values[2], output_values[3], + output_values[4], output_values[5], output_values[6], + output_values[7], output_values[8]); + } + +out: + if (output_values) { + for (i = 0; i < number_of_fields; i++) { + if (output_values[i]) + GF_FREE (output_values[i]); + } + GF_FREE (output_values); + } + + if (hyphens) + GF_FREE (hyphens); + + return ret; +} + +int +gf_cli_read_status_data (dict_t *dict, + gf_cli_gsync_status_t **sts_vals, + int *spacing, int gsync_count, + int number_of_fields) +{ + int ret = 0; + int i = 0; + int j = 0; + char mst[PATH_MAX] = {0, }; + char slv[PATH_MAX] = {0, }; + char sts[PATH_MAX] = {0, }; + char nds[PATH_MAX] = {0, }; + char *status = NULL; + char *tmp = NULL; + + /* Storing per node status info in each object */ + for (i = 0; i < gsync_count; i++) { + snprintf (nds, sizeof(nds), "node%d", i + 1); + snprintf (mst, sizeof(mst), "master%d", i + 1); + snprintf (slv, sizeof(slv), "slave%d", i + 1); + snprintf (sts, sizeof(sts), "status%d", i + 1); + + /* Fetching the values from dict, and calculating + the max length for each field */ + ret = dict_get_str (dict, nds, &(sts_vals[i]->node)); + if (ret) + goto out; + + ret = dict_get_str (dict, mst, &(sts_vals[i]->master)); + if (ret) + goto out; + + ret = dict_get_str (dict, slv, &(sts_vals[i]->slave)); + if (ret) + goto out; + + ret = dict_get_str (dict, sts, &status); + if (ret) + goto out; + + /* Fetching health and uptime from sts_val */ + ret = gf_cli_fetch_gsyncd_status_values (status, sts_vals[i]); + if (ret) + goto out; + + for (j = 0; j < number_of_fields; j++) { + tmp = get_struct_variable(j, sts_vals[i]); + if (!tmp) { + gf_log ("", GF_LOG_ERROR, + "struct member empty."); + ret = -1; + goto out; + } + if (strlen (tmp) > spacing[j]) + spacing[j] = strlen (tmp); + } + } + +out: + return ret; +} + +int +gf_cli_gsync_status_output (dict_t *dict, int status_detail) +{ + int gsync_count = 0; + int i = 0; + int j = 0; + int ret = 0; + int spacing[10] = {0}; + int num_of_fields = 9; + char errmsg[1024] = ""; + char *master = NULL; + char *slave = NULL; + char *tmp = NULL; + char *title_values[] = {"NODE", "MASTER", "SLAVE", + "HEALTH", "UPTIME", + "FILES SYNCD", + "FILES PENDING", + "BYTES PENDING", + "DELETES PENDING"}; + gf_cli_gsync_status_t **sts_vals = NULL; + + /* Checks if any session is active or not */ + ret = dict_get_int32 (dict, "gsync-count", &gsync_count); + if (ret) { + ret = dict_get_str (dict, "master", &master); + + ret = dict_get_str (dict, "slave", &slave); + + if (master) { + if (slave) + snprintf (errmsg, sizeof(errmsg), "No active " + "geo-replication sessions between %s" + " and %s", master, slave); + else + snprintf (errmsg, sizeof(errmsg), "No active " + "geo-replication sessions for %s", + master); + } else + snprintf (errmsg, sizeof(errmsg), "No active " + "geo-replication sessions"); + + gf_log ("cli", GF_LOG_INFO, "%s", errmsg); + cli_out ("%s", errmsg); + ret = 0; + goto out; + } + + for (i = 0; i < num_of_fields; i++) + spacing[i] = strlen(title_values[i]); + + /* gsync_count = number of nodes reporting output. + each sts_val object will store output of each + node */ + sts_vals = GF_CALLOC (gsync_count, sizeof (gf_cli_gsync_status_t *), + gf_common_mt_char); + if (!sts_vals) { + ret = -1; + goto out; + } + for (i = 0; i < gsync_count; i++) { + sts_vals[i] = GF_CALLOC (1, sizeof (gf_cli_gsync_status_t), + gf_common_mt_char); + if (!sts_vals[i]) { + ret = -1; + goto out; + } + } + + ret = gf_cli_read_status_data (dict, sts_vals, spacing, + gsync_count, num_of_fields); + if (ret) { + gf_log ("", GF_LOG_ERROR, "Unable to read status data"); + goto out; + } + + ret = gf_cli_print_status (title_values, sts_vals, spacing, gsync_count, + num_of_fields, status_detail); + if (ret) { + gf_log ("", GF_LOG_ERROR, "Unable to print status output"); + goto out; + } + +out: + if (sts_vals) { + for (i = 0; i < gsync_count; i++) { + for (j = 3; j < num_of_fields; j++) { + tmp = get_struct_variable(j, sts_vals[i]); + if (tmp) + GF_FREE (tmp); + } + } + GF_FREE (sts_vals); + } + + return ret; +} + +static int32_t +write_contents_to_common_pem_file (dict_t *dict, int output_count) +{ + char *workdir = NULL; + char common_pem_file[PATH_MAX] = ""; + char *output = NULL; + char output_name[PATH_MAX] = ""; + int bytes_writen = 0; + int fd = -1; + int ret = -1; + int i = -1; + + ret = dict_get_str (dict, "glusterd_workdir", &workdir); + if (ret || !workdir) { + gf_log ("", GF_LOG_ERROR, "Unable to fetch workdir"); + ret = -1; + goto out; + } + + snprintf (common_pem_file, sizeof(common_pem_file), + "%s/geo-replication/common_secret.pem.pub", + workdir); + + unlink (common_pem_file); + + fd = open (common_pem_file, O_WRONLY | O_CREAT, 0600); + if (fd == -1) { + gf_log ("", GF_LOG_ERROR, "Failed to open %s" + " Error : %s", common_pem_file, + strerror (errno)); + ret = -1; + goto out; + } + + for (i = 1; i <= output_count; i++) { + memset (output_name, '\0', sizeof (output_name)); + snprintf (output_name, sizeof (output_name), + "output_%d", i); + ret = dict_get_str (dict, output_name, &output); + if (ret) { + gf_log ("", GF_LOG_ERROR, "Failed to get %s.", + output_name); + cli_out ("Unable to fetch output."); + } + if (output) { + bytes_writen = write (fd, output, strlen(output)); + if (bytes_writen != strlen(output)) { + gf_log ("", GF_LOG_ERROR, "Failed to write " + "to %s", common_pem_file); + ret = -1; + goto out; + } + /* Adding the new line character */ + bytes_writen = write (fd, "\n", strlen("\n")); + if (bytes_writen != strlen("\n")) { + gf_log ("", GF_LOG_ERROR, + "Failed to add new line char"); + ret = -1; + goto out; + } + output = NULL; + } + } + + cli_out ("Common secret pub file present at %s", common_pem_file); + ret = 0; +out: + if (fd) + close (fd); + + gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int +gf_cli_sys_exec_cbk (struct rpc_req *req, struct iovec *iov, + int count, void *myframe) +{ + int ret = -1; + int output_count = -1; + int i = -1; + char *output = NULL; + char *command = NULL; + char output_name[PATH_MAX] = ""; + gf_cli_rsp rsp = {0, }; + dict_t *dict = NULL; + call_frame_t *frame = NULL; + + if (req->rpc_status == -1) { + ret = -1; + goto out; + } + + frame = myframe; + + ret = xdr_to_generic (*iov, &rsp, (xdrproc_t)xdr_gf_cli_rsp); + if (ret < 0) { + gf_log (frame->this->name, GF_LOG_ERROR, + "Failed to decode xdr response"); + goto out; + } + + dict = dict_new (); + + if (!dict) { + ret = -1; + goto out; + } + + ret = dict_unserialize (rsp.dict.dict_val, rsp.dict.dict_len, &dict); + + if (ret) + goto out; + + if (rsp.op_ret) { + cli_err ("%s", rsp.op_errstr ? rsp.op_errstr : + "Command failed."); + ret = rsp.op_ret; + goto out; + } + + ret = dict_get_int32 (dict, "output_count", &output_count); + if (ret) { + cli_out ("Command executed successfully."); + ret = 0; + goto out; + } + + ret = dict_get_str (dict, "command", &command); + if (ret) { + gf_log ("", GF_LOG_ERROR, + "Unable to get command from dict"); + goto out; + } + + if (!strcmp (command, "gsec_create")) { + ret = write_contents_to_common_pem_file (dict, output_count); + if (!ret) + goto out; + } + + for (i = 1; i <= output_count; i++) { + memset (output_name, '\0', sizeof (output_name)); + snprintf (output_name, sizeof (output_name), + "output_%d", i); + ret = dict_get_str (dict, output_name, &output); + if (ret) { + gf_log ("", GF_LOG_ERROR, "Failed to get %s.", + output_name); + cli_out ("Unable to fetch output."); + } + if (output) { + cli_out ("%s", output); + output = NULL; + } + } + + ret = 0; +out: + if (dict) + dict_unref (dict); + cli_cmd_broadcast_response (ret); + + free (rsp.dict.dict_val); + + return ret; +} + +int +gf_cli_copy_file_cbk (struct rpc_req *req, struct iovec *iov, + int count, void *myframe) +{ + int ret = -1; + gf_cli_rsp rsp = {0, }; + dict_t *dict = NULL; + call_frame_t *frame = NULL; + + if (req->rpc_status == -1) { + ret = -1; + goto out; + } + + frame = myframe; + + ret = xdr_to_generic (*iov, &rsp, (xdrproc_t)xdr_gf_cli_rsp); + if (ret < 0) { + gf_log (frame->this->name, GF_LOG_ERROR, + "Failed to decode xdr response"); + goto out; + } + + dict = dict_new (); + + if (!dict) { + ret = -1; + goto out; + } + + ret = dict_unserialize (rsp.dict.dict_val, rsp.dict.dict_len, &dict); + + if (ret) + goto out; + + if (rsp.op_ret) { + cli_err ("%s", rsp.op_errstr ? rsp.op_errstr : + "Copy unsuccessful"); + ret = rsp.op_ret; + goto out; + } + + cli_out ("Successfully copied file."); + +out: + if (dict) + dict_unref (dict); + cli_cmd_broadcast_response (ret); + + free (rsp.dict.dict_val); + + return ret; +} + +int +gf_cli_gsync_set_cbk (struct rpc_req *req, struct iovec *iov, + int count, void *myframe) +{ + int ret = -1; + gf_cli_rsp rsp = {0, }; + dict_t *dict = NULL; + char *gsync_status = NULL; + char *master = NULL; + char *slave = NULL; + int32_t type = 0; + call_frame_t *frame = NULL; + gf_boolean_t status_detail = _gf_false; + + + if (req->rpc_status == -1) { + ret = -1; + goto out; + } + + frame = myframe; + + ret = xdr_to_generic (*iov, &rsp, (xdrproc_t)xdr_gf_cli_rsp); + if (ret < 0) { + gf_log (frame->this->name, GF_LOG_ERROR, + "Failed to decode xdr response"); + goto out; + } + + dict = dict_new (); + + if (!dict) { + ret = -1; + goto out; + } + + ret = dict_unserialize (rsp.dict.dict_val, rsp.dict.dict_len, &dict); + + if (ret) + goto out; + + if (global_state->mode & GLUSTER_MODE_XML) { + ret = cli_xml_output_vol_gsync (dict, rsp.op_ret, rsp.op_errno, + rsp.op_errstr); + if (ret) + gf_log ("cli", GF_LOG_ERROR, + "Error outputting to xml"); + goto out; + } + + if (rsp.op_ret) { + cli_err ("%s", rsp.op_errstr ? rsp.op_errstr : + GEOREP" command unsuccessful"); + ret = rsp.op_ret; + goto out; + } + + ret = dict_get_str (dict, "gsync-status", &gsync_status); + if (!ret) + cli_out ("%s", gsync_status); + else + ret = 0; + + ret = dict_get_int32 (dict, "type", &type); + if (ret) { + gf_log (frame->this->name, GF_LOG_ERROR, "failed to get type"); + goto out; + } + + switch (type) { + case GF_GSYNC_OPTION_TYPE_START: + case GF_GSYNC_OPTION_TYPE_STOP: + if (dict_get_str (dict, "master", &master) != 0) + master = "???"; + if (dict_get_str (dict, "slave", &slave) != 0) + slave = "???"; + + cli_out ("%s " GEOREP " session between %s & %s" + " has been successful", + type == GF_GSYNC_OPTION_TYPE_START ? + "Starting" : "Stopping", + master, slave); + break; + + case GF_GSYNC_OPTION_TYPE_CONFIG: + ret = gf_cli_gsync_config_command (dict); + break; + + case GF_GSYNC_OPTION_TYPE_STATUS: + status_detail = dict_get_str_boolean (dict, + "status-detail", + _gf_false); + ret = gf_cli_gsync_status_output (dict, status_detail); + break; + + case GF_GSYNC_OPTION_TYPE_DELETE: + if (dict_get_str (dict, "master", &master) != 0) + master = "???"; + if (dict_get_str (dict, "slave", &slave) != 0) + slave = "???"; + cli_out ("Deleting " GEOREP " session between %s & %s" + " has been successful", master, slave); + break; + + case GF_GSYNC_OPTION_TYPE_CREATE: + if (dict_get_str (dict, "master", &master) != 0) + master = "???"; + if (dict_get_str (dict, "slave", &slave) != 0) + slave = "???"; + cli_out ("Creating " GEOREP " session between %s & %s" + " has been successful", master, slave); + break; + + default: + cli_out (GEOREP" command executed successfully"); + } + +out: + if (dict) + dict_unref (dict); + cli_cmd_broadcast_response (ret); + + free (rsp.dict.dict_val); + + return ret; +} + +int32_t +gf_cli_sys_exec (call_frame_t *frame, xlator_t *this, void *data) +{ + int ret = 0; + dict_t *dict = NULL; + gf_cli_req req = {{0,}}; + + if (!frame || !this || !data) { + ret = -1; + gf_log ("cli", GF_LOG_ERROR, "Invalid data"); + goto out; + } + + dict = data; + + ret = cli_to_glusterd (&req, frame, gf_cli_sys_exec_cbk, + (xdrproc_t) xdr_gf_cli_req, dict, + GLUSTER_CLI_SYS_EXEC, this, cli_rpc_prog, + NULL); +out: + GF_FREE (req.dict.dict_val); + return ret; +} + +int32_t +gf_cli_copy_file (call_frame_t *frame, xlator_t *this, void *data) +{ + int ret = 0; + dict_t *dict = NULL; + gf_cli_req req = {{0,}}; + + if (!frame || !this || !data) { + ret = -1; + gf_log ("cli", GF_LOG_ERROR, "Invalid data"); + goto out; + } + + dict = data; + + ret = cli_to_glusterd (&req, frame, gf_cli_copy_file_cbk, + (xdrproc_t) xdr_gf_cli_req, dict, + GLUSTER_CLI_COPY_FILE, this, cli_rpc_prog, + NULL); +out: + GF_FREE (req.dict.dict_val); + return ret; +} + +int32_t +gf_cli_gsync_set (call_frame_t *frame, xlator_t *this, + void *data) +{ + int ret = 0; + dict_t *dict = NULL; + gf_cli_req req = {{0,}}; + + if (!frame || !this || !data) { + ret = -1; + goto out; + } + + dict = data; + + ret = cli_to_glusterd (&req, frame, gf_cli_gsync_set_cbk, + (xdrproc_t) xdr_gf_cli_req, dict, + GLUSTER_CLI_GSYNC_SET, this, cli_rpc_prog, + NULL); + +out: + GF_FREE (req.dict.dict_val); + + return ret; +} + + +int +cli_profile_info_percentage_cmp (void *a, void *b) +{ + cli_profile_info_t *ia = NULL; + cli_profile_info_t *ib = NULL; + int ret = 0; + + ia = a; + ib = b; + if (ia->percentage_avg_latency < ib->percentage_avg_latency) + ret = -1; + else if (ia->percentage_avg_latency > ib->percentage_avg_latency) + ret = 1; + else + ret = 0; + return ret; +} + + +void +cmd_profile_volume_brick_out (dict_t *dict, int count, int interval) +{ + char key[256] = {0}; + int i = 0; + uint64_t sec = 0; + uint64_t r_count = 0; + uint64_t w_count = 0; + uint64_t rb_counts[32] = {0}; + uint64_t wb_counts[32] = {0}; + cli_profile_info_t profile_info[GF_FOP_MAXVALUE] = {{0}}; + char output[128] = {0}; + int per_line = 0; + char read_blocks[128] = {0}; + char write_blocks[128] = {0}; + int index = 0; + int is_header_printed = 0; + int ret = 0; + double total_percentage_latency = 0; + + for (i = 0; i < 32; i++) { + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%d-%d-read-%d", count, + interval, (1 << i)); + ret = dict_get_uint64 (dict, key, &rb_counts[i]); + } + + for (i = 0; i < 32; i++) { + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%d-%d-write-%d", count, interval, + (1<<i)); + ret = dict_get_uint64 (dict, key, &wb_counts[i]); + } + + for (i = 0; i < GF_FOP_MAXVALUE; i++) { + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%d-%d-%d-hits", count, + interval, i); + ret = dict_get_uint64 (dict, key, &profile_info[i].fop_hits); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%d-%d-%d-avglatency", count, + interval, i); + ret = dict_get_double (dict, key, &profile_info[i].avg_latency); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%d-%d-%d-minlatency", count, + interval, i); + ret = dict_get_double (dict, key, &profile_info[i].min_latency); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%d-%d-%d-maxlatency", count, + interval, i); + ret = dict_get_double (dict, key, &profile_info[i].max_latency); + profile_info[i].fop_name = (char *)gf_fop_list[i]; + + total_percentage_latency += + (profile_info[i].fop_hits * profile_info[i].avg_latency); + } + if (total_percentage_latency) { + for (i = 0; i < GF_FOP_MAXVALUE; i++) { + profile_info[i].percentage_avg_latency = 100 * ( + (profile_info[i].avg_latency* profile_info[i].fop_hits) / + total_percentage_latency); + } + gf_array_insertionsort (profile_info, 1, GF_FOP_MAXVALUE - 1, + sizeof (cli_profile_info_t), + cli_profile_info_percentage_cmp); + } + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%d-%d-duration", count, interval); + ret = dict_get_uint64 (dict, key, &sec); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%d-%d-total-read", count, interval); + ret = dict_get_uint64 (dict, key, &r_count); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%d-%d-total-write", count, interval); + ret = dict_get_uint64 (dict, key, &w_count); + + if (ret == 0) { + } + + if (interval == -1) + cli_out ("Cumulative Stats:"); + else + cli_out ("Interval %d Stats:", interval); + snprintf (output, sizeof (output), "%14s", "Block Size:"); + snprintf (read_blocks, sizeof (read_blocks), "%14s", "No. of Reads:"); + snprintf (write_blocks, sizeof (write_blocks), "%14s", "No. of Writes:"); + index = 14; + for (i = 0; i < 32; i++) { + if ((rb_counts[i] == 0) && (wb_counts[i] == 0)) + continue; + per_line++; + snprintf (output+index, sizeof (output)-index, "%19db+ ", (1<<i)); + if (rb_counts[i]) { + snprintf (read_blocks+index, sizeof (read_blocks)-index, + "%21"PRId64" ", rb_counts[i]); + } else { + snprintf (read_blocks+index, sizeof (read_blocks)-index, + "%21s ", "0"); + } + if (wb_counts[i]) { + snprintf (write_blocks+index, sizeof (write_blocks)-index, + "%21"PRId64" ", wb_counts[i]); + } else { + snprintf (write_blocks+index, sizeof (write_blocks)-index, + "%21s ", "0"); + } + index += 22; + if (per_line == 3) { + cli_out ("%s", output); + cli_out ("%s", read_blocks); + cli_out ("%s", write_blocks); + cli_out (" "); + per_line = 0; + memset (output, 0, sizeof (output)); + memset (read_blocks, 0, sizeof (read_blocks)); + memset (write_blocks, 0, sizeof (write_blocks)); + snprintf (output, sizeof (output), "%14s", "Block Size:"); + snprintf (read_blocks, sizeof (read_blocks), "%14s", + "No. of Reads:"); + snprintf (write_blocks, sizeof (write_blocks), "%14s", + "No. of Writes:"); + index = 14; + } + } + + if (per_line != 0) { + cli_out ("%s", output); + cli_out ("%s", read_blocks); + cli_out ("%s", write_blocks); + } + for (i = 0; i < GF_FOP_MAXVALUE; i++) { + if (profile_info[i].fop_hits == 0) + continue; + if (is_header_printed == 0) { + cli_out ("%10s %13s %13s %13s %14s %11s", "%-latency", + "Avg-latency", "Min-Latency", "Max-Latency", + "No. of calls", "Fop"); + cli_out ("%10s %13s %13s %13s %14s %11s", "---------", + "-----------", "-----------", "-----------", + "------------", "----"); + is_header_printed = 1; + } + if (profile_info[i].fop_hits) { + cli_out ("%10.2lf %10.2lf us %10.2lf us %10.2lf us" + " %14"PRId64" %11s", + profile_info[i].percentage_avg_latency, + profile_info[i].avg_latency, + profile_info[i].min_latency, + profile_info[i].max_latency, + profile_info[i].fop_hits, + profile_info[i].fop_name); + } + } + cli_out (" "); + cli_out ("%12s: %"PRId64" seconds", "Duration", sec); + cli_out ("%12s: %"PRId64" bytes", "Data Read", r_count); + cli_out ("%12s: %"PRId64" bytes", "Data Written", w_count); + cli_out (" "); +} + +int32_t +gf_cli_profile_volume_cbk (struct rpc_req *req, struct iovec *iov, + int count, void *myframe) +{ + gf_cli_rsp rsp = {0,}; + int ret = -1; + dict_t *dict = NULL; + gf1_cli_stats_op op = GF_CLI_STATS_NONE; + char key[256] = {0}; + int interval = 0; + int i = 1; + int32_t brick_count = 0; + char *volname = NULL; + char *brick = NULL; + char str[1024] = {0,}; + + if (-1 == req->rpc_status) { + goto out; + } + + gf_log ("cli", GF_LOG_DEBUG, "Received resp to profile"); + ret = xdr_to_generic (*iov, &rsp, (xdrproc_t)xdr_gf_cli_rsp); + if (ret < 0) { + gf_log (((call_frame_t *) myframe)->this->name, GF_LOG_ERROR, + "Failed to decode xdr response"); + goto out; + } + + dict = dict_new (); + + if (!dict) { + ret = -1; + goto out; + } + + ret = dict_unserialize (rsp.dict.dict_val, + rsp.dict.dict_len, + &dict); + + if (ret) { + gf_log ("", GF_LOG_ERROR, + "Unable to allocate memory"); + goto out; + } else { + dict->extra_stdfree = rsp.dict.dict_val; + } + + if (global_state->mode & GLUSTER_MODE_XML) { + ret = cli_xml_output_vol_profile (dict, rsp.op_ret, + rsp.op_errno, + rsp.op_errstr); + if (ret) + gf_log ("cli", GF_LOG_ERROR, + "Error outputting to xml"); + goto out; + } + + ret = dict_get_str (dict, "volname", &volname); + if (ret) + goto out; + + ret = dict_get_int32 (dict, "op", (int32_t*)&op); + if (ret) + goto out; + + if (rsp.op_ret && strcmp (rsp.op_errstr, "")) { + cli_err ("%s", rsp.op_errstr); + } else { + switch (op) { + case GF_CLI_STATS_START: + cli_out ("Starting volume profile on %s has been %s ", + volname, + (rsp.op_ret) ? "unsuccessful": "successful"); + break; + case GF_CLI_STATS_STOP: + cli_out ("Stopping volume profile on %s has been %s ", + volname, + (rsp.op_ret) ? "unsuccessful": "successful"); + break; + case GF_CLI_STATS_INFO: + break; + default: + cli_out ("volume profile on %s has been %s ", + volname, + (rsp.op_ret) ? "unsuccessful": "successful"); + break; + } + } + + if (rsp.op_ret) { + ret = rsp.op_ret; + goto out; + } + + if (op != GF_CLI_STATS_INFO) { + ret = 0; + goto out; + } + + ret = dict_get_int32 (dict, "count", &brick_count); + if (ret) + goto out; + + if (!brick_count) { + cli_err ("All bricks of volume %s are down.", volname); + goto out; + } + + while (i <= brick_count) { + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%d-brick", i); + ret = dict_get_str (dict, key, &brick); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Couldn't get brick name"); + goto out; + } + + ret = dict_get_str_boolean (dict, "nfs", _gf_false); + if (ret) + snprintf (str, sizeof (str), "NFS Server : %s", brick); + else + snprintf (str, sizeof (str), "Brick: %s", brick); + cli_out ("%s", str); + memset (str, '-', strlen (str)); + cli_out ("%s", str); + + snprintf (key, sizeof (key), "%d-cumulative", i); + ret = dict_get_int32 (dict, key, &interval); + if (ret == 0) { + cmd_profile_volume_brick_out (dict, i, interval); + } + snprintf (key, sizeof (key), "%d-interval", i); + ret = dict_get_int32 (dict, key, &interval); + if (ret == 0) { + cmd_profile_volume_brick_out (dict, i, interval); + } + i++; + } + ret = rsp.op_ret; + +out: + if (dict) + dict_unref (dict); + free (rsp.op_errstr); + cli_cmd_broadcast_response (ret); + return ret; +} + +int32_t +gf_cli_profile_volume (call_frame_t *frame, xlator_t *this, void *data) +{ + int ret = -1; + gf_cli_req req = {{0,}}; + dict_t *dict = NULL; + + GF_ASSERT (frame); + GF_ASSERT (this); + GF_ASSERT (data); + + if (!frame || !this || !data) + goto out; + dict = data; + + ret = cli_to_glusterd (&req, frame, gf_cli_profile_volume_cbk, + (xdrproc_t) xdr_gf_cli_req, dict, + GLUSTER_CLI_PROFILE_VOLUME, this, cli_rpc_prog, + NULL); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + + GF_FREE (req.dict.dict_val); + return ret; +} + +int32_t +gf_cli_top_volume_cbk (struct rpc_req *req, struct iovec *iov, + int count, void *myframe) +{ + gf_cli_rsp rsp = {0,}; + int ret = -1; + dict_t *dict = NULL; + gf1_cli_stats_op op = GF_CLI_STATS_NONE; + char key[256] = {0}; + int i = 0; + int32_t brick_count = 0; + char brick[1024]; + int32_t members = 0; + char *filename; + char *bricks; + uint64_t value = 0; + int32_t j = 0; + gf1_cli_top_op top_op = GF_CLI_TOP_NONE; + uint64_t nr_open = 0; + uint64_t max_nr_open = 0; + double throughput = 0; + double time = 0; + int32_t time_sec = 0; + long int time_usec = 0; + char timestr[256] = {0, }; + char *openfd_str = NULL; + gf_boolean_t nfs = _gf_false; + gf_boolean_t clear_stats = _gf_false; + int stats_cleared = 0; + + if (-1 == req->rpc_status) { + goto out; + } + + gf_log ("cli", GF_LOG_DEBUG, "Received resp to top"); + ret = xdr_to_generic (*iov, &rsp, (xdrproc_t)xdr_gf_cli_rsp); + if (ret < 0) { + gf_log (((call_frame_t *) myframe)->this->name, GF_LOG_ERROR, + "Failed to decode xdr response"); + goto out; + } + + if (rsp.op_ret) { + if (strcmp (rsp.op_errstr, "")) + cli_err ("%s", rsp.op_errstr); + cli_err ("volume top unsuccessful"); + ret = rsp.op_ret; + goto out; + } + + dict = dict_new (); + + if (!dict) { + ret = -1; + goto out; + } + + ret = dict_unserialize (rsp.dict.dict_val, + rsp.dict.dict_len, + &dict); + + if (ret) { + gf_log ("", GF_LOG_ERROR, + "Unable to allocate memory"); + goto out; + } + + ret = dict_get_int32 (dict, "op", (int32_t*)&op); + + if (op != GF_CLI_STATS_TOP) { + ret = 0; + goto out; + } + + if (global_state->mode & GLUSTER_MODE_XML) { + ret = cli_xml_output_vol_top (dict, rsp.op_ret, + rsp.op_errno, + rsp.op_errstr); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, + "Error outputting to xml"); + } + goto out; + } + + ret = dict_get_int32 (dict, "count", &brick_count); + if (ret) + goto out; + snprintf (key, sizeof (key), "%d-top-op", 1); + ret = dict_get_int32 (dict, key, (int32_t*)&top_op); + if (ret) + goto out; + + clear_stats = dict_get_str_boolean (dict, "clear-stats", _gf_false); + + while (i < brick_count) { + i++; + snprintf (brick, sizeof (brick), "%d-brick", i); + ret = dict_get_str (dict, brick, &bricks); + if (ret) + goto out; + + nfs = dict_get_str_boolean (dict, "nfs", _gf_false); + + if (clear_stats) { + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%d-stats-cleared", i); + ret = dict_get_int32 (dict, key, &stats_cleared); + if (ret) + goto out; + cli_out (stats_cleared ? "Cleared stats for %s %s" : + "Failed to clear stats for %s %s", + nfs ? "NFS server on" : "brick", bricks); + continue; + } + + if (nfs) + cli_out ("NFS Server : %s", bricks); + else + cli_out ("Brick: %s", bricks); + + snprintf(key, sizeof (key), "%d-members", i); + ret = dict_get_int32 (dict, key, &members); + + switch (top_op) { + case GF_CLI_TOP_OPEN: + snprintf (key, sizeof (key), "%d-current-open", i); + ret = dict_get_uint64 (dict, key, &nr_open); + if (ret) + break; + snprintf (key, sizeof (key), "%d-max-open", i); + ret = dict_get_uint64 (dict, key, &max_nr_open); + if (ret) + goto out; + snprintf (key, sizeof (key), "%d-max-openfd-time", i); + ret = dict_get_str (dict, key, &openfd_str); + if (ret) + goto out; + cli_out ("Current open fds: %"PRIu64", Max open" + " fds: %"PRIu64", Max openfd time: %s", nr_open, + max_nr_open, openfd_str); + case GF_CLI_TOP_READ: + case GF_CLI_TOP_WRITE: + case GF_CLI_TOP_OPENDIR: + case GF_CLI_TOP_READDIR: + if (!members) { + continue; + } + cli_out ("Count\t\tfilename\n======================="); + break; + case GF_CLI_TOP_READ_PERF: + case GF_CLI_TOP_WRITE_PERF: + snprintf (key, sizeof (key), "%d-throughput", i); + ret = dict_get_double (dict, key, &throughput); + if (!ret) { + snprintf (key, sizeof (key), "%d-time", i); + ret = dict_get_double (dict, key, &time); + } + if (!ret) + cli_out ("Throughput %.2f MBps time %.4f secs", throughput, + time / 1e6); + + if (!members) { + continue; + } + cli_out ("%*s %-*s %-*s", + VOL_TOP_PERF_SPEED_WIDTH, "MBps", + VOL_TOP_PERF_FILENAME_DEF_WIDTH, "Filename", + VOL_TOP_PERF_TIME_WIDTH, "Time"); + cli_out ("%*s %-*s %-*s", + VOL_TOP_PERF_SPEED_WIDTH, "====", + VOL_TOP_PERF_FILENAME_DEF_WIDTH, "========", + VOL_TOP_PERF_TIME_WIDTH, "===="); + break; + default: + goto out; + } + + for (j = 1; j <= members; j++) { + snprintf (key, sizeof (key), "%d-filename-%d", i, j); + ret = dict_get_str (dict, key, &filename); + if (ret) + break; + snprintf (key, sizeof (key), "%d-value-%d", i, j); + ret = dict_get_uint64 (dict, key, &value); + if (ret) + goto out; + if ( top_op == GF_CLI_TOP_READ_PERF || + top_op == GF_CLI_TOP_WRITE_PERF) { + snprintf (key, sizeof (key), "%d-time-sec-%d", i, j); + ret = dict_get_int32 (dict, key, (int32_t *)&time_sec); + if (ret) + goto out; + snprintf (key, sizeof (key), "%d-time-usec-%d", i, j); + ret = dict_get_int32 (dict, key, (int32_t *)&time_usec); + if (ret) + goto out; + gf_time_fmt (timestr, sizeof timestr, + time_sec, gf_timefmt_FT); + snprintf (timestr + strlen (timestr), sizeof timestr - strlen (timestr), + ".%"GF_PRI_SUSECONDS, time_usec); + if (strlen (filename) < VOL_TOP_PERF_FILENAME_DEF_WIDTH) + cli_out ("%*"PRIu64" %-*s %-*s", + VOL_TOP_PERF_SPEED_WIDTH, + value, + VOL_TOP_PERF_FILENAME_DEF_WIDTH, + filename, + VOL_TOP_PERF_TIME_WIDTH, + timestr); + else + cli_out ("%*"PRIu64" ...%-*s %-*s", + VOL_TOP_PERF_SPEED_WIDTH, + value, + VOL_TOP_PERF_FILENAME_ALT_WIDTH , + filename + strlen (filename) - + VOL_TOP_PERF_FILENAME_ALT_WIDTH, + VOL_TOP_PERF_TIME_WIDTH, + timestr); + } else { + cli_out ("%"PRIu64"\t\t%s", value, filename); + } + } + } + ret = rsp.op_ret; + +out: + cli_cmd_broadcast_response (ret); + + if (dict) + dict_unref (dict); + + free (rsp.dict.dict_val); + return ret; +} + +int32_t +gf_cli_top_volume (call_frame_t *frame, xlator_t *this, void *data) +{ + int ret = -1; + gf_cli_req req = {{0,}}; + dict_t *dict = NULL; + + GF_ASSERT (frame); + GF_ASSERT (this); + GF_ASSERT (data); + + if (!frame || !this || !data) + goto out; + dict = data; + + ret = cli_to_glusterd (&req, frame, gf_cli_top_volume_cbk, + (xdrproc_t) xdr_gf_cli_req, dict, + GLUSTER_CLI_PROFILE_VOLUME, this, cli_rpc_prog, + NULL); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + GF_FREE (req.dict.dict_val); + return ret; +} + + +int +gf_cli_getwd_cbk (struct rpc_req *req, struct iovec *iov, + int count, void *myframe) +{ + gf1_cli_getwd_rsp rsp = {0,}; + int ret = -1; + + if (-1 == req->rpc_status) { + goto out; + } + + ret = xdr_to_generic (*iov, &rsp, (xdrproc_t)xdr_gf1_cli_getwd_rsp); + if (ret < 0) { + gf_log (((call_frame_t *) myframe)->this->name, GF_LOG_ERROR, + "Failed to decode xdr response"); + goto out; + } + + if (rsp.op_ret == -1) { + cli_err ("getwd failed"); + ret = rsp.op_ret; + goto out; + } + + gf_log ("cli", GF_LOG_INFO, "Received resp to getwd"); + + cli_out ("%s", rsp.wd); + + ret = 0; + +out: + cli_cmd_broadcast_response (ret); + return ret; +} + +int32_t +gf_cli_getwd (call_frame_t *frame, xlator_t *this, void *data) +{ + int ret = -1; + gf1_cli_getwd_req req = {0,}; + + GF_ASSERT (frame); + GF_ASSERT (this); + + if (!frame || !this) + goto out; + + ret = cli_cmd_submit (&req, frame, cli_rpc_prog, + GLUSTER_CLI_GETWD, NULL, + this, gf_cli_getwd_cbk, + (xdrproc_t) xdr_gf1_cli_getwd_req); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + + return ret; +} + +void +cli_print_volume_status_mempool (dict_t *dict, char *prefix) +{ + int ret = -1; + int32_t mempool_count = 0; + char *name = NULL; + int32_t hotcount = 0; + int32_t coldcount = 0; + uint64_t paddedsizeof = 0; + uint64_t alloccount = 0; + int32_t maxalloc = 0; + uint64_t pool_misses = 0; + int32_t maxstdalloc = 0; + char key[1024] = {0,}; + int i = 0; + + GF_ASSERT (dict); + GF_ASSERT (prefix); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.mempool-count",prefix); + ret = dict_get_int32 (dict, key, &mempool_count); + if (ret) + goto out; + + cli_out ("Mempool Stats\n-------------"); + cli_out ("%-30s %9s %9s %12s %10s %8s %8s %12s", "Name", "HotCount", + "ColdCount", "PaddedSizeof", "AllocCount", "MaxAlloc", + "Misses", "Max-StdAlloc"); + cli_out ("%-30s %9s %9s %12s %10s %8s %8s %12s", "----", "--------", + "---------", "------------", "----------", + "--------", "--------", "------------"); + + for (i = 0; i < mempool_count; i++) { + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.pool%d.name", prefix, i); + ret = dict_get_str (dict, key, &name); + if (ret) + goto out; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.pool%d.hotcount", prefix, i); + ret = dict_get_int32 (dict, key, &hotcount); + if (ret) + goto out; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.pool%d.coldcount", prefix, i); + ret = dict_get_int32 (dict, key, &coldcount); + if (ret) + goto out; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.pool%d.paddedsizeof", + prefix, i); + ret = dict_get_uint64 (dict, key, &paddedsizeof); + if (ret) + goto out; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.pool%d.alloccount", prefix, i); + ret = dict_get_uint64 (dict, key, &alloccount); + if (ret) + goto out; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.pool%d.max_alloc", prefix, i); + ret = dict_get_int32 (dict, key, &maxalloc); + if (ret) + goto out; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.pool%d.max-stdalloc", prefix, i); + ret = dict_get_int32 (dict, key, &maxstdalloc); + if (ret) + goto out; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.pool%d.pool-misses", prefix, i); + ret = dict_get_uint64 (dict, key, &pool_misses); + if (ret) + goto out; + + cli_out ("%-30s %9d %9d %12"PRIu64" %10"PRIu64" %8d %8"PRIu64 + " %12d", name, hotcount, coldcount, paddedsizeof, + alloccount, maxalloc, pool_misses, maxstdalloc); + } + +out: + return; + +} + +void +cli_print_volume_status_mem (dict_t *dict, gf_boolean_t notbrick) +{ + int ret = -1; + char *volname = NULL; + char *hostname = NULL; + char *path = NULL; + int online = -1; + char key[1024] = {0,}; + int brick_index_max = -1; + int other_count = 0; + int index_max = 0; + int val = 0; + int i = 0; + + GF_ASSERT (dict); + + ret = dict_get_str (dict, "volname", &volname); + if (ret) + goto out; + cli_out ("Memory status for volume : %s", volname); + + ret = dict_get_int32 (dict, "brick-index-max", &brick_index_max); + if (ret) + goto out; + ret = dict_get_int32 (dict, "other-count", &other_count); + if (ret) + goto out; + + index_max = brick_index_max + other_count; + + for (i = 0; i <= index_max; i++) { + cli_out ("----------------------------------------------"); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.hostname", i); + ret = dict_get_str (dict, key, &hostname); + if (ret) + continue; + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.path", i); + ret = dict_get_str (dict, key, &path); + if (ret) + continue; + if (notbrick) + cli_out ("%s : %s", hostname, path); + else + cli_out ("Brick : %s:%s", hostname, path); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.status", i); + ret = dict_get_int32 (dict, key, &online); + if (ret) + goto out; + if (!online) { + if (notbrick) + cli_out ("%s is offline", hostname); + else + cli_out ("Brick is offline"); + continue; + } + + cli_out ("Mallinfo\n--------"); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.mallinfo.arena", i); + ret = dict_get_int32 (dict, key, &val); + if (ret) + goto out; + cli_out ("%-8s : %d","Arena", val); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.mallinfo.ordblks", i); + ret = dict_get_int32 (dict, key, &val); + if(ret) + goto out; + cli_out ("%-8s : %d","Ordblks", val); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.mallinfo.smblks", i); + ret = dict_get_int32 (dict, key, &val); + if(ret) + goto out; + cli_out ("%-8s : %d","Smblks", val); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.mallinfo.hblks", i); + ret = dict_get_int32 (dict, key, &val); + if(ret) + goto out; + cli_out ("%-8s : %d", "Hblks", val); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.mallinfo.hblkhd", i); + ret = dict_get_int32 (dict, key, &val); + if (ret) + goto out; + cli_out ("%-8s : %d", "Hblkhd", val); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.mallinfo.usmblks", i); + ret = dict_get_int32 (dict, key, &val); + if (ret) + goto out; + cli_out ("%-8s : %d", "Usmblks", val); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.mallinfo.fsmblks", i); + ret = dict_get_int32 (dict, key, &val); + if (ret) + goto out; + cli_out ("%-8s : %d", "Fsmblks", val); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.mallinfo.uordblks", i); + ret = dict_get_int32 (dict, key, &val); + if (ret) + goto out; + cli_out ("%-8s : %d", "Uordblks", val); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.mallinfo.fordblks", i); + ret = dict_get_int32 (dict, key, &val); + if (ret) + goto out; + cli_out ("%-8s : %d", "Fordblks", val); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.mallinfo.keepcost", i); + ret = dict_get_int32 (dict, key, &val); + if (ret) + goto out; + cli_out ("%-8s : %d", "Keepcost", val); + + cli_out (" "); + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d", i); + cli_print_volume_status_mempool (dict, key); + } +out: + cli_out ("----------------------------------------------\n"); + return; +} + +void +cli_print_volume_status_clients (dict_t *dict, gf_boolean_t notbrick) +{ + int ret = -1; + char *volname = NULL; + int brick_index_max = -1; + int other_count = 0; + int index_max = 0; + char *hostname = NULL; + char *path = NULL; + int online = -1; + int client_count = 0; + char *clientname = NULL; + uint64_t bytesread = 0; + uint64_t byteswrite = 0; + char key[1024] = {0,}; + int i = 0; + int j = 0; + + GF_ASSERT (dict); + + ret = dict_get_str (dict, "volname", &volname); + if (ret) + goto out; + cli_out ("Client connections for volume %s", volname); + + ret = dict_get_int32 (dict, "brick-index-max", &brick_index_max); + if (ret) + goto out; + ret = dict_get_int32 (dict, "other-count", &other_count); + if (ret) + goto out; + + index_max = brick_index_max + other_count; + + for (i = 0; i <= index_max; i++) { + cli_out ("----------------------------------------------"); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.hostname", i); + ret = dict_get_str (dict, key, &hostname); + if (ret) + goto out; + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.path", i); + ret = dict_get_str (dict, key, &path); + if (ret) + goto out; + + if (notbrick) + cli_out ("%s : %s", hostname, path); + else + cli_out ("Brick : %s:%s", hostname, path); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.status", i); + ret = dict_get_int32 (dict, key, &online); + if (ret) + goto out; + if (!online) { + if (notbrick) + cli_out ("%s is offline", hostname); + else + cli_out ("Brick is offline"); + continue; + } + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.clientcount", i); + ret = dict_get_int32 (dict, key, &client_count); + if (ret) + goto out; + + cli_out ("Clients connected : %d", client_count); + if (client_count == 0) + continue; + + cli_out ("%-48s %15s %15s", "Hostname", "BytesRead", + "BytesWritten"); + cli_out ("%-48s %15s %15s", "--------", "---------", + "------------"); + for (j =0; j < client_count; j++) { + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), + "brick%d.client%d.hostname", i, j); + ret = dict_get_str (dict, key, &clientname); + if (ret) + goto out; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), + "brick%d.client%d.bytesread", i, j); + ret = dict_get_uint64 (dict, key, &bytesread); + if (ret) + goto out; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), + "brick%d.client%d.byteswrite", i, j); + ret = dict_get_uint64 (dict, key, &byteswrite); + if (ret) + goto out; + + cli_out ("%-48s %15"PRIu64" %15"PRIu64, + clientname, bytesread, byteswrite); + } + } +out: + cli_out ("----------------------------------------------\n"); + return; +} + +void +cli_print_volume_status_inode_entry (dict_t *dict, char *prefix) +{ + int ret = -1; + char key[1024] = {0,}; + char *gfid = NULL; + uint64_t nlookup = 0; + uint32_t ref = 0; + int ia_type = 0; + char inode_type; + + GF_ASSERT (dict); + GF_ASSERT (prefix); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.gfid", prefix); + ret = dict_get_str (dict, key, &gfid); + if (ret) + goto out; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.nlookup", prefix); + ret = dict_get_uint64 (dict, key, &nlookup); + if (ret) + goto out; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.ref", prefix); + ret = dict_get_uint32 (dict, key, &ref); + if (ret) + goto out; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.ia_type", prefix); + ret = dict_get_int32 (dict, key, &ia_type); + if (ret) + goto out; + + switch (ia_type) { + case IA_IFREG: + inode_type = 'R'; + break; + case IA_IFDIR: + inode_type = 'D'; + break; + case IA_IFLNK: + inode_type = 'L'; + break; + case IA_IFBLK: + inode_type = 'B'; + break; + case IA_IFCHR: + inode_type = 'C'; + break; + case IA_IFIFO: + inode_type = 'F'; + break; + case IA_IFSOCK: + inode_type = 'S'; + break; + default: + inode_type = 'I'; + break; + } + + cli_out ("%-40s %14"PRIu64" %14"PRIu32" %9c", + gfid, nlookup, ref, inode_type); + +out: + return; + +} + +void +cli_print_volume_status_itables (dict_t *dict, char *prefix) +{ + int ret = -1; + char key[1024] = {0,}; + uint32_t active_size = 0; + uint32_t lru_size = 0; + uint32_t purge_size = 0; + int i =0; + + GF_ASSERT (dict); + GF_ASSERT (prefix); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.active_size", prefix); + ret = dict_get_uint32 (dict, key, &active_size); + if (ret) + goto out; + if (active_size != 0) { + cli_out ("Active inodes:"); + cli_out ("%-40s %14s %14s %9s", "GFID", "Lookups", "Ref", + "IA type"); + cli_out ("%-40s %14s %14s %9s", "----", "-------", "---", + "-------"); + } + for (i = 0; i < active_size; i++) { + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.active%d", prefix, i); + cli_print_volume_status_inode_entry (dict, key); + } + cli_out (" "); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.lru_size", prefix); + ret = dict_get_uint32 (dict, key, &lru_size); + if (ret) + goto out; + if (lru_size != 0) { + cli_out ("LRU inodes:"); + cli_out ("%-40s %14s %14s %9s", "GFID", "Lookups", "Ref", + "IA type"); + cli_out ("%-40s %14s %14s %9s", "----", "-------", "---", + "-------"); + } + for (i = 0; i < lru_size; i++) { + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.lru%d", prefix, i); + cli_print_volume_status_inode_entry (dict, key); + } + cli_out (" "); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.purge_size", prefix); + ret = dict_get_uint32 (dict, key, &purge_size); + if (ret) + goto out; + if (purge_size != 0) { + cli_out ("Purged inodes:"); + cli_out ("%-40s %14s %14s %9s", "GFID", "Lookups", "Ref", + "IA type"); + cli_out ("%-40s %14s %14s %9s", "----", "-------", "---", + "-------"); + } + for (i = 0; i < purge_size; i++) { + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.purge%d", prefix, i); + cli_print_volume_status_inode_entry (dict, key); + } + +out: + return; +} + +void +cli_print_volume_status_inode (dict_t *dict, gf_boolean_t notbrick) +{ + int ret = -1; + char *volname = NULL; + int brick_index_max = -1; + int other_count = 0; + int index_max = 0; + char *hostname = NULL; + char *path = NULL; + int online = -1; + int conn_count = 0; + char key[1024] = {0,}; + int i = 0; + int j = 0; + + GF_ASSERT (dict); + + ret = dict_get_str (dict, "volname", &volname); + if (ret) + goto out; + cli_out ("Inode tables for volume %s", volname); + + ret = dict_get_int32 (dict, "brick-index-max", &brick_index_max); + if (ret) + goto out; + ret = dict_get_int32 (dict, "other-count", &other_count); + if (ret) + goto out; + + index_max = brick_index_max + other_count; + + for ( i = 0; i <= index_max; i++) { + cli_out ("----------------------------------------------"); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.hostname", i); + ret = dict_get_str (dict, key, &hostname); + if (ret) + goto out; + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.path", i); + ret = dict_get_str (dict, key, &path); + if (ret) + goto out; + if (notbrick) + cli_out ("%s : %s", hostname, path); + else + cli_out ("Brick : %s:%s", hostname, path); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.status", i); + ret = dict_get_int32 (dict, key, &online); + if (ret) + goto out; + if (!online) { + if (notbrick) + cli_out ("%s is offline", hostname); + else + cli_out ("Brick is offline"); + continue; + } + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.conncount", i); + ret = dict_get_int32 (dict, key, &conn_count); + if (ret) + goto out; + + for (j = 0; j < conn_count; j++) { + if (conn_count > 1) + cli_out ("Connection %d:", j+1); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.conn%d.itable", + i, j); + cli_print_volume_status_itables (dict, key); + cli_out (" "); + } + } +out: + cli_out ("----------------------------------------------"); + return; +} + +void +cli_print_volume_status_fdtable (dict_t *dict, char *prefix) +{ + int ret = -1; + char key[1024] = {0,}; + int refcount = 0; + uint32_t maxfds = 0; + int firstfree = 0; + int openfds = 0; + int fd_pid = 0; + int fd_refcount = 0; + int fd_flags = 0; + int i = 0; + + GF_ASSERT (dict); + GF_ASSERT (prefix); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.refcount", prefix); + ret = dict_get_int32 (dict, key, &refcount); + if (ret) + goto out; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.maxfds", prefix); + ret = dict_get_uint32 (dict, key, &maxfds); + if (ret) + goto out; + + memset (key, 0 ,sizeof (key)); + snprintf (key, sizeof (key), "%s.firstfree", prefix); + ret = dict_get_int32 (dict, key, &firstfree); + if (ret) + goto out; + + cli_out ("RefCount = %d MaxFDs = %d FirstFree = %d", + refcount, maxfds, firstfree); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.openfds", prefix); + ret = dict_get_int32 (dict, key, &openfds); + if (ret) + goto out; + if (0 == openfds) { + cli_err ("No open fds"); + goto out; + } + + cli_out ("%-19s %-19s %-19s %-19s", "FD Entry", "PID", + "RefCount", "Flags"); + cli_out ("%-19s %-19s %-19s %-19s", "--------", "---", + "--------", "-----"); + + for (i = 0; i < maxfds ; i++) { + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.fdentry%d.pid", prefix, i); + ret = dict_get_int32 (dict, key, &fd_pid); + if (ret) + continue; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.fdentry%d.refcount", + prefix, i); + ret = dict_get_int32 (dict, key, &fd_refcount); + if (ret) + continue; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.fdentry%d.flags", prefix, i); + ret = dict_get_int32 (dict, key, &fd_flags); + if (ret) + continue; + + cli_out ("%-19d %-19d %-19d %-19d", i, fd_pid, fd_refcount, + fd_flags); + } + +out: + return; +} + +void +cli_print_volume_status_fd (dict_t *dict, gf_boolean_t notbrick) +{ + int ret = -1; + char *volname = NULL; + int brick_index_max = -1; + int other_count = 0; + int index_max = 0; + char *hostname = NULL; + char *path = NULL; + int online = -1; + int conn_count = 0; + char key[1024] = {0,}; + int i = 0; + int j = 0; + + GF_ASSERT (dict); + + ret = dict_get_str (dict, "volname", &volname); + if (ret) + goto out; + cli_out ("FD tables for volume %s", volname); + + ret = dict_get_int32 (dict, "brick-index-max", &brick_index_max); + if (ret) + goto out; + ret = dict_get_int32 (dict, "other-count", &other_count); + if (ret) + goto out; + + index_max = brick_index_max + other_count; + + for (i = 0; i <= index_max; i++) { + cli_out ("----------------------------------------------"); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.hostname", i); + ret = dict_get_str (dict, key, &hostname); + if (ret) + goto out; + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.path", i); + ret = dict_get_str (dict, key, &path); + if (ret) + goto out; + + if (notbrick) + cli_out ("%s : %s", hostname, path); + else + cli_out ("Brick : %s:%s", hostname, path); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.status", i); + ret = dict_get_int32 (dict, key, &online); + if (ret) + goto out; + if (!online) { + if (notbrick) + cli_out ("%s is offline", hostname); + else + cli_out ("Brick is offline"); + continue; + } + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.conncount", i); + ret = dict_get_int32 (dict, key, &conn_count); + if (ret) + goto out; + + for (j = 0; j < conn_count; j++) { + cli_out ("Connection %d:", j+1); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.conn%d.fdtable", + i, j); + cli_print_volume_status_fdtable (dict, key); + cli_out (" "); + } + } +out: + cli_out ("----------------------------------------------"); + return; +} + +void +cli_print_volume_status_call_frame (dict_t *dict, char *prefix) +{ + int ret = -1; + char key[1024] = {0,}; + int ref_count = 0; + char *translator = 0; + int complete = 0; + char *parent = NULL; + char *wind_from = NULL; + char *wind_to = NULL; + char *unwind_from = NULL; + char *unwind_to = NULL; + + if (!dict || !prefix) + return; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.refcount", prefix); + ret = dict_get_int32 (dict, key, &ref_count); + if (ret) + return; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.translator", prefix); + ret = dict_get_str (dict, key, &translator); + if (ret) + return; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.complete", prefix); + ret = dict_get_int32 (dict, key, &complete); + if (ret) + return; + + cli_out (" Ref Count = %d", ref_count); + cli_out (" Translator = %s", translator); + cli_out (" Completed = %s", (complete ? "Yes" : "No")); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.parent", prefix); + ret = dict_get_str (dict, key, &parent); + if (!ret) + cli_out (" Parent = %s", parent); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.windfrom", prefix); + ret = dict_get_str (dict, key, &wind_from); + if (!ret) + cli_out (" Wind From = %s", wind_from); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.windto", prefix); + ret = dict_get_str (dict, key, &wind_to); + if (!ret) + cli_out (" Wind To = %s", wind_to); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.unwindfrom", prefix); + ret = dict_get_str (dict, key, &unwind_from); + if (!ret) + cli_out (" Unwind From = %s", unwind_from); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.unwindto", prefix); + ret = dict_get_str (dict, key, &unwind_to); + if (!ret) + cli_out (" Unwind To = %s", unwind_to); +} + +void +cli_print_volume_status_call_stack (dict_t *dict, char *prefix) +{ + int ret = -1; + char key[1024] = {0,}; + int uid = 0; + int gid = 0; + int pid = 0; + uint64_t unique = 0; + //char *op = NULL; + int count = 0; + int i = 0; + + if (!dict || !prefix) + return; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.uid", prefix); + ret = dict_get_int32 (dict, key, &uid); + if (ret) + return; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.gid", prefix); + ret = dict_get_int32 (dict, key, &gid); + if (ret) + return; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.pid", prefix); + ret = dict_get_int32 (dict, key, &pid); + if (ret) + return; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.unique", prefix); + ret = dict_get_uint64 (dict, key, &unique); + if (ret) + return; + + /* + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.op", prefix); + ret = dict_get_str (dict, key, &op); + if (ret) + return; + */ + + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.count", prefix); + ret = dict_get_int32 (dict, key, &count); + if (ret) + return; + + cli_out (" UID : %d", uid); + cli_out (" GID : %d", gid); + cli_out (" PID : %d", pid); + cli_out (" Unique : %"PRIu64, unique); + //cli_out ("\tOp : %s", op); + cli_out (" Frames : %d", count); + + for (i = 0; i < count; i++) { + cli_out (" Frame %d", i+1); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.frame%d", prefix, i); + cli_print_volume_status_call_frame (dict, key); + } + + cli_out (" "); +} + +void +cli_print_volume_status_callpool (dict_t *dict, gf_boolean_t notbrick) +{ + int ret = -1; + char *volname = NULL; + int brick_index_max = -1; + int other_count = 0; + int index_max = 0; + char *hostname = NULL; + char *path = NULL; + int online = -1; + int call_count = 0; + char key[1024] = {0,}; + int i = 0; + int j = 0; + + GF_ASSERT (dict); + + ret = dict_get_str (dict, "volname", &volname); + if (ret) + goto out; + cli_out ("Pending calls for volume %s", volname); + + ret = dict_get_int32 (dict, "brick-index-max", &brick_index_max); + if (ret) + goto out; + ret = dict_get_int32 (dict, "other-count", &other_count); + if (ret) + goto out; + + index_max = brick_index_max + other_count; + + for (i = 0; i <= index_max; i++) { + cli_out ("----------------------------------------------"); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.hostname", i); + ret = dict_get_str (dict, key, &hostname); + if (ret) + goto out; + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.path", i); + ret = dict_get_str (dict, key, &path); + if (ret) + goto out; + + if (notbrick) + cli_out ("%s : %s", hostname, path); + else + cli_out ("Brick : %s:%s", hostname, path); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.status", i); + ret = dict_get_int32 (dict, key, &online); + if (ret) + goto out; + if (!online) { + if (notbrick) + cli_out ("%s is offline", hostname); + else + cli_out ("Brick is offline"); + continue; + } + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.callpool.count", i); + ret = dict_get_int32 (dict, key, &call_count); + if (ret) + goto out; + cli_out ("Pending calls: %d", call_count); + + if (0 == call_count) + continue; + + for (j = 0; j < call_count; j++) { + cli_out ("Call Stack%d", j+1); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), + "brick%d.callpool.stack%d", i, j); + cli_print_volume_status_call_stack (dict, key); + } + } + +out: + cli_out ("----------------------------------------------"); + return; +} + +static void +cli_print_volume_status_tasks (dict_t *dict) +{ + int ret = -1; + int i = 0; + int j = 0; + int count = 0; + int task_count = 0; + int status = 0; + char *op = NULL; + char *task_id_str = NULL; + char *volname = NULL; + char key[1024] = {0,}; + char task[1024] = {0,}; + char *brick = NULL; + char *src_brick = NULL; + char *dest_brick = NULL; + + ret = dict_get_str (dict, "volname", &volname); + if (ret) + goto out; + + ret = dict_get_int32 (dict, "tasks", &task_count); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Failed to get tasks count"); + return; + } + + cli_out ("Task Status of Volume %s", volname); + cli_print_line (CLI_BRICK_STATUS_LINE_LEN); + + if (task_count == 0) { + cli_out ("There are no active volume tasks"); + cli_out (" "); + return; + } + + for (i = 0; i < task_count; i++) { + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "task%d.type", i); + ret = dict_get_str(dict, key, &op); + if (ret) + return; + cli_out ("%-20s : %-20s", "Task", op); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "task%d.id", i); + ret = dict_get_str (dict, key, &task_id_str); + if (ret) + return; + cli_out ("%-20s : %-20s", "ID", task_id_str); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "task%d.status", i); + ret = dict_get_int32 (dict, key, &status); + if (ret) + return; + + snprintf (task, sizeof (task), "task%d", i); + + /* + Replace brick only has two states - In progress and Complete + Ref: xlators/mgmt/glusterd/src/glusterd-replace-brick.c + */ + + if (!strcmp (op, "Replace brick")) { + if (status) + status = GF_DEFRAG_STATUS_COMPLETE; + else + status = GF_DEFRAG_STATUS_STARTED; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.src-brick", task); + ret = dict_get_str (dict, key, &src_brick); + if (ret) + goto out; + + cli_out ("%-20s : %-20s", "Source Brick", src_brick); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.dst-brick", task); + ret = dict_get_str (dict, key, &dest_brick); + if (ret) + goto out; + + cli_out ("%-20s : %-20s", "Destination Brick", + dest_brick); + + } else if (!strcmp (op, "Remove brick")) { + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.count", task); + ret = dict_get_int32 (dict, key, &count); + if (ret) + goto out; + + cli_out ("%-20s", "Removed bricks:"); + + for (j = 1; j <= count; j++) { + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key),"%s.brick%d", + task, j); + ret = dict_get_str (dict, key, &brick); + if (ret) + goto out; + + cli_out ("%-20s", brick); + } + } + cli_out ("%-20s : %-20s", "Status", + cli_vol_task_status_str[status]); + cli_out (" "); + } + +out: + return; +} + +static int +gf_cli_status_cbk (struct rpc_req *req, struct iovec *iov, + int count, void *myframe) +{ + int ret = -1; + int brick_index_max = -1; + int other_count = 0; + int index_max = 0; + int i = 0; + int pid = -1; + uint32_t cmd = 0; + gf_boolean_t notbrick = _gf_false; + char key[1024] = {0,}; + char *hostname = NULL; + char *path = NULL; + char *volname = NULL; + dict_t *dict = NULL; + gf_cli_rsp rsp = {0,}; + cli_volume_status_t status = {0}; + cli_local_t *local = NULL; + gf_boolean_t wipe_local = _gf_false; + char msg[1024] = {0,}; + + if (req->rpc_status == -1) + goto out; + + ret = xdr_to_generic (*iov, &rsp, (xdrproc_t)xdr_gf_cli_rsp); + if (ret < 0) { + gf_log (((call_frame_t *) myframe)->this->name, GF_LOG_ERROR, + "Failed to decode xdr response"); + goto out; + } + + gf_log ("cli", GF_LOG_DEBUG, "Received response to status cmd"); + + local = ((call_frame_t *)myframe)->local; + if (!local) { + local = cli_local_get (); + if (!local) { + ret = -1; + gf_log ("cli", GF_LOG_ERROR, "Failed to get local"); + goto out; + } + wipe_local = _gf_true; + } + + if (rsp.op_ret) { + if (strcmp (rsp.op_errstr, "")) + snprintf (msg, sizeof (msg), "%s", rsp.op_errstr); + else + snprintf (msg, sizeof (msg), "Unable to obtain volume " + "status information."); + + if (global_state->mode & GLUSTER_MODE_XML) { + if (!local->all) + cli_xml_output_str ("volStatus", msg, + rsp.op_ret, rsp.op_errno, + rsp.op_errstr); + ret = 0; + goto out; + } + + cli_err ("%s", msg); + if (local && local->all) { + ret = 0; + cli_out (" "); + } else + ret = -1; + + goto out; + } + + dict = dict_new (); + if (!dict) + goto out; + + ret = dict_unserialize (rsp.dict.dict_val, + rsp.dict.dict_len, + &dict); + if (ret) + goto out; + + ret = dict_get_uint32 (dict, "cmd", &cmd); + if (ret) + goto out; + + if ((cmd & GF_CLI_STATUS_ALL)) { + if (local && local->dict) { + dict_ref (dict); + ret = dict_set_static_ptr (local->dict, "rsp-dict", dict); + ret = 0; + } else { + gf_log ("cli", GF_LOG_ERROR, "local not found"); + ret = -1; + } + goto out; + } + + if ((cmd & GF_CLI_STATUS_NFS) || (cmd & GF_CLI_STATUS_SHD)) + notbrick = _gf_true; + + if (global_state->mode & GLUSTER_MODE_XML) { + if (!local->all) { + ret = cli_xml_output_vol_status_begin (local, + rsp.op_ret, + rsp.op_errno, + rsp.op_errstr); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, + "Error outputting to xml"); + goto out; + } + } + if (cmd & GF_CLI_STATUS_TASKS) { + ret = cli_xml_output_vol_status_tasks_detail (local, + dict); + if (ret) { + gf_log ("cli", GF_LOG_ERROR,"Error outputting " + "to xml"); + goto out; + } + } else { + ret = cli_xml_output_vol_status (local, dict); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, + "Error outputting to xml"); + goto out; + } + } + + if (!local->all) { + ret = cli_xml_output_vol_status_end (local); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, + "Error outputting to xml"); + } + } + goto out; + } + + status.brick = GF_CALLOC (1, PATH_MAX + 256, gf_common_mt_strdup); + + switch (cmd & GF_CLI_STATUS_MASK) { + case GF_CLI_STATUS_MEM: + cli_print_volume_status_mem (dict, notbrick); + goto cont; + break; + case GF_CLI_STATUS_CLIENTS: + cli_print_volume_status_clients (dict, notbrick); + goto cont; + break; + case GF_CLI_STATUS_INODE: + cli_print_volume_status_inode (dict, notbrick); + goto cont; + break; + case GF_CLI_STATUS_FD: + cli_print_volume_status_fd (dict, notbrick); + goto cont; + break; + case GF_CLI_STATUS_CALLPOOL: + cli_print_volume_status_callpool (dict, notbrick); + goto cont; + break; + case GF_CLI_STATUS_TASKS: + cli_print_volume_status_tasks (dict); + goto cont; + break; + default: + break; + } + + ret = dict_get_str (dict, "volname", &volname); + if (ret) + goto out; + + ret = dict_get_int32 (dict, "brick-index-max", &brick_index_max); + if (ret) + goto out; + + ret = dict_get_int32 (dict, "other-count", &other_count); + if (ret) + goto out; + + index_max = brick_index_max + other_count; + + + cli_out ("Status of volume: %s", volname); + + if ((cmd & GF_CLI_STATUS_DETAIL) == 0) { + cli_out ("Gluster process\t\t\t\t\t\tPort\tOnline\tPid"); + cli_print_line (CLI_BRICK_STATUS_LINE_LEN); + } + + for (i = 0; i <= index_max; i++) { + + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.hostname", i); + ret = dict_get_str (dict, key, &hostname); + if (ret) + continue; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.path", i); + ret = dict_get_str (dict, key, &path); + if (ret) + continue; + + /* Brick/not-brick is handled seperately here as all + * types of nodes are contained in the default output + */ + memset (status.brick, 0, PATH_MAX + 255); + if (!strcmp (hostname, "NFS Server") || + !strcmp (hostname, "Self-heal Daemon")) + snprintf (status.brick, PATH_MAX + 255, "%s on %s", + hostname, path); + else + snprintf (status.brick, PATH_MAX + 255, "Brick %s:%s", + hostname, path); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.port", i); + ret = dict_get_int32 (dict, key, &(status.port)); + if (ret) + continue; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.status", i); + ret = dict_get_int32 (dict, key, &(status.online)); + if (ret) + continue; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.pid", i); + ret = dict_get_int32 (dict, key, &pid); + if (ret) + continue; + if (pid == -1) + ret = gf_asprintf (&(status.pid_str), "%s", "N/A"); + else + ret = gf_asprintf (&(status.pid_str), "%d", pid); + + if (ret == -1) + goto out; + + if ((cmd & GF_CLI_STATUS_DETAIL)) { + ret = cli_get_detail_status (dict, i, &status); + if (ret) + goto out; + cli_print_line (CLI_BRICK_STATUS_LINE_LEN); + cli_print_detailed_status (&status); + + } else { + cli_print_brick_status (&status); + } + } + cli_out (" "); + + if ((cmd & GF_CLI_STATUS_MASK) == GF_CLI_STATUS_NONE) + cli_print_volume_status_tasks (dict); +cont: + ret = rsp.op_ret; + +out: + if (dict) + dict_unref (dict); + GF_FREE (status.brick); + if (local && wipe_local) { + cli_local_wipe (local); + } + + cli_cmd_broadcast_response (ret); + return ret; +} + +int32_t +gf_cli_status_volume (call_frame_t *frame, xlator_t *this, + void *data) +{ + gf_cli_req req = {{0,}}; + int ret = -1; + dict_t *dict = NULL; + + if (!frame || !this || !data) + goto out; + + dict = data; + + ret = cli_to_glusterd (&req, frame, gf_cli_status_cbk, + (xdrproc_t) xdr_gf_cli_req, dict, + GLUSTER_CLI_STATUS_VOLUME, this, cli_rpc_prog, + NULL); + out: + gf_log ("cli", GF_LOG_DEBUG, "Returning: %d", ret); + return ret; +} + +int +gf_cli_status_volume_all (call_frame_t *frame, xlator_t *this, void *data) +{ + int i = 0; + int ret = -1; + int vol_count = -1; + uint32_t cmd = 0; + char key[1024] = {0}; + char *volname = NULL; + void *vol_dict = NULL; + dict_t *dict = NULL; + cli_local_t *local = NULL; + + if (frame->local) { + local = frame->local; + local->all = _gf_true; + } else + goto out; + + ret = dict_get_uint32 (local->dict, "cmd", &cmd); + if (ret) + goto out; + + + ret = gf_cli_status_volume (frame, this, data); + if (ret) + goto out; + + ret = dict_get_ptr (local->dict, "rsp-dict", &vol_dict); + if (ret) + goto out; + + ret = dict_get_int32 ((dict_t *)vol_dict, "vol_count", &vol_count); + if (ret) { + cli_err ("Failed to get names of volumes"); + goto out; + } + + /* remove the "all" flag in cmd */ + cmd &= ~GF_CLI_STATUS_ALL; + cmd |= GF_CLI_STATUS_VOL; + + if (global_state->mode & GLUSTER_MODE_XML) { + //TODO: Pass proper op_* values + ret = cli_xml_output_vol_status_begin (local, 0,0, NULL); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, + "Error outputting to xml"); + goto out; + } + } + + if (vol_count == 0 && !(global_state->mode & GLUSTER_MODE_XML)) { + cli_err ("No volumes present"); + ret = 0; + goto out; + } + + for (i = 0; i < vol_count; i++) { + + dict = dict_new (); + if (!dict) + goto out; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "vol%d", i); + ret = dict_get_str (vol_dict, key, &volname); + if (ret) + goto out; + + ret = dict_set_str (dict, "volname", volname); + if (ret) + goto out; + + ret = dict_set_uint32 (dict, "cmd", cmd); + if (ret) + goto out; + + ret = gf_cli_status_volume (frame, this, dict); + if (ret) + goto out; + + dict_unref (dict); + } + + if (global_state->mode & GLUSTER_MODE_XML) { + ret = cli_xml_output_vol_status_end (local); + } + + out: + if (ret) + gf_log ("cli", GF_LOG_ERROR, "status all failed"); + + if (vol_dict) + dict_unref (vol_dict); + + if (ret && dict) + dict_unref (dict); + + if (local) + cli_local_wipe (local); + + if (frame) + frame->local = NULL; + + return ret; +} + +static int +gf_cli_mount_cbk (struct rpc_req *req, struct iovec *iov, + int count, void *myframe) +{ + gf1_cli_mount_rsp rsp = {0,}; + int ret = -1; + + if (-1 == req->rpc_status) { + goto out; + } + + ret = xdr_to_generic (*iov, &rsp, (xdrproc_t)xdr_gf1_cli_mount_rsp); + if (ret < 0) { + gf_log (((call_frame_t *) myframe)->this->name, GF_LOG_ERROR, + "Failed to decode xdr response"); + goto out; + } + + gf_log ("cli", GF_LOG_INFO, "Received resp to mount"); + + if (rsp.op_ret == 0) { + ret = 0; + cli_out ("%s", rsp.path); + } else { + /* weird sounding but easy to parse... */ + cli_err ("%d : failed with this errno (%s)", + rsp.op_errno, strerror (rsp.op_errno)); + ret = -1; + } + +out: + cli_cmd_broadcast_response (ret); + return ret; +} + +int32_t +gf_cli_mount (call_frame_t *frame, xlator_t *this, void *data) +{ + gf1_cli_mount_req req = {0,}; + int ret = -1; + void **dataa = data; + char *label = NULL; + dict_t *dict = NULL; + + if (!frame || !this || !data) + goto out; + + label = dataa[0]; + dict = dataa[1]; + + req.label = label; + ret = dict_allocate_and_serialize (dict, &req.dict.dict_val, + &req.dict.dict_len); + if (ret) { + ret = -1; + goto out; + } + + ret = cli_cmd_submit (&req, frame, cli_rpc_prog, + GLUSTER_CLI_MOUNT, NULL, + this, gf_cli_mount_cbk, + (xdrproc_t)xdr_gf1_cli_mount_req); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +static int +gf_cli_umount_cbk (struct rpc_req *req, struct iovec *iov, + int count, void *myframe) +{ + gf1_cli_umount_rsp rsp = {0,}; + int ret = -1; + + if (-1 == req->rpc_status) { + goto out; + } + + ret = xdr_to_generic (*iov, &rsp, (xdrproc_t)xdr_gf1_cli_umount_rsp); + if (ret < 0) { + gf_log (((call_frame_t *) myframe)->this->name, GF_LOG_ERROR, + "Failed to decode xdr response"); + goto out; + } + + gf_log ("cli", GF_LOG_INFO, "Received resp to mount"); + + if (rsp.op_ret == 0) + ret = 0; + else { + cli_err ("umount failed"); + ret = -1; + } + +out: + cli_cmd_broadcast_response (ret); + return ret; +} + +int32_t +gf_cli_umount (call_frame_t *frame, xlator_t *this, void *data) +{ + gf1_cli_umount_req req = {0,}; + int ret = -1; + dict_t *dict = NULL; + + if (!frame || !this || !data) + goto out; + + dict = data; + + ret = dict_get_str (dict, "path", &req.path); + if (ret == 0) + ret = dict_get_int32 (dict, "lazy", &req.lazy); + + if (ret) { + ret = -1; + goto out; + } + + ret = cli_cmd_submit (&req, frame, cli_rpc_prog, + GLUSTER_CLI_UMOUNT, NULL, + this, gf_cli_umount_cbk, + (xdrproc_t)xdr_gf1_cli_umount_req); + + out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +void +cmd_heal_volume_statistics_out (dict_t *dict, int brick) +{ + + uint64_t num_entries = 0; + int ret = 0; + char key[256] = {0}; + char *hostname = NULL; + uint64_t i = 0; + uint64_t healed_count = 0; + uint64_t split_brain_count = 0; + uint64_t heal_failed_count = 0; + char *start_time_str = NULL; + char *end_time_str = NULL; + char *crawl_type = NULL; + int progress = -1; + + snprintf (key, sizeof key, "%d-hostname", brick); + ret = dict_get_str (dict, key, &hostname); + if (ret) + goto out; + cli_out ("------------------------------------------------"); + cli_out ("\nCrawl statistics for brick no %d", brick); + cli_out ("Hostname of brick %s", hostname); + + snprintf (key, sizeof key, "statistics-%d-count", brick); + ret = dict_get_uint64 (dict, key, &num_entries); + if (ret) + goto out; + + for (i = 0; i < num_entries; i++) + { + snprintf (key, sizeof key, "statistics_crawl_type-%d-%"PRIu64, + brick, i); + ret = dict_get_str (dict, key, &crawl_type); + if (ret) + goto out; + + snprintf (key, sizeof key, "statistics_healed_cnt-%d-%"PRIu64, + brick,i); + ret = dict_get_uint64 (dict, key, &healed_count); + if (ret) + goto out; + + snprintf (key, sizeof key, "statistics_sb_cnt-%d-%"PRIu64, + brick, i); + ret = dict_get_uint64 (dict, key, &split_brain_count); + if (ret) + goto out; + snprintf (key, sizeof key, "statistics_heal_failed_cnt-%d-%"PRIu64, + brick, i); + ret = dict_get_uint64 (dict, key, &heal_failed_count); + if (ret) + goto out; + snprintf (key, sizeof key, "statistics_strt_time-%d-%"PRIu64, + brick, i); + ret = dict_get_str (dict, key, &start_time_str); + if (ret) + goto out; + snprintf (key, sizeof key, "statistics_end_time-%d-%"PRIu64, + brick, i); + ret = dict_get_str (dict, key, &end_time_str); + if (ret) + goto out; + snprintf (key, sizeof key, "statistics_inprogress-%d-%"PRIu64, + brick, i); + ret = dict_get_int32 (dict, key, &progress); + if (ret) + goto out; + + cli_out ("\nStarting time of crawl: %s", start_time_str); + if (progress == 1) + cli_out ("Crawl is in progress"); + else + cli_out ("Ending time of crawl: %s", end_time_str); + + cli_out ("Type of crawl: %s", crawl_type); + cli_out ("No. of entries healed: %"PRIu64, + healed_count); + cli_out ("No. of entries in split-brain: %"PRIu64, + split_brain_count); + cli_out ("No. of heal failed entries: %"PRIu64, + heal_failed_count); + + } + + +out: + return; +} + +void +cmd_heal_volume_brick_out (dict_t *dict, int brick) +{ + uint64_t num_entries = 0; + int ret = 0; + char key[256] = {0}; + char *hostname = NULL; + char *path = NULL; + char *status = NULL; + uint64_t i = 0; + uint32_t time = 0; + char timestr[32] = {0}; + char *shd_status = NULL; + + snprintf (key, sizeof key, "%d-hostname", brick); + ret = dict_get_str (dict, key, &hostname); + if (ret) + goto out; + snprintf (key, sizeof key, "%d-path", brick); + ret = dict_get_str (dict, key, &path); + if (ret) + goto out; + cli_out ("\nBrick %s:%s", hostname, path); + + snprintf (key, sizeof key, "%d-status", brick); + ret = dict_get_str (dict, key, &status); + if (status && strlen (status)) + cli_out ("Status: %s", status); + + snprintf (key, sizeof key, "%d-shd-status",brick); + ret = dict_get_str (dict, key, &shd_status); + + if(!shd_status) + { + snprintf (key, sizeof key, "%d-count", brick); + ret = dict_get_uint64 (dict, key, &num_entries); + cli_out ("Number of entries: %"PRIu64, num_entries); + + + for (i = 0; i < num_entries; i++) { + snprintf (key, sizeof key, "%d-%"PRIu64, brick, i); + ret = dict_get_str (dict, key, &path); + if (ret) + continue; + time = 0; + snprintf (key, sizeof key, "%d-%"PRIu64"-time", + brick, i); + ret = dict_get_uint32 (dict, key, &time); + if (!time) { + cli_out ("%s", path); + } else { + gf_time_fmt (timestr, sizeof timestr, + time, gf_timefmt_FT); + if (i == 0) { + cli_out ("at path on brick"); + cli_out ("-----------------------------------"); + } + cli_out ("%s %s", timestr, path); + } + } + } + +out: + return; +} + + +void +cmd_heal_volume_statistics_heal_count_out (dict_t *dict, int brick) +{ + uint64_t num_entries = 0; + int ret = 0; + char key[256] = {0}; + char *hostname = NULL; + char *path = NULL; + char *status = NULL; + char *shd_status = NULL; + + snprintf (key, sizeof key, "%d-hostname", brick); + ret = dict_get_str (dict, key, &hostname); + if (ret) + goto out; + snprintf (key, sizeof key, "%d-path", brick); + ret = dict_get_str (dict, key, &path); + if (ret) + goto out; + cli_out ("\nBrick %s:%s", hostname, path); + + snprintf (key, sizeof key, "%d-status", brick); + ret = dict_get_str (dict, key, &status); + if (status && strlen (status)) + cli_out ("Status: %s", status); + + snprintf (key, sizeof key, "%d-shd-status",brick); + ret = dict_get_str (dict, key, &shd_status); + + if(!shd_status) + { + snprintf (key, sizeof key, "%d-hardlinks", brick); + ret = dict_get_uint64 (dict, key, &num_entries); + if (ret) + cli_out ("No gathered input for this brick"); + else + cli_out ("Number of entries: %"PRIu64, num_entries); + + + } + +out: + return; +} + + +int +gf_cli_heal_volume_cbk (struct rpc_req *req, struct iovec *iov, + int count, void *myframe) +{ + gf_cli_rsp rsp = {0,}; + int ret = -1; + cli_local_t *local = NULL; + char *volname = NULL; + call_frame_t *frame = NULL; + dict_t *input_dict = NULL; + dict_t *dict = NULL; + int brick_count = 0; + int i = 0; + gf_xl_afr_op_t heal_op = GF_AFR_OP_INVALID; + char *operation = NULL; + char *substr = NULL; + char *heal_op_str = NULL; + + if (-1 == req->rpc_status) { + goto out; + } + + frame = myframe; + + ret = xdr_to_generic (*iov, &rsp, (xdrproc_t)xdr_gf_cli_rsp); + if (ret < 0) { + gf_log (frame->this->name, GF_LOG_ERROR, + "Failed to decode xdr response"); + goto out; + } + + if (frame) + local = frame->local; + + if (local) { + input_dict = local->dict; + ret = dict_get_int32 (input_dict, "heal-op", + (int32_t*)&heal_op); + } +//TODO: Proper XML output +//#if (HAVE_LIB_XML) +// if (global_state->mode & GLUSTER_MODE_XML) { +// ret = cli_xml_output_dict ("volHeal", dict, rsp.op_ret, +// rsp.op_errno, rsp.op_errstr); +// if (ret) +// gf_log ("cli", GF_LOG_ERROR, +// "Error outputting to xml"); +// goto out; +// } +//#endif + + ret = dict_get_str (input_dict, "volname", &volname); + if (ret) { + gf_log (frame->this->name, GF_LOG_ERROR, "failed to get volname"); + goto out; + } + + gf_log ("cli", GF_LOG_INFO, "Received resp to heal volume"); + + switch (heal_op) { + case GF_AFR_OP_HEAL_INDEX: + heal_op_str = "to perform index self heal"; + break; + case GF_AFR_OP_HEAL_FULL: + heal_op_str = "to perform full self heal"; + break; + case GF_AFR_OP_INDEX_SUMMARY: + heal_op_str = "list of entries to be healed"; + break; + case GF_AFR_OP_HEALED_FILES: + heal_op_str = "list of healed entries"; + break; + case GF_AFR_OP_HEAL_FAILED_FILES: + heal_op_str = "list of heal failed entries"; + break; + case GF_AFR_OP_SPLIT_BRAIN_FILES: + heal_op_str = "list of split brain entries"; + break; + case GF_AFR_OP_STATISTICS: + heal_op_str = "crawl statistics"; + break; + case GF_AFR_OP_STATISTICS_HEAL_COUNT: + heal_op_str = "count of entries to be healed"; + break; + case GF_AFR_OP_STATISTICS_HEAL_COUNT_PER_REPLICA: + heal_op_str = "count of entries to be healed per replica"; + break; + case GF_AFR_OP_INVALID: + heal_op_str = "invalid heal op"; + break; + } + + if ((heal_op == GF_AFR_OP_HEAL_FULL) || + (heal_op == GF_AFR_OP_HEAL_INDEX)) { + operation = "Launching heal operation"; + substr = "\nUse heal info commands to check status"; + } else { + operation = "Gathering"; + substr = ""; + } + + if (rsp.op_ret) { + if (strcmp (rsp.op_errstr, "")) { + cli_err ("%s", rsp.op_errstr); + } else { + cli_err ("%s %s on volume %s has been unsuccessful", + operation, heal_op_str, volname); + } + + ret = rsp.op_ret; + goto out; + } else { + cli_out ("%s %s on volume %s has been successful %s", operation, + heal_op_str, volname, substr); + } + + ret = rsp.op_ret; + if ((heal_op == GF_AFR_OP_HEAL_FULL) || + (heal_op == GF_AFR_OP_HEAL_INDEX)) + goto out; + + dict = dict_new (); + if (!dict) { + ret = -1; + goto out; + } + + ret = dict_unserialize (rsp.dict.dict_val, + rsp.dict.dict_len, + &dict); + + if (ret) { + gf_log ("", GF_LOG_ERROR, + "Unable to allocate memory"); + goto out; + } else { + dict->extra_stdfree = rsp.dict.dict_val; + } + ret = dict_get_int32 (dict, "count", &brick_count); + if (ret) + goto out; + + if (!brick_count) { + cli_err ("All bricks of volume %s are down.", volname); + goto out; + } + + switch (heal_op) { + case GF_AFR_OP_STATISTICS: + for (i = 0; i < brick_count; i++) + cmd_heal_volume_statistics_out (dict, i); + break; + case GF_AFR_OP_STATISTICS_HEAL_COUNT: + case GF_AFR_OP_STATISTICS_HEAL_COUNT_PER_REPLICA: + for (i = 0; i < brick_count; i++) + cmd_heal_volume_statistics_heal_count_out (dict, + i); + break; + case GF_AFR_OP_INDEX_SUMMARY: + case GF_AFR_OP_HEALED_FILES: + case GF_AFR_OP_HEAL_FAILED_FILES: + case GF_AFR_OP_SPLIT_BRAIN_FILES: + for (i = 0; i < brick_count; i++) + cmd_heal_volume_brick_out (dict, i); + break; + default: + break; + } + + ret = rsp.op_ret; + +out: + cli_cmd_broadcast_response (ret); + free (rsp.op_errstr); + if (dict) + dict_unref (dict); + return ret; +} + +int32_t +gf_cli_heal_volume (call_frame_t *frame, xlator_t *this, + void *data) +{ + gf_cli_req req = {{0,}}; + int ret = 0; + dict_t *dict = NULL; + + if (!frame || !this || !data) { + ret = -1; + goto out; + } + + dict = data; + + ret = cli_to_glusterd (&req, frame, gf_cli_heal_volume_cbk, + (xdrproc_t) xdr_gf_cli_req, dict, + GLUSTER_CLI_HEAL_VOLUME, this, cli_rpc_prog, + NULL); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + + GF_FREE (req.dict.dict_val); + + return ret; +} + +int32_t +gf_cli_statedump_volume_cbk (struct rpc_req *req, struct iovec *iov, + int count, void *myframe) +{ + gf_cli_rsp rsp = {0,}; + int ret = -1; + char msg[1024] = {0,}; + + if (-1 == req->rpc_status) + goto out; + ret = xdr_to_generic (*iov, &rsp, + (xdrproc_t)xdr_gf_cli_rsp); + if (ret < 0) { + gf_log (((call_frame_t *) myframe)->this->name, GF_LOG_ERROR, + "Failed to decode xdr response"); + goto out; + } + gf_log ("cli", GF_LOG_DEBUG, "Received response to statedump"); + if (rsp.op_ret) + snprintf (msg, sizeof(msg), "%s", rsp.op_errstr); + else + snprintf (msg, sizeof (msg), "Volume statedump successful"); + + if (global_state->mode & GLUSTER_MODE_XML) { + ret = cli_xml_output_str ("volStatedump", msg, rsp.op_ret, + rsp.op_errno, rsp.op_errstr); + if (ret) + gf_log ("cli", GF_LOG_ERROR, + "Error outputting to xml"); + goto out; + } + + if (rsp.op_ret) + cli_err ("volume statedump: failed: %s", msg); + else + cli_out ("volume statedump: success"); + ret = rsp.op_ret; + +out: + cli_cmd_broadcast_response (ret); + return ret; +} + +int32_t +gf_cli_statedump_volume (call_frame_t *frame, xlator_t *this, + void *data) +{ + gf_cli_req req = {{0,}}; + dict_t *options = NULL; + int ret = -1; + + if (!frame || !this || !data) + goto out; + + options = data; + + ret = cli_to_glusterd (&req, frame, gf_cli_statedump_volume_cbk, + (xdrproc_t) xdr_gf_cli_req, options, + GLUSTER_CLI_STATEDUMP_VOLUME, this, cli_rpc_prog, + NULL); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + + GF_FREE (req.dict.dict_val); + return ret; +} + +int32_t +gf_cli_list_volume_cbk (struct rpc_req *req, struct iovec *iov, + int count, void *myframe) +{ + int ret = -1; + gf_cli_rsp rsp = {0,}; + dict_t *dict = NULL; + int vol_count = 0;; + char *volname = NULL; + char key[1024] = {0,}; + int i = 0; + + if (-1 == req->rpc_status) + goto out; + ret = xdr_to_generic (*iov, &rsp, + (xdrproc_t)xdr_gf_cli_rsp); + if (ret < 0) { + gf_log (((call_frame_t *) myframe)->this->name, GF_LOG_ERROR, + "Failed to decode xdr response"); + goto out; + } + + dict = dict_new (); + if (!dict) { + ret = -1; + goto out; + } + + ret = dict_unserialize (rsp.dict.dict_val, rsp.dict.dict_len, &dict); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Unable to allocate memory"); + goto out; + } + + if (global_state->mode & GLUSTER_MODE_XML) { + ret = cli_xml_output_vol_list (dict, rsp.op_ret, rsp.op_errno, + rsp.op_errstr); + if (ret) + gf_log ("cli", GF_LOG_ERROR, + "Error outputting to xml"); + goto out; + } + + if (rsp.op_ret) + cli_err ("%s", rsp.op_errstr); + else { + ret = dict_get_int32 (dict, "count", &vol_count); + if (ret) + goto out; + + if (vol_count == 0) { + cli_err ("No volumes present in cluster"); + goto out; + } + for (i = 0; i < vol_count; i++) { + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "volume%d", i); + ret = dict_get_str (dict, key, &volname); + if (ret) + goto out; + cli_out ("%s", volname); + } + } + + ret = rsp.op_ret; + +out: + cli_cmd_broadcast_response (ret); + return ret; +} + +int32_t +gf_cli_list_volume (call_frame_t *frame, xlator_t *this, void *data) +{ + int ret = -1; + gf_cli_req req = {{0,}}; + + if (!frame || !this) + goto out; + + ret = cli_cmd_submit (&req, frame, cli_rpc_prog, + GLUSTER_CLI_LIST_VOLUME, NULL, + this, gf_cli_list_volume_cbk, + (xdrproc_t)xdr_gf_cli_req); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int32_t +gf_cli_clearlocks_volume_cbk (struct rpc_req *req, struct iovec *iov, + int count, void *myframe) +{ + gf_cli_rsp rsp = {0,}; + int ret = -1; + char *lk_summary = NULL; + char *volname = NULL; + dict_t *dict = NULL; + + if (-1 == req->rpc_status) + goto out; + ret = xdr_to_generic (*iov, &rsp, + (xdrproc_t)xdr_gf_cli_rsp); + if (ret < 0) { + gf_log (((call_frame_t *) myframe)->this->name, GF_LOG_ERROR, + "Failed to decode xdr response"); + goto out; + } + gf_log ("cli", GF_LOG_DEBUG, "Received response to clear-locks"); + + if (rsp.op_ret) { + cli_err ("Volume clear-locks unsuccessful"); + cli_err ("%s", rsp.op_errstr); + + } else { + if (!rsp.dict.dict_len) { + cli_err ("Possibly no locks cleared"); + ret = 0; + goto out; + } + + dict = dict_new (); + + if (!dict) { + ret = -1; + goto out; + } + + ret = dict_unserialize (rsp.dict.dict_val, + rsp.dict.dict_len, + &dict); + + if (ret) { + gf_log ("cli", GF_LOG_ERROR, + "Unable to serialize response dictionary"); + goto out; + } + + ret = dict_get_str (dict, "volname", &volname); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Unable to get volname " + "from dictionary"); + goto out; + } + + ret = dict_get_str (dict, "lk-summary", &lk_summary); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Unable to get lock " + "summary from dictionary"); + goto out; + } + cli_out ("Volume clear-locks successful"); + cli_out ("%s", lk_summary); + + } + + ret = rsp.op_ret; + +out: + if (dict) + dict_unref (dict); + cli_cmd_broadcast_response (ret); + return ret; +} + +int32_t +gf_cli_clearlocks_volume (call_frame_t *frame, xlator_t *this, + void *data) +{ + gf_cli_req req = {{0,}}; + dict_t *options = NULL; + int ret = -1; + + if (!frame || !this || !data) + goto out; + + options = data; + + ret = cli_to_glusterd (&req, frame, gf_cli_clearlocks_volume_cbk, + (xdrproc_t) xdr_gf_cli_req, options, + GLUSTER_CLI_CLRLOCKS_VOLUME, this, cli_rpc_prog, + NULL); +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + + GF_FREE (req.dict.dict_val); + return ret; +} + +int32_t +cli_snapshot_remove_reply (gf_cli_rsp *rsp, dict_t *dict, call_frame_t *frame) +{ + int32_t ret = -1; + char *snap_name = NULL; + + GF_ASSERT (rsp); + GF_ASSERT (dict); + GF_ASSERT (frame); + + if (rsp->op_ret) { + cli_err("snapshot delete: failed: %s", + rsp->op_errstr ? rsp->op_errstr : + "Please check log file for details"); + ret = rsp->op_ret; + goto out; + } + + ret = dict_get_str (dict, "snapname", &snap_name); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Failed to get snapname"); + goto out; + } + + cli_out ("snapshot delete: %s: snap removed successfully", + snap_name); + ret = 0; + +out: + return ret; +} + +int +cli_snapshot_config_display (dict_t *dict, gf_cli_rsp *rsp) +{ + char buf[PATH_MAX] = ""; + char *volname = NULL; + int ret = -1; + int config_command = 0; + uint64_t value = 0; + uint64_t hard_limit = 0; + uint64_t soft_limit = 0; + uint64_t i = 0; + uint64_t voldisplaycount = 0; + + GF_ASSERT (dict); + GF_ASSERT (rsp); + + if (rsp->op_ret) { + cli_err ("Snapshot Config : failed: %s", + rsp->op_errstr ? rsp->op_errstr : + "Please check log file for details"); + ret = rsp->op_ret; + goto out; + } + + ret = dict_get_int32 (dict, "config-command", &config_command); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Could not fetch config type"); + goto out; + } + + ret = dict_get_str (dict, "volname", &volname); + /* Ignore the error, as volname is optional */ + + if (!volname) { + volname = "System"; + } + + ret = dict_get_uint64 (dict, "snap-max-hard-limit", &hard_limit); + /* Ignore the error, as the key specified is optional */ + ret = dict_get_uint64 (dict, "snap-max-soft-limit", &soft_limit); + + if (!hard_limit && !soft_limit + && config_command != GF_SNAP_CONFIG_DISPLAY) { + ret = -1; + gf_log(THIS->name, GF_LOG_ERROR, + "Could not fetch config-key"); + goto out; + } + + switch (config_command) { + case GF_SNAP_CONFIG_TYPE_SET: + if (hard_limit && soft_limit) { + cli_out ("snapshot config: snap-max-hard-limit " + "& snap-max-soft-limit for system set " + "successfully"); + } else if (hard_limit){ + cli_out ("snapshot config: %s " + "for snap-max-hard-limit set successfully", + volname); + } else if (soft_limit) { + cli_out ("snapshot config: %s " + "for snap-max-soft-limit set successfully", + volname); + } + break; + + case GF_SNAP_CONFIG_DISPLAY : + cli_out ("\nSnapshot System Configuration:"); + ret = dict_get_uint64 (dict, "snap-max-hard-limit", + &value); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Could not fetch " + "snap_max_hard_limit for %s", volname); + ret = -1; + goto out; + } + cli_out ("snap-max-hard-limit : %"PRIu64, value); + + ret = dict_get_uint64 (dict, "snap-max-soft-limit", + &soft_limit); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Could not fetch " + "snap-max-soft-limit for %s", volname); + ret = -1; + goto out; + } + cli_out ("snap-max-soft-limit : %"PRIu64"%%\n", + soft_limit); + + cli_out ("Snapshot Volume Configuration:"); + + ret = dict_get_uint64 (dict, "voldisplaycount", + &voldisplaycount); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, + "Could not fetch voldisplaycount"); + ret = -1; + goto out; + } + + for (i = 0; i < voldisplaycount; i++) { + snprintf (buf, sizeof(buf), "volume%ld-volname", i); + ret = dict_get_str (dict, buf, &volname); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Could not fetch " + " %s", buf); + ret = -1; + goto out; + } + cli_out ("\nVolume : %s", volname); + + snprintf (buf, sizeof(buf), + "volume%ld-snap-max-hard-limit", i); + ret = dict_get_uint64 (dict, buf, &value); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Could not fetch " + " %s", buf); + ret = -1; + goto out; + } + cli_out ("snap-max-hard-limit : %"PRIu64, value); + + snprintf (buf, sizeof(buf), + "volume%ld-active-hard-limit", i); + ret = dict_get_uint64 (dict, buf, &value); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Could not fetch" + " effective snap_max_hard_limit for " + "%s", volname); + ret = -1; + goto out; + } + cli_out ("Effective snap-max-hard-limit : %"PRIu64, + value); + + snprintf (buf, sizeof(buf), + "volume%ld-snap-max-soft-limit", i); + ret = dict_get_uint64 (dict, buf, &value); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Could not fetch " + " %s", buf); + ret = -1; + goto out; + } + cli_out ("Effective snap-max-soft-limit : %"PRIu64" " + "(%"PRIu64"%%)", value, soft_limit); + } + break; + default : + break; + } + + ret = 0; +out: + return ret; +} + +/* This function is used to print the volume related information + * of a snap. + * + * arg - 0, dict : Response Dictionary. + * arg - 1, prefix str : snaplist.snap{0..}.vol{0..}.* + */ +int +cli_get_each_volinfo_in_snap (dict_t *dict, char *keyprefix, + gf_boolean_t snap_driven) { + char key[PATH_MAX] = ""; + char *get_buffer = NULL; + int value = 0; + int ret = -1; + char indent[5] = "\t"; + char *volname = NULL; + + GF_ASSERT (dict); + GF_ASSERT (keyprefix); + + if (snap_driven) { + ret = snprintf (key, sizeof (key), "%s.volname", keyprefix); + if (ret < 0) { + goto out; + } + + ret = dict_get_str (dict, key, &get_buffer); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Failed to get %s", key); + goto out; + } + cli_out ("%s" INDENT_MAIN_HEAD "%s", indent, + "Snap Volume Name", ":", get_buffer); + + ret = snprintf (key, sizeof (key), + "%s.origin-volname", keyprefix); + if (ret < 0) { + goto out; + } + + ret = dict_get_str (dict, key, &volname); + if (ret) { + gf_log ("cli", GF_LOG_WARNING, "Failed to get %s", key); + cli_out ("%-12s", "Origin:"); + } + cli_out ("%s" INDENT_MAIN_HEAD "%s", indent, + "Origin Volume name", ":", volname); + + + ret = snprintf (key, sizeof (key), "%s.snapcount", + keyprefix); + if (ret < 0) { + goto out; + } + + ret = dict_get_int32 (dict, key, &value); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Failed to get %s", key); + goto out; + } + cli_out ("%s%s %s %s %d", indent, "Snaps taken for", + volname, ":", value); + + ret = snprintf (key, sizeof (key), "%s.snaps-available", + keyprefix); + if (ret < 0) { + goto out; + } + + ret = dict_get_int32 (dict, key, &value); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Failed to get %s", key); + goto out; + } + cli_out ("%s%s %s %s %d", indent, "Snaps available for", + volname, ":", value); + } + + + ret = snprintf (key, sizeof (key), "%s.vol-status", keyprefix); + if (ret < 0) { + goto out; + } + + ret = dict_get_str (dict, key, &get_buffer); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Failed to get %s", key); + goto out; + } + cli_out ("%s" INDENT_MAIN_HEAD "%s", indent, "Status", + ":", get_buffer); +out : + return ret; +} + +/* This function is used to print snap related information + * arg - 0, dict : Response dictionary. + * arg - 1, prefix_str : snaplist.snap{0..}.* + */ +int +cli_get_volinfo_in_snap (dict_t *dict, char *keyprefix) { + + char key[PATH_MAX] = ""; + int i = 0; + int volcount = 0; + int ret = -1; + + GF_ASSERT (dict); + GF_ASSERT (keyprefix); + + ret = snprintf (key, sizeof (key), "%s.vol-count", keyprefix); + if (ret < 0) { + goto out; + } + + ret = dict_get_int32 (dict, key, &volcount); + for (i = 1 ; i <= volcount ; i++) { + ret = snprintf (key, sizeof (key), + "%s.vol%d", keyprefix, i); + if (ret < 0) { + goto out; + } + ret = cli_get_each_volinfo_in_snap (dict, key, _gf_true); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Could not list " + "details of volume in a snap"); + goto out; + } + cli_out (" "); + } + +out : + return ret; +} + +int +cli_get_each_snap_info (dict_t *dict, char *prefix_str, + gf_boolean_t snap_driven) { + char key_buffer[PATH_MAX] = ""; + char *get_buffer = NULL; + int ret = -1; + char indent[5] = ""; + + GF_ASSERT (dict); + GF_ASSERT (prefix_str); + + if (!snap_driven) + strcat (indent, "\t"); + + ret = snprintf (key_buffer, sizeof (key_buffer), "%s.snapname", + prefix_str); + if (ret < 0 ) { + goto out; + } + + ret = dict_get_str (dict, key_buffer, &get_buffer); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Unable to fetch snapname %s ", + key_buffer); + goto out; + } + cli_out ("%s" INDENT_MAIN_HEAD "%s", indent, "Snapshot", + ":", get_buffer); + + ret = snprintf (key_buffer, sizeof (key_buffer), "%s.snap-id", + prefix_str); + if (ret < 0 ) { + goto out; + } + + ret = dict_get_str (dict, key_buffer, &get_buffer); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Unable to fetch snap-id %s ", + key_buffer); + goto out; + } + cli_out ("%s" INDENT_MAIN_HEAD "%s", indent, "Snap UUID", + ":", get_buffer); + + ret = snprintf (key_buffer, sizeof (key_buffer), "%s.snap-desc", + prefix_str); + if (ret < 0 ) { + goto out; + } + + ret = dict_get_str (dict, key_buffer, &get_buffer); + if (!ret) { + /* Ignore error for description */ + cli_out ("%s" INDENT_MAIN_HEAD "%s", indent, + "Description", ":", get_buffer); + } + + ret = snprintf (key_buffer, sizeof (key_buffer), "%s.snap-time", + prefix_str); + if (ret < 0 ) { + goto out; + } + + ret = dict_get_str (dict, key_buffer, &get_buffer); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Unable to fetch snap-time %s ", + prefix_str); + goto out; + } + cli_out ("%s" INDENT_MAIN_HEAD "%s", indent, "Created", + ":", get_buffer); + + if (snap_driven) { + cli_out ("%-12s", "Snap Volumes:\n"); + ret = cli_get_volinfo_in_snap (dict, prefix_str); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Unable to list details " + "of the snaps"); + goto out; + } + } +out : + return ret; +} + +/* This is a generic function to print snap related information. + * arg - 0, dict : Response Dictionary + */ +int +cli_call_snapshot_info (dict_t *dict, gf_boolean_t bool_snap_driven) { + int snap_count = 0; + char key[PATH_MAX] = ""; + int ret = -1; + int i = 0; + + GF_ASSERT (dict); + + ret = dict_get_int32 (dict, "snap-count", &snap_count); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Unable to get snap-count"); + goto out; + } + + if (snap_count == 0) { + cli_out ("No snapshots present"); + } + + for (i = 1 ; i <= snap_count ; i++) { + ret = snprintf (key, sizeof (key), "snap%d", i); + if (ret < 0) { + goto out; + } + ret = cli_get_each_snap_info (dict, key, bool_snap_driven); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, + "Unable to print snap details"); + goto out; + } + } +out : + return ret; +} + +int +cli_get_snaps_in_volume (dict_t *dict) { + int ret = -1; + int i = 0; + int count = 0; + int avail = 0; + char key[PATH_MAX] = ""; + char *get_buffer = NULL; + + GF_ASSERT (dict); + + ret = dict_get_str (dict, "origin-volname", &get_buffer); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Could not fetch origin-volname"); + goto out; + } + cli_out (INDENT_MAIN_HEAD "%s", "Volume Name", ":", get_buffer); + + ret = dict_get_int32 (dict, "snap-count", &avail); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Could not fetch snap-count"); + goto out; + } + cli_out (INDENT_MAIN_HEAD "%d", "Snaps Taken", ":", avail); + + ret = dict_get_int32 (dict, "snaps-available", &count); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Could not fetch snaps-available"); + goto out; + } + cli_out (INDENT_MAIN_HEAD "%d", "Snaps Available", ":", count); + + for (i = 1 ; i <= avail ; i++) { + snprintf (key, sizeof (key), "snap%d", i); + ret = cli_get_each_snap_info (dict, key, _gf_false); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, + "Unable to print snap details"); + goto out; + } + + ret = snprintf (key, sizeof (key), "snap%d.vol1", i); + if (ret < 0) { + goto out; + } + ret = cli_get_each_volinfo_in_snap (dict, key, _gf_false); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Could not get volume " + "related information"); + goto out; + } + + cli_out (" "); + } +out : + return ret; +} + +int +cli_snapshot_list (dict_t *dict) { + int snapcount = 0; + char key[PATH_MAX] = ""; + int ret = -1; + int i = 0; + char *get_buffer = NULL; + + GF_ASSERT (dict); + + ret = dict_get_int32 (dict, "snap-count", &snapcount); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Could not fetch snap count"); + goto out; + } + + if (snapcount == 0) { + cli_out ("No snapshots present"); + } + + for (i = 1 ; i <= snapcount ; i++) { + ret = snprintf (key, sizeof (key), "snapname%d",i); + if (ret < 0) { + goto out; + } + + ret = dict_get_str (dict, key, &get_buffer); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Could not get %s ", key); + goto out; + } else { + cli_out ("%s", get_buffer); + } + } +out : + return ret; +} + +int +cli_get_snap_volume_status (dict_t *dict, char *key_prefix) +{ + int ret = -1; + char key[PATH_MAX] = ""; + char *buffer = NULL; + int brickcount = 0; + int i = 0; + int pid = 0; + + GF_ASSERT (dict); + GF_ASSERT (key_prefix); + + ret = snprintf (key, sizeof (key), "%s.brickcount", key_prefix); + if (ret < 0) { + goto out; + } + ret = dict_get_int32 (dict, key, &brickcount); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Failed to fetch brickcount"); + goto out; + } + + for ( i = 0 ; i < brickcount ; i++ ) { + ret = snprintf (key, sizeof (key), "%s.brick%d.path", + key_prefix, i); + if (ret < 0) { + goto out; + } + + ret = dict_get_str (dict, key, &buffer); + if (ret) { + gf_log ("cli", GF_LOG_INFO, + "Unable to get Brick Path"); + continue; + } + cli_out ("\n\t%-17s %s %s", "Brick Path", ":", buffer); + + ret = snprintf (key, sizeof (key), "%s.brick%d.vgname", + key_prefix, i); + if (ret < 0) { + goto out; + } + + ret = dict_get_str (dict, key, &buffer); + if (ret) { + gf_log ("cli", GF_LOG_INFO, + "Unable to get Volume Group"); + cli_out ("\t%-17s %s %s", "Volume Group", ":", "N/A"); + } else + cli_out ("\t%-17s %s %s", "Volume Group", ":", buffer); + + ret = snprintf (key, sizeof (key), "%s.brick%d.status", + key_prefix, i); + if (ret < 0) { + goto out; + } + + ret = dict_get_str (dict, key, &buffer); + if (ret) { + gf_log ("cli", GF_LOG_INFO, + "Unable to get Brick Running"); + cli_out ("\t%-17s %s %s", "Brick Running", ":", "N/A"); + } else + cli_out ("\t%-17s %s %s", "Brick Running", ":", buffer); + + ret = snprintf (key, sizeof (key), "%s.brick%d.pid", + key_prefix, i); + if (ret < 0) { + goto out; + } + + ret = dict_get_int32 (dict, key, &pid); + if (ret) { + gf_log ("cli", GF_LOG_INFO, + "Unable to get pid"); + cli_out ("\t%-17s %s %s", "Brick PID", ":", "N/A"); + } else + cli_out ("\t%-17s %s %d", "Brick PID", ":", pid); + + ret = snprintf (key, sizeof (key), "%s.brick%d.data", + key_prefix, i); + if (ret < 0) { + goto out; + } + + ret = dict_get_str (dict, key, &buffer); + if (ret) { + gf_log ("cli", GF_LOG_INFO, + "Unable to get Data Percent"); + cli_out ("\t%-17s %s %s", "Data Percentage", ":", "N/A"); + } else + cli_out ("\t%-17s %s %s", "Data Percentage", ":", buffer); + + ret = snprintf (key, sizeof (key), "%s.brick%d.lvsize", + key_prefix, i); + if (ret < 0) { + goto out; + } + ret = dict_get_str (dict, key, &buffer); + if (ret) { + gf_log ("cli", GF_LOG_INFO, "Unable to get LV Size"); + cli_out ("\t%-17s %s %s", "LV Size", ":", "N/A"); + } else + cli_out ("\t%-17s %s %s", "LV Size", ":", buffer); + + } +out : + return ret; +} + + + +int +cli_get_single_snap_status (dict_t *dict, char *keyprefix) +{ + int ret = -1; + char key[PATH_MAX] = ""; + int i = 0; + int volcount = 0; + char *get_buffer = NULL; + + GF_ASSERT (dict); + GF_ASSERT (keyprefix); + + ret = snprintf (key, sizeof (key), "%s.snapname", keyprefix); + if (ret < 0) { + goto out; + } + + ret = dict_get_str (dict, key, &get_buffer); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Unable to get snapname"); + goto out; + } + cli_out ("\nSnap Name : %s", get_buffer); + + ret = snprintf (key, sizeof (key), "%s.uuid", keyprefix); + if (ret < 0) { + goto out; + } + + ret = dict_get_str (dict, key, &get_buffer); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Unable to get snap UUID"); + goto out; + } + cli_out ("Snap UUID : %s", get_buffer); + + ret = snprintf (key, sizeof (key), "%s.volcount", keyprefix); + if (ret < 0) { + goto out; + } + + ret = dict_get_int32 (dict, key, &volcount); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Unable to get volume count"); + goto out; + } + + for (i = 0 ; i < volcount ; i++) { + ret = snprintf (key, sizeof (key), "%s.vol%d", keyprefix, i); + if (ret < 0) { + goto out; + } + + ret = cli_get_snap_volume_status (dict, key); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, + "Could not get snap volume status"); + goto out; + } + } +out : + return ret; +} + +int +cli_snap_status_all (dict_t *dict) { + int ret = -1; + char key[PATH_MAX] = ""; + int snapcount = 0; + int i = 0; + + GF_ASSERT (dict); + + ret = dict_get_int32 (dict, "status.snapcount", &snapcount); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Could not get snapcount"); + goto out; + } + + if (snapcount == 0) { + cli_out ("No snapshots present"); + } + + for (i = 0 ; i < snapcount; i++) { + ret = snprintf (key, sizeof (key), "status.snap%d",i); + if (ret < 0) { + goto out; + } + ret = cli_get_single_snap_status (dict, key); + } +out: + return ret; +} + + +int +cli_snapshot_status_display (dict_t *dict, gf_cli_rsp *rsp) +{ + char key[PATH_MAX] = ""; + int ret = -1; + int status_cmd = -1; + + GF_ASSERT (dict); + GF_ASSERT (rsp); + + if (rsp->op_ret) { + cli_err ("Snapshot Status : failed: %s", + rsp->op_errstr ? rsp->op_errstr : + "Please check log file for details"); + ret = rsp->op_ret; + goto out; + } + + ret = dict_get_int32 (dict, "cmd", &status_cmd); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Could not fetch status type"); + goto out; + } + switch (status_cmd) { + case GF_SNAP_STATUS_TYPE_ALL : + { + ret = cli_snap_status_all (dict); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Could not fetch " + "status of all snap"); + goto out; + } + break; + } + + case GF_SNAP_STATUS_TYPE_SNAP : + { + ret = snprintf (key, sizeof (key), "status.snap0"); + if (ret < 0) { + goto out; + } + ret = cli_get_single_snap_status (dict, key); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Could not fetch " + "status of snap"); + goto out; + } + break; + } + + case GF_SNAP_STATUS_TYPE_VOL : + { + ret = cli_snap_status_all (dict); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Could not fetch " + "status of snap in a volume"); + goto out; + } + break; + } + default : + break; + } +out : + return ret; +} + +int +gf_cli_snapshot_cbk (struct rpc_req *req, struct iovec *iov, + int count, void *myframe) +{ + int ret = -1; + gf_cli_rsp rsp = {0, }; + dict_t *dict = NULL; + char *snap_name = NULL; + int32_t type = 0; + call_frame_t *frame = NULL; + gf_boolean_t snap_driven = _gf_false; + + if (req->rpc_status == -1) { + ret = -1; + goto out; + } + + frame = myframe; + + ret = xdr_to_generic (*iov, &rsp, (xdrproc_t)xdr_gf_cli_rsp); + if (ret < 0) { + gf_log (frame->this->name, GF_LOG_ERROR, + "Failed to decode xdr response"); + goto out; + } + + dict = dict_new (); + + if (!dict) { + ret = -1; + goto out; + } + + ret = dict_unserialize (rsp.dict.dict_val, rsp.dict.dict_len, &dict); + + if (ret) + goto out; + + ret = dict_get_int32 (dict, "type", &type); + if (ret) { + gf_log (frame->this->name, GF_LOG_ERROR, "failed to get type"); + goto out; + } + + switch (type) { + case GF_SNAP_OPTION_TYPE_CREATE: + if (rsp.op_ret) { + cli_err("snapshot create: failed: %s", + rsp.op_errstr ? rsp.op_errstr : + "Please check log file for details"); + ret = rsp.op_ret; + goto out; + } + + ret = dict_get_str (dict, "snapname", &snap_name); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, + "Failed to get snap name"); + goto out; + } + cli_out ("snapshot create: %s: snap created successfully", + snap_name); + break; + + case GF_SNAP_OPTION_TYPE_RESTORE: + /* TODO: Check if rsp.op_ret needs to be checked here. Or is + * it ok to check this in the start of the function where we + * get rsp.*/ + if (rsp.op_ret) { + cli_err("snapshot restore: failed: %s", + rsp.op_errstr ? rsp.op_errstr : + "Please check log file for details"); + ret = rsp.op_ret; + goto out; + } + + ret = dict_get_str (dict, "snapname", &snap_name); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, + "Failed to get snap name"); + goto out; + } + + cli_out ("Snapshot restore: %s: Snap restored " + "successfully", snap_name); + + ret = 0; + break; + + case GF_SNAP_OPTION_TYPE_INFO: + if (rsp.op_ret) { + cli_err ("Snapshot info : failed: %s", + rsp.op_errstr ? rsp.op_errstr : + "Please check log file for details"); + ret = rsp.op_ret; + goto out; + } + + snap_driven = dict_get_str_boolean (dict, "snap-driven", + _gf_false); + if (snap_driven == _gf_true) { + ret = cli_call_snapshot_info (dict, snap_driven); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, + "Snapshot info failed"); + goto out; + } + } else if (snap_driven == _gf_false) { + ret = cli_get_snaps_in_volume (dict); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, + "Snapshot info failed"); + goto out; + } + } + break; + + case GF_SNAP_OPTION_TYPE_CONFIG: + ret = cli_snapshot_config_display (dict, &rsp); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Failed to display " + "snapshot config output."); + goto out; + } + break; + + case GF_SNAP_OPTION_TYPE_LIST: + if (rsp.op_ret) { + cli_err ("Snapshot list : failed: %s", + rsp.op_errstr ? rsp.op_errstr : + "Please check log file for details"); + ret = rsp.op_ret; + goto out; + } + + ret = cli_snapshot_list (dict); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Failed to display " + "snapshot list"); + goto out; + } + break; + + case GF_SNAP_OPTION_TYPE_DELETE: + ret = cli_snapshot_remove_reply (&rsp, dict, frame); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, + "Failed to delete snap"); + goto out; + } + break; + + case GF_SNAP_OPTION_TYPE_STATUS: + ret = cli_snapshot_status_display (dict, &rsp); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Failed to display " + "snapshot status output."); + goto out; + } + break; + + default: + cli_err ("Unknown command executed"); + ret = -1; + goto out; + } +out: + if (dict) + dict_unref (dict); + cli_cmd_broadcast_response (ret); + + free (rsp.dict.dict_val); + free (rsp.op_errstr); + + return ret; +} + +int32_t +gf_cli_snapshot (call_frame_t *frame, xlator_t *this, + void *data) +{ + gf_cli_req req = {{0,}}; + dict_t *options = NULL; + int ret = -1; + + if (!frame || !this || !data) + goto out; + + options = data; + + ret = cli_to_glusterd (&req, frame, gf_cli_snapshot_cbk, + (xdrproc_t) xdr_gf_cli_req, options, + GLUSTER_CLI_SNAP, this, cli_rpc_prog, + NULL); +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + + GF_FREE (req.dict.dict_val); + return ret; +} + +int +cli_to_glusterd (gf_cli_req *req, call_frame_t *frame, + fop_cbk_fn_t cbkfn, xdrproc_t xdrproc, dict_t *dict, + int procnum, xlator_t *this, rpc_clnt_prog_t *prog, + struct iobref *iobref) +{ + int ret = 0; + size_t len = 0; + char *cmd = NULL; + int i = 0; + const char **words = NULL; + cli_local_t *local = NULL; + + if (!this || !frame || !dict) { + ret = -1; + goto out; + } + + if (!frame->local) { + ret = -1; + goto out; + } + + local = frame->local; + + if (!local->words) { + ret = -1; + goto out; + } + + words = local->words; + + while (words[i]) + len += strlen (words[i++]) + 1; + + cmd = GF_CALLOC (1, len, gf_common_mt_char); + + if (!cmd) { + ret = -1; + goto out; + } + + for (i = 0; words[i]; i++) { + strncat (cmd, words[i], strlen (words[i])); + if (words[i+1] != NULL) + strncat (cmd, " ", strlen (" ")); + } + + cmd [len - 1] = '\0'; + + ret = dict_set_dynstr (dict, "cmd-str", cmd); + if (ret) + goto out; + + ret = dict_allocate_and_serialize (dict, &(req->dict).dict_val, + &(req->dict).dict_len); + + if (ret < 0) { + gf_log (this->name, GF_LOG_DEBUG, + "failed to get serialized length of dict"); + goto out; + } + + ret = cli_cmd_submit (req, frame, prog, procnum, iobref, this, + cbkfn, (xdrproc_t) xdrproc); + +out: + return ret; + +} + +struct rpc_clnt_procedure gluster_cli_actors[GLUSTER_CLI_MAXVALUE] = { + [GLUSTER_CLI_NULL] = {"NULL", NULL }, + [GLUSTER_CLI_PROBE] = {"PROBE_QUERY", gf_cli_probe}, + [GLUSTER_CLI_DEPROBE] = {"DEPROBE_QUERY", gf_cli_deprobe}, + [GLUSTER_CLI_LIST_FRIENDS] = {"LIST_FRIENDS", gf_cli_list_friends}, + [GLUSTER_CLI_UUID_RESET] = {"UUID_RESET", gf_cli3_1_uuid_reset}, + [GLUSTER_CLI_UUID_GET] = {"UUID_GET", gf_cli3_1_uuid_get}, + [GLUSTER_CLI_CREATE_VOLUME] = {"CREATE_VOLUME", gf_cli_create_volume}, + [GLUSTER_CLI_DELETE_VOLUME] = {"DELETE_VOLUME", gf_cli_delete_volume}, + [GLUSTER_CLI_START_VOLUME] = {"START_VOLUME", gf_cli_start_volume}, + [GLUSTER_CLI_STOP_VOLUME] = {"STOP_VOLUME", gf_cli_stop_volume}, + [GLUSTER_CLI_RENAME_VOLUME] = {"RENAME_VOLUME", gf_cli_rename_volume}, + [GLUSTER_CLI_DEFRAG_VOLUME] = {"DEFRAG_VOLUME", gf_cli_defrag_volume}, + [GLUSTER_CLI_GET_VOLUME] = {"GET_VOLUME", gf_cli_get_volume}, + [GLUSTER_CLI_GET_NEXT_VOLUME] = {"GET_NEXT_VOLUME", gf_cli_get_next_volume}, + [GLUSTER_CLI_SET_VOLUME] = {"SET_VOLUME", gf_cli_set_volume}, + [GLUSTER_CLI_ADD_BRICK] = {"ADD_BRICK", gf_cli_add_brick}, + [GLUSTER_CLI_REMOVE_BRICK] = {"REMOVE_BRICK", gf_cli_remove_brick}, + [GLUSTER_CLI_REPLACE_BRICK] = {"REPLACE_BRICK", gf_cli_replace_brick}, + [GLUSTER_CLI_LOG_ROTATE] = {"LOG ROTATE", gf_cli_log_rotate}, + [GLUSTER_CLI_GETSPEC] = {"GETSPEC", gf_cli_getspec}, + [GLUSTER_CLI_PMAP_PORTBYBRICK] = {"PMAP PORTBYBRICK", gf_cli_pmap_b2p}, + [GLUSTER_CLI_SYNC_VOLUME] = {"SYNC_VOLUME", gf_cli_sync_volume}, + [GLUSTER_CLI_RESET_VOLUME] = {"RESET_VOLUME", gf_cli_reset_volume}, + [GLUSTER_CLI_FSM_LOG] = {"FSM_LOG", gf_cli_fsm_log}, + [GLUSTER_CLI_GSYNC_SET] = {"GSYNC_SET", gf_cli_gsync_set}, + [GLUSTER_CLI_PROFILE_VOLUME] = {"PROFILE_VOLUME", gf_cli_profile_volume}, + [GLUSTER_CLI_QUOTA] = {"QUOTA", gf_cli_quota}, + [GLUSTER_CLI_TOP_VOLUME] = {"TOP_VOLUME", gf_cli_top_volume}, + [GLUSTER_CLI_GETWD] = {"GETWD", gf_cli_getwd}, + [GLUSTER_CLI_STATUS_VOLUME] = {"STATUS_VOLUME", gf_cli_status_volume}, + [GLUSTER_CLI_STATUS_ALL] = {"STATUS_ALL", gf_cli_status_volume_all}, + [GLUSTER_CLI_MOUNT] = {"MOUNT", gf_cli_mount}, + [GLUSTER_CLI_UMOUNT] = {"UMOUNT", gf_cli_umount}, + [GLUSTER_CLI_HEAL_VOLUME] = {"HEAL_VOLUME", gf_cli_heal_volume}, + [GLUSTER_CLI_STATEDUMP_VOLUME] = {"STATEDUMP_VOLUME", gf_cli_statedump_volume}, + [GLUSTER_CLI_LIST_VOLUME] = {"LIST_VOLUME", gf_cli_list_volume}, + [GLUSTER_CLI_CLRLOCKS_VOLUME] = {"CLEARLOCKS_VOLUME", gf_cli_clearlocks_volume}, + [GLUSTER_CLI_COPY_FILE] = {"COPY_FILE", gf_cli_copy_file}, + [GLUSTER_CLI_SYS_EXEC] = {"SYS_EXEC", gf_cli_sys_exec}, + [GLUSTER_CLI_SNAP] = {"SNAP", gf_cli_snapshot}, +}; + +struct rpc_clnt_program cli_prog = { + .progname = "Gluster CLI", + .prognum = GLUSTER_CLI_PROGRAM, + .progver = GLUSTER_CLI_VERSION, + .numproc = GLUSTER_CLI_MAXVALUE, + .proctable = gluster_cli_actors, +}; diff --git a/cli/src/cli-xml-output.c b/cli/src/cli-xml-output.c new file mode 100644 index 000000000..d8884d44b --- /dev/null +++ b/cli/src/cli-xml-output.c @@ -0,0 +1,3772 @@ +/* + Copyright (c) 2010-2012 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ +#include <stdlib.h> +#include "cli.h" +#include "cli1-xdr.h" +#include "run.h" +#include "compat.h" +#include "syscall.h" + + +enum gf_task_types { + GF_TASK_TYPE_REBALANCE, + GF_TASK_TYPE_REMOVE_BRICK +}; + +/* + * IMPORTANT NOTE: + * All exported functions in this file which use libxml need use a + * #if (HAVE_LIB_XML), #else, #endif + * For eg, + * int exported_func () { + * #if (HAVE_LIB_XML) + * <Stuff using libxml> + * #else + * return 0; + * #endif + * } + * + * All other functions, which are called internally within this file need to be + * within #if (HAVE_LIB_XML), #endif statements + * For eg, + * #if (HAVE_LIB_XML) + * int internal_func () + * { + * } + * #endif + * + * Following the above formate ensures that all xml related code is compliled + * only when libxml2 is present, and also keeps the rest of the codebase free + * of #if (HAVE_LIB_XML) + */ + + +#if (HAVE_LIB_XML) + +#include <libxml/encoding.h> +#include <libxml/xmlwriter.h> + +#define XML_RET_CHECK_AND_GOTO(ret, label) do { \ + if (ret < 0) { \ + ret = -1; \ + goto label; \ + } \ + else \ + ret = 0; \ + }while (0) \ + +int +cli_begin_xml_output (xmlTextWriterPtr *writer, xmlDocPtr *doc) +{ + int ret = -1; + + *writer = xmlNewTextWriterDoc (doc, 0); + if (writer == NULL) { + ret = -1; + goto out; + } + + ret = xmlTextWriterStartDocument (*writer, "1.0", "UTF-8", "yes"); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* <cliOutput> */ + ret = xmlTextWriterStartElement (*writer, (xmlChar *)"cliOutput"); + XML_RET_CHECK_AND_GOTO (ret, out); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int +cli_end_xml_output (xmlTextWriterPtr writer, xmlDocPtr doc) +{ + int ret = -1; + + /* </cliOutput> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterEndDocument (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + + + /* Dump xml document to stdout and pretty format it */ + xmlSaveFormatFileEnc ("-", doc, "UTF-8", 1); + + xmlFreeTextWriter (writer); + xmlFreeDoc (doc); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int +cli_xml_output_common (xmlTextWriterPtr writer, int op_ret, int op_errno, + char *op_errstr) +{ + int ret = -1; + + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"opRet", + "%d", op_ret); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"opErrno", + "%d", op_errno); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"opErrstr", + "%s", op_errstr); + XML_RET_CHECK_AND_GOTO (ret, out); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} +#endif + +int +cli_xml_output_str (char *op, char *str, int op_ret, int op_errno, + char *op_errstr) +{ +#if (HAVE_LIB_XML) + int ret = -1; + xmlTextWriterPtr writer = NULL; + xmlDocPtr doc = NULL; + + ret = cli_begin_xml_output (&writer, &doc); + if (ret) + goto out; + + ret = cli_xml_output_common (writer, op_ret, op_errno, op_errstr); + if (ret) + goto out; + + if (op) { + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"cliOp", + "%s", op); + XML_RET_CHECK_AND_GOTO (ret, out); + } + + if (str) { + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"output", + "%s", str); + XML_RET_CHECK_AND_GOTO (ret, out); + } + + ret = cli_end_xml_output (writer, doc); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +#else + return 0; +#endif +} + +#if (HAVE_LIB_XML) +int +cli_xml_output_data_pair (dict_t *this, char *key, data_t *value, + void *data) +{ + int ret = -1; + xmlTextWriterPtr *writer = NULL; + + writer = (xmlTextWriterPtr *)data; + + ret = xmlTextWriterWriteFormatElement (*writer, (xmlChar *)key, + "%s", value->data); + + return ret; +} +#endif + +int +cli_xml_output_dict ( char *op, dict_t *dict, int op_ret, int op_errno, + char *op_errstr) +{ +#if (HAVE_LIB_XML) + int ret = -1; + xmlTextWriterPtr writer = NULL; + xmlDocPtr doc = NULL; + + ret = cli_begin_xml_output (&writer, &doc); + if (ret) + goto out; + + ret = cli_xml_output_common (writer, op_ret, op_errno, op_errstr); + if (ret) + goto out; + + /* <"op"> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)op); + XML_RET_CHECK_AND_GOTO (ret, out); + + if (dict) + dict_foreach (dict, cli_xml_output_data_pair, &writer); + + /* </"op"> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = cli_end_xml_output (writer, doc); +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +#else + return 0; +#endif +} + +#if (HAVE_LIB_XML) +int +cli_xml_output_vol_status_common (xmlTextWriterPtr writer, dict_t *dict, + int brick_index, int *online, + gf_boolean_t *node_present) +{ + int ret = -1; + char *hostname = NULL; + char *path = NULL; + int port = 0; + int status = 0; + int pid = 0; + char key[1024] = {0,}; + + snprintf (key, sizeof (key), "brick%d.hostname", brick_index); + ret = dict_get_str (dict, key, &hostname); + if (ret) { + *node_present = _gf_false; + goto out; + } + *node_present = _gf_true; + + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"hostname", + "%s", hostname); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.path", brick_index); + ret = dict_get_str (dict, key, &path); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"path", + "%s", path); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.status", brick_index); + ret = dict_get_int32 (dict, key, &status); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"status", + "%d", status); + XML_RET_CHECK_AND_GOTO (ret, out); + *online = status; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.port", brick_index); + ret = dict_get_int32 (dict, key, &port); + if (ret) + goto out; + + /* If the process is either offline or doesn't provide a port (shd) + * port = "N/A" + * else print the port number of the process. + */ + + if (*online == 1 && port != 0) + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"port", + "%d", port); + else + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"port", + "%s", "N/A"); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.pid", brick_index); + ret = dict_get_int32 (dict, key, &pid); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"pid", + "%d", pid); + XML_RET_CHECK_AND_GOTO (ret, out); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int +cli_xml_output_vol_status_detail (xmlTextWriterPtr writer, dict_t *dict, + int brick_index) +{ + int ret = -1; + uint64_t size_total = 0; + uint64_t size_free = 0; + char *device = NULL; + uint64_t block_size = 0; + char *mnt_options = NULL; + char *fs_name = NULL; + char *inode_size = NULL; + uint64_t inodes_total = 0; + uint64_t inodes_free = 0; + char key[1024] = {0,}; + + snprintf (key, sizeof (key), "brick%d.total", brick_index); + ret = dict_get_uint64 (dict, key, &size_total); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"sizeTotal", + "%"PRIu64, size_total); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.free", brick_index); + ret = dict_get_uint64 (dict, key, &size_free); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"sizeFree", + "%"PRIu64, size_free); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.device", brick_index); + ret = dict_get_str (dict, key, &device); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"device", + "%s", device); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.block_size", brick_index); + ret = dict_get_uint64 (dict, key, &block_size); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"blockSize", + "%"PRIu64, block_size); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.mnt_options", brick_index); + ret = dict_get_str (dict, key, &mnt_options); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"mntOptions", + "%s", mnt_options); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.fs_name", brick_index); + ret = dict_get_str (dict, key, &fs_name); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"fsName", + "%s", fs_name); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* inode details are only available for ext 2/3/4 & xfs */ + if (!IS_EXT_FS(fs_name) || strcmp (fs_name, "xfs")) { + ret = 0; + goto out; + } + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.inode_size", brick_index); + ret = dict_get_str (dict, key, &inode_size); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"inodeSize", + "%s", fs_name); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.total_inodes", brick_index); + ret = dict_get_uint64 (dict, key, &inodes_total); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"inodesTotal", + "%"PRIu64, inodes_total); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.free_inodes", brick_index); + ret = dict_get_uint64 (dict, key, &inodes_free); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"inodesFree", + "%"PRIu64, inodes_free); + XML_RET_CHECK_AND_GOTO (ret, out); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int +cli_xml_output_vol_status_mempool (xmlTextWriterPtr writer, dict_t *dict, + char *prefix) +{ + int ret = -1; + int mempool_count = 0; + char *name = NULL; + int hotcount = 0; + int coldcount = 0; + uint64_t paddedsizeof = 0; + uint64_t alloccount = 0; + int maxalloc = 0; + char key[1024] = {0,}; + int i = 0; + + /* <mempool> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"mempool"); + XML_RET_CHECK_AND_GOTO (ret, out); + + snprintf (key, sizeof (key), "%s.mempool-count", prefix); + ret = dict_get_int32 (dict, key, &mempool_count); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"count", + "%d", mempool_count); + XML_RET_CHECK_AND_GOTO (ret, out); + + for (i = 0; i < mempool_count; i++) { + /* <pool> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"pool"); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.pool%d.name", prefix, i); + ret = dict_get_str (dict, key, &name); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"name", + "%s", name); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.pool%d.hotcount", prefix, i); + ret = dict_get_int32 (dict, key, &hotcount); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"hotCount", + "%d", hotcount); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.pool%d.coldcount", prefix, i); + ret = dict_get_int32 (dict, key, &coldcount); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"coldCount", + "%d", coldcount); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.pool%d.paddedsizeof", + prefix, i); + ret = dict_get_uint64 (dict, key, &paddedsizeof); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement + (writer, (xmlChar *)"padddedSizeOf", "%"PRIu64, + paddedsizeof); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.pool%d.alloccount", prefix, i); + ret = dict_get_uint64 (dict, key, &alloccount); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"allocCount", + "%"PRIu64, alloccount); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.pool%d.max_alloc", prefix, i); + ret = dict_get_int32 (dict, key, &maxalloc); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"maxAlloc", + "%d", maxalloc); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.pool%d.pool-misses", prefix, i); + ret = dict_get_uint64 (dict, key, &alloccount); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"poolMisses", + "%"PRIu64, alloccount); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.pool%d.max-stdalloc", prefix, i); + ret = dict_get_int32 (dict, key, &maxalloc); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"maxStdAlloc", + "%d", maxalloc); + XML_RET_CHECK_AND_GOTO (ret, out); + + + /* </pool> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + } + + /* </mempool> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int +cli_xml_output_vol_status_mem (xmlTextWriterPtr writer, dict_t *dict, + int brick_index) +{ + int ret = -1; + int arena = 0; + int ordblks = 0; + int smblks = 0; + int hblks = 0; + int hblkhd = 0; + int usmblks = 0; + int fsmblks = 0; + int uordblks = 0; + int fordblks = 0; + int keepcost = 0; + char key[1024] = {0,}; + + /* <memStatus> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"memStatus"); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* <mallinfo> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"mallinfo"); + XML_RET_CHECK_AND_GOTO (ret, out); + + snprintf (key, sizeof (key), "brick%d.mallinfo.arena", brick_index); + ret = dict_get_int32 (dict, key, &arena); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"arena", + "%d", arena); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.mallinfo.ordblks", brick_index); + ret = dict_get_int32 (dict, key, &ordblks); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"ordblks", + "%d", ordblks); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.mallinfo.smblks", brick_index); + ret = dict_get_int32 (dict, key, &smblks); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"smblks", + "%d", smblks); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.mallinfo.hblks", brick_index); + ret = dict_get_int32 (dict, key, &hblks); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"hblks", + "%d", hblks); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.mallinfo.hblkhd", brick_index); + ret = dict_get_int32 (dict, key, &hblkhd); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"hblkhd", + "%d", hblkhd); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.mallinfo.usmblks", brick_index); + ret = dict_get_int32 (dict, key, &usmblks); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"usmblks", + "%d", usmblks); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.mallinfo.fsmblks", brick_index); + ret = dict_get_int32 (dict, key, &fsmblks); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"fsmblks", + "%d", fsmblks); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.mallinfo.uordblks", brick_index); + ret = dict_get_int32 (dict, key, &uordblks); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"uordblks", + "%d", uordblks); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.mallinfo.fordblks", brick_index); + ret = dict_get_int32 (dict, key, &fordblks); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"fordblks", + "%d", fordblks); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.mallinfo.keepcost", brick_index); + ret = dict_get_int32 (dict, key, &keepcost); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"keepcost", + "%d", keepcost); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* </mallinfo> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d", brick_index); + ret = cli_xml_output_vol_status_mempool (writer, dict, key); + if (ret) + goto out; + + /* </memStatus> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int +cli_xml_output_vol_status_clients (xmlTextWriterPtr writer, dict_t *dict, + int brick_index) +{ + int ret = -1; + int client_count = 0; + char *hostname = NULL; + uint64_t bytes_read = 0; + uint64_t bytes_write = 0; + char key[1024] = {0,}; + int i = 0; + + /* <clientsStatus> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"clientsStatus"); + XML_RET_CHECK_AND_GOTO (ret, out); + + snprintf (key, sizeof (key), "brick%d.clientcount", brick_index); + ret = dict_get_int32 (dict, key, &client_count); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"clientCount", + "%d", client_count); + XML_RET_CHECK_AND_GOTO (ret, out); + + for (i = 0; i < client_count; i++) { + /* <client> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"client"); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.client%d.hostname", + brick_index, i); + ret = dict_get_str (dict, key, &hostname); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"hostname", + "%s", hostname); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.client%d.bytesread", + brick_index, i); + ret = dict_get_uint64 (dict, key, &bytes_read); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"bytesRead", + "%"PRIu64, bytes_read); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.client%d.byteswrite", + brick_index, i); + ret = dict_get_uint64 (dict, key, &bytes_write); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"bytesWrite", + "%"PRIu64, bytes_write); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* </client> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + } + + /* </clientsStatus> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int +cli_xml_output_vol_status_inode_entry (xmlTextWriterPtr writer, dict_t *dict, + char *prefix) +{ + int ret = -1; + char *gfid = NULL; + uint64_t nlookup = 0; + uint32_t ref = 0; + int ia_type = 0; + char key[1024] = {0,}; + + /* <inode> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"inode"); + XML_RET_CHECK_AND_GOTO (ret, out); + + snprintf (key, sizeof (key), "%s.gfid", prefix); + ret = dict_get_str (dict, key, &gfid); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"gfid", + "%s", gfid); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key,0, sizeof (key)); + snprintf (key, sizeof (key), "%s.nlookup", prefix); + ret = dict_get_uint64 (dict, key, &nlookup); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"nLookup", + "%"PRIu64, nlookup); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key,0, sizeof (key)); + snprintf (key, sizeof (key), "%s.ref", prefix); + ret = dict_get_uint32 (dict, key, &ref); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"ref", + "%"PRIu32, ref); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key,0, sizeof (key)); + snprintf (key, sizeof (key), "%s.ia_type", prefix); + ret = dict_get_int32 (dict, key, &ia_type); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"iaType", + "%d", ia_type); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* </inode> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int +cli_xml_output_vol_status_itable (xmlTextWriterPtr writer, dict_t *dict, + char *prefix) +{ + int ret = -1; + uint32_t active_size = 0; + uint32_t lru_size = 0; + uint32_t purge_size = 0; + char key[1024] = {0,}; + int i = 0; + + snprintf (key, sizeof (key), "%s.active_size", prefix); + ret = dict_get_uint32 (dict, key, &active_size); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"activeSize", + "%"PRIu32, active_size); + XML_RET_CHECK_AND_GOTO (ret, out); + if (active_size != 0) { + /* <active> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"active"); + XML_RET_CHECK_AND_GOTO (ret, out); + + for (i = 0; i < active_size; i++) { + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.active%d", prefix, i); + ret = cli_xml_output_vol_status_inode_entry + (writer, dict, key); + if (ret) + goto out; + } + /* </active> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + } + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.lru_size", prefix); + ret = dict_get_uint32 (dict, key, &lru_size); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"lruSize", + "%"PRIu32, lru_size); + XML_RET_CHECK_AND_GOTO (ret, out); + if (lru_size != 0) { + /* <lru> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"lru"); + XML_RET_CHECK_AND_GOTO (ret, out); + + for (i = 0; i < lru_size; i++) { + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.lru%d", prefix, i); + ret = cli_xml_output_vol_status_inode_entry + (writer, dict, key); + if (ret) + goto out; + } + /* </lru> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + } + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.purge_size", prefix); + ret = dict_get_uint32 (dict, key, &purge_size); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"purgeSize", + "%"PRIu32, purge_size); + XML_RET_CHECK_AND_GOTO (ret, out); + if (purge_size != 0) { + /* <purge> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"purge"); + XML_RET_CHECK_AND_GOTO (ret, out); + + for (i = 0; i < purge_size; i++) { + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.purge%d", prefix, i); + ret = cli_xml_output_vol_status_inode_entry + (writer, dict, key); + if (ret) + goto out; + } + /* </purge> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + } + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int +cli_xml_output_vol_status_inode (xmlTextWriterPtr writer, dict_t *dict, + int brick_index) +{ + int ret = -1; + int conn_count = 0; + char key[1024] = {0,}; + int i = 0; + + /* <inodeStatus> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"inodeStatus"); + XML_RET_CHECK_AND_GOTO (ret, out); + + snprintf (key, sizeof (key), "brick%d.conncount", brick_index); + ret = dict_get_int32 (dict, key, &conn_count); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"connections", + "%d", conn_count); + XML_RET_CHECK_AND_GOTO (ret, out); + + for (i = 0; i < conn_count; i++) { + /* <connection> */ + ret = xmlTextWriterStartElement (writer, + (xmlChar *)"connection"); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.conn%d.itable", + brick_index, i); + ret = cli_xml_output_vol_status_itable (writer, dict, key); + if (ret) + goto out; + + /* </connection> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + } + + /* </inodeStatus> */ + ret= xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int +cli_xml_output_vol_status_fdtable (xmlTextWriterPtr writer, dict_t *dict, + char *prefix) +{ + int ret = -1; + int refcount = 0; + uint32_t maxfds = 0; + int firstfree = 0; + int openfds = 0; + int fd_pid = 0; + int fd_refcount = 0; + int fd_flags = 0; + char key[1024] = {0,}; + int i = 0; + + /* <fdTable> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"fdTable"); + XML_RET_CHECK_AND_GOTO (ret, out); + + snprintf (key, sizeof (key), "%s.refcount", prefix); + ret = dict_get_int32 (dict, key, &refcount); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"refCount", + "%d", refcount); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.maxfds", prefix); + ret = dict_get_uint32 (dict, key, &maxfds); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"maxFds", + "%"PRIu32, maxfds); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.firstfree", prefix); + ret = dict_get_int32 (dict, key, &firstfree); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"firstFree", + "%d", firstfree); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.openfds", prefix); + ret = dict_get_int32 (dict, key, &openfds); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"openFds", + "%d", openfds); + XML_RET_CHECK_AND_GOTO (ret, out); + + for (i = 0; i < maxfds; i++) { + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.fdentry%d.pid", prefix, i); + ret = dict_get_int32 (dict, key, &fd_pid); + if (ret) + continue; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.fdentry%d.refcount", + prefix, i); + ret = dict_get_int32 (dict, key, &fd_refcount); + if (ret) + continue; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.fdentry%d.flags", prefix, i); + ret = dict_get_int32 (dict, key, &fd_flags); + if (ret) + continue; + + /* <fd> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"fd"); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"entry", + "%d", i+1); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"pid", + "%d", fd_pid); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"refCount", + "%d", fd_refcount); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"flags", + "%d", fd_flags); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* </fd> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + } + + /* </fdTable> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int +cli_xml_output_vol_status_fd (xmlTextWriterPtr writer, dict_t *dict, + int brick_index) +{ + int ret = -1; + int conn_count = 0; + char key[1024] = {0,}; + int i = 0; + + /* <fdStatus> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"fdStatus"); + XML_RET_CHECK_AND_GOTO (ret, out); + + snprintf (key, sizeof (key), "brick%d.conncount", brick_index); + ret = dict_get_int32 (dict, key, &conn_count); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"connections", + "%d", conn_count); + XML_RET_CHECK_AND_GOTO (ret, out); + + for (i = 0; i < conn_count; i++) { + /* <connection> */ + ret = xmlTextWriterStartElement (writer, + (xmlChar *)"connection"); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.conn%d.fdtable", + brick_index, i); + ret = cli_xml_output_vol_status_fdtable (writer, dict, key); + if (ret) + goto out; + + /* </connection> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + } + + /* </fdStatus> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int +cli_xml_output_vol_status_callframe (xmlTextWriterPtr writer, dict_t *dict, + char *prefix) +{ + int ret = -1; + int ref_count = 0; + char *translator = NULL; + int complete = 0; + char *parent = NULL; + char *wind_from = NULL; + char *wind_to = NULL; + char *unwind_from = NULL; + char *unwind_to = NULL; + char key[1024] = {0,}; + + /* <callFrame> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"callFrame"); + XML_RET_CHECK_AND_GOTO (ret, out); + + snprintf (key, sizeof (key), "%s.refcount", prefix); + ret = dict_get_int32 (dict, key, &ref_count); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"refCount", + "%d", ref_count); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.translator", prefix); + ret = dict_get_str (dict, key, &translator); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"translator", + "%s", translator); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.complete", prefix); + ret = dict_get_int32 (dict, key, &complete); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"complete", + "%d", complete); + XML_RET_CHECK_AND_GOTO (ret ,out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.parent", prefix); + ret = dict_get_str (dict, key, &parent); + if (!ret) { + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"parent", + "%s", parent); + XML_RET_CHECK_AND_GOTO (ret, out); + } + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.windfrom", prefix); + ret = dict_get_str (dict, key, &wind_from); + if (!ret) { + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"windFrom", + "%s", wind_from); + XML_RET_CHECK_AND_GOTO (ret, out); + } + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.windto", prefix); + ret = dict_get_str (dict, key, &wind_to); + if (!ret) { + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"windTo", + "%s", wind_to); + XML_RET_CHECK_AND_GOTO (ret, out); + } + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.unwindfrom", prefix); + ret = dict_get_str (dict, key, &unwind_from); + if (!ret) { + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"unwindFrom", + "%s", unwind_from); + XML_RET_CHECK_AND_GOTO (ret, out); + } + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.unwindto", prefix); + ret = dict_get_str (dict, key, &unwind_to); + if (!ret) { + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"unwindTo", + "%s", unwind_to); + XML_RET_CHECK_AND_GOTO (ret, out); + } + + /* </callFrame> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int +cli_xml_output_vol_status_callstack (xmlTextWriterPtr writer, dict_t *dict, + char *prefix) +{ + int ret = -1; + int uid = 0; + int gid = 0; + int pid = 0; + uint64_t unique = 0; + int frame_count = 0; + char key[1024] = {0,}; + int i = 0; + + /* <callStack> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"callStack"); + XML_RET_CHECK_AND_GOTO (ret, out); + + snprintf (key, sizeof (key), "%s.uid", prefix); + ret = dict_get_int32 (dict, key, &uid); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"uid", + "%d", uid); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.gid", prefix); + ret = dict_get_int32 (dict, key, &gid); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"gid", + "%d", gid); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.pid", prefix); + ret = dict_get_int32 (dict, key, &pid); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"pid", + "%d", pid); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.unique", prefix); + ret = dict_get_uint64 (dict, key, &unique); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"unique", + "%"PRIu64, unique); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.count", prefix); + ret = dict_get_int32 (dict, key, &frame_count); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"frameCount", + "%d", frame_count); + XML_RET_CHECK_AND_GOTO (ret, out); + + for (i = 0; i < frame_count; i++) { + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.frame%d", prefix, i); + ret = cli_xml_output_vol_status_callframe (writer, dict, + key); + if (ret) + goto out; + } + + /* </callStack> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int +cli_xml_output_vol_status_callpool (xmlTextWriterPtr writer, dict_t *dict, + int brick_index) +{ + int ret = -1; + int call_count = 0; + char key[1024] = {0,}; + int i = 0; + + /* <callpoolStatus> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"callpoolStatus"); + XML_RET_CHECK_AND_GOTO (ret, out); + + snprintf (key, sizeof (key), "brick%d.callpool.count", brick_index); + ret = dict_get_int32 (dict, key, &call_count); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"count", + "%d", call_count); + + for (i = 0; i < call_count; i++) { + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.callpool.stack%d", + brick_index, i); + ret = cli_xml_output_vol_status_callstack (writer, dict, + key); + if (ret) + goto out; + } + + /* </callpoolStatus> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} +#endif + +int +cli_xml_output_vol_status_begin (cli_local_t *local, int op_ret, int op_errno, + char *op_errstr) +{ +#if (HAVE_LIB_XML) + int ret = -1; + + ret = cli_begin_xml_output (&(local->writer), &(local->doc)); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = cli_xml_output_common (local->writer, op_ret, op_errno, + op_errstr); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* <volStatus> */ + ret = xmlTextWriterStartElement (local->writer, + (xmlChar *) "volStatus"); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* <volumes> */ + ret = xmlTextWriterStartElement (local->writer, (xmlChar *)"volumes"); + XML_RET_CHECK_AND_GOTO (ret, out); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +#else + return 0; +#endif +} + +int +cli_xml_output_vol_status_end (cli_local_t *local) +{ +#if (HAVE_LIB_XML) + int ret = -1; + + /* </volumes> */ + ret = xmlTextWriterEndElement (local->writer); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* </volStatus> */ + ret = xmlTextWriterEndElement (local->writer); + XML_RET_CHECK_AND_GOTO(ret, out); + + ret = cli_end_xml_output (local->writer, local->doc); +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +#else + return 0; +#endif +} + +#if (HAVE_LIB_XML) +int +cli_xml_output_remove_brick_task_params (xmlTextWriterPtr writer, dict_t *dict, + char *prefix) +{ + int ret = -1; + char key[1024] = {0,}; + int count = 0; + int i = 0; + char *brick = NULL; + + /* <params> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"params"); + XML_RET_CHECK_AND_GOTO (ret, out); + + snprintf (key, sizeof (key), "%s.count", prefix); + ret = dict_get_int32 (dict, key, &count); + if (ret) + goto out; + + for (i = 1; i <= count; i++) { + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.brick%d", prefix, i); + ret = dict_get_str (dict, key, &brick); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"brick", + "%s", brick); + XML_RET_CHECK_AND_GOTO (ret, out); + brick = NULL; + } + + /* </param> */ + ret = xmlTextWriterEndElement (writer); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int +cli_xml_output_replace_brick_task_params (xmlTextWriterPtr writer, dict_t *dict, + char *prefix) +{ + + int ret = -1; + char key[1024] = {0,}; + char *brick = NULL; + + /* <params> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"params"); + XML_RET_CHECK_AND_GOTO (ret, out); + + snprintf (key, sizeof (key), "%s.src-brick", prefix); + ret = dict_get_str (dict, key, &brick); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"srcBrick", + "%s", brick); + XML_RET_CHECK_AND_GOTO (ret, out); + + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.dst-brick", prefix); + ret = dict_get_str (dict, key, &brick); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"dstBrick", + "%s", brick); + XML_RET_CHECK_AND_GOTO (ret, out); + + + /* </param> */ + ret = xmlTextWriterEndElement (writer); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int +cli_xml_output_vol_status_tasks (cli_local_t *local, dict_t *dict) { + int ret = -1; + char *task_type = NULL; + char *task_id_str = NULL; + int status = 0; + int tasks = 0; + char key[1024] = {0,}; + int i = 0; + + /* <tasks> */ + ret = xmlTextWriterStartElement (local->writer, (xmlChar *)"tasks"); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = dict_get_int32 (dict, "tasks", &tasks); + if (ret) + goto out; + + for (i = 0; i < tasks; i++) { + /* <task> */ + ret = xmlTextWriterStartElement (local->writer, + (xmlChar *)"task"); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "task%d.type", i); + ret = dict_get_str (dict, key, &task_type); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (local->writer, + (xmlChar *)"type", + "%s", task_type); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "task%d.id", i); + ret = dict_get_str (dict, key, &task_id_str); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (local->writer, + (xmlChar *)"id", + "%s", task_id_str); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "task%d.status", i); + ret = dict_get_int32 (dict, key, &status); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (local->writer, + (xmlChar *)"status", + "%d", status); + XML_RET_CHECK_AND_GOTO (ret, out); + + if (!strcmp (task_type, "Replace brick")) { + if (status) { + status = GF_DEFRAG_STATUS_COMPLETE; + } else { + status = GF_DEFRAG_STATUS_STARTED; + } + } + + ret = xmlTextWriterWriteFormatElement (local->writer, + (xmlChar *)"statusStr", + "%s", + cli_vol_task_status_str[status]); + + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "task%d", i); + if (!strcmp (task_type, "Replace brick")) { + ret = cli_xml_output_replace_brick_task_params + (local->writer, dict, key); + if (ret) + goto out; + } else if (!strcmp (task_type, "Remove brick")) { + ret = cli_xml_output_remove_brick_task_params + (local->writer, dict, key); + if (ret) + goto out; + } + + + /* </task> */ + ret = xmlTextWriterEndElement (local->writer); + XML_RET_CHECK_AND_GOTO (ret, out); + } + + /* </tasks> */ + ret = xmlTextWriterEndElement (local->writer); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int +cli_xml_output_vol_status_tasks_detail (cli_local_t *local, dict_t *dict) +{ + int ret = -1; + char *volname = NULL; + + /*<volume>*/ + ret = xmlTextWriterStartElement (local->writer, (xmlChar *)"volume"); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = dict_get_str (dict, "volname", &volname); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (local->writer, + (xmlChar *)"volName", "%s", + volname); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = cli_xml_output_vol_status_tasks (local, dict); + if (ret) + goto out; + + /* </volume> */ + ret = xmlTextWriterEndElement (local->writer); + XML_RET_CHECK_AND_GOTO (ret, out); + +out: + return ret; +} +#endif + +int +cli_xml_output_vol_status (cli_local_t *local, dict_t *dict) +{ +#if (HAVE_LIB_XML) + int ret = -1; + char *volname = NULL; + int brick_count = 0; + int brick_index_max = -1; + int other_count = 0; + int index_max = 0; + uint32_t cmd = GF_CLI_STATUS_NONE; + int online = 0; + gf_boolean_t node_present = _gf_true; + int i; + + + /* <volume> */ + ret = xmlTextWriterStartElement (local->writer, (xmlChar *)"volume"); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = dict_get_str (dict, "volname", &volname); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (local->writer, + (xmlChar *)"volName", "%s", + volname); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = dict_get_int32 (dict, "count", &brick_count); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (local->writer, + (xmlChar *)"nodeCount", "%d", + brick_count); + if (ret) + goto out; + + ret = dict_get_uint32 (dict, "cmd", &cmd); + if (ret) + goto out; + + ret = dict_get_int32 (dict, "brick-index-max", &brick_index_max); + if (ret) + goto out; + ret = dict_get_int32 (dict, "other-count", &other_count); + if (ret) + goto out; + + index_max = brick_index_max + other_count; + + for (i = 0; i <= index_max; i++) { + /* <node> */ + ret = xmlTextWriterStartElement (local->writer, + (xmlChar *)"node"); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = cli_xml_output_vol_status_common (local->writer, dict, i, + &online, &node_present); + if (ret) { + if (node_present) + goto out; + else + continue; + } + + switch (cmd & GF_CLI_STATUS_MASK) { + case GF_CLI_STATUS_DETAIL: + ret = cli_xml_output_vol_status_detail (local->writer, + dict, i); + if (ret) + goto out; + break; + + case GF_CLI_STATUS_MEM: + if (online) { + ret = cli_xml_output_vol_status_mem + (local->writer, dict, i); + if (ret) + goto out; + } + break; + + case GF_CLI_STATUS_CLIENTS: + if (online) { + ret = cli_xml_output_vol_status_clients + (local->writer, dict, i); + if (ret) + goto out; + } + break; + + case GF_CLI_STATUS_INODE: + if (online) { + ret = cli_xml_output_vol_status_inode + (local->writer, dict, i); + if (ret) + goto out; + } + break; + + case GF_CLI_STATUS_FD: + if (online) { + ret = cli_xml_output_vol_status_fd + (local->writer, dict, i); + if (ret) + goto out; + } + break; + + case GF_CLI_STATUS_CALLPOOL: + if (online) { + ret = cli_xml_output_vol_status_callpool + (local->writer, dict, i); + if (ret) + goto out; + } + break; + default: + break; + + } + /* </node> */ + ret = xmlTextWriterEndElement (local->writer); + XML_RET_CHECK_AND_GOTO (ret, out); + } + + /* Tasks are only present when a normal volume status call is done on a + * single volume or on all volumes + */ + if (((cmd & GF_CLI_STATUS_MASK) == GF_CLI_STATUS_NONE) && + (cmd & (GF_CLI_STATUS_VOL|GF_CLI_STATUS_ALL))) { + ret = cli_xml_output_vol_status_tasks (local, dict); + if (ret) + goto out; + } + + /* </volume> */ + ret = xmlTextWriterEndElement (local->writer); + XML_RET_CHECK_AND_GOTO (ret, out); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +#else + return 0; +#endif +} + +#if (HAVE_LIB_XML) +int +cli_xml_output_vol_top_rw_perf (xmlTextWriterPtr writer, dict_t *dict, + int brick_index, int member_index) +{ + int ret = -1; + char *filename = NULL; + uint64_t throughput = 0; + long int time_sec = 0; + long int time_usec = 0; + char timestr[256] = {0,}; + char key[1024] = {0,}; + + /* <file> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"file"); + XML_RET_CHECK_AND_GOTO (ret, out); + + snprintf (key, sizeof (key), "%d-filename-%d", brick_index, + member_index); + ret = dict_get_str (dict, key, &filename); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"filename", + "%s", filename); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%d-value-%d", brick_index, member_index); + ret = dict_get_uint64 (dict, key, &throughput); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"count", + "%"PRIu64, throughput); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%d-time-sec-%d", brick_index, + member_index); + ret = dict_get_int32 (dict, key, (int32_t *)&time_sec); + if (ret) + goto out; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%d-time-usec-%d", brick_index, + member_index); + ret = dict_get_int32 (dict, key, (int32_t *)&time_usec); + if (ret) + goto out; + + gf_time_fmt (timestr, sizeof timestr, time_sec, gf_timefmt_FT); + snprintf (timestr + strlen (timestr), + sizeof timestr - strlen (timestr), + ".%"GF_PRI_SUSECONDS, time_usec); + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"time", + "%s", timestr); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* </file> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int +cli_xml_output_vol_top_other (xmlTextWriterPtr writer, dict_t *dict, + int brick_index, int member_index) +{ + int ret = -1; + char *filename = NULL; + uint64_t count = 0; + char key[1024] = {0,}; + + /* <file> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"file"); + XML_RET_CHECK_AND_GOTO (ret, out); + + snprintf (key, sizeof (key), "%d-filename-%d", brick_index, + member_index); + ret = dict_get_str (dict, key, &filename); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"filename", + "%s", filename); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%d-value-%d", brick_index, member_index); + ret = dict_get_uint64 (dict, key, &count); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"count", + "%"PRIu64, count); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* </file> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} +#endif + +int +cli_xml_output_vol_top (dict_t *dict, int op_ret, int op_errno, + char *op_errstr) +{ +#if (HAVE_LIB_XML) + int ret = -1; + xmlTextWriterPtr writer = NULL; + xmlDocPtr doc = NULL; + int brick_count = 0; + int top_op = GF_CLI_TOP_NONE; + char *brick_name = NULL; + int members = 0; + uint64_t current_open = 0; + uint64_t max_open = 0; + char *max_open_time = NULL; + double throughput = 0.0; + double time_taken = 0.0; + char key[1024] = {0,}; + int i = 0; + int j = 0; + + ret = cli_begin_xml_output (&writer, &doc); + if (ret) + goto out; + + ret = cli_xml_output_common (writer, op_ret, op_errno, op_errstr); + if (ret) + goto out; + + /* <volTop> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"volTop"); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = dict_get_int32 (dict, "count", &brick_count); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"brickCount", + "%d", brick_count); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = dict_get_int32 (dict, "1-top-op", &top_op); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"topOp", + "%d", top_op); + XML_RET_CHECK_AND_GOTO (ret, out); + + while (i < brick_count) { + i++; + + /* <brick> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"brick"); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%d-brick", i); + ret = dict_get_str (dict, key, &brick_name); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"name", + "%s", brick_name); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key , sizeof (key), "%d-members", i); + ret = dict_get_int32 (dict, key, &members); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"members", + "%d", members); + XML_RET_CHECK_AND_GOTO (ret, out); + + switch (top_op) { + case GF_CLI_TOP_OPEN: + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%d-current-open", i); + ret = dict_get_uint64 (dict, key, ¤t_open); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement + (writer, (xmlChar *)"currentOpen", "%"PRIu64, + current_open); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%d-max-open", i); + ret = dict_get_uint64 (dict, key, &max_open); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement + (writer, (xmlChar *)"maxOpen", "%"PRIu64, + max_open); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%d-max-openfd-time", i); + ret = dict_get_str (dict, key, &max_open_time); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement + (writer, (xmlChar *)"maxOpenTime", "%s", + max_open_time); + XML_RET_CHECK_AND_GOTO (ret, out); + + case GF_CLI_TOP_READ: + case GF_CLI_TOP_WRITE: + case GF_CLI_TOP_OPENDIR: + case GF_CLI_TOP_READDIR: + + break; + + case GF_CLI_TOP_READ_PERF: + case GF_CLI_TOP_WRITE_PERF: + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%d-throughput", i); + ret = dict_get_double (dict, key, &throughput); + if (!ret) { + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%d-time", i); + ret = dict_get_double (dict, key, &time_taken); + } + + if (!ret) { + ret = xmlTextWriterWriteFormatElement + (writer, (xmlChar *)"throughput", + "%f", throughput); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement + (writer, (xmlChar *)"timeTaken", + "%f", time_taken); + } + + break; + + default: + ret = -1; + goto out; + } + + for (j = 1; j <= members; j++) { + if (top_op == GF_CLI_TOP_READ_PERF || + top_op == GF_CLI_TOP_WRITE_PERF) { + ret = cli_xml_output_vol_top_rw_perf + (writer, dict, i, j); + } else { + ret = cli_xml_output_vol_top_other + (writer, dict, i, j); + } + if (ret) + goto out; + } + + + /* </brick> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + } + + /* </volTop> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + ret = cli_end_xml_output (writer, doc); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +#else + return 0; +#endif +} + +#if (HAVE_LIB_XML) +int +cli_xml_output_vol_profile_stats (xmlTextWriterPtr writer, dict_t *dict, + int brick_index, int interval) +{ + int ret = -1; + uint64_t read_count = 0; + uint64_t write_count = 0; + uint64_t hits = 0; + double avg_latency = 0.0; + double max_latency = 0.0; + double min_latency = 0.0; + uint64_t duration = 0; + uint64_t total_read = 0; + uint64_t total_write = 0; + char key[1024] = {0}; + int i = 0; + + /* <cumulativeStats> || <intervalStats> */ + if (interval == -1) + ret = xmlTextWriterStartElement (writer, + (xmlChar *)"cumulativeStats"); + else + ret = xmlTextWriterStartElement (writer, + (xmlChar *)"intervalStats"); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* <blockStats> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"blockStats"); + XML_RET_CHECK_AND_GOTO (ret, out); + + for (i = 0; i < 32; i++) { + /* <block> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"block"); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement + (writer, (xmlChar *)"size", "%"PRIu32, (1 << i)); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%d-%d-read-%d", brick_index, + interval, (1 << i)); + ret = dict_get_uint64 (dict, key, &read_count); + if (ret) + read_count = 0; + ret = xmlTextWriterWriteFormatElement + (writer, (xmlChar *)"reads", "%"PRIu64, read_count); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%d-%d-write-%d", brick_index, + interval, (1 << i)); + ret = dict_get_uint64 (dict, key, &write_count); + if (ret) + write_count = 0; + ret = xmlTextWriterWriteFormatElement + (writer, (xmlChar *)"writes", "%"PRIu64, write_count); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* </block> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + } + + /* </blockStats> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* <fopStats> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"fopStats"); + XML_RET_CHECK_AND_GOTO (ret, out); + + for (i = 0; i < GF_FOP_MAXVALUE; i++) { + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%d-%d-%d-hits", brick_index, + interval, i); + ret = dict_get_uint64 (dict, key, &hits); + if (ret) + goto cont; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%d-%d-%d-avglatency", brick_index, + interval, i); + ret = dict_get_double (dict, key, &avg_latency); + if (ret) + goto cont; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%d-%d-%d-minlatency", brick_index, + interval, i); + ret = dict_get_double (dict, key, &min_latency); + if (ret) + goto cont; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%d-%d-%d-maxlatency", brick_index, + interval, i); + ret = dict_get_double (dict, key, &max_latency); + if (ret) + goto cont; + + /* <fop> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"fop"); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement + (writer, (xmlChar *)"name","%s", gf_fop_list[i]); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement + (writer, (xmlChar *)"hits", "%"PRIu64, hits); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement + (writer, (xmlChar *)"avgLatency", "%f", avg_latency); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement + (writer, (xmlChar *)"minLatency", "%f", min_latency); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement + (writer, (xmlChar *)"maxLatency", "%f", max_latency); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* </fop> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + +cont: + hits = 0; + avg_latency = 0.0; + min_latency = 0.0; + max_latency = 0.0; + } + + /* </fopStats> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%d-%d-duration", brick_index, interval); + ret = dict_get_uint64 (dict, key, &duration); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"duration", + "%"PRIu64, duration); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%d-%d-total-read", brick_index, interval); + ret = dict_get_uint64 (dict, key, &total_read); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"totalRead", + "%"PRIu64, total_read); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%d-%d-total-write", brick_index, interval); + ret = dict_get_uint64 (dict, key, &total_write); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"totalWrite", + "%"PRIu64, total_write); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* </cumulativeStats> || </intervalStats> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} +#endif + +int +cli_xml_output_vol_profile (dict_t *dict, int op_ret, int op_errno, + char *op_errstr) +{ +#if (HAVE_LIB_XML) + int ret = -1; + xmlTextWriterPtr writer = NULL; + xmlDocPtr doc = NULL; + char *volname = NULL; + int op = GF_CLI_STATS_NONE; + int brick_count = 0; + char *brick_name = NULL; + int interval = 0; + char key[1024] = {0,}; + int i = 0; + + ret = cli_begin_xml_output (&writer, &doc); + if (ret) + goto out; + + ret = cli_xml_output_common (writer, op_ret, op_errno, op_errstr); + if (ret) + goto out; + + /* <volProfile> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"volProfile"); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = dict_get_str (dict, "volname", &volname); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"volname", + "%s", volname); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = dict_get_int32 (dict, "op", &op); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"profileOp", + "%d", op); + XML_RET_CHECK_AND_GOTO (ret, out); + + if (op != GF_CLI_STATS_INFO) + goto cont; + + ret = dict_get_int32 (dict, "count", &brick_count); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"brickCount", + "%d", brick_count); + XML_RET_CHECK_AND_GOTO (ret, out); + + while (i < brick_count) { + i++; + + /* <brick> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"brick"); + XML_RET_CHECK_AND_GOTO (ret, out); + + snprintf (key, sizeof (key), "%d-brick", i); + ret = dict_get_str (dict, key, &brick_name); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement + (writer, (xmlChar *)"brickName", "%s", brick_name); + XML_RET_CHECK_AND_GOTO (ret, out); + + snprintf (key, sizeof (key), "%d-cumulative", i); + ret = dict_get_int32 (dict, key, &interval); + if (ret == 0) { + ret = cli_xml_output_vol_profile_stats + (writer, dict, i, interval); + if (ret) + goto out; + } + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%d-interval", i); + ret = dict_get_int32 (dict, key, &interval); + if (ret == 0) { + ret = cli_xml_output_vol_profile_stats + (writer, dict, i, interval); + if (ret) + goto out; + } + + /* </brick> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + } + +cont: + /* </volProfile> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = cli_end_xml_output (writer, doc); +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +#else + return 0; +#endif +} + +int +cli_xml_output_vol_list (dict_t *dict, int op_ret, int op_errno, + char *op_errstr) +{ +#if (HAVE_LIB_XML) + int ret = -1; + xmlTextWriterPtr writer = NULL; + xmlDocPtr doc = NULL; + int count = 0; + char *volname = NULL; + char key[1024] = {0,}; + int i = 0; + + ret = cli_begin_xml_output (&writer, &doc); + if (ret) + goto out; + + ret = cli_xml_output_common (writer, op_ret, op_errno, op_errstr); + if (ret) + goto out; + + /* <volList> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"volList"); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = dict_get_int32 (dict, "count", &count); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"count", + "%d", count); + XML_RET_CHECK_AND_GOTO (ret, out); + + for (i = 0; i < count; i++) { + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "volume%d", i); + ret = dict_get_str (dict, key, &volname); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"volume", + "%s", volname); + XML_RET_CHECK_AND_GOTO (ret, out); + } + + /* </volList> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = cli_end_xml_output (writer, doc); +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +#else + return 0; +#endif +} + +#if (HAVE_LIB_XML) +int +cli_xml_output_vol_info_option (xmlTextWriterPtr writer, char *substr, + char *optstr, char *valstr) +{ + int ret = -1; + char *ptr1 = NULL; + char *ptr2 = NULL; + + ptr1 = substr; + ptr2 = optstr; + + while (ptr1) { + if (*ptr1 != *ptr2) + break; + ptr1++; + ptr2++; + if (!ptr1) + goto out; + if (!ptr2) + goto out; + } + if (*ptr2 == '\0') + goto out; + + /* <option> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"option"); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"name", + "%s", ptr2); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"value", + "%s", valstr); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* </option> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +struct tmp_xml_option_logger { + char *key; + xmlTextWriterPtr writer; +}; + +static int +_output_vol_info_option (dict_t *d, char *k, data_t *v, + void *data) +{ + int ret = 0; + char *ptr = NULL; + struct tmp_xml_option_logger *tmp = NULL; + + tmp = data; + + ptr = strstr (k, "option."); + if (!ptr) + goto out; + + if (!v) { + ret = -1; + goto out; + } + ret = cli_xml_output_vol_info_option (tmp->writer, tmp->key, k, + v->data); + +out: + return ret; +} + +int +cli_xml_output_vol_info_options (xmlTextWriterPtr writer, dict_t *dict, + char *prefix) +{ + int ret = -1; + int opt_count = 0; + char key[1024] = {0,}; + struct tmp_xml_option_logger tmp = {0,}; + + snprintf (key, sizeof (key), "%s.opt_count", prefix); + ret = dict_get_int32 (dict, key, &opt_count); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"optCount", + "%d", opt_count); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* <options> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"options"); + XML_RET_CHECK_AND_GOTO (ret, out); + snprintf (key, sizeof (key), "%s.option.", prefix); + + tmp.key = key; + tmp.writer = writer; + ret = dict_foreach (dict, _output_vol_info_option, &tmp); + if (ret) + goto out; + + /* </options> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} +#endif + +int +cli_xml_output_vol_info (cli_local_t *local, dict_t *dict) +{ +#if (HAVE_LIB_XML) + int ret = 0; + int count = 0; + char *volname = NULL; + char *volume_id = NULL; + char *uuid = NULL; + int type = 0; + int status = 0; + int brick_count = 0; + int dist_count = 0; + int stripe_count = 0; + int replica_count = 0; + int transport = 0; + char *brick = NULL; + char key[1024] = {0,}; + int i = 0; + int j = 1; + char *caps = NULL; + int k __attribute__((unused)) = 0; + char *snap_volume = NULL; + + ret = dict_get_int32 (dict, "count", &count); + if (ret) + goto out; + + for (i = 0; i < count; i++) { + /* <volume> */ + ret = xmlTextWriterStartElement (local->writer, + (xmlChar *)"volume"); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "volume%d.name", i); + ret = dict_get_str (dict, key, &volname); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (local->writer, + (xmlChar *)"name", + "%s", volname); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "volume%d.volume_id", i); + ret = dict_get_str (dict, key, &volume_id); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (local->writer, + (xmlChar *)"id", + "%s", volume_id); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "volume%d.status", i); + ret = dict_get_int32 (dict, key, &status); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (local->writer, + (xmlChar *)"status", + "%d", status); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "volume%d.snap_volume", i); + ret = dict_get_str (dict, key, &snap_volume); + if (ret) + goto out; + if (snap_volume) { + ret = xmlTextWriterWriteFormatElement (local->writer, + (xmlChar *)"snapVol", + "%s", snap_volume); + XML_RET_CHECK_AND_GOTO (ret, out); + } + + ret =xmlTextWriterWriteFormatElement + (local->writer, (xmlChar *)"statusStr", "%s", + cli_vol_status_str[status]); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "volume%d.brick_count", i); + ret = dict_get_int32 (dict, key, &brick_count); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (local->writer, + (xmlChar *)"brickCount", + "%d", brick_count); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "volume%d.dist_count", i); + ret = dict_get_int32 (dict, key, &dist_count); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (local->writer, + (xmlChar *)"distCount", + "%d", dist_count); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "volume%d.stripe_count", i); + ret = dict_get_int32 (dict, key, &stripe_count); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (local->writer, + (xmlChar *)"stripeCount", + "%d", stripe_count); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "volume%d.replica_count", i); + ret = dict_get_int32 (dict, key, &replica_count); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (local->writer, + (xmlChar *)"replicaCount", + "%d", replica_count); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "volume%d.type", i); + ret = dict_get_int32 (dict, key, &type); + if (ret) + goto out; + /* For Distributed-(stripe,replicate,stipe-replicate) types */ + if ((type > 0) && (dist_count < brick_count)) + type += 3; + ret = xmlTextWriterWriteFormatElement (local->writer, + (xmlChar *)"type", + "%d", type); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement (local->writer, + (xmlChar *)"typeStr", + "%s", + cli_vol_type_str[type]); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "volume%d.transport", i); + ret = dict_get_int32 (dict, key, &transport); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (local->writer, + (xmlChar *)"transport", + "%d", transport); + XML_RET_CHECK_AND_GOTO (ret, out); + +#ifdef HAVE_BD_XLATOR + /* <xlators> */ + ret = xmlTextWriterStartElement (local->writer, + (xmlChar *)"xlators"); + XML_RET_CHECK_AND_GOTO (ret, out); + + for (k = 0; ; k++) { + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key),"volume%d.xlator%d", i, k); + ret = dict_get_str (dict, key, &caps); + if (ret) + break; + + /* <xlator> */ + ret = xmlTextWriterStartElement (local->writer, + (xmlChar *)"xlator"); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement + (local->writer, (xmlChar *)"name", "%s", caps); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* <capabilities> */ + ret = xmlTextWriterStartElement (local->writer, + (xmlChar *) + "capabilities"); + XML_RET_CHECK_AND_GOTO (ret, out); + + j = 0; + for (j = 0; ;j++) { + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), + "volume%d.xlator%d.caps%d", i, k, j); + ret = dict_get_str (dict, key, &caps); + if (ret) + break; + ret = xmlTextWriterWriteFormatElement + (local->writer, (xmlChar *)"capability", + "%s", caps); + XML_RET_CHECK_AND_GOTO (ret, out); + } + /* </capabilities> */ + ret = xmlTextWriterEndElement (local->writer); + XML_RET_CHECK_AND_GOTO (ret, out); + /* </xlator> */ + ret = xmlTextWriterEndElement (local->writer); + XML_RET_CHECK_AND_GOTO (ret, out); + } + ret = xmlTextWriterFullEndElement (local->writer); + XML_RET_CHECK_AND_GOTO (ret, out); + /* </xlators> */ +#else + caps = 0; /* Avoid compiler warnings when BD not enabled */ +#endif + j = 1; + + /* <bricks> */ + ret = xmlTextWriterStartElement (local->writer, + (xmlChar *)"bricks"); + XML_RET_CHECK_AND_GOTO (ret, out); + while (j <= brick_count) { + ret = xmlTextWriterStartElement + (local->writer, (xmlChar *)"brick"); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "volume%d.brick%d.uuid", + i, j); + ret = dict_get_str (dict, key, &uuid); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatAttribute + (local->writer, (xmlChar *)"uuid", "%s", + uuid); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "volume%d.brick%d", i, j); + ret = dict_get_str (dict, key, &brick); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatString + (local->writer, "%s", brick); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* </brick> */ + ret = xmlTextWriterEndElement (local->writer); + XML_RET_CHECK_AND_GOTO (ret, out); + + j++; + } + /* </bricks> */ + ret = xmlTextWriterEndElement (local->writer); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "volume%d", i); + ret = cli_xml_output_vol_info_options (local->writer, dict, + key); + if (ret) + goto out; + + /* </volume> */ + ret = xmlTextWriterEndElement (local->writer); + XML_RET_CHECK_AND_GOTO (ret, out); + } + + if (volname) { + GF_FREE (local->get_vol.volname); + local->get_vol.volname = gf_strdup (volname); + local->vol_count += count; + } +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +#else + return 0; +#endif +} + +int +cli_xml_output_vol_info_begin (cli_local_t *local, int op_ret, int op_errno, + char *op_errstr) +{ +#if (HAVE_LIB_XML) + int ret = -1; + + GF_ASSERT (local); + + ret = cli_begin_xml_output (&(local->writer), &(local->doc)); + if (ret) + goto out; + + ret = cli_xml_output_common (local->writer, op_ret, op_errno, + op_errstr); + if (ret) + goto out; + + /* <volInfo> */ + ret = xmlTextWriterStartElement (local->writer, (xmlChar *)"volInfo"); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* <volumes> */ + ret = xmlTextWriterStartElement (local->writer, (xmlChar *)"volumes"); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* Init vol count */ + local->vol_count = 0; + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +#else + return 0; +#endif +} + +int +cli_xml_output_vol_info_end (cli_local_t *local) +{ +#if (HAVE_LIB_XML) + int ret = -1; + + GF_ASSERT (local); + + ret = xmlTextWriterWriteFormatElement (local->writer, + (xmlChar *)"count", + "%d", local->vol_count); + + /* </volumes> */ + ret = xmlTextWriterEndElement (local->writer); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* </volInfo> */ + ret = xmlTextWriterEndElement (local->writer); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = cli_end_xml_output (local->writer, local->doc); + +out: + gf_log ("cli", GF_LOG_ERROR, "Returning %d", ret); + return ret; +#else + return 0; +#endif +} + +int +cli_xml_output_vol_quota_limit_list (char *volname, char *limit_list, + int op_ret, int op_errno, + char *op_errstr) +{ +#if (HAVE_LIB_XML) + int ret = -1; + xmlTextWriterPtr writer = NULL; + xmlDocPtr doc = NULL; + int64_t size = 0; + int64_t limit_value = 0; + int i = 0; + int j = 0; + int k = 0; + int len = 0; + char *size_str = NULL; + char path[PATH_MAX] = {0,}; + char ret_str[1024] = {0,}; + char value[1024] = {0,}; + char mountdir[] = "/tmp/mountXXXXXX"; + char abspath[PATH_MAX] = {0,}; + runner_t runner = {0,}; + + GF_ASSERT (volname); + GF_ASSERT (limit_list); + + ret = cli_begin_xml_output (&writer, &doc); + if (ret) + goto out; + + ret = cli_xml_output_common (writer, op_ret, op_errno, op_errstr); + if (ret) + goto out; + + /* <volQuota> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"volQuota"); + XML_RET_CHECK_AND_GOTO (ret, out); + + if (!limit_list) + goto cont; + + len = strlen (limit_list); + if (len == 0) + goto cont; + + if (mkdtemp (mountdir) == NULL) { + gf_log ("cli", GF_LOG_ERROR, "failed to create a temporary" + " mount directory"); + ret = -1; + goto out; + } + + ret = runcmd (SBIN_DIR"/glusterfs", "-s", "localhost", + "--volfile-id", volname, "-l", + DEFAULT_LOG_FILE_DIRECTORY"/quota-list-xml.log", + mountdir, NULL); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, + "failed to mount glusterfs client"); + ret = -1; + goto rm_dir; + } + + while (i < len) { + j = 0; + k = 0; + size = 0; + + while (limit_list[i] != ':') + path[k++] = limit_list[i++]; + path[k] = '\0'; + + i++; + + while (limit_list[i] != ',' && limit_list[i] != '\0') + value[j++] = limit_list[i++]; + i++; + + snprintf (abspath, sizeof (abspath), "%s/%s", mountdir, path); + ret = sys_lgetxattr (abspath, "trusted.limit.list", + (void *)ret_str, 4096); + if (ret >= 0) { + sscanf (ret_str, "%"SCNd64",%"SCNd64, &size, + &limit_value); + size_str = gf_uint64_2human_readable ((uint64_t)size); + } + + /* <quota> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"quota"); + XML_RET_CHECK_AND_GOTO (ret, unmount); + + ret = xmlTextWriterWriteFormatElement + (writer, (xmlChar *)"path", "%s", path); + XML_RET_CHECK_AND_GOTO (ret, unmount); + + ret = xmlTextWriterWriteFormatElement + (writer, (xmlChar *)"limit", "%s", value); + XML_RET_CHECK_AND_GOTO (ret, unmount); + + if (size_str) { + ret = xmlTextWriterWriteFormatElement + (writer, (xmlChar *)"size", "%s", size_str); + XML_RET_CHECK_AND_GOTO (ret, unmount); + GF_FREE (size_str); + } else { + ret = xmlTextWriterWriteFormatElement + (writer, (xmlChar *)"size", "%"PRId64, size); + XML_RET_CHECK_AND_GOTO (ret, unmount); + } + + /* </quota> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, unmount); + + } + +unmount: + runinit (&runner); + runner_add_args (&runner, "umount", +#if GF_LINUX_HOST_OS + "-l", +#endif + mountdir, NULL); + ret = runner_run_reuse (&runner); + if (ret) + runner_log (&runner, "cli", GF_LOG_WARNING, "error executing"); + runner_end (&runner); + +rm_dir: + rmdir (mountdir); + +cont: + /* </volQuota> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = cli_end_xml_output (writer, doc); + +out: + GF_FREE (size_str); + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +#else + return 0; +#endif +} + +int +cli_xml_output_peer_status (dict_t *dict, int op_ret, int op_errno, + char *op_errstr) +{ +#if (HAVE_LIB_XML) + int ret = -1; + xmlTextWriterPtr writer = NULL; + xmlDocPtr doc = NULL; + int count = 0; + char *uuid = NULL; + char *hostname = NULL; + int connected = 0; + int state_id = 0; + char *state_str = NULL; + int i = 1; + char key[1024] = {0,}; + + ret = cli_begin_xml_output (&writer, &doc); + if (ret) + goto out; + + ret = cli_xml_output_common (writer, op_ret, op_errno, op_errstr); + if (ret) + goto out; + + /* <peerStatus> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"peerStatus"); + XML_RET_CHECK_AND_GOTO (ret, out); + + if (!dict) + goto cont; + + ret = dict_get_int32 (dict, "count", &count); + if (ret) + goto out; + + while (i <= count) { + /* <peer> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"peer"); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "friend%d.uuid", i); + ret = dict_get_str (dict, key, &uuid); + if (ret) + goto out; + + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"uuid", + "%s", uuid); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "friend%d.hostname", i); + ret = dict_get_str (dict, key, &hostname); + if (ret) + goto out; + + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"hostname", + "%s", hostname); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "friend%d.connected", i); + ret = dict_get_int32 (dict, key, &connected); + if (ret) + goto out; + + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"connected", + "%d", connected); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "friend%d.stateId", i); + ret = dict_get_int32 (dict, key, &state_id); + if (!ret) { + /* ignore */ + + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"state", "%d", state_id); + XML_RET_CHECK_AND_GOTO (ret, out); + } + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "friend%d.state", i); + ret = dict_get_str (dict, key, &state_str); + if (!ret) { + /* ignore */ + + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"stateStr", "%s", state_str); + XML_RET_CHECK_AND_GOTO (ret, out); + } + + /* </peer> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + + i++; + } + +cont: + /* </peerStatus> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = cli_end_xml_output (writer, doc); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +#else + return 0; +#endif +} + +#if (HAVE_LIB_XML) +/* Used for rebalance stop/status, remove-brick status */ +int +cli_xml_output_vol_rebalance_status (xmlTextWriterPtr writer, dict_t *dict, + enum gf_task_types task_type) +{ + int ret = -1; + int count = 0; + char *node_name = NULL; + char *node_uuid = NULL; + uint64_t files = 0; + uint64_t size = 0; + uint64_t lookups = 0; + int status_rcd = 0; + uint64_t failures = 0; + uint64_t skipped = 0; + uint64_t total_files = 0; + uint64_t total_size = 0; + uint64_t total_lookups = 0; + uint64_t total_failures = 0; + uint64_t total_skipped = 0; + char key[1024] = {0,}; + int i = 0; + int overall_status = -1; + double elapsed = 0; + double overall_elapsed = 0; + + if (!dict) { + ret = 0; + goto out; + } + + ret = dict_get_int32 (dict, "count", &count); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"nodeCount", + "%d", count); + XML_RET_CHECK_AND_GOTO (ret, out); + + while (i < count) { + i++; + + /* <node> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"node"); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "node-name-%d", i); + ret = dict_get_str (dict, key, &node_name); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"nodeName", + "%s", node_name); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "node-uuid-%d", i); + ret = dict_get_str (dict, key, &node_uuid); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"id", + "%s", node_uuid); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "files-%d", i); + ret = dict_get_uint64 (dict, key, &files); + if (ret) + goto out; + total_files += files; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"files", + "%"PRIu64, files); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "size-%d", i); + ret = dict_get_uint64 (dict, key, &size); + if (ret) + goto out; + total_size += size; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"size", + "%"PRIu64,size); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "lookups-%d", i); + ret = dict_get_uint64 (dict, key, &lookups); + if (ret) + goto out; + total_lookups += lookups; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"lookups", + "%"PRIu64, lookups); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "failures-%d", i); + ret = dict_get_uint64 (dict, key, &failures); + if (ret) + goto out; + total_failures += failures; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"failures", + "%"PRIu64, failures); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* skipped-%d is not available for remove brick in dict, + so using failures as skipped count in case of remove-brick + similar to logic used in CLI(non xml output) */ + if (task_type == GF_TASK_TYPE_REBALANCE) { + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "skipped-%d", i); + } + else { + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "failures-%d", i); + } + + ret = dict_get_uint64 (dict, key, &skipped); + if (ret) + goto out; + total_skipped += skipped; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"skipped", + "%"PRIu64, skipped); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "status-%d", i); + ret = dict_get_int32 (dict, key, &status_rcd); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"status", + "%d", status_rcd); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"statusStr", + "%s", + cli_vol_task_status_str[status_rcd]); + + memset (key, 0, 256); + snprintf (key, 256, "run-time-%d", i); + ret = dict_get_double (dict, key, &elapsed); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"runtime", + "%.2f", elapsed); + XML_RET_CHECK_AND_GOTO (ret, out); + + if (elapsed > overall_elapsed) { + overall_elapsed = elapsed; + } + + if (-1 == overall_status) + overall_status = status_rcd; + else if ((GF_DEFRAG_STATUS_COMPLETE == overall_status || + status_rcd > overall_status) && + (status_rcd != GF_DEFRAG_STATUS_COMPLETE)) + overall_status = status_rcd; + XML_RET_CHECK_AND_GOTO (ret, out); + + /* </node> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + } + + /* Aggregate status */ + /* <aggregate> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"aggregate"); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement (writer,(xmlChar *)"files", + "%"PRIu64, total_files); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement (writer,(xmlChar *)"size", + "%"PRIu64, total_size); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement (writer,(xmlChar *)"lookups", + "%"PRIu64, total_lookups); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement (writer,(xmlChar *)"failures", + "%"PRIu64, total_failures); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement (writer,(xmlChar *)"skipped", + "%"PRIu64, total_skipped); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement (writer,(xmlChar *)"status", + "%d", overall_status); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement (writer,(xmlChar *)"statusStr", + "%s", + cli_vol_task_status_str[overall_status]); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement (writer,(xmlChar *)"runtime", + "%.2f", overall_elapsed); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* </aggregate> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} +#endif + +int +cli_xml_output_vol_rebalance (gf_cli_defrag_type op, dict_t *dict, int op_ret, + int op_errno, char *op_errstr) +{ +#if (HAVE_LIB_XML) + int ret = -1; + xmlTextWriterPtr writer = NULL; + xmlDocPtr doc = NULL; + char *task_id_str = NULL; + + ret = cli_begin_xml_output (&writer, &doc); + if (ret) + goto out; + + ret = cli_xml_output_common (writer, op_ret, op_errno, op_errstr); + if (ret) + goto out; + + /* <volRebalance> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"volRebalance"); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = dict_get_str (dict, GF_REBALANCE_TID_KEY, &task_id_str); + if (ret == 0) { + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"task-id", + "%s", task_id_str); + XML_RET_CHECK_AND_GOTO (ret, out); + } + + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"op", + "%d", op); + XML_RET_CHECK_AND_GOTO (ret, out); + + if ((GF_DEFRAG_CMD_STOP == op) || (GF_DEFRAG_CMD_STATUS == op)) { + ret = cli_xml_output_vol_rebalance_status (writer, dict, + GF_TASK_TYPE_REBALANCE); + if (ret) + goto out; + } + + /* </volRebalance> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + + + ret = cli_end_xml_output (writer, doc); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +#else + return 0; +#endif +} + +int +cli_xml_output_vol_remove_brick (gf_boolean_t status_op, dict_t *dict, + int op_ret, int op_errno, char *op_errstr) +{ +#if (HAVE_LIB_XML) + int ret = -1; + xmlTextWriterPtr writer = NULL; + xmlDocPtr doc = NULL; + char *task_id_str = NULL; + + ret = cli_begin_xml_output (&writer, &doc); + if (ret) + goto out; + + ret = cli_xml_output_common (writer, op_ret, op_errno, op_errstr); + if (ret) + goto out; + + /* <volRemoveBrick> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"volRemoveBrick"); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = dict_get_str (dict, GF_REMOVE_BRICK_TID_KEY, &task_id_str); + if (ret == 0) { + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"task-id", + "%s", task_id_str); + XML_RET_CHECK_AND_GOTO (ret, out); + } + + if (status_op) { + ret = cli_xml_output_vol_rebalance_status (writer, dict, + GF_TASK_TYPE_REMOVE_BRICK); + if (ret) + goto out; + } + + /* </volRemoveBrick> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + + + ret = cli_end_xml_output (writer, doc); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +#else + return 0; +#endif +} + +int +cli_xml_output_vol_replace_brick (gf1_cli_replace_op op, dict_t *dict, + int op_ret, int op_errno, char *op_errstr) +{ +#if (HAVE_LIB_XML) + int ret = -1; + int status = 0; + uint64_t files = 0; + char *current_file = 0; + char *task_id_str = NULL; + xmlTextWriterPtr writer = NULL; + xmlDocPtr doc = NULL; + + ret = cli_begin_xml_output (&writer, &doc); + if (ret) + goto out; + + ret = cli_xml_output_common (writer, op_ret, op_errno, op_errstr); + if (ret) + goto out; + + /* <volReplaceBrick> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"volReplaceBrick"); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = dict_get_str (dict, GF_REPLACE_BRICK_TID_KEY, &task_id_str); + if (ret == 0) { + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"task-id", + "%s", task_id_str); + XML_RET_CHECK_AND_GOTO (ret, out); + } + + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"op", + "%d", op); + XML_RET_CHECK_AND_GOTO (ret, out); + + if (GF_REPLACE_OP_STATUS == op) { + ret = dict_get_int32 (dict, "status", &status); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"status", + "%d", status); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = dict_get_uint64 (dict, "files", &files); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"files", + "%"PRIu64, files); + XML_RET_CHECK_AND_GOTO (ret, out); + + if (status) + goto cont; + + ret = dict_get_str (dict, "current_file", ¤t_file); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"currentFile", + "%s", current_file); + XML_RET_CHECK_AND_GOTO (ret, out); + } +cont: + /* </volReplaceBrick> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = cli_end_xml_output (writer, doc); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +#else + return 0; +#endif +} + +int +cli_xml_output_vol_create (dict_t *dict, int op_ret, int op_errno, + char *op_errstr) +{ +#if (HAVE_LIB_XML) + int ret = -1; + xmlTextWriterPtr writer = NULL; + xmlDocPtr doc = NULL; + char *volname = NULL; + char *volid = NULL; + + ret = cli_begin_xml_output (&writer, &doc); + if (ret) + goto out; + + ret = cli_xml_output_common (writer, op_ret, op_errno, op_errstr); + if (ret) + goto out; + + if (dict) { + /* <volCreate> */ + ret = xmlTextWriterStartElement (writer, + (xmlChar *)"volCreate"); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* <volume> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"volume"); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = dict_get_str (dict, "volname", &volname); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *) "name", + "%s", volname); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = dict_get_str (dict, "volume-id", &volid); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"id", + "%s", volid); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* </volume> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* </volCreate> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + } + + ret = cli_end_xml_output (writer, doc); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +#else + return 0; +#endif +} + +int +cli_xml_output_generic_volume (char *op, dict_t *dict, int op_ret, int op_errno, + char *op_errstr) +{ +#if (HAVE_LIB_XML) + int ret = -1; + xmlTextWriterPtr writer = NULL; + xmlDocPtr doc = NULL; + char *volname = NULL; + char *volid = NULL; + + GF_ASSERT (op); + + ret = cli_begin_xml_output (&writer, &doc); + if (ret) + goto out; + + ret = cli_xml_output_common (writer, op_ret, op_errno, op_errstr); + if (ret) + goto out; + + if (dict) { + /* <"op"> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)op); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* <volume> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"volume"); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = dict_get_str (dict, "volname", &volname); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *) "name", + "%s", volname); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = dict_get_str (dict, "vol-id", &volid); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"id", + "%s", volid); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* </volume> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* </"op"> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + } + + ret = cli_end_xml_output (writer, doc); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +#else + return 0; +#endif +} + +#if (HAVE_LIB_XML) +int +cli_xml_output_vol_gsync_status (dict_t *dict, xmlTextWriterPtr writer) +{ + char master_key[PATH_MAX] = ""; + char slave_key[PATH_MAX] = ""; + char status_key[PATH_MAX] = ""; + char node_key[PATH_MAX] = ""; + char *master = NULL; + char *slave = NULL; + char *status = NULL; + char *node = NULL; + int ret = -1; + int gsync_count = 0; + int i = 1; + + ret = dict_get_int32 (dict, "gsync-count", &gsync_count); + if (ret) + goto out; + + for (i=1; i <= gsync_count; i++) { + snprintf (node_key, sizeof(node_key), "node%d", i); + snprintf (master_key, sizeof(master_key), "master%d", i); + snprintf (slave_key, sizeof(slave_key), "slave%d", i); + snprintf (status_key, sizeof(status_key), "status%d", i); + + ret = dict_get_str (dict, node_key, &node); + if (ret) + goto out; + + ret = dict_get_str (dict, master_key, &master); + if (ret) + goto out; + + ret = dict_get_str (dict, slave_key, &slave); + if (ret) + goto out; + + ret = dict_get_str (dict, status_key, &status); + if (ret) + goto out; + + /* <pair> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"pair"); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"node", + "%s", node); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"master", + "%s", master); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"slave", + "%s", slave); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"status", + "%s", status); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* </pair> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + + } + +out: + gf_log ("cli",GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} +#endif + +int +cli_xml_output_vol_gsync (dict_t *dict, int op_ret, int op_errno, + char *op_errstr) +{ +#if (HAVE_LIB_XML) + int ret = -1; + xmlTextWriterPtr writer = NULL; + xmlDocPtr doc = NULL; + char *master = NULL; + char *slave = NULL; + int type = 0; + + GF_ASSERT (dict); + + ret = cli_begin_xml_output (&writer, &doc); + if (ret) + goto out; + + ret = cli_xml_output_common (writer, op_ret, op_errno, op_errstr); + if (ret) + goto out; + + /* <geoRep> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"geoRep"); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = dict_get_int32 (dict, "type", &type); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Failed to get type"); + goto out; + } + + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"type", + "%d", type); + XML_RET_CHECK_AND_GOTO (ret, out); + + switch (type) { + case GF_GSYNC_OPTION_TYPE_START: + case GF_GSYNC_OPTION_TYPE_STOP: + if (dict_get_str (dict, "master", &master) != 0) + master = "???"; + if (dict_get_str (dict, "slave", &slave) != 0) + slave = "???"; + + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"master", + "%s", master); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"slave", + "%s", slave); + XML_RET_CHECK_AND_GOTO (ret, out); + + break; + + case GF_GSYNC_OPTION_TYPE_CONFIG: + break; + case GF_GSYNC_OPTION_TYPE_STATUS: + ret = cli_xml_output_vol_gsync_status(dict, writer); + break; + default: + ret = 0; + break; + } + + /* </geoRep> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = cli_end_xml_output (writer, doc); +out: + gf_log ("cli",GF_LOG_DEBUG, "Returning %d", ret); + return ret; +#else + return 0; +#endif +} diff --git a/cli/src/cli.c b/cli/src/cli.c index a08d2d214..91b315ff1 100644 --- a/cli/src/cli.c +++ b/cli/src/cli.c @@ -1,22 +1,12 @@ /* - Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. - - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ + Copyright (c) 2010-2012 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ #include <stdio.h> #include <string.h> #include <stdlib.h> @@ -74,17 +64,19 @@ #include "call-stub.h" #include <fnmatch.h> +#include "xdr-generic.h" + extern int connected; /* using argp for command line parsing */ const char *argp_program_version = "" \ PACKAGE_NAME" "PACKAGE_VERSION" built on "__DATE__" "__TIME__ \ "\nRepository revision: " GLUSTERFS_REPOSITORY_REVISION "\n" \ - "Copyright (c) 2006-2010 Gluster Inc. " \ + "Copyright (c) 2006-2011 Gluster Inc. " \ "<http://www.gluster.com>\n" \ "GlusterFS comes with ABSOLUTELY NO WARRANTY.\n" \ "You may redistribute copies of GlusterFS under the terms of "\ - "the GNU Affero General Public License."; + "the GNU General Public License."; const char *argp_program_bug_address = "<" PACKAGE_BUGREPORT ">"; @@ -95,44 +87,7 @@ struct rpc_clnt *global_rpc; rpc_clnt_prog_t *cli_rpc_prog; -extern struct rpc_clnt_program cli3_1_prog; - - - - -static char * -generate_uuid () -{ - char tmp_str[1024] = {0,}; - char hostname[256] = {0,}; - struct timeval tv = {0,}; - struct tm now = {0, }; - char now_str[32]; - - if (gettimeofday (&tv, NULL) == -1) { - gf_log ("glusterfsd", GF_LOG_ERROR, - "gettimeofday: failed %s", - strerror (errno)); - } - - if (gethostname (hostname, 256) == -1) { - gf_log ("glusterfsd", GF_LOG_ERROR, - "gethostname: failed %s", - strerror (errno)); - } - - localtime_r (&tv.tv_sec, &now); - strftime (now_str, 32, "%Y/%m/%d-%H:%M:%S", &now); - snprintf (tmp_str, 1024, "%s-%d-%s:%" -#ifdef GF_DARWIN_HOST_OS - PRId32, -#else - "ld", -#endif - hostname, getpid(), now_str, tv.tv_usec); - - return gf_strdup (tmp_str); -} +extern struct rpc_clnt_program cli_prog; static int glusterfs_ctx_defaults_init (glusterfs_ctx_t *ctx) @@ -143,13 +98,13 @@ glusterfs_ctx_defaults_init (glusterfs_ctx_t *ctx) xlator_mem_acct_init (THIS, cli_mt_end); - ctx->process_uuid = generate_uuid (); + ctx->process_uuid = generate_glusterfs_ctx_id (); if (!ctx->process_uuid) return -1; ctx->page_size = 128 * GF_UNIT_KB; - ctx->iobuf_pool = iobuf_pool_new (8 * GF_UNIT_MB, ctx->page_size); + ctx->iobuf_pool = iobuf_pool_new (); if (!ctx->iobuf_pool) return -1; @@ -162,22 +117,33 @@ glusterfs_ctx_defaults_init (glusterfs_ctx_t *ctx) if (!pool) return -1; - /* frame_mem_pool size 112 * 16k */ - pool->frame_mem_pool = mem_pool_new (call_frame_t, 16384); - + /* frame_mem_pool size 112 * 64 */ + pool->frame_mem_pool = mem_pool_new (call_frame_t, 32); if (!pool->frame_mem_pool) return -1; - /* stack_mem_pool size 256 * 8k */ - pool->stack_mem_pool = mem_pool_new (call_stack_t, 8192); + /* stack_mem_pool size 256 * 128 */ + pool->stack_mem_pool = mem_pool_new (call_stack_t, 16); if (!pool->stack_mem_pool) return -1; - ctx->stub_mem_pool = mem_pool_new (call_stub_t, 1024); + ctx->stub_mem_pool = mem_pool_new (call_stub_t, 16); if (!ctx->stub_mem_pool) return -1; + ctx->dict_pool = mem_pool_new (dict_t, 32); + if (!ctx->dict_pool) + return -1; + + ctx->dict_pair_pool = mem_pool_new (data_pair_t, 512); + if (!ctx->dict_pair_pool) + return -1; + + ctx->dict_data_pool = mem_pool_new (data_t, 512); + if (!ctx->dict_data_pool) + return -1; + INIT_LIST_HEAD (&pool->all_frames); LOCK_INIT (&pool->lock); ctx->pool = pool; @@ -186,10 +152,6 @@ glusterfs_ctx_defaults_init (glusterfs_ctx_t *ctx) cmd_args = &ctx->cmd_args; - /* parsing command line arguments */ - cmd_args->log_file = "/dev/stderr"; - cmd_args->log_level = GF_LOG_NONE; - INIT_LIST_HEAD (&cmd_args->xlator_options); lim.rlim_cur = RLIM_INFINITY; @@ -201,20 +163,22 @@ glusterfs_ctx_defaults_init (glusterfs_ctx_t *ctx) static int -logging_init (glusterfs_ctx_t *ctx) +logging_init (glusterfs_ctx_t *ctx, struct cli_state *state) { - cmd_args_t *cmd_args = NULL; - - cmd_args = &ctx->cmd_args; + char *log_file = state->log_file ? state->log_file : + DEFAULT_CLI_LOG_FILE_DIRECTORY "/cli.log"; - if (gf_log_init (cmd_args->log_file) == -1) { - fprintf (stderr, - "failed to open logfile %s. exiting\n", - cmd_args->log_file); + /* passing ident as NULL means to use default ident for syslog */ + if (gf_log_init (ctx, log_file, NULL) == -1) { + fprintf (stderr, "ERROR: failed to open logfile %s\n", + log_file); return -1; } - gf_log_set_loglevel (cmd_args->log_level); + /* CLI should not have something to DEBUG after the release, + hence defaulting to INFO loglevel */ + gf_log_set_loglevel ((state->log_level == -1) ? GF_LOG_INFO : + state->log_level); return 0; } @@ -223,41 +187,41 @@ int cli_submit_request (void *req, call_frame_t *frame, rpc_clnt_prog_t *prog, int procnum, struct iobref *iobref, - cli_serialize_t sfunc, xlator_t *this, - fop_cbk_fn_t cbkfn) + xlator_t *this, fop_cbk_fn_t cbkfn, xdrproc_t xdrproc) { int ret = -1; int count = 0; - char start_ping = 0; struct iovec iov = {0, }; struct iobuf *iobuf = NULL; char new_iobref = 0; + ssize_t xdr_size = 0; GF_ASSERT (this); - iobuf = iobuf_get (this->ctx->iobuf_pool); - if (!iobuf) { - goto out; - }; + if (req) { + xdr_size = xdr_sizeof (xdrproc, req); + iobuf = iobuf_get2 (this->ctx->iobuf_pool, xdr_size); + if (!iobuf) { + goto out; + }; - if (!iobref) { - iobref = iobref_new (); if (!iobref) { - goto out; - } + iobref = iobref_new (); + if (!iobref) { + goto out; + } - new_iobref = 1; - } + new_iobref = 1; + } - iobref_add (iobref, iobuf); + iobref_add (iobref, iobuf); - iov.iov_base = iobuf->ptr; - iov.iov_len = 128 * GF_UNIT_KB; + iov.iov_base = iobuf->ptr; + iov.iov_len = iobuf_size (iobuf); - /* Create the xdr payload */ - if (req && sfunc) { - ret = sfunc (iov, req); + /* Create the xdr payload */ + ret = xdr_serialize_generic (iov, req, xdrproc); if (ret == -1) { goto out; } @@ -269,23 +233,13 @@ cli_submit_request (void *req, call_frame_t *frame, ret = rpc_clnt_submit (global_rpc, prog, procnum, cbkfn, &iov, count, NULL, 0, iobref, frame, NULL, 0, NULL, 0, NULL); - - if (ret == 0) { - pthread_mutex_lock (&global_rpc->conn.lock); - { - if (!global_rpc->conn.ping_started) { - start_ping = 1; - } - } - pthread_mutex_unlock (&global_rpc->conn.lock); - } - - if (start_ping) - //client_start_ping ((void *) this); - ret = 0; out: + if (new_iobref) + iobref_unref (iobref); + if (iobuf) + iobuf_unref (iobuf); return ret; } @@ -311,6 +265,12 @@ cli_rpc_notify (struct rpc_clnt *rpc, void *mydata, rpc_clnt_event_t event, { gf_log (this->name, GF_LOG_TRACE, "got RPC_CLNT_DISCONNECT"); connected = 0; + if (!global_state->prompt && global_state->await_connected) { + ret = 1; + cli_out ("Connection failed. Please check if gluster " + "daemon is operational."); + exit (ret); + } break; } @@ -324,11 +284,44 @@ cli_rpc_notify (struct rpc_clnt *rpc, void *mydata, rpc_clnt_event_t event, return ret; } + +/* + * ret: 0: option successfully processed + * 1: signalling end of option list + * -1: unknown option or other issue + */ int cli_opt_parse (char *opt, struct cli_state *state) { char *oarg; + if (strcmp (opt, "") == 0) + return 1; + + if (strcmp (opt, "version") == 0) { + cli_out ("%s", argp_program_version); + exit (0); + } + + if (strcmp (opt, "print-logdir") == 0) { + cli_out ("%s", DEFAULT_LOG_FILE_DIRECTORY); + exit (0); + } + + if (strcmp (opt, "print-statedumpdir") == 0) { + cli_out ("%s", DEFAULT_VAR_RUN_DIRECTORY); + exit (0); + } + + if (strcmp (opt, "xml") == 0) { +#if (HAVE_LIB_XML) + state->mode |= GLUSTER_MODE_XML; +#else + cli_err ("XML output not supported. Ignoring '--xml' option"); +#endif + return 0; + } + oarg = strtail (opt, "mode="); if (oarg) { if (strcmp (oarg, "script") == 0) { @@ -346,6 +339,26 @@ cli_opt_parse (char *opt, struct cli_state *state) return 0; } + oarg = strtail (opt, "log-file="); + if (oarg) { + state->log_file = oarg; + return 0; + } + + oarg = strtail (opt, "log-level="); + if (oarg) { + state->log_level = glusterd_check_log_level(oarg); + if (state->log_level == -1) + return -1; + return 0; + } + + oarg = strtail (opt, "glusterd-sock="); + if (oarg) { + state->glusterd_sock = oarg; + return 0; + } + return -1; } @@ -371,9 +384,18 @@ parse_cmdline (int argc, char *argv[], struct cli_state *state) for (j = i; j < state->argc - 1; j++) state->argv[j] = state->argv[j + 1]; state->argc--; + /* argv shifted, next check should be at i again */ + i--; + if (ret == 1) { + /* end of cli options */ + ret = 0; + break; + } } } + state->argv[state->argc] = NULL; + return ret; } @@ -398,7 +420,7 @@ cli_state_init (struct cli_state *state) int ret = 0; - state->remote_host = "localhost"; + state->log_level = -1; tree = &state->tree; tree->state = state; @@ -408,9 +430,45 @@ cli_state_init (struct cli_state *state) return ret; } +int +cli_usage_out (const char *usage) +{ + GF_ASSERT (usage); + GF_ASSERT (usage[0] != '\0'); + + if (!usage || usage[0] == '\0') + return -1; + + cli_err ("Usage: %s", usage); + return 0; +} int -cli_out (const char *fmt, ...) +_cli_err (const char *fmt, ...) +{ + struct cli_state *state = NULL; + va_list ap; + int ret = 0; + + state = global_state; + + va_start (ap, fmt); + +#ifdef HAVE_READLINE + if (state->rl_enabled && !state->rl_processing) + return cli_rl_err(state, fmt, ap); +#endif + + ret = vfprintf (stderr, fmt, ap); + fprintf (stderr, "\n"); + va_end (ap); + + return ret; +} + + +int +_cli_out (const char *fmt, ...) { struct cli_state *state = NULL; va_list ap; @@ -427,6 +485,7 @@ cli_out (const char *fmt, ...) ret = vprintf (fmt, ap); printf ("\n"); + va_end (ap); return ret; } @@ -435,7 +494,6 @@ struct rpc_clnt * cli_rpc_init (struct cli_state *state) { struct rpc_clnt *rpc = NULL; - struct rpc_clnt_config rpc_cfg = {0,}; dict_t *options = NULL; int ret = -1; int port = CLI_GLUSTERD_PORT; @@ -443,35 +501,67 @@ cli_rpc_init (struct cli_state *state) this = THIS; - cli_rpc_prog = &cli3_1_prog; + cli_rpc_prog = &cli_prog; options = dict_new (); if (!options) goto out; - ret = dict_set_str (options, "remote-host", state->remote_host); - if (ret) - goto out; + /* Connect using to glusterd using the specified method, giving + * preference to unix socket connection. If nothing is specified connect + * to the default glusterd socket + */ + if (state->glusterd_sock) { + gf_log ("cli", GF_LOG_INFO, "Connecting to glusterd using " + "sockfile %s", state->glusterd_sock); + ret = rpc_transport_unix_options_build (&options, + state->glusterd_sock, + 0); + if (ret) + goto out; + } else if (state->remote_host) { + gf_log ("cli", GF_LOG_INFO, "Connecting to remote glusterd at " + "%s", state->remote_host); + ret = dict_set_str (options, "remote-host", state->remote_host); + if (ret) + goto out; - if (state->remote_port) - port = state->remote_port; + if (state->remote_port) + port = state->remote_port; - rpc_cfg.remote_host = state->remote_host; - rpc_cfg.remote_port = port; + ret = dict_set_int32 (options, "remote-port", port); + if (ret) + goto out; - ret = dict_set_int32 (options, "remote-port", port); - if (ret) - goto out; + ret = dict_set_str (options, "transport.address-family", + "inet"); + if (ret) + goto out; + } else { + gf_log ("cli", GF_LOG_DEBUG, "Connecting to glusterd using " + "default socket"); + ret = rpc_transport_unix_options_build + (&options, DEFAULT_GLUSTERD_SOCKFILE, 0); + if (ret) + goto out; + } - ret = dict_set_str (options, "transport.address-family", "inet"); - if (ret) + rpc = rpc_clnt_new (options, this->ctx, this->name, 16); + if (!rpc) goto out; - rpc = rpc_clnt_init (&rpc_cfg, options, this->ctx, this->name); - - if (rpc) { - ret = rpc_clnt_register_notify (rpc, cli_rpc_notify, this); + ret = rpc_clnt_register_notify (rpc, cli_rpc_notify, this); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "failed to register notify"); + goto out; } + + ret = rpc_clnt_start (rpc); out: + if (ret) { + if (rpc) + rpc_clnt_unref (rpc); + rpc = NULL; + } return rpc; } @@ -489,32 +579,15 @@ void cli_local_wipe (cli_local_t *local) { if (local) { + GF_FREE (local->get_vol.volname); + if (local->dict) + dict_unref (local->dict); GF_FREE (local); } return; } -void -cli_path_strip_trailing_slashes (char *path) -{ - int i = 0; - int len = 0; - - if (!path) - return; - - len = strlen (path); - for (i = len - 1; i > 0 ; i--) { - if (path[i] != '/') - break; - - } - - if (i < (len - 1)) - path[i + 1] = '\0'; -} - struct cli_state *global_state; int @@ -524,18 +597,19 @@ main (int argc, char *argv[]) int ret = -1; glusterfs_ctx_t *ctx = NULL; - if (geteuid ()) { - printf ("Only super user can run this command\n"); - return EPERM; - } + ctx = glusterfs_ctx_new (); + if (!ctx) + return ENOMEM; + +#ifdef DEBUG + gf_mem_acct_enable_set (ctx); +#endif - ret = glusterfs_globals_init (); + ret = glusterfs_globals_init (ctx); if (ret) return ret; - ctx = glusterfs_ctx_get (); - if (!ctx) - return ENOMEM; + THIS->ctx = ctx; ret = glusterfs_ctx_defaults_init (ctx); if (ret) @@ -552,12 +626,12 @@ main (int argc, char *argv[]) if (ret) goto out; - global_rpc = cli_rpc_init (&state); - if (!global_rpc) + ret = logging_init (ctx, &state); + if (ret) goto out; - ret = logging_init (ctx); - if (ret) + global_rpc = cli_rpc_init (&state); + if (!global_rpc) goto out; ret = cli_cmds_register (&state); @@ -579,3 +653,14 @@ out: return ret; } + +void +cli_print_line (int len) +{ + GF_ASSERT (len > 0); + + while (len--) + printf ("-"); + + printf ("\n"); +} diff --git a/cli/src/cli.h b/cli/src/cli.h index 57be8c6f6..8daa4b741 100644 --- a/cli/src/cli.h +++ b/cli/src/cli.h @@ -1,22 +1,12 @@ /* - Copyright (c) 2006-2010 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2006-2012 Red Hat, Inc. <http://www.redhat.com> This file is part of GlusterFS. - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. */ - #ifndef __CLI_H__ #define __CLI_H__ @@ -28,11 +18,24 @@ #include "rpc-clnt.h" #include "glusterfs.h" #include "protocol-common.h" +#include "logging.h" + +#include "cli1-xdr.h" + +#if (HAVE_LIB_XML) +#include <libxml/encoding.h> +#include <libxml/xmlwriter.h> +#endif #define DEFAULT_EVENT_POOL_SIZE 16384 #define CLI_GLUSTERD_PORT 24007 #define CLI_DEFAULT_CONN_TIMEOUT 120 #define CLI_DEFAULT_CMD_TIMEOUT 120 +#define CLI_TEN_MINUTES_TIMEOUT 600 //Longer timeout for volume top +#define DEFAULT_CLI_LOG_FILE_DIRECTORY DATADIR "/log/glusterfs" +#define CLI_VOL_STATUS_BRICK_LEN 55 +#define CLI_TAB_LENGTH 8 +#define CLI_BRICK_STATUS_LINE_LEN 78 enum argp_option_keys { ARGP_DEBUG_KEY = 133, @@ -41,15 +44,22 @@ enum argp_option_keys { #define GLUSTER_MODE_SCRIPT (1 << 0) #define GLUSTER_MODE_ERR_FATAL (1 << 1) - +#define GLUSTER_MODE_XML (1 << 2) struct cli_state; struct cli_cmd_word; struct cli_cmd_tree; +struct cli_cmd; + +extern char *cli_vol_type_str[]; +extern char *cli_vol_status_str[]; +extern char *cli_vol_task_status_str[]; typedef int (cli_cmd_cbk_t)(struct cli_state *state, struct cli_cmd_word *word, const char **words, int wordcount); +typedef void (cli_cmd_reg_cbk_t)( struct cli_cmd *this); + typedef int (cli_cmd_match_t)(struct cli_cmd_word *word); typedef int (cli_cmd_filler_t)(struct cli_cmd_word *word); @@ -60,7 +70,7 @@ struct cli_cmd_word { cli_cmd_match_t *match; cli_cmd_cbk_t *cbkfn; const char *desc; - + const char *pattern; int nextwords_cnt; struct cli_cmd_word **nextwords; }; @@ -101,53 +111,81 @@ struct cli_state { char *remote_host; int remote_port; int mode; + int await_connected; + + char *log_file; + gf_loglevel_t log_level; + + char *glusterd_sock; }; struct cli_local { - union { - struct { - dict_t *dict; - } create_vol; - - struct { - char *volname; - int flags; - } start_vol; - - struct { - char *volname; - int flags; - } stop_vol; - - struct { - char *volname; - } delete_vol; - - struct { - char *volname; - int cmd; - } defrag_vol; - - struct { - char *volname; - dict_t *dict; - } replace_brick; - - struct { - char *volname; - int flags; - } get_vol; - } u; + struct { + char *volname; + int flags; + } get_vol; + + dict_t *dict; + const char **words; + /* Marker for volume status all */ + gf_boolean_t all; +#if (HAVE_LIB_XML) + xmlTextWriterPtr writer; + xmlDocPtr doc; + int vol_count; +#endif }; +struct gf_cli_gsync_detailed_status_ { + char *node; + char *master; + char *slave; + char *health; + char *uptime; + char *files_syncd; + char *files_pending; + char *bytes_pending; + char *deletes_pending; +}; + +struct cli_volume_status { + int port; + int online; + uint64_t block_size; + uint64_t total_inodes; + uint64_t free_inodes; + char *brick; + char *pid_str; + char *free; + char *total; +#ifdef GF_LINUX_HOST_OS + char *fs_name; + char *mount_options; + char *device; + char *inode_size; +#endif +}; + +struct snap_config_opt_vals_ { + char *op_name; + char *question; +}; + +typedef struct gf_cli_gsync_detailed_status_ gf_cli_gsync_status_t; + +typedef struct cli_volume_status cli_volume_status_t; + typedef struct cli_local cli_local_t; typedef ssize_t (*cli_serialize_t) (struct iovec outmsg, void *args); extern struct cli_state *global_state; /* use only in readline callback */ -int cli_cmd_register (struct cli_cmd_tree *tree, const char *template, - cli_cmd_cbk_t cbk, const char *desc); +typedef const char *(*cli_selector_t) (void *wcon); + +void *cli_getunamb (const char *tok, void **choices, cli_selector_t sel); + +int cli_cmd_register (struct cli_cmd_tree *tree, struct cli_cmd *cmd); int cli_cmds_register (struct cli_state *state); int cli_input_init (struct cli_state *state); @@ -157,15 +195,32 @@ int cli_cmd_process_line (struct cli_state *state, const char *line); int cli_rl_enable (struct cli_state *state); int cli_rl_out (struct cli_state *state, const char *fmt, va_list ap); +int cli_rl_err (struct cli_state *state, const char *fmt, va_list ap); + +int cli_usage_out (const char *usage); -int cli_out (const char *fmt, ...); +int _cli_out (const char *fmt, ...); +int _cli_err (const char *fmt, ...); + +#define cli_out(fmt...) do { \ + FMT_WARN (fmt); \ + \ + _cli_out(fmt); \ + \ + } while (0) + +#define cli_err(fmt...) do { \ + FMT_WARN (fmt); \ + \ + _cli_err(fmt); \ + \ + } while (0) int cli_submit_request (void *req, call_frame_t *frame, rpc_clnt_prog_t *prog, int procnum, struct iobref *iobref, - cli_serialize_t sfunc, xlator_t *this, - fop_cbk_fn_t cbkfn); + xlator_t *this, fop_cbk_fn_t cbkfn, xdrproc_t xdrproc); int32_t cli_cmd_volume_create_parse (const char **words, int wordcount, @@ -175,8 +230,14 @@ int32_t cli_cmd_volume_reset_parse (const char **words, int wordcount, dict_t **opt); int32_t +cli_cmd_gsync_set_parse (const char **words, int wordcount, dict_t **opt); + +int32_t +cli_cmd_quota_parse (const char **words, int wordcount, dict_t **opt); + +int32_t cli_cmd_volume_set_parse (const char **words, int wordcount, - dict_t **options); + dict_t **options, char **op_errstr); int32_t cli_cmd_volume_add_brick_parse (const char **words, int wordcount, @@ -184,7 +245,7 @@ cli_cmd_volume_add_brick_parse (const char **words, int wordcount, int32_t cli_cmd_volume_remove_brick_parse (const char **words, int wordcount, - dict_t **options); + dict_t **options, int *question); int32_t cli_cmd_volume_replace_brick_parse (const char **words, int wordcount, @@ -197,6 +258,13 @@ cli_cmd_log_locate_parse (const char **words, int wordcount, dict_t **options); int32_t cli_cmd_log_filename_parse (const char **words, int wordcount, dict_t **options); +int32_t +cli_cmd_volume_statedump_options_parse (const char **words, int wordcount, + dict_t **options); +int32_t +cli_cmd_volume_clrlks_opts_parse (const char **words, int wordcount, + dict_t **options); + cli_local_t * cli_local_get (); void @@ -211,6 +279,122 @@ cli_cmd_broadcast_connected (); int cli_rpc_notify (struct rpc_clnt *rpc, void *mydata, rpc_clnt_event_t event, void *data); + +int32_t +cli_cmd_volume_profile_parse (const char **words, int wordcount, + dict_t **options); +int32_t +cli_cmd_volume_top_parse (const char **words, int wordcount, + dict_t **options); + +int32_t +cli_cmd_log_level_parse (const char **words, int wordcount, + dict_t **options); + +int32_t +cli_cmd_volume_status_parse (const char **words, int wordcount, + dict_t **options); + +int +cli_cmd_volume_heal_options_parse (const char **words, int wordcount, + dict_t **options); + +int +cli_cmd_volume_defrag_parse (const char **words, int wordcount, + dict_t **options); + +int +cli_print_brick_status (cli_volume_status_t *status); + void -cli_path_strip_trailing_slashes (char *path); +cli_print_detailed_status (cli_volume_status_t *status); + +int +cli_get_detail_status (dict_t *dict, int i, cli_volume_status_t *status); + +void +cli_print_line (int len); + +int +cli_xml_output_str (char *op, char *str, int op_ret, int op_errno, + char *op_errstr); + +int +cli_xml_output_dict (char *op, dict_t *dict, int op_ret, int op_errno, + char *op_errstr); + +int +cli_xml_output_vol_top (dict_t *dict, int op_ret, int op_errno, + char *op_errstr); + +int +cli_xml_output_vol_profile (dict_t *dict, int op_ret, int op_errno, + char *op_errstr); + +int +cli_xml_output_vol_status_begin (cli_local_t *local, int op_ret, int op_errno, + char *op_errstr); + +int +cli_xml_output_vol_status_end (cli_local_t *local); + +int +cli_xml_output_vol_status (cli_local_t *local, dict_t *dict); + +int +cli_xml_output_vol_list (dict_t *dict, int op_ret, int op_errno, + char *op_errstr); + +int +cli_xml_output_vol_info_begin (cli_local_t *local, int op_ret, int op_errno, + char *op_errstr); + +int +cli_xml_output_vol_info_end (cli_local_t *local); + +int +cli_xml_output_vol_info (cli_local_t *local, dict_t *dict); + +int +cli_xml_output_vol_quota_limit_list (char *volname, char *limit_list, + int op_ret, int op_errno, + char *op_errstr); + +int +cli_xml_output_peer_status (dict_t *dict, int op_ret, int op_errno, + char *op_errstr); + +int +cli_xml_output_vol_rebalance (gf_cli_defrag_type op, dict_t *dict, int op_ret, + int op_errno, char *op_errstr); + +int +cli_xml_output_vol_remove_brick (gf_boolean_t status_op, dict_t *dict, + int op_ret, int op_errno, char *op_errstr); + +int +cli_xml_output_vol_replace_brick (gf1_cli_replace_op op, dict_t *dict, + int op_ret, int op_errno, char *op_errstr); + +int +cli_xml_output_vol_create (dict_t *dict, int op_ret, int op_errno, + char *op_errstr); + +int +cli_xml_output_generic_volume (char *op, dict_t *dict, int op_ret, int op_errno, + char *op_errstr); + +int +cli_xml_output_vol_gsync (dict_t *dict, int op_ret, int op_errno, + char *op_errstr); +int +cli_xml_output_vol_status_tasks_detail (cli_local_t *local, dict_t *dict); + +char * +is_server_debug_xlator (void *myframe); + +int32_t +cli_cmd_snapshot_parse (const char **words, int wordcount, dict_t **options, + struct cli_state *state); + #endif /* __CLI_H__ */ diff --git a/cli/src/cli3_1-cops.c b/cli/src/cli3_1-cops.c deleted file mode 100644 index 9e1338cb3..000000000 --- a/cli/src/cli3_1-cops.c +++ /dev/null @@ -1,2260 +0,0 @@ -/* - Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. - - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ - - -#ifndef _CONFIG_H -#define _CONFIG_H -#include "config.h" -#endif - -#include "cli.h" -#include "compat-errno.h" -#include "cli-cmd.h" -#include <sys/uio.h> - -#include "cli1-xdr.h" -#include "cli1.h" -#include "protocol-common.h" -#include "cli-mem-types.h" -#include "compat.h" - -#include "glusterfs3.h" -#include "portmap.h" - -extern rpc_clnt_prog_t *cli_rpc_prog; -extern int cli_op_ret; - -char *cli_volume_type[] = {"Distribute", - "Stripe", - "Replicate", - "Distributed-Stripe", - "Distributed-Replicate", -}; - - -char *cli_volume_status[] = {"Created", - "Started", - "Stopped" -}; - -int32_t -gf_cli3_1_get_volume (call_frame_t *frame, xlator_t *this, - void *data); - - -rpc_clnt_prog_t cli_handshake_prog = { - .progname = "cli handshake", - .prognum = GLUSTER_HNDSK_PROGRAM, - .progver = GLUSTER_HNDSK_VERSION, -}; - -rpc_clnt_prog_t cli_pmap_prog = { - .progname = "cli portmap", - .prognum = GLUSTER_PMAP_PROGRAM, - .progver = GLUSTER_PMAP_VERSION, -}; - - -int -gf_cli3_1_probe_cbk (struct rpc_req *req, struct iovec *iov, - int count, void *myframe) -{ - gf1_cli_probe_rsp rsp = {0,}; - int ret = 0; - - if (-1 == req->rpc_status) { - goto out; - } - - ret = gf_xdr_to_cli_probe_rsp (*iov, &rsp); - if (ret < 0) { - gf_log ("", GF_LOG_ERROR, "error"); - //rsp.op_ret = -1; - //rsp.op_errno = EINVAL; - goto out; - } - - gf_log ("cli", GF_LOG_NORMAL, "Received resp to probe"); - if (!rsp.op_ret) { - switch (rsp.op_errno) { - case GF_PROBE_SUCCESS: - cli_out ("Probe successful"); - break; - case GF_PROBE_LOCALHOST: - cli_out ("Probe on localhost not needed"); - break; - case GF_PROBE_FRIEND: - cli_out ("Probe on host %s port %d already" - " a friend",rsp.hostname, rsp.port); - break; - default: - cli_out ("Probe returned with unknown errno %d", - rsp.op_errno); - break; - } - } - - if (rsp.op_ret) { - switch (rsp.op_errno) { - case GF_PROBE_ANOTHER_CLUSTER: - cli_out ("%s is already part of " - "another cluster", rsp.hostname); - break; - case GF_PROBE_VOLUME_CONFLICT: - cli_out ("Atleast one volume on %s conflicts " - "with existing volumes in the " - "cluster", rsp.hostname); - break; - case GF_PROBE_UNKNOWN_PEER: - cli_out ("%s responded with 'unknown peer' error, " - "this could happen if %s doesn't have" - " localhost in its peer database", - rsp.hostname, rsp.hostname); - break; - case GF_PROBE_ADD_FAILED: - cli_out ("Failed to add peer information " - "on %s" , rsp.hostname); - break; - - default: - cli_out ("Probe returned with unknown errno %d", - rsp.op_errno); - break; - } - cli_out ("Probe unsuccessful"); - gf_log ("glusterd",GF_LOG_ERROR,"Probe failed with op_ret %d" - " and op_errno %d", rsp.op_ret, rsp.op_errno); - } - ret = rsp.op_ret; - -out: - cli_cmd_broadcast_response (ret); - return ret; -} - -int -gf_cli3_1_deprobe_cbk (struct rpc_req *req, struct iovec *iov, - int count, void *myframe) -{ - gf1_cli_deprobe_rsp rsp = {0,}; - int ret = 0; - - if (-1 == req->rpc_status) { - goto out; - } - - ret = gf_xdr_to_cli_deprobe_rsp (*iov, &rsp); - if (ret < 0) { - gf_log ("", GF_LOG_ERROR, "error"); - //rsp.op_ret = -1; - //rsp.op_errno = EINVAL; - goto out; - } - - gf_log ("cli", GF_LOG_NORMAL, "Received resp to deprobe"); - if (rsp.op_ret) { - switch (rsp.op_errno) { - case GF_DEPROBE_LOCALHOST: - cli_out ("%s is localhost", - rsp.hostname); - break; - case GF_DEPROBE_NOT_FRIEND: - cli_out ("%s is not part of cluster", - rsp.hostname); - break; - case GF_DEPROBE_BRICK_EXIST: - cli_out ("Brick(s) with the peer %s exist in " - "cluster", rsp.hostname); - break; - default: - cli_out ("Detach returned with unknown errno %d", - rsp.op_errno); - break; - } - cli_out ("Detach unsuccessful"); - gf_log ("glusterd",GF_LOG_ERROR,"Detach failed with op_ret %d" - " and op_errno %d", rsp.op_ret, rsp.op_errno); - } else { - cli_out ("Detach successful"); - } - - - ret = rsp.op_ret; - -out: - cli_cmd_broadcast_response (ret); - return ret; -} - -int -gf_cli3_1_list_friends_cbk (struct rpc_req *req, struct iovec *iov, - int count, void *myframe) -{ - gf1_cli_peer_list_rsp rsp = {0,}; - int ret = 0; - dict_t *dict = NULL; - char *uuid_buf = NULL; - char *hostname_buf = NULL; - int32_t i = 1; - char key[256] = {0,}; - char *state = NULL; - int32_t port = 0; - int32_t connected = 0; - char *connected_str = NULL; - - if (-1 == req->rpc_status) { - goto out; - } - - ret = gf_xdr_to_cli_peer_list_rsp (*iov, &rsp); - if (ret < 0) { - gf_log ("", GF_LOG_ERROR, "error"); - //rsp.op_ret = -1; - //rsp.op_errno = EINVAL; - goto out; - } - - - gf_log ("cli", GF_LOG_NORMAL, "Received resp to list: %d", - rsp.op_ret); - - ret = rsp.op_ret; - - if (!rsp.op_ret) { - - if (!rsp.friends.friends_len) { - cli_out ("No peers present"); - ret = 0; - goto out; - } - - dict = dict_new (); - - if (!dict) { - ret = -1; - goto out; - } - - ret = dict_unserialize (rsp.friends.friends_val, - rsp.friends.friends_len, - &dict); - - if (ret) { - gf_log ("", GF_LOG_ERROR, - "Unable to allocate memory"); - goto out; - } - - ret = dict_get_int32 (dict, "count", &count); - - if (ret) { - goto out; - } - - cli_out ("Number of Peers: %d", count); - - while ( i <= count) { - snprintf (key, 256, "friend%d.uuid", i); - ret = dict_get_str (dict, key, &uuid_buf); - if (ret) - goto out; - - snprintf (key, 256, "friend%d.hostname", i); - ret = dict_get_str (dict, key, &hostname_buf); - if (ret) - goto out; - - snprintf (key, 256, "friend%d.connected", i); - ret = dict_get_int32 (dict, key, &connected); - if (ret) - goto out; - if (connected) - connected_str = "Connected"; - else - connected_str = "Disconnected"; - - snprintf (key, 256, "friend%d.port", i); - ret = dict_get_int32 (dict, key, &port); - if (ret) - goto out; - - snprintf (key, 256, "friend%d.state", i); - ret = dict_get_str (dict, key, &state); - if (ret) - goto out; - - if (!port) { - cli_out ("\nHostname: %s\nUuid: %s\nState: %s " - "(%s)", - hostname_buf, uuid_buf, state, - connected_str); - } else { - cli_out ("\nHostname: %s\nPort: %d\nUuid: %s\n" - "State: %s (%s)", hostname_buf, port, - uuid_buf, state, connected_str); - } - i++; - } - } else { - ret = -1; - goto out; - } - - - ret = 0; - -out: - cli_cmd_broadcast_response (ret); - if (ret) - cli_out ("Command Execution Failed"); - - if (dict) - dict_destroy (dict); - - return ret; -} - -void -cli_out_options ( char *substr, char *optstr, char *valstr) -{ - char *ptr1 = NULL; - char *ptr2 = NULL; - - ptr1 = substr; - ptr2 = optstr; - - while (ptr1) - { - if (*ptr1 != *ptr2) - break; - ptr1++; - ptr2++; - if (!ptr1) - return; - if (!ptr2) - return; - } - - if (*ptr2 == '\0') - return; - cli_out ("%s: %s",ptr2 , valstr); -} - - -int -gf_cli3_1_get_volume_cbk (struct rpc_req *req, struct iovec *iov, - int count, void *myframe) -{ - gf1_cli_get_vol_rsp rsp = {0,}; - int ret = 0; - dict_t *dict = NULL; - char *volname = NULL; - int32_t i = 0; - char key[1024] = {0,}; - int32_t status = 0; - int32_t type = 0; - int32_t brick_count = 0; - int32_t sub_count = 0; - int32_t vol_type = 0; - char *brick = NULL; - int32_t j = 1; - cli_local_t *local = NULL; - int32_t transport = 0; - data_pair_t *pairs = NULL; - char *ptr = NULL; - data_t *value = NULL; - int opt_count = 0; - int k = 0; - - - - if (-1 == req->rpc_status) { - goto out; - } - - ret = gf_xdr_to_cli_get_vol_rsp (*iov, &rsp); - if (ret < 0) { - gf_log ("", GF_LOG_ERROR, "error"); - //rsp.op_ret = -1; - //rsp.op_errno = EINVAL; - goto out; - } - - - gf_log ("cli", GF_LOG_NORMAL, "Received resp to get vol: %d", - rsp.op_ret); - - if (!rsp.op_ret) { - - if (!rsp.volumes.volumes_len) { - cli_out ("No volumes present"); - ret = 0; - goto out; - } - - dict = dict_new (); - - if (!dict) { - ret = -1; - goto out; - } - - ret = dict_unserialize (rsp.volumes.volumes_val, - rsp.volumes.volumes_len, - &dict); - - if (ret) { - gf_log ("", GF_LOG_ERROR, - "Unable to allocate memory"); - goto out; - } - - ret = dict_get_int32 (dict, "count", &count); - - if (ret) { - goto out; - } - - local = ((call_frame_t *)myframe)->local; - //cli_out ("Number of Volumes: %d", count); - - if (!count && (local->u.get_vol.flags == - GF_CLI_GET_NEXT_VOLUME)) { - local->u.get_vol.volname = NULL; - ret = 0; - goto out; - } else if (!count && (local->u.get_vol.flags == - GF_CLI_GET_VOLUME)) { - cli_out ("Volume %s not present", - local->u.get_vol.volname); - ret = 0; - goto out; - } - - while ( i < count) { - cli_out (""); - snprintf (key, 256, "volume%d.name", i); - ret = dict_get_str (dict, key, &volname); - if (ret) - goto out; - - snprintf (key, 256, "volume%d.type", i); - ret = dict_get_int32 (dict, key, &type); - if (ret) - goto out; - - snprintf (key, 256, "volume%d.status", i); - ret = dict_get_int32 (dict, key, &status); - if (ret) - goto out; - - snprintf (key, 256, "volume%d.brick_count", i); - ret = dict_get_int32 (dict, key, &brick_count); - if (ret) - goto out; - - snprintf (key, 256, "volume%d.sub_count", i); - ret = dict_get_int32 (dict, key, &sub_count); - if (ret) - goto out; - - snprintf (key, 256, "volume%d.transport", i); - ret = dict_get_int32 (dict, key, &transport); - if (ret) - goto out; - - vol_type = type; - - // Stripe - if ((type == 1) && (sub_count < brick_count)) - vol_type = 3; - - // Replicate - if ((type == 2) && (sub_count < brick_count)) - vol_type = 4; - - cli_out ("Volume Name: %s", volname); - cli_out ("Type: %s", cli_volume_type[vol_type]); - cli_out ("Status: %s", cli_volume_status[status], brick_count); - if ((sub_count > 1) && (brick_count > sub_count)) - cli_out ("Number of Bricks: %d x %d = %d", - brick_count / sub_count, sub_count, - brick_count); - else - cli_out ("Number of Bricks: %d", brick_count); - - cli_out ("Transport-type: %s", ((transport == 0)? - "tcp" : "rdma")); - j = 1; - - - GF_FREE (local->u.get_vol.volname); - local->u.get_vol.volname = gf_strdup (volname); - - if (brick_count) - cli_out ("Bricks:"); - - while ( j <= brick_count) { - snprintf (key, 1024, "volume%d.brick%d", - i, j); - ret = dict_get_str (dict, key, &brick); - if (ret) - goto out; - cli_out ("Brick%d: %s", j, brick); - j++; - } - pairs = dict->members_list; - if (!pairs) { - ret = -1; - goto out; - } - - snprintf (key, 256, "volume%d.opt_count",i); - ret = dict_get_int32 (dict, key, &opt_count); - if (ret) - goto out; - - if (!opt_count) - goto out; - - cli_out ("Options Reconfigured:"); - k = 0; - while ( k < opt_count) { - - snprintf (key, 256, "volume%d.option.",i); - while (pairs) { - ptr = strstr (pairs->key, "option."); - if (ptr) { - value = pairs->value; - if (!value) { - ret = -1; - goto out; - } - cli_out_options (key, pairs->key, - value->data); - } - pairs = pairs->next; - } - k++; - } - - i++; - } - - - } else { - ret = -1; - goto out; - } - - - ret = 0; - -out: - cli_cmd_broadcast_response (ret); - if (ret) - cli_out ("Command Execution Failed"); - - if (dict) - dict_destroy (dict); - - gf_log ("", GF_LOG_NORMAL, "Returning: %d", ret); - return ret; -} - -int -gf_cli3_1_create_volume_cbk (struct rpc_req *req, struct iovec *iov, - int count, void *myframe) -{ - gf1_cli_create_vol_rsp rsp = {0,}; - int ret = 0; - cli_local_t *local = NULL; - char *volname = NULL; - dict_t *dict = NULL; - - if (-1 == req->rpc_status) { - goto out; - } - - ret = gf_xdr_to_cli_create_vol_rsp (*iov, &rsp); - if (ret < 0) { - gf_log ("", GF_LOG_ERROR, "error"); - goto out; - } - - local = ((call_frame_t *) (myframe))->local; - - dict = local->u.create_vol.dict; - - ret = dict_get_str (dict, "volname", &volname); - - gf_log ("cli", GF_LOG_NORMAL, "Received resp to create volume"); - cli_out ("Creation of volume %s has been %s", volname, - (rsp.op_ret) ? "unsuccessful": "successful"); - if (rsp.op_ret && rsp.op_errstr) - cli_out ("%s", rsp.op_errstr); - - ret = rsp.op_ret; - -out: - cli_cmd_broadcast_response (ret); - return ret; -} - -int -gf_cli3_1_delete_volume_cbk (struct rpc_req *req, struct iovec *iov, - int count, void *myframe) -{ - gf1_cli_delete_vol_rsp rsp = {0,}; - int ret = 0; - cli_local_t *local = NULL; - char *volname = NULL; - call_frame_t *frame = NULL; - - if (-1 == req->rpc_status) { - goto out; - } - - ret = gf_xdr_to_cli_delete_vol_rsp (*iov, &rsp); - if (ret < 0) { - gf_log ("", GF_LOG_ERROR, "error"); - goto out; - } - - frame = myframe; - local = frame->local; - - if (local) - volname = local->u.delete_vol.volname; - - - gf_log ("cli", GF_LOG_NORMAL, "Received resp to delete volume"); - cli_out ("Deleting volume %s has been %s", volname, - (rsp.op_ret) ? "unsuccessful": "successful"); - - ret = rsp.op_ret; - -out: - cli_cmd_broadcast_response (ret); - gf_log ("", GF_LOG_NORMAL, "Returning with %d", ret); - return ret; -} - -int -gf_cli3_1_start_volume_cbk (struct rpc_req *req, struct iovec *iov, - int count, void *myframe) -{ - gf1_cli_start_vol_rsp rsp = {0,}; - int ret = 0; - cli_local_t *local = NULL; - char *volname = NULL; - call_frame_t *frame = NULL; - - if (-1 == req->rpc_status) { - goto out; - } - - ret = gf_xdr_to_cli_start_vol_rsp (*iov, &rsp); - if (ret < 0) { - gf_log ("", GF_LOG_ERROR, "error"); - goto out; - } - - frame = myframe; - - if (frame) - local = frame->local; - - if (local) - volname = local->u.start_vol.volname; - - gf_log ("cli", GF_LOG_NORMAL, "Received resp to start volume"); - cli_out ("Starting volume %s has been %s", volname, - (rsp.op_ret) ? "unsuccessful": "successful"); - - if (rsp.op_ret && rsp.op_errstr) - cli_out ("%s", rsp.op_errstr); - - ret = rsp.op_ret; - -out: - cli_cmd_broadcast_response (ret); - return ret; -} - -int -gf_cli3_1_stop_volume_cbk (struct rpc_req *req, struct iovec *iov, - int count, void *myframe) -{ - gf1_cli_stop_vol_rsp rsp = {0,}; - int ret = 0; - cli_local_t *local = NULL; - char *volname = NULL; - call_frame_t *frame = NULL; - - if (-1 == req->rpc_status) { - goto out; - } - - ret = gf_xdr_to_cli_stop_vol_rsp (*iov, &rsp); - if (ret < 0) { - gf_log ("", GF_LOG_ERROR, "error"); - goto out; - } - - frame = myframe; - - if (frame) - local = frame->local; - - if (local) - volname = local->u.start_vol.volname; - - gf_log ("cli", GF_LOG_NORMAL, "Received resp to stop volume"); - cli_out ("Stopping volume %s has been %s", volname, - (rsp.op_ret) ? "unsuccessful": "successful"); - - ret = rsp.op_ret; - -out: - cli_cmd_broadcast_response (ret); - return ret; -} - -int -gf_cli3_1_defrag_volume_cbk (struct rpc_req *req, struct iovec *iov, - int count, void *myframe) -{ - gf1_cli_defrag_vol_rsp rsp = {0,}; - cli_local_t *local = NULL; - char *volname = NULL; - call_frame_t *frame = NULL; - int cmd = 0; - int ret = 0; - - if (-1 == req->rpc_status) { - goto out; - } - - ret = gf_xdr_to_cli_defrag_vol_rsp (*iov, &rsp); - if (ret < 0) { - gf_log ("", GF_LOG_ERROR, "error"); - goto out; - } - - frame = myframe; - - if (frame) - local = frame->local; - - if (local) { - volname = local->u.defrag_vol.volname; - cmd = local->u.defrag_vol.cmd; - } - if (cmd == GF_DEFRAG_CMD_START) { - cli_out ("starting rebalance on volume %s has been %s", volname, - (rsp.op_ret) ? "unsuccessful": "successful"); - if (rsp.op_ret && rsp.op_errno == EEXIST) - cli_out ("Rebalance already started on volume %s", - volname); - } - if (cmd == GF_DEFRAG_CMD_STOP) { - if (rsp.op_ret == -1) - cli_out ("rebalance volume %s stop failed", volname); - else - cli_out ("stopped rebalance process of volume %s \n" - "(after rebalancing %"PRId64" files totaling " - "%"PRId64" bytes)", volname, rsp.files, rsp.size); - } - if (cmd == GF_DEFRAG_CMD_STATUS) { - if (rsp.op_ret == -1) - cli_out ("failed to get the status of rebalance process"); - else { - char *status = "unknown"; - if (rsp.op_errno == 0) - status = "not started"; - if (rsp.op_errno == 1) - status = "step 1: layout fix in progress"; - if (rsp.op_errno == 2) - status = "step 2: data migration in progress"; - if (rsp.op_errno == 3) - status = "stopped"; - if (rsp.op_errno == 4) - status = "completed"; - if (rsp.op_errno == 5) - status = "failed"; - - if (rsp.files && (rsp.op_errno == 1)) { - cli_out ("rebalance %s: fixed layout %"PRId64, - status, rsp.files); - } else if (rsp.files) { - cli_out ("rebalance %s: rebalanced %"PRId64 - " files of size %"PRId64" (total files" - " scanned %"PRId64")", status, - rsp.files, rsp.size, rsp.lookedup_files); - } else { - cli_out ("rebalance %s", status); - } - } - } - - if (volname) - GF_FREE (volname); - - ret = rsp.op_ret; - -out: - cli_cmd_broadcast_response (ret); - return ret; -} - -int -gf_cli3_1_rename_volume_cbk (struct rpc_req *req, struct iovec *iov, - int count, void *myframe) -{ - gf1_cli_rename_vol_rsp rsp = {0,}; - int ret = 0; - - if (-1 == req->rpc_status) { - goto out; - } - - ret = gf_xdr_to_cli_rename_vol_rsp (*iov, &rsp); - if (ret < 0) { - gf_log ("", GF_LOG_ERROR, "error"); - goto out; - } - - - gf_log ("cli", GF_LOG_NORMAL, "Received resp to probe"); - cli_out ("Rename volume %s", (rsp.op_ret) ? "unsuccessful": - "successful"); - - ret = rsp.op_ret; - -out: - cli_cmd_broadcast_response (ret); - return ret; -} - -int -gf_cli3_1_reset_volume_cbk (struct rpc_req *req, struct iovec *iov, - int count, void *myframe) -{ - gf1_cli_reset_vol_rsp rsp = {0,}; - int ret = 0; - - if (-1 == req->rpc_status) { - goto out; - } - - ret = gf_xdr_to_cli_reset_vol_rsp (*iov, &rsp); - if (ret < 0) { - gf_log ("", GF_LOG_ERROR, "error"); - goto out; - } - - gf_log ("cli", GF_LOG_NORMAL, "Received resp to reset"); - cli_out ("reset volume %s", (rsp.op_ret) ? "unsuccessful": - "successful"); - - if (rsp.op_ret && rsp.op_errstr) - cli_out ("%s", rsp.op_errstr); - - ret = rsp.op_ret; - -out: - cli_cmd_broadcast_response (ret); - return ret; -} - -void -_cli_out_options (dict_t *this, char *key, data_t *value, void *count) -{ - - (*((int *) count))++; - cli_out ("%s - %s", key, value->data); -} - -int -gf_cli3_1_set_volume_cbk (struct rpc_req *req, struct iovec *iov, - int count, void *myframe) -{ - gf1_cli_set_vol_rsp rsp = {0,}; - int ret = 0; - dict_t *dict = NULL; - int dict_count = 0; - - if (-1 == req->rpc_status) { - goto out; - } - - ret = gf_xdr_to_cli_set_vol_rsp (*iov, &rsp); - if (ret < 0) { - gf_log ("", GF_LOG_ERROR, "error"); - goto out; - } - - if (rsp.op_ret == 1) { // if the command was volume set <vol> history - - if (!rsp.dict.dict_len) { - cli_out ("No volumes present"); - ret = 0; - goto out; - } - - dict = dict_new (); - - if (!dict) { - ret = -1; - goto out; - } - - ret = dict_unserialize (rsp.dict.dict_val, - rsp.dict.dict_len, - &dict); - - if (ret) { - gf_log ("", GF_LOG_ERROR, - "Unable to allocate memory"); - goto out; - } - cli_out ("Options:"); - dict_foreach (dict, _cli_out_options, &dict_count); - if (!dict_count) - cli_out ("No Options Reconfigured!!"); - goto out; - } - - - - gf_log ("cli", GF_LOG_NORMAL, "Received resp to set"); - cli_out ("Set volume %s", (rsp.op_ret) ? "unsuccessful": - "successful"); - - if (rsp.op_ret && rsp.op_errstr) - cli_out ("%s", rsp.op_errstr); - - ret = rsp.op_ret; - -out: - cli_cmd_broadcast_response (ret); - return ret; -} - -int -gf_cli3_1_add_brick_cbk (struct rpc_req *req, struct iovec *iov, - int count, void *myframe) -{ - gf1_cli_add_brick_rsp rsp = {0,}; - int ret = 0; - - if (-1 == req->rpc_status) { - goto out; - } - - ret = gf_xdr_to_cli_add_brick_rsp (*iov, &rsp); - if (ret < 0) { - gf_log ("", GF_LOG_ERROR, "error"); - goto out; - } - - - gf_log ("cli", GF_LOG_NORMAL, "Received resp to add brick"); - cli_out ("Add Brick %s", (rsp.op_ret) ? "unsuccessful": - "successful"); - - if (rsp.op_ret && rsp.op_errstr) - cli_out ("%s", rsp.op_errstr); - ret = rsp.op_ret; - -out: - cli_cmd_broadcast_response (ret); - return ret; -} - - -int -gf_cli3_1_remove_brick_cbk (struct rpc_req *req, struct iovec *iov, - int count, void *myframe) -{ - gf1_cli_remove_brick_rsp rsp = {0,}; - int ret = 0; - - if (-1 == req->rpc_status) { - goto out; - } - - ret = gf_xdr_to_cli_remove_brick_rsp (*iov, &rsp); - if (ret < 0) { - gf_log ("", GF_LOG_ERROR, "error"); - goto out; - } - - gf_log ("cli", GF_LOG_NORMAL, "Received resp to remove brick"); - cli_out ("Remove Brick %s", (rsp.op_ret) ? "unsuccessful": - "successful"); - if (rsp.op_ret && rsp.op_errstr) - cli_out ("%s", rsp.op_errstr); - - ret = rsp.op_ret; - -out: - cli_cmd_broadcast_response (ret); - return ret; -} - - - -int -gf_cli3_1_replace_brick_cbk (struct rpc_req *req, struct iovec *iov, - int count, void *myframe) -{ - gf1_cli_replace_brick_rsp rsp = {0,}; - int ret = 0; - cli_local_t *local = NULL; - call_frame_t *frame = NULL; - dict_t *dict = NULL; - char *src_brick = NULL; - char *dst_brick = NULL; - char *status_reply = NULL; - gf1_cli_replace_op replace_op = 0; - char *rb_operation_str = NULL; - - if (-1 == req->rpc_status) { - goto out; - } - - frame = (call_frame_t *) myframe; - - ret = gf_xdr_to_cli_replace_brick_rsp (*iov, &rsp); - if (ret < 0) { - gf_log ("", GF_LOG_ERROR, "error"); - goto out; - } - - local = frame->local; - GF_ASSERT (local); - dict = local->u.replace_brick.dict; - - ret = dict_get_int32 (dict, "operation", (int32_t *)&replace_op); - if (ret) { - gf_log ("", GF_LOG_DEBUG, - "dict_get on operation failed"); - goto out; - } - - switch (replace_op) { - case GF_REPLACE_OP_START: - if (rsp.op_ret) - rb_operation_str = "replace-brick failed to start"; - else - rb_operation_str = "replace-brick started successfully"; - break; - - case GF_REPLACE_OP_STATUS: - - status_reply = rsp.status; - if (rsp.op_ret || ret) - rb_operation_str = "replace-brick status unknown"; - else - rb_operation_str = status_reply; - - break; - - case GF_REPLACE_OP_PAUSE: - if (rsp.op_ret) - rb_operation_str = "replace-brick pause failed"; - else - rb_operation_str = "replace-brick paused successfully"; - break; - - case GF_REPLACE_OP_ABORT: - if (rsp.op_ret) - rb_operation_str = "replace-brick abort failed"; - else - rb_operation_str = "replace-brick aborted successfully"; - break; - - case GF_REPLACE_OP_COMMIT: - case GF_REPLACE_OP_COMMIT_FORCE: - ret = dict_get_str (dict, "src-brick", &src_brick); - if (ret) { - gf_log ("", GF_LOG_DEBUG, - "dict_get on src-brick failed"); - goto out; - } - - ret = dict_get_str (dict, "dst-brick", &dst_brick); - if (ret) { - gf_log ("", GF_LOG_DEBUG, - "dict_get on dst-brick failed"); - goto out; - } - - - if (rsp.op_ret || ret) - rb_operation_str = "replace-brick commit failed"; - else - rb_operation_str = "replace-brick commit successful"; - - break; - - default: - gf_log ("", GF_LOG_DEBUG, - "Unknown operation"); - break; - } - - if (rsp.op_ret && (strcmp (rsp.op_errstr, ""))) { - rb_operation_str = rsp.op_errstr; - } - - gf_log ("cli", GF_LOG_NORMAL, "Received resp to replace brick"); - cli_out ("%s", - rb_operation_str ? rb_operation_str : "Unknown operation"); - - ret = rsp.op_ret; - -out: - if (local) { - dict_unref (local->u.replace_brick.dict); - GF_FREE (local->u.replace_brick.volname); - cli_local_wipe (local); - } - - cli_cmd_broadcast_response (ret); - return ret; -} - -static int -gf_cli3_1_log_filename_cbk (struct rpc_req *req, struct iovec *iov, - int count, void *myframe) -{ - gf1_cli_log_filename_rsp rsp = {0,}; - int ret = -1; - - if (-1 == req->rpc_status) { - goto out; - } - - ret = gf_xdr_to_cli_log_filename_rsp (*iov, &rsp); - if (ret < 0) { - gf_log ("", GF_LOG_ERROR, "error"); - goto out; - } - - gf_log ("cli", GF_LOG_DEBUG, "Received resp to log filename"); - cli_out ("log filename : %s", - (rsp.op_ret) ? "unsuccessful": "successful"); - - ret = rsp.op_ret; - -out: - cli_cmd_broadcast_response (ret); - return ret; -} - -static int -gf_cli3_1_log_locate_cbk (struct rpc_req *req, struct iovec *iov, - int count, void *myframe) -{ - gf1_cli_log_locate_rsp rsp = {0,}; - int ret = -1; - - if (-1 == req->rpc_status) { - goto out; - } - - ret = gf_xdr_to_cli_log_locate_rsp (*iov, &rsp); - if (ret < 0) { - gf_log ("", GF_LOG_ERROR, "error"); - goto out; - } - - gf_log ("cli", GF_LOG_DEBUG, "Received resp to log locate"); - cli_out ("log file location: %s", rsp.path); - - ret = rsp.op_ret; - -out: - cli_cmd_broadcast_response (ret); - return ret; -} - -static int -gf_cli3_1_log_rotate_cbk (struct rpc_req *req, struct iovec *iov, - int count, void *myframe) -{ - gf1_cli_log_rotate_rsp rsp = {0,}; - int ret = -1; - - if (-1 == req->rpc_status) { - goto out; - } - - ret = gf_xdr_to_cli_log_rotate_rsp (*iov, &rsp); - if (ret < 0) { - gf_log ("", GF_LOG_ERROR, "error"); - goto out; - } - - gf_log ("cli", GF_LOG_DEBUG, "Received resp to log rotate"); - cli_out ("log rotate %s", (rsp.op_ret) ? "unsuccessful": "successful"); - - ret = rsp.op_ret; - -out: - cli_cmd_broadcast_response (ret); - return ret; -} - -static int -gf_cli3_1_sync_volume_cbk (struct rpc_req *req, struct iovec *iov, - int count, void *myframe) -{ - gf1_cli_sync_volume_rsp rsp = {0,}; - int ret = -1; - - if (-1 == req->rpc_status) { - goto out; - } - - ret = gf_xdr_to_cli_sync_volume_rsp (*iov, &rsp); - if (ret < 0) { - gf_log ("", GF_LOG_ERROR, "error"); - goto out; - } - - gf_log ("cli", GF_LOG_DEBUG, "Received resp to sync"); - cli_out ("volume sync: %s", - (rsp.op_ret) ? "unsuccessful": "successful"); - - if (rsp.op_ret && rsp.op_errstr) - cli_out (rsp.op_errstr); - ret = rsp.op_ret; - -out: - cli_cmd_broadcast_response (ret); - return ret; -} - -int -gf_cli3_1_getspec_cbk (struct rpc_req *req, struct iovec *iov, - int count, void *myframe) -{ - gf_getspec_rsp rsp = {0,}; - int ret = 0; - char *spec = NULL; - - if (-1 == req->rpc_status) { - goto out; - } - - ret = xdr_to_getspec_rsp (*iov, &rsp); - if (ret < 0 || rsp.op_ret == -1) { - gf_log ("", GF_LOG_ERROR, "error"); - goto out; - } - - gf_log ("cli", GF_LOG_NORMAL, "Received resp to getspec"); - - spec = GF_MALLOC (rsp.op_ret + 1, cli_mt_char); - if (!spec) { - gf_log("", GF_LOG_ERROR, "out of memory"); - goto out; - } - memcpy (spec, rsp.spec, rsp.op_ret); - spec[rsp.op_ret] = '\0'; - cli_out ("%s", spec); - GF_FREE (spec); - - ret = 0; - -out: - cli_cmd_broadcast_response (ret); - return ret; -} - -int -gf_cli3_1_pmap_b2p_cbk (struct rpc_req *req, struct iovec *iov, - int count, void *myframe) -{ - pmap_port_by_brick_rsp rsp = {0,}; - int ret = 0; - char *spec = NULL; - - if (-1 == req->rpc_status) { - goto out; - } - - ret = xdr_to_pmap_port_by_brick_rsp (*iov, &rsp); - if (ret < 0 || rsp.op_ret == -1) { - gf_log ("", GF_LOG_ERROR, "error"); - goto out; - } - - gf_log ("cli", GF_LOG_NORMAL, "Received resp to pmap b2p"); - - cli_out ("%d", rsp.port); - GF_FREE (spec); - - ret = rsp.op_ret; - -out: - cli_cmd_broadcast_response (ret); - return ret; -} - - -int32_t -gf_cli3_1_probe (call_frame_t *frame, xlator_t *this, - void *data) -{ - gf1_cli_probe_req req = {0,}; - int ret = 0; - dict_t *dict = NULL; - char *hostname = NULL; - int port = 0; - - if (!frame || !this || !data) { - ret = -1; - goto out; - } - - dict = data; - ret = dict_get_str (dict, "hostname", &hostname); - if (ret) - goto out; - - ret = dict_get_int32 (dict, "port", &port); - if (ret) - port = CLI_GLUSTERD_PORT; - - req.hostname = hostname; - req.port = port; - - ret = cli_cmd_submit (&req, frame, cli_rpc_prog, - GD_MGMT_CLI_PROBE, NULL, gf_xdr_from_cli_probe_req, - this, gf_cli3_1_probe_cbk); - -out: - gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); - return ret; -} - -int32_t -gf_cli3_1_deprobe (call_frame_t *frame, xlator_t *this, - void *data) -{ - gf1_cli_deprobe_req req = {0,}; - int ret = 0; - dict_t *dict = NULL; - char *hostname = NULL; - int port = 0; - - if (!frame || !this || !data) { - ret = -1; - goto out; - } - - dict = data; - ret = dict_get_str (dict, "hostname", &hostname); - if (ret) - goto out; - - ret = dict_get_int32 (dict, "port", &port); - if (ret) - port = CLI_GLUSTERD_PORT; - - req.hostname = hostname; - req.port = port; - - ret = cli_cmd_submit (&req, frame, cli_rpc_prog, - GD_MGMT_CLI_DEPROBE, NULL, - gf_xdr_from_cli_deprobe_req, - this, gf_cli3_1_deprobe_cbk); - -out: - gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); - return ret; -} - -int32_t -gf_cli3_1_list_friends (call_frame_t *frame, xlator_t *this, - void *data) -{ - gf1_cli_peer_list_req req = {0,}; - int ret = 0; - - if (!frame || !this) { - ret = -1; - goto out; - } - - req.flags = GF_CLI_LIST_ALL; - - ret = cli_cmd_submit (&req, frame, cli_rpc_prog, - GD_MGMT_CLI_LIST_FRIENDS, NULL, - gf_xdr_from_cli_peer_list_req, - this, gf_cli3_1_list_friends_cbk); - -out: - gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); - return ret; -} - -int32_t -gf_cli3_1_get_next_volume (call_frame_t *frame, xlator_t *this, - void *data) -{ - - int ret = 0; - cli_cmd_volume_get_ctx_t *ctx = NULL; - cli_local_t *local = NULL; - - if (!frame || !this || !data) { - ret = -1; - goto out; - } - - ctx = data; - - ret = gf_cli3_1_get_volume (frame, this, data); - - local = frame->local; - - if (!local || !local->u.get_vol.volname) { - cli_out ("No volumes present"); - goto out; - } - - ctx->volname = local->u.get_vol.volname; - - while (ctx->volname) { - ret = gf_cli3_1_get_volume (frame, this, ctx); - if (ret) - goto out; - ctx->volname = local->u.get_vol.volname; - } - -out: - return ret; -} - -int32_t -gf_cli3_1_get_volume (call_frame_t *frame, xlator_t *this, - void *data) -{ - gf1_cli_get_vol_req req = {0,}; - int ret = 0; - cli_cmd_volume_get_ctx_t *ctx = NULL; - dict_t *dict = NULL; - - if (!frame || !this || !data) { - ret = -1; - goto out; - } - - ctx = data; - req.flags = ctx->flags; - - dict = dict_new (); - if (!dict) - goto out; - - if (ctx->volname) { - ret = dict_set_str (dict, "volname", ctx->volname); - if (ret) - goto out; - } - - ret = dict_allocate_and_serialize (dict, - &req.dict.dict_val, - (size_t *)&req.dict.dict_len); - - ret = cli_cmd_submit (&req, frame, cli_rpc_prog, - GD_MGMT_CLI_GET_VOLUME, NULL, - gf_xdr_from_cli_get_vol_req, - this, gf_cli3_1_get_volume_cbk); - -out: - gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); - return ret; -} - - -int32_t -gf_cli3_1_create_volume (call_frame_t *frame, xlator_t *this, - void *data) -{ - gf1_cli_create_vol_req req = {0,}; - int ret = 0; - dict_t *dict = NULL; - cli_local_t *local = NULL; - - if (!frame || !this || !data) { - ret = -1; - goto out; - } - - dict = dict_ref ((dict_t *)data); - - ret = dict_get_str (dict, "volname", &req.volname); - - if (ret) - goto out; - - ret = dict_get_int32 (dict, "type", (int32_t *)&req.type); - - if (ret) - goto out; - - ret = dict_get_int32 (dict, "count", &req.count); - if (ret) - goto out; - - ret = dict_allocate_and_serialize (dict, - &req.bricks.bricks_val, - (size_t *)&req.bricks.bricks_len); - if (ret < 0) { - gf_log (this->name, GF_LOG_DEBUG, - "failed to get serialized length of dict"); - goto out; - } - - local = cli_local_get (); - - if (local) { - local->u.create_vol.dict = dict_ref (dict); - frame->local = local; - } - - ret = cli_cmd_submit (&req, frame, cli_rpc_prog, - GD_MGMT_CLI_CREATE_VOLUME, NULL, - gf_xdr_from_cli_create_vol_req, - this, gf_cli3_1_create_volume_cbk); - - - -out: - gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); - - if (req.bricks.bricks_val) { - GF_FREE (req.bricks.bricks_val); - } - - return ret; -} - -int32_t -gf_cli3_1_delete_volume (call_frame_t *frame, xlator_t *this, - void *data) -{ - gf1_cli_delete_vol_req req = {0,}; - int ret = 0; - cli_local_t *local = NULL; - - if (!frame || !this || !data) { - ret = -1; - goto out; - } - - local = cli_local_get (); - - if (local) { - local->u.delete_vol.volname = data; - frame->local = local; - } - - req.volname = data; - - ret = cli_cmd_submit (&req, frame, cli_rpc_prog, - GD_MGMT_CLI_DELETE_VOLUME, NULL, - gf_xdr_from_cli_delete_vol_req, - this, gf_cli3_1_delete_volume_cbk); - -out: - gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); - - return ret; -} - -int32_t -gf_cli3_1_start_volume (call_frame_t *frame, xlator_t *this, - void *data) -{ - gf1_cli_start_vol_req *req = NULL; - int ret = 0; - cli_local_t *local = NULL; - - if (!frame || !this || !data) { - ret = -1; - goto out; - } - - req = data; - local = cli_local_get (); - - if (local) { - local->u.start_vol.volname = req->volname; - local->u.start_vol.flags = req->flags; - frame->local = local; - } - - ret = cli_cmd_submit (req, frame, cli_rpc_prog, - GD_MGMT_CLI_START_VOLUME, NULL, - gf_xdr_from_cli_start_vol_req, - this, gf_cli3_1_start_volume_cbk); - -out: - gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); - - return ret; -} - -int32_t -gf_cli3_1_stop_volume (call_frame_t *frame, xlator_t *this, - void *data) -{ - gf1_cli_stop_vol_req req = {0,}; - int ret = 0; - cli_local_t *local = NULL; - - if (!frame || !this || !data) { - ret = -1; - goto out; - } - - req = *((gf1_cli_stop_vol_req*)data); - local = cli_local_get (); - - if (local) { - local->u.stop_vol.volname = req.volname; - local->u.stop_vol.flags = req.flags; - frame->local = local; - } - - ret = cli_cmd_submit (&req, frame, cli_rpc_prog, - GD_MGMT_CLI_STOP_VOLUME, NULL, - gf_xdr_from_cli_stop_vol_req, - this, gf_cli3_1_stop_volume_cbk); - -out: - gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); - - return ret; -} - -int32_t -gf_cli3_1_defrag_volume (call_frame_t *frame, xlator_t *this, - void *data) -{ - gf1_cli_defrag_vol_req req = {0,}; - int ret = 0; - cli_local_t *local = NULL; - char *volname = NULL; - char *cmd_str = NULL; - dict_t *dict = NULL; - - if (!frame || !this || !data) { - ret = -1; - goto out; - } - - dict = data; - - ret = dict_get_str (dict, "volname", &volname); - if (ret) - gf_log ("", GF_LOG_DEBUG, "error"); - - ret = dict_get_str (dict, "command", &cmd_str); - if (ret) { - gf_log ("", GF_LOG_DEBUG, "error"); - goto out; - } - - if (strncasecmp (cmd_str, "start", 6) == 0) { - req.cmd = GF_DEFRAG_CMD_START; - } else if (strncasecmp (cmd_str, "stop", 5) == 0) { - req.cmd = GF_DEFRAG_CMD_STOP; - } else if (strncasecmp (cmd_str, "status", 7) == 0) { - req.cmd = GF_DEFRAG_CMD_STATUS; - } - - - local = cli_local_get (); - - if (local) { - local->u.defrag_vol.volname = gf_strdup (volname); - local->u.defrag_vol.cmd = req.cmd; - frame->local = local; - } - - req.volname = volname; - - ret = cli_cmd_submit (&req, frame, cli_rpc_prog, - GD_MGMT_CLI_DEFRAG_VOLUME, NULL, - gf_xdr_from_cli_defrag_vol_req, - this, gf_cli3_1_defrag_volume_cbk); - -out: - gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); - - return ret; -} - -int32_t -gf_cli3_1_rename_volume (call_frame_t *frame, xlator_t *this, - void *data) -{ - gf1_cli_rename_vol_req req = {0,}; - int ret = 0; - dict_t *dict = NULL; - - if (!frame || !this || !data) { - ret = -1; - goto out; - } - - dict = data; - - ret = dict_get_str (dict, "old-volname", &req.old_volname); - - if (ret) - goto out; - - ret = dict_get_str (dict, "new-volname", &req.new_volname); - - if (ret) - goto out; - - ret = cli_cmd_submit (&req, frame, cli_rpc_prog, - GD_MGMT_CLI_RENAME_VOLUME, NULL, - gf_xdr_from_cli_rename_vol_req, - this, gf_cli3_1_rename_volume_cbk); - -out: - gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); - - return ret; -} - -int32_t -gf_cli3_1_reset_volume (call_frame_t *frame, xlator_t *this, - void *data) -{ - gf1_cli_reset_vol_req req = {0,}; - int ret = 0; - dict_t *dict = NULL; - - if (!frame || !this || !data) { - ret = -1; - goto out; - } - - dict = data; - - ret = dict_get_str (dict, "volname", &req.volname); - - if (ret) - goto out; - - ret = dict_allocate_and_serialize (dict, - &req.dict.dict_val, - (size_t *)&req.dict.dict_len); - if (ret < 0) { - gf_log (this->name, GF_LOG_ERROR, - "failed to get serialized length of dict"); - goto out; - } - - - ret = cli_cmd_submit (&req, frame, cli_rpc_prog, - GD_MGMT_CLI_RESET_VOLUME, NULL, - gf_xdr_from_cli_reset_vol_req, - this, gf_cli3_1_reset_volume_cbk); - -out: - gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); - - return ret; -} - -int32_t -gf_cli3_1_set_volume (call_frame_t *frame, xlator_t *this, - void *data) -{ - gf1_cli_set_vol_req req = {0,}; - int ret = 0; - dict_t *dict = NULL; - - if (!frame || !this || !data) { - ret = -1; - goto out; - } - - dict = data; - - ret = dict_get_str (dict, "volname", &req.volname); - - if (ret) - goto out; - - ret = dict_allocate_and_serialize (dict, - &req.dict.dict_val, - (size_t *)&req.dict.dict_len); - if (ret < 0) { - gf_log (this->name, GF_LOG_DEBUG, - "failed to get serialized length of dict"); - goto out; - } - - - ret = cli_cmd_submit (&req, frame, cli_rpc_prog, - GD_MGMT_CLI_SET_VOLUME, NULL, - gf_xdr_from_cli_set_vol_req, - this, gf_cli3_1_set_volume_cbk); - -out: - gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); - - return ret; -} - -int32_t -gf_cli3_1_add_brick (call_frame_t *frame, xlator_t *this, - void *data) -{ - gf1_cli_add_brick_req req = {0,}; - int ret = 0; - dict_t *dict = NULL; - - if (!frame || !this || !data) { - ret = -1; - goto out; - } - - dict = data; - - ret = dict_get_str (dict, "volname", &req.volname); - - if (ret) - goto out; - - ret = dict_get_int32 (dict, "count", &req.count); - if (ret) - goto out; - - - ret = dict_allocate_and_serialize (dict, - &req.bricks.bricks_val, - (size_t *)&req.bricks.bricks_len); - if (ret < 0) { - gf_log (this->name, GF_LOG_DEBUG, - "failed to get serialized length of dict"); - goto out; - } - - ret = cli_cmd_submit (&req, frame, cli_rpc_prog, - GD_MGMT_CLI_ADD_BRICK, NULL, - gf_xdr_from_cli_add_brick_req, - this, gf_cli3_1_add_brick_cbk); - -out: - gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); - - if (req.bricks.bricks_val) { - GF_FREE (req.bricks.bricks_val); - } - - return ret; -} - -int32_t -gf_cli3_1_remove_brick (call_frame_t *frame, xlator_t *this, - void *data) -{ - gf1_cli_remove_brick_req req = {0,}; - int ret = 0; - dict_t *dict = NULL; - - if (!frame || !this || !data) { - ret = -1; - goto out; - } - - dict = data; - - ret = dict_get_str (dict, "volname", &req.volname); - - if (ret) - goto out; - - ret = dict_get_int32 (dict, "type", (int32_t *)&req.type); - - if (ret) - goto out; - - ret = dict_get_int32 (dict, "count", &req.count); - - if (ret) - goto out; - - ret = dict_allocate_and_serialize (dict, - &req.bricks.bricks_val, - (size_t *)&req.bricks.bricks_len); - if (ret < 0) { - gf_log (this->name, GF_LOG_DEBUG, - "failed to get serialized length of dict"); - goto out; - } - - ret = cli_cmd_submit (&req, frame, cli_rpc_prog, - GD_MGMT_CLI_REMOVE_BRICK, NULL, - gf_xdr_from_cli_remove_brick_req, - this, gf_cli3_1_remove_brick_cbk); - - -out: - gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); - - if (req.bricks.bricks_val) { - GF_FREE (req.bricks.bricks_val); - } - - return ret; -} - -int32_t -gf_cli3_1_replace_brick (call_frame_t *frame, xlator_t *this, - void *data) -{ - gf1_cli_replace_brick_req req = {0,}; - int ret = 0; - cli_local_t *local = NULL; - dict_t *dict = NULL; - char *src_brick = NULL; - char *dst_brick = NULL; - - if (!frame || !this || !data) { - ret = -1; - goto out; - } - - dict = data; - - local = cli_local_get (); - if (!local) { - ret = -1; - gf_log (this->name, GF_LOG_ERROR, - "Out of memory"); - goto out; - } - - local->u.replace_brick.dict = dict_ref (dict); - frame->local = local; - - ret = dict_get_int32 (dict, "operation", (int32_t *)&req.op); - if (ret) { - gf_log (this->name, GF_LOG_DEBUG, - "dict_get on operation failed"); - goto out; - } - ret = dict_get_str (dict, "volname", &req.volname); - if (ret) { - gf_log (this->name, GF_LOG_DEBUG, - "dict_get on volname failed"); - goto out; - } - - local->u.replace_brick.volname = gf_strdup (req.volname); - if (!local->u.replace_brick.volname) { - gf_log (this->name, GF_LOG_ERROR, - "Out of memory"); - ret = -1; - goto out; - } - - ret = dict_get_str (dict, "src-brick", &src_brick); - if (ret) { - gf_log (this->name, GF_LOG_DEBUG, - "dict_get on src-brick failed"); - goto out; - } - - ret = dict_get_str (dict, "dst-brick", &dst_brick); - if (ret) { - gf_log (this->name, GF_LOG_DEBUG, - "dict_get on dst-brick failed"); - goto out; - } - - gf_log (this->name, GF_LOG_DEBUG, - "Recevied command replace-brick %s with " - "%s with operation=%d", src_brick, - dst_brick, req.op); - - - ret = dict_allocate_and_serialize (dict, - &req.bricks.bricks_val, - (size_t *)&req.bricks.bricks_len); - if (ret < 0) { - gf_log (this->name, GF_LOG_DEBUG, - "failed to get serialized length of dict"); - goto out; - } - - ret = cli_cmd_submit (&req, frame, cli_rpc_prog, - GD_MGMT_CLI_REPLACE_BRICK, NULL, - gf_xdr_from_cli_replace_brick_req, - this, gf_cli3_1_replace_brick_cbk); - -out: - gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); - - if (req.bricks.bricks_val) { - GF_FREE (req.bricks.bricks_val); - } - - return ret; -} - -int32_t -gf_cli3_1_log_filename (call_frame_t *frame, xlator_t *this, - void *data) -{ - gf1_cli_log_filename_req req = {0,}; - int ret = 0; - dict_t *dict = NULL; - - if (!frame || !this || !data) { - ret = -1; - goto out; - } - - dict = data; - - ret = dict_get_str (dict, "volname", &req.volname); - if (ret) - goto out; - - ret = dict_get_str (dict, "brick", &req.brick); - if (ret) - req.brick = ""; - - ret = dict_get_str (dict, "path", &req.path); - if (ret) - goto out; - - ret = cli_cmd_submit (&req, frame, cli_rpc_prog, - GD_MGMT_CLI_LOG_FILENAME, NULL, - gf_xdr_from_cli_log_filename_req, - this, gf_cli3_1_log_filename_cbk); - -out: - gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); - - return ret; -} - - -int32_t -gf_cli3_1_log_locate (call_frame_t *frame, xlator_t *this, - void *data) -{ - gf1_cli_log_locate_req req = {0,}; - int ret = 0; - dict_t *dict = NULL; - - if (!frame || !this || !data) { - ret = -1; - goto out; - } - - dict = data; - - ret = dict_get_str (dict, "volname", &req.volname); - if (ret) - goto out; - - ret = dict_get_str (dict, "brick", &req.brick); - if (ret) - req.brick = ""; - - ret = cli_cmd_submit (&req, frame, cli_rpc_prog, - GD_MGMT_CLI_LOG_LOCATE, NULL, - gf_xdr_from_cli_log_locate_req, - this, gf_cli3_1_log_locate_cbk); - -out: - gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); - - return ret; -} - -int32_t -gf_cli3_1_log_rotate (call_frame_t *frame, xlator_t *this, - void *data) -{ - gf1_cli_log_locate_req req = {0,}; - int ret = 0; - dict_t *dict = NULL; - - if (!frame || !this || !data) { - ret = -1; - goto out; - } - - dict = data; - - ret = dict_get_str (dict, "volname", &req.volname); - if (ret) - goto out; - - ret = dict_get_str (dict, "brick", &req.brick); - if (ret) - req.brick = ""; - - ret = cli_cmd_submit (&req, frame, cli_rpc_prog, - GD_MGMT_CLI_LOG_ROTATE, NULL, - gf_xdr_from_cli_log_rotate_req, - this, gf_cli3_1_log_rotate_cbk); - - -out: - gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); - - return ret; -} - -int32_t -gf_cli3_1_sync_volume (call_frame_t *frame, xlator_t *this, - void *data) -{ - int ret = 0; - - if (!frame || !this || !data) { - ret = -1; - goto out; - } - - ret = cli_cmd_submit ((gf1_cli_sync_volume_req*)data, frame, - cli_rpc_prog, GD_MGMT_CLI_SYNC_VOLUME, - NULL, gf_xdr_from_cli_sync_volume_req, - this, gf_cli3_1_sync_volume_cbk); - -out: - gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); - - return ret; -} - -int32_t -gf_cli3_1_getspec (call_frame_t *frame, xlator_t *this, - void *data) -{ - gf_getspec_req req = {0,}; - int ret = 0; - dict_t *dict = NULL; - - if (!frame || !this || !data) { - ret = -1; - goto out; - } - - dict = data; - - ret = dict_get_str (dict, "volid", &req.key); - if (ret) - goto out; - - ret = cli_cmd_submit (&req, frame, &cli_handshake_prog, - GF_HNDSK_GETSPEC, NULL, - xdr_from_getspec_req, - this, gf_cli3_1_getspec_cbk); - -out: - gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); - - return ret; -} - -int32_t -gf_cli3_1_pmap_b2p (call_frame_t *frame, xlator_t *this, void *data) -{ - pmap_port_by_brick_req req = {0,}; - int ret = 0; - dict_t *dict = NULL; - - if (!frame || !this || !data) { - ret = -1; - goto out; - } - - dict = data; - - ret = dict_get_str (dict, "brick", &req.brick); - if (ret) - goto out; - - ret = cli_cmd_submit (&req, frame, &cli_pmap_prog, - GF_PMAP_PORTBYBRICK, NULL, - xdr_from_pmap_port_by_brick_req, - this, gf_cli3_1_pmap_b2p_cbk); - -out: - gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); - - return ret; -} - -struct rpc_clnt_procedure gluster3_1_cli_actors[GF1_CLI_MAXVALUE] = { - [GF1_CLI_NULL] = {"NULL", NULL }, - [GF1_CLI_PROBE] = { "PROBE_QUERY", gf_cli3_1_probe}, - [GF1_CLI_DEPROBE] = { "DEPROBE_QUERY", gf_cli3_1_deprobe}, - [GF1_CLI_LIST_FRIENDS] = { "LIST_FRIENDS", gf_cli3_1_list_friends}, - [GF1_CLI_CREATE_VOLUME] = {"CREATE_VOLUME", gf_cli3_1_create_volume}, - [GF1_CLI_DELETE_VOLUME] = {"DELETE_VOLUME", gf_cli3_1_delete_volume}, - [GF1_CLI_START_VOLUME] = {"START_VOLUME", gf_cli3_1_start_volume}, - [GF1_CLI_STOP_VOLUME] = {"STOP_VOLUME", gf_cli3_1_stop_volume}, - [GF1_CLI_RENAME_VOLUME] = {"RENAME_VOLUME", gf_cli3_1_rename_volume}, - [GF1_CLI_DEFRAG_VOLUME] = {"DEFRAG_VOLUME", gf_cli3_1_defrag_volume}, - [GF1_CLI_GET_VOLUME] = {"GET_VOLUME", gf_cli3_1_get_volume}, - [GF1_CLI_GET_NEXT_VOLUME] = {"GET_NEXT_VOLUME", gf_cli3_1_get_next_volume}, - [GF1_CLI_SET_VOLUME] = {"SET_VOLUME", gf_cli3_1_set_volume}, - [GF1_CLI_ADD_BRICK] = {"ADD_BRICK", gf_cli3_1_add_brick}, - [GF1_CLI_REMOVE_BRICK] = {"REMOVE_BRICK", gf_cli3_1_remove_brick}, - [GF1_CLI_REPLACE_BRICK] = {"REPLACE_BRICK", gf_cli3_1_replace_brick}, - [GF1_CLI_LOG_FILENAME] = {"LOG FILENAME", gf_cli3_1_log_filename}, - [GF1_CLI_LOG_LOCATE] = {"LOG LOCATE", gf_cli3_1_log_locate}, - [GF1_CLI_LOG_ROTATE] = {"LOG ROTATE", gf_cli3_1_log_rotate}, - [GF1_CLI_GETSPEC] = {"GETSPEC", gf_cli3_1_getspec}, - [GF1_CLI_PMAP_PORTBYBRICK] = {"PMAP PORTBYBRICK", gf_cli3_1_pmap_b2p}, - [GF1_CLI_SYNC_VOLUME] = {"SYNC_VOLUME", gf_cli3_1_sync_volume}, - [GF1_CLI_RESET_VOLUME] = {"RESET_VOLUME", gf_cli3_1_reset_volume} -}; - -struct rpc_clnt_program cli3_1_prog = { - .progname = "CLI 3.1", - .prognum = GLUSTER3_1_CLI_PROGRAM, - .progver = GLUSTER3_1_CLI_VERSION, - .proctable = gluster3_1_cli_actors, - .numproc = GLUSTER3_1_CLI_PROCCNT, -}; diff --git a/cli/src/input.c b/cli/src/input.c index 5c38efe13..a8ea46c6d 100644 --- a/cli/src/input.c +++ b/cli/src/input.c @@ -1,22 +1,12 @@ /* - Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. - - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ + Copyright (c) 2010-2012 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ #include <stdio.h> #include <string.h> #include <stdlib.h> @@ -43,8 +33,8 @@ cli_batch (void *d) ret = cli_cmd_process (state, state->argc, state->argv); - gf_log ("", GF_LOG_NORMAL, "Exiting with: %d", ret); - exit (ret); + gf_log ("", GF_LOG_INFO, "Exiting with: %d", ret); + exit (-ret); return NULL; } @@ -71,11 +61,11 @@ cli_input (void *d) if (len > 0 && cmd[len - 1] == '\n') //strip trailing \n cmd[len - 1] = '\0'; ret = cli_cmd_process_line (state, cmd); - if (ret == -1 && state->mode & GLUSTER_MODE_ERR_FATAL) + if (ret != 0 && state->mode & GLUSTER_MODE_ERR_FATAL) break; } - exit (ret); + exit (-ret); return NULL; } diff --git a/cli/src/registry.c b/cli/src/registry.c index c3634d974..c4abe3be0 100644 --- a/cli/src/registry.c +++ b/cli/src/registry.c @@ -1,22 +1,12 @@ /* - Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. - - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ + Copyright (c) 2010-2012 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ #ifndef _CONFIG_H #define _CONFIG_H @@ -260,29 +250,49 @@ err: return NULL; } - -struct cli_cmd_word * -cli_cmd_nextword (struct cli_cmd_word *word, const char *token) +void * +cli_getunamb (const char *tok, void **choices, cli_selector_t sel) { - struct cli_cmd_word *next = NULL; - struct cli_cmd_word **trav = NULL; - int ret = 0; + void **wcon = NULL; + char *w = NULL; + unsigned mn = 0; + void *ret = NULL; - if (!word->nextwords) + if (!choices || !tok || !*tok) return NULL; - for (trav = word->nextwords; (next = *trav); trav++) { - if (next->match) { -// ret = next->match (); - } else { - ret = strcmp (next->word, token); - } + for (wcon = choices; *wcon; wcon++) { + w = strtail ((char *)sel (*wcon), tok); + if (!w) + /* no match */ + continue; + if (!*w) + /* exact match */ + return *wcon; - if (ret == 0) - break; + ret = *wcon; + mn++; } - return next; +#ifdef FORCE_MATCH_EXACT + return NULL; +#else + return (mn == 1) ? ret : NULL; +#endif +} + +static const char * +sel_cmd_word (void *wcon) +{ + return ((struct cli_cmd_word *)wcon)->word; +} + +struct cli_cmd_word * +cli_cmd_nextword (struct cli_cmd_word *word, const char *token) +{ + return (struct cli_cmd_word *)cli_getunamb (token, + (void **)word->nextwords, + sel_cmd_word); } @@ -319,7 +329,7 @@ cli_cmd_newword (struct cli_cmd_word *word, const char *token) int cli_cmd_ingest (struct cli_cmd_tree *tree, char **tokens, cli_cmd_cbk_t *cbkfn, - const char *desc) + const char *desc, const char *pattern) { int ret = 0; char **tokenp = NULL; @@ -351,6 +361,7 @@ cli_cmd_ingest (struct cli_cmd_tree *tree, char **tokens, cli_cmd_cbk_t *cbkfn, word->cbkfn = cbkfn; word->desc = desc; + word->pattern = pattern; /* end of static strings in command template */ @@ -361,28 +372,40 @@ cli_cmd_ingest (struct cli_cmd_tree *tree, char **tokens, cli_cmd_cbk_t *cbkfn, int -cli_cmd_register (struct cli_cmd_tree *tree, const char *template, - cli_cmd_cbk_t cbk, const char *desc) +cli_cmd_register (struct cli_cmd_tree *tree, struct cli_cmd *cmd) { char **tokens = NULL; int ret = 0; - if (!template) - return -1; + GF_ASSERT (cmd); - tokens = cli_cmd_tokenize (template); - if (!tokens) - return -1; + if (cmd->reg_cbk) + cmd->reg_cbk (cmd); - ret = cli_cmd_ingest (tree, tokens, cbk, desc); - if (ret) - goto err; + if (cmd->disable) { + ret = 0; + goto out; + } - return 0; -err: + tokens = cli_cmd_tokenize (cmd->pattern); + if (!tokens) { + ret = -1; + goto out; + } + + ret = cli_cmd_ingest (tree, tokens, cmd->cbk, cmd->desc, cmd->pattern); + if (ret) { + ret = -1; + goto out; + } + + ret = 0; + +out: if (tokens) cli_cmd_tokens_destroy (tokens); + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); return ret; } |
