summaryrefslogtreecommitdiffstats
path: root/cli/src/cli-cmd-parser.c
diff options
context:
space:
mode:
Diffstat (limited to 'cli/src/cli-cmd-parser.c')
-rw-r--r--cli/src/cli-cmd-parser.c3422
1 files changed, 3027 insertions, 395 deletions
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;
+}