diff options
Diffstat (limited to 'cli/src/cli-cmd-parser.c')
| -rw-r--r-- | cli/src/cli-cmd-parser.c | 2582 |
1 files changed, 2174 insertions, 408 deletions
diff --git a/cli/src/cli-cmd-parser.c b/cli/src/cli-cmd-parser.c index 6fa1f80bd..1513e0c5e 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-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> @@ -36,36 +26,154 @@ #include "protocol-common.h" #include "cli1-xdr.h" +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 *free_list_ptr = NULL; 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", + 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) @@ -83,9 +191,12 @@ cli_cmd_volume_create_parse (const char **words, int wordcount, dict_t **options if (volname[0] == '-') goto out; - if (!strcmp (volname, "all")) { - cli_out ("\"all\" cannot be the name of a volume."); - 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, '/')) @@ -99,187 +210,169 @@ 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_dynstr (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); - free_list_ptr = tmp_list; - 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]); - if (free_list_ptr) - free (free_list_ptr); - 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 (free_list_ptr) - free (free_list_ptr); - } - /* 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; } - bricks = gf_strdup (brick_list); - if (!bricks) { - ret = -1; + /* 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) @@ -289,6 +382,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: @@ -297,6 +394,9 @@ out: if (dict) dict_destroy (dict); } + + GF_FREE (trans_type); + return ret; } @@ -310,9 +410,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) @@ -321,6 +418,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) { @@ -329,45 +429,445 @@ 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", "alert-time", + "soft-timeout", "hard-timeout", + "default-soft-limit", NULL}; + char *w = NULL; + uint32_t time = 0; + double percent = 0; 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) { + cli_out ("Invalid quota option : %s", words[3]); + 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 || wordcount > 7) { + ret = -1; + goto out; + } + + type = GF_QUOTA_OPTION_TYPE_LIMIT_USAGE; + + if (words[4][0] != '/') { + cli_err ("Please enter absolute path"); + ret = -1; + goto out; + } + 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"); + ret = -1; + goto out; + } + + ret = gf_string2bytesize (words[5], &value); + if (ret != 0) { + if (errno == ERANGE) + cli_err ("Value too large: %s", words[5]); + else + cli_err ("Please enter a correct value"); + goto out; + } + + ret = dict_set_str (dict, "hard-limit", (char *) words[5]); + if (ret < 0) + goto out; + + if (wordcount == 7) { + + ret = gf_string2percent (words[6], &percent); + if (ret != 0) { + cli_err ("Please enter a correct value"); + goto out; + } + + ret = dict_set_str (dict, "soft-limit", + (char *) words[6]); + 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"); + ret = -1; + goto out; + } + + 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, "alert-time") == 0) { + if (wordcount != 5) { + ret = -1; + goto out; + } + type = GF_QUOTA_OPTION_TYPE_ALERT_TIME; + + ret = gf_string2time (words[4], &time); + if (ret) { + cli_err ("Invalid argument %s. Please enter a valid " + "string", words[4]); + goto out; + } + + ret = dict_set_str (dict, "value", (char *)words[4]); + if (ret < 0) + goto out; + goto set_type; + } + if (strcmp (w, "soft-timeout") == 0) { + if (wordcount != 5) { + ret = -1; + goto out; + } + type = GF_QUOTA_OPTION_TYPE_SOFT_TIMEOUT; + + ret = gf_string2time (words[4], &time); + if (ret) { + cli_err ("Invalid argument %s. Please enter a valid " + "string", words[4]); + goto out; + } + + ret = dict_set_str (dict, "value", (char *)words[4]); + if (ret < 0) + goto out; + goto set_type; + } + if (strcmp (w, "hard-timeout") == 0) { + if(wordcount != 5) { + ret = -1; + goto out; + } + type = GF_QUOTA_OPTION_TYPE_HARD_TIMEOUT; + + ret = gf_string2time (words[4], &time); + if (ret) { + cli_err ("Invalid argument %s. Please enter a valid " + "string", words[4]); + goto out; + } + + ret = dict_set_str (dict, "value", (char *)words[4]); + if (ret < 0) + goto out; + goto set_type; + } + if (strcmp (w, "default-soft-limit") == 0) { + if(wordcount != 5) { + ret = -1; + goto out; + } + type = GF_QUOTA_OPTION_TYPE_DEFAULT_SOFT_LIMIT; + + ret = dict_set_str (dict, "value", (char *)words[4]); + if (ret < 0) + goto out; + goto set_type; + } 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]; @@ -379,32 +879,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) @@ -425,10 +958,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; } @@ -439,26 +970,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; 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 *free_list_ptr = 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) @@ -480,87 +1005,68 @@ 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; + } - 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]); + 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; - } 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); + count = strtol (words[4], NULL, 0); + if (!count || (count < 2)) { + cli_err ("replica count should be greater than 1"); ret = -1; goto out; } - - host_name = gf_strdup(words[brick_index]); - if (!host_name) { + ret = dict_set_int32 (dict, "replica-count", count); + if (ret) + goto out; + index = 5; + } else if ((strcmp (w, "stripe")) == 0) { + type = GF_CLUSTER_TYPE_STRIPE; + if (wordcount < 5) { 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"); + count = strtol (words[4], NULL, 0); + if (!count || (count < 2)) { + cli_err ("stripe count should be greater than 1"); ret = -1; - GF_FREE (freeptr); goto out; } - GF_FREE (freeptr); + ret = dict_set_int32 (dict, "stripe-count", count); + if (ret) + goto out; + index = 5; + } else { + GF_ASSERT (!"opword mismatch"); + ret = -1; + goto out; + } - tmp_list = strdup(brick_list+1); - free_list_ptr = tmp_list; - 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]); - if (free_list_ptr) - free (free_list_ptr); - 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 (free_list_ptr) - free (free_list_ptr); + if (strcmp (words[wordcount - 1], "force") == 0) { + is_force = _gf_true; + wc = wordcount - 1; } - bricks = gf_strdup (brick_list); - if (!bricks) { - ret = -1; + 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) @@ -571,6 +1077,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: @@ -586,7 +1096,7 @@ 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; @@ -598,39 +1108,94 @@ cli_cmd_volume_remove_brick_parse (const char **words, int wordcount, 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; + brick_index = 3; + w = str_getunamb (words[3], type_opword); + if (w && !strcmp ("replica", w)) { + if (wordcount < 5) { + ret = -1; + goto out; + } + count = strtol (words[4], NULL, 0); + if (count < 1) { + cli_err ("replica count should be greater than 0 in " + "case of remove-brick"); + ret = -1; + goto out; + } + + 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 { + /* 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; + } + } + if (wordcount < 4) { ret = -1; goto out; } - brick_index = 3; - + 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); @@ -641,7 +1206,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) { @@ -652,15 +1217,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; @@ -670,7 +1236,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; @@ -685,7 +1251,6 @@ cli_cmd_volume_remove_brick_parse (const char **words, int wordcount, } ret = dict_set_int32 (dict, "count", brick_count); - if (ret) goto out; @@ -698,10 +1263,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; } @@ -714,17 +1277,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) @@ -747,15 +1310,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]); @@ -767,15 +1331,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; } @@ -790,21 +1355,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)) { @@ -813,9 +1381,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; } } @@ -829,14 +1405,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); } @@ -856,10 +1433,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; @@ -876,12 +1449,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) @@ -907,6 +1482,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; @@ -918,10 +1550,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; @@ -937,12 +1565,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); @@ -971,15 +1601,14 @@ 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; - volname = (char *)words[3]; + if (strcmp ("rotate", words[3]) == 0) + volname = (char *)words[2]; + else if (strcmp ("rotate", words[2]) == 0) + volname = (char *)words[3]; GF_ASSERT (volname); ret = dict_set_str (dict, "volname", volname); @@ -990,12 +1619,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); @@ -1012,98 +1643,1233 @@ 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; + + GF_FREE (append_str); + append_str = GF_CALLOC (1, 300, cli_mt_append_str); + if (!append_str) { + ret = -1; + goto out; + } + snprintf (append_str, 300, "now:%ld.%06ld", + tv.tv_sec, tv.tv_usec); + } + + 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 = 0; - int32_t config_type = 0; - dict_t *dict = NULL; - gf1_cli_gsync_set type = GF_GSYNC_OPTION_TYPE_NONE; + 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); - GF_ASSERT ((strcmp (words[0], "volume")) == 0); - GF_ASSERT ((strcmp (words[1], "gsync")) == 0); - dict = dict_new (); if (!dict) goto out; - if (wordcount < 5) + /* 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; - ret = dict_set_str (dict, "master", (char *)words[3]); - if (ret < 0) + 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; - ret = dict_set_str (dict, "slave", (char *)words[4]); - if (ret < 0) + /* 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 (words[2], "start")) == 0) { + 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; - goto set_type; + 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 ((strcmp (words[2], "stop")) == 0) { - type = GF_GSYNC_OPTION_TYPE_STOP; + if (type != GF_GSYNC_OPTION_TYPE_CONFIG && + (cmdi < wordcount - 1 || glob)) + goto out; - goto set_type; + /* 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; + gf1_cli_info_op info_op = GF_CLI_INFO_NONE; + gf_boolean_t is_peek = _gf_false; + + 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) + 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 (words[2], "configure")) == 0) { - type = GF_GSYNC_OPTION_TYPE_CONFIGURE; + if ((strcmp (w, "start") == 0 || strcmp (w, "stop") == 0) && + wordcount > 5) + goto out; - if (strcmp (words [5], "config-set") == 0) { - config_type = GF_GSYNC_OPTION_TYPE_CONFIG_SET; + if (strcmp (w, "info") == 0 && wordcount > 7) + goto out; - ret = dict_set_str (dict, "op_name", (char *)words[6]); - if (ret < 0) + 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; + info_op = GF_CLI_INFO_ALL; + if (wordcount > 4) { + if (strcmp (words[4], "incremental") == 0) { + info_op = GF_CLI_INFO_INCREMENTAL; + if (wordcount > 5 && + strcmp (words[5], "peek") == 0) { + is_peek = _gf_true; + } + } else if (strcmp (words[4], "cumulative") == 0) { + info_op = GF_CLI_INFO_CUMULATIVE; + } else if (strcmp (words[4], "clear") == 0) { + info_op = GF_CLI_INFO_CLEAR; + } else if (strcmp (words[4], "peek") == 0) { + is_peek = _gf_true; + } + } + } else + GF_ASSERT (!"opword mismatch"); + + ret = dict_set_int32 (dict, "op", (int32_t)op); + if (ret) + goto out; + + ret = dict_set_int32 (dict, "info-op", (int32_t)info_op); + if (ret) + goto out; + + ret = dict_set_int32 (dict, "peek", is_peek); + if (ret) + goto out; + + if (!strcmp (words[wordcount - 1], "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 = dict_set_str (dict, "op_value", (char *)words[7]); - if (ret < 0) + 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 ((strcmp (words [5], "config-del")) == 0) { - config_type = GF_GSYNC_OPTION_TYPE_CONFIG_DEL; + 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; + } - ret = dict_set_str (dict, "op_name", (char *)words[6]); - if (ret < 0) - 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; } + } - if ((strcmp (words [5], "config-get")) == 0) { - config_type = GF_GSYNC_OPTION_TYPE_CONFIG_GET; + out: + return ret; +} - ret = dict_set_str (dict, "op_name", (char *)words[6]); - if (ret < 0) +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 if (!strcmp (words[3], "quotad")) { + cmd |= GF_CLI_STATUS_QUOTAD; + } else { + cmd = GF_CLI_STATUS_BRICK; + ret = dict_set_str (dict, "brick", + (char *)words[3]); + } + + } else { + cmd |= GF_CLI_STATUS_VOL; + ret = 0; + } } - if ((strcmp (words [5], "config-get-all")) == 0) { - config_type = GF_GSYNC_OPTION_TYPE_CONFIG_GET_ALL; + break; + + case 5: + if (!strcmp (words[2], "all")) { + cli_err ("Cannot specify brick/nfs for \"all\""); + ret = -1; + goto out; } - ret = dict_set_int32 (dict, "config_type", config_type); - if (ret < 0) + 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 (!strcmp (words[3], "quotad")) { + if (cmd == GF_CLI_STATUS_FD || + cmd == GF_CLI_STATUS_CLIENTS || + cmd == GF_CLI_STATUS_DETAIL || + cmd == GF_CLI_STATUS_INODE) { + cli_err ("Detail/FD/Clients/Inode status not " + "available for Quota Daemon"); + ret = -1; + goto out; + } + cmd |= GF_CLI_STATUS_QUOTAD; + } 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; } -set_type: - ret = dict_set_int32 (dict, "type", type); - if (ret < 0) + 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", + "quotad", 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); + } + if((strstr (option_str, "nfs")) && strstr (option_str, "quotad")) { + ret = -1; + goto out; + } + + 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) - if (dict) - dict_destroy (dict); + 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; +} |
