diff options
author | Amar Tumballi <amar@gluster.com> | 2010-07-08 08:16:13 +0000 |
---|---|---|
committer | Anand V. Avati <avati@dev.gluster.com> | 2010-07-08 23:28:08 -0700 |
commit | 915adb9c1291d140e57765b7fad0c5bb0e7d5ed5 (patch) | |
tree | 0330fa8796e18601ef7ef1441b6d4eb0df8cb9b6 /cli/src | |
parent | 7e489f3cc7f3eb738d2698dcf588bad0bdc12a8b (diff) |
gluster-CLI-and-mgmt-glusterd-added-to-codebase
Signed-off-by: Vijay Bellur <vijay@gluster.com>
Signed-off-by: Amar Tumballi <amar@gluster.com>
Signed-off-by: Anand V. Avati <avati@dev.gluster.com>
BUG: 971 (dynamic volume management)
URL: http://bugs.gluster.com/cgi-bin/bugzilla3/show_bug.cgi?id=971
Diffstat (limited to 'cli/src')
-rw-r--r-- | cli/src/Makefile.am | 23 | ||||
-rw-r--r-- | cli/src/cli-cmd-parser.c | 451 | ||||
-rw-r--r-- | cli/src/cli-cmd-probe.c | 89 | ||||
-rw-r--r-- | cli/src/cli-cmd-volume.c | 485 | ||||
-rw-r--r-- | cli/src/cli-cmd.c | 199 | ||||
-rw-r--r-- | cli/src/cli-cmd.h | 46 | ||||
-rw-r--r-- | cli/src/cli-mem-types.h | 37 | ||||
-rw-r--r-- | cli/src/cli-rl.c | 368 | ||||
-rw-r--r-- | cli/src/cli.c | 467 | ||||
-rw-r--r-- | cli/src/cli.h | 139 | ||||
-rw-r--r-- | cli/src/cli3_1-cops.c | 805 | ||||
-rw-r--r-- | cli/src/input.c | 98 | ||||
-rw-r--r-- | cli/src/registry.c | 386 |
13 files changed, 3593 insertions, 0 deletions
diff --git a/cli/src/Makefile.am b/cli/src/Makefile.am new file mode 100644 index 00000000000..8e173260325 --- /dev/null +++ b/cli/src/Makefile.am @@ -0,0 +1,23 @@ +sbin_PROGRAMS = gluster + +gluster_SOURCES = cli.c registry.c input.c cli-cmd.c cli-rl.c \ + cli-cmd-volume.c cli-cmd-probe.c cli3_1-cops.c cli-cmd-parser.c + +gluster_LDADD = $(top_builddir)/libglusterfs/src/libglusterfs.la $(GF_LDADD)\ + $(RLLIBS) $(top_builddir)/xlators/protocol/lib/src/libgfproto1.la\ + $(top_builddir)/rpc/rpc-lib/src/libgfrpc.la + +gluster_LDFLAGS = $(GF_LDFLAGS) $(GF_GLUSTERFS_LDFLAGS) +noinst_HEADERS = cli.h cli-mem-types.h cli-cmd.h + +AM_CFLAGS = -fPIC -Wall -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -D$(GF_HOST_OS)\ + -I$(top_srcdir)/libglusterfs/src -I$(top_srcdir)/rpc/rpc-lib/src\ + -I$(top_srcdir)/xlators/protocol/lib/src\ + -DDATADIR=\"$(localstatedir)\" \ + -DCONFDIR=\"$(sysconfdir)/glusterfs\" $(GF_GLUSTERFS_CFLAGS) + + +CLEANFILES = + +$(top_builddir)/libglusterfs/src/libglusterfs.la: + $(MAKE) -C $(top_builddir)/libglusterfs/src/ all diff --git a/cli/src/cli-cmd-parser.c b/cli/src/cli-cmd-parser.c new file mode 100644 index 00000000000..68c6a29c865 --- /dev/null +++ b/cli/src/cli-cmd-parser.c @@ -0,0 +1,451 @@ +/* + 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 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see + <http://www.gnu.org/licenses/>. +*/ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stdint.h> +#include <pthread.h> + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include "cli.h" +#include "cli-cmd.h" +#include "cli-mem-types.h" +#include "protocol-common.h" +#include "dict.h" +#include "gluster1.h" + +int32_t +cli_cmd_volume_create_parse (const char **words, int wordcount, dict_t **options) +{ + dict_t *dict = NULL; + char *volname = NULL; + int ret = -1; + gf1_cluster_type type = GF_CLUSTER_TYPE_NONE; + int count = 0; + int brick_count = 0, brick_index = 0; + char brick_list[8192] = {0,}; + + 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) + goto out; + + volname = (char *)words[2]; + + GF_ASSERT (volname); + + ret = dict_set_str (dict, "volname", volname); + + if (ret) + goto out; + + if ((strcasecmp (words[3], "replica")) == 0) { + type = GF_CLUSTER_TYPE_REPLICATE; + count = strtol (words[4], NULL, 0); + if (!count) { + /* Wrong number of replica count */ + 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; + count = strtol (words[4], NULL, 0); + if (!count) { + /* Wrong number of stripe count */ + 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; + } + + ret = dict_set_int32 (dict, "type", type); + if (ret) + goto out; + strcpy (brick_list, " "); + while (brick_index < wordcount) { + GF_ASSERT (words[brick_index]); + if (!strchr (words[brick_index], ':')) { + gf_log ("cli", GF_LOG_ERROR, + "wrong brick type, use <HOSTNAME>:<export-dir>"); + ret = -1; + goto out; + } + + strcat (brick_list, words[brick_index]); + strcat (brick_list, " "); + ++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; + */ + } + ret = dict_set_str (dict, "bricks", brick_list); + if (ret) + goto out; + + ret = dict_set_int32 (dict, "count", brick_count); + if (ret) + goto out; + + *options = dict; + +out: + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Unable to parse create volume CLI"); + if (dict) + dict_destroy (dict); + } + + return ret; +} + + +int32_t +cli_cmd_volume_set_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,}; + + 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; + + volname = (char *)words[2]; + + GF_ASSERT (volname); + + ret = dict_set_str (dict, "volname", volname); + + if (ret) + goto out; + + for (i = 3; i < wordcount; i++) { + key = strtok ((char *)words[i], "="); + value = strtok (NULL, "="); + + GF_ASSERT (key); + GF_ASSERT (value); + + count++; + + sprintf (str, "key%d", count); + ret = dict_set_str (dict, str, key); + if (ret) + goto out; + + sprintf (str, "value%d", count); + ret = dict_set_str (dict, str, value); + + if (ret) + goto out; + } + + ret = dict_set_int32 (dict, "count", count); + + if (ret) + goto out; + + *options = dict; + +out: + if (ret) { + if (dict) + dict_destroy (dict); + } + + return ret; +} + +int32_t +cli_cmd_volume_add_brick_parse (const char **words, int wordcount, + dict_t **options) +{ + dict_t *dict = NULL; + char *volname = 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; + + 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) + goto out; + + volname = (char *)words[2]; + + GF_ASSERT (volname); + + ret = dict_set_str (dict, "volname", volname); + + if (ret) + goto out; + + if ((strcasecmp (words[3], "replica")) == 0) { + type = GF_CLUSTER_TYPE_REPLICATE; + count = strtol (words[4], NULL, 0); + brick_index = 5; + } else if ((strcasecmp (words[3], "stripe")) == 0) { + type = GF_CLUSTER_TYPE_STRIPE; + count = strtol (words[4], NULL, 0); + brick_index = 5; + } else { + brick_index = 3; + } + + ret = dict_set_int32 (dict, "type", type); + + if (ret) + goto out; + + while (brick_index < wordcount) { + GF_ASSERT (words[brick_index]); + + snprintf (key, 50, "brick%d", ++brick_count); + ret = dict_set_str (dict, key, (char *)words[brick_index++]); + + if (ret) + goto out; + } + + ret = dict_set_int32 (dict, "count", brick_count); + + if (ret) + goto out; + + *options = dict; + +out: + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Unable to parse add-brick CLI"); + if (dict) + dict_destroy (dict); + } + + return ret; +} + + +int32_t +cli_cmd_volume_remove_brick_parse (const char **words, int wordcount, + dict_t **options) +{ + dict_t *dict = NULL; + char *volname = 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; + + GF_ASSERT (words); + GF_ASSERT (options); + + GF_ASSERT ((strcmp (words[0], "volume")) == 0); + GF_ASSERT ((strcmp (words[1], "remove-brick")) == 0); + + dict = dict_new (); + + if (!dict) + goto out; + + volname = (char *)words[2]; + + GF_ASSERT (volname); + + ret = dict_set_str (dict, "volname", volname); + + if (ret) + goto out; + + if ((strcasecmp (words[3], "replica")) == 0) { + type = GF_CLUSTER_TYPE_REPLICATE; + count = strtol (words[4], NULL, 0); + brick_index = 5; + } else if ((strcasecmp (words[3], "stripe")) == 0) { + type = GF_CLUSTER_TYPE_STRIPE; + count = strtol (words[4], NULL, 0); + brick_index = 5; + } else { + brick_index = 3; + } + + ret = dict_set_int32 (dict, "type", type); + + if (ret) + goto out; + + while (brick_index < wordcount) { + GF_ASSERT (words[brick_index]); + + snprintf (key, 50, "brick%d", ++brick_count); + ret = dict_set_str (dict, key, (char *)words[brick_index++]); + + if (ret) + goto out; + } + + ret = dict_set_int32 (dict, "count", brick_count); + + if (ret) + goto out; + + *options = dict; + +out: + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Unable to parse remove-brick CLI"); + if (dict) + dict_destroy (dict); + } + + return ret; +} + + +int32_t +cli_cmd_volume_replace_brick_parse (const char **words, int wordcount, + dict_t **options) +{ + dict_t *dict = NULL; + char *volname = NULL; + int ret = -1; + char *op = NULL; + int op_index = 0; + gf1_cli_replace_op replace_op = GF_REPLACE_OP_NONE; + + 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) + goto out; + + volname = (char *)words[2]; + + GF_ASSERT (volname); + + ret = dict_set_str (dict, "volname", volname); + + if (ret) + goto out; + + if (strchr ((char *)words[3], ':')) { + ret = dict_set_str (dict, "src-brick", (char *)words[3]); + + if (ret) + goto out; + + GF_ASSERT (words[4]); + + ret = dict_set_str (dict, "dst-brick", (char *)words[4]); + + if (ret) + goto out; + + op_index = 5; + } else { + op_index = 3; + } + + GF_ASSERT (words[op_index]); + + op = (char *) words[op_index]; + + if (!strcasecmp ("start", op)) { + replace_op = GF_REPLACE_OP_START; + } else if (!strcasecmp ("stop", op)) { + replace_op = GF_REPLACE_OP_STOP; + } else if (!strcasecmp ("pause", op)) { + replace_op = GF_REPLACE_OP_PAUSE; + } else if (!strcasecmp ("abort", op)) { + replace_op = GF_REPLACE_OP_ABORT; + } else if (!strcasecmp ("status", op)) { + replace_op = GF_REPLACE_OP_STATUS; + } + + GF_ASSERT (replace_op != GF_REPLACE_OP_NONE); + + ret = dict_set_int32 (dict, "operation", (int32_t) replace_op); + + if (ret) + goto out; + + *options = dict; + +out: + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Unable to parse remove-brick CLI"); + if (dict) + dict_destroy (dict); + } + + return ret; +} diff --git a/cli/src/cli-cmd-probe.c b/cli/src/cli-cmd-probe.c new file mode 100644 index 00000000000..dccdaedbef9 --- /dev/null +++ b/cli/src/cli-cmd-probe.c @@ -0,0 +1,89 @@ +/* + 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 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see + <http://www.gnu.org/licenses/>. +*/ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stdint.h> +#include <pthread.h> + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include "cli.h" +#include "cli-cmd.h" +#include "cli-mem-types.h" +#include "protocol-common.h" + +extern struct rpc_clnt *global_rpc; + +extern rpc_clnt_prog_t *cli_rpc_prog; + +int +cli_cmd_probe_cbk (struct cli_state *state, struct cli_cmd_word *word, + const char **words, int wordcount) +{ + int ret = -1; + rpc_clnt_procedure_t *proc = NULL; + call_frame_t *frame = NULL; + + //cli_out ("probe not implemented\n"); + proc = &cli_rpc_prog->proctable[GF1_CLI_PROBE]; + + frame = create_frame (THIS, THIS->ctx->pool); + if (!frame) + goto out; + + if (proc->fn) { + ret = proc->fn (frame, THIS, "localhost"); + } + +out: + if (ret) + cli_out ("Probe failed!"); + return ret; +} + + + +struct cli_cmd cli_probe_cmds[] = { + { "probe <VOLNAME>", + cli_cmd_probe_cbk }, + + + { NULL, NULL } +}; + + +int +cli_cmd_probe_register (struct cli_state *state) +{ + int ret = 0; + struct cli_cmd *cmd = NULL; + + for (cmd = cli_probe_cmds; cmd->pattern; cmd++) { + ret = cli_cmd_register (&state->tree, cmd->pattern, cmd->cbk); + if (ret) + goto out; + } +out: + return ret; +} diff --git a/cli/src/cli-cmd-volume.c b/cli/src/cli-cmd-volume.c new file mode 100644 index 00000000000..227438db479 --- /dev/null +++ b/cli/src/cli-cmd-volume.c @@ -0,0 +1,485 @@ +/* + 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 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see + <http://www.gnu.org/licenses/>. +*/ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stdint.h> +#include <pthread.h> + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include "cli.h" +#include "cli-cmd.h" +#include "cli-mem-types.h" + +extern struct rpc_clnt *global_rpc; + +extern rpc_clnt_prog_t *cli_rpc_prog; + +int +cli_cmd_volume_info_cbk (struct cli_state *state, struct cli_cmd_word *word, + const char **words, int wordcount) +{ + int ret = -1; + rpc_clnt_procedure_t *proc = NULL; + call_frame_t *frame = NULL; + + proc = &cli_rpc_prog->proctable[GF1_CLI_GET_VOLUME]; + + frame = create_frame (THIS, THIS->ctx->pool); + if (!frame) + goto out; + + if (proc->fn) { + ret = proc->fn (frame, THIS, "localhost"); + } + +out: + if (ret) + cli_out ("Probe failed!"); + return ret; + +} + + +int +cli_cmd_volume_create_cbk (struct cli_state *state, struct cli_cmd_word *word, + const char **words, int wordcount) +{ + int ret = -1; + rpc_clnt_procedure_t *proc = NULL; + call_frame_t *frame = NULL; + dict_t *options = NULL; + + proc = &cli_rpc_prog->proctable[GF1_CLI_CREATE_VOLUME]; + + frame = create_frame (THIS, THIS->ctx->pool); + if (!frame) + goto out; + + ret = cli_cmd_volume_create_parse (words, wordcount, &options); + + if (ret) + goto out; + + if (proc->fn) { + ret = proc->fn (frame, THIS, options); + } + +out: + if (ret) { + char *volname = (char *) words[2]; + cli_out ("Creating Volume %s failed",volname ); + } + return ret; +} + + +int +cli_cmd_volume_delete_cbk (struct cli_state *state, struct cli_cmd_word *word, + const char **words, int wordcount) +{ + int ret = -1; + rpc_clnt_procedure_t *proc = NULL; + call_frame_t *frame = NULL; + char *volname = NULL; + + proc = &cli_rpc_prog->proctable[GF1_CLI_DELETE_VOLUME]; + + frame = create_frame (THIS, THIS->ctx->pool); + if (!frame) + goto out; + + //TODO: Build validation here + volname = (char *)words[2]; + GF_ASSERT (volname); + + if (proc->fn) { + ret = proc->fn (frame, THIS, volname); + } + +out: + if (ret) + cli_out ("Deleting Volume %s failed", volname); + + return ret; +} + + +int +cli_cmd_volume_start_cbk (struct cli_state *state, struct cli_cmd_word *word, + const char **words, int wordcount) +{ + int ret = -1; + rpc_clnt_procedure_t *proc = NULL; + call_frame_t *frame = NULL; + char *volname = NULL; + + proc = &cli_rpc_prog->proctable[GF1_CLI_START_VOLUME]; + + frame = create_frame (THIS, THIS->ctx->pool); + if (!frame) + goto out; + + //TODO: Build validation here + volname = (char *)words[2]; + GF_ASSERT (volname); + + if (proc->fn) { + ret = proc->fn (frame, THIS, volname); + } + +out: + if (ret) + cli_out ("Starting Volume %s failed", volname); + + return ret; +} + + +int +cli_cmd_volume_stop_cbk (struct cli_state *state, struct cli_cmd_word *word, + const char **words, int wordcount) +{ + int ret = -1; + rpc_clnt_procedure_t *proc = NULL; + call_frame_t *frame = NULL; + char *volname = NULL; + + proc = &cli_rpc_prog->proctable[GF1_CLI_STOP_VOLUME]; + + frame = create_frame (THIS, THIS->ctx->pool); + if (!frame) + goto out; + + //TODO: Build validation here + volname = (char *)words[2]; + GF_ASSERT (volname); + + if (proc->fn) { + ret = proc->fn (frame, THIS, volname); + } + +out: + if (ret) + cli_out ("Stopping Volume %s failed", volname); + + return ret; +} + + +int +cli_cmd_volume_rename_cbk (struct cli_state *state, struct cli_cmd_word *word, + const char **words, int wordcount) +{ + int ret = -1; + rpc_clnt_procedure_t *proc = NULL; + call_frame_t *frame = NULL; + dict_t *dict = NULL; + + proc = &cli_rpc_prog->proctable[GF1_CLI_RENAME_VOLUME]; + + frame = create_frame (THIS, THIS->ctx->pool); + if (!frame) + goto out; + + dict = dict_new (); + + if (dict) + goto out; + + GF_ASSERT (words[2]); + GF_ASSERT (words[3]); + + //TODO: Build validation here + ret = dict_set_str (dict, "old-volname", (char *)words[2]); + + if (ret) + goto out; + + ret = dict_set_str (dict, "new-volname", (char *)words[3]); + + if (ret) + goto out; + + if (proc->fn) { + ret = proc->fn (frame, THIS, dict); + } + +out: + if (ret) { + char *volname = (char *) words[2]; + if (dict) + dict_destroy (dict); + cli_out ("Renaming Volume %s failed", volname ); + } + + return ret; +} + + +int +cli_cmd_volume_defrag_cbk (struct cli_state *state, struct cli_cmd_word *word, + const char **words, int wordcount) +{ + int ret = -1; + rpc_clnt_procedure_t *proc = NULL; + call_frame_t *frame = NULL; + char *volname = NULL; + + proc = &cli_rpc_prog->proctable[GF1_CLI_DEFRAG_VOLUME]; + + frame = create_frame (THIS, THIS->ctx->pool); + if (!frame) + goto out; + + //TODO: Build validation here + volname = (char *)words[2]; + GF_ASSERT (volname); + + if (proc->fn) { + ret = proc->fn (frame, THIS, volname); + } + +out: + if (ret) + cli_out ("Defrag of Volume %s failed", volname); + + return 0; +} + + +int +cli_cmd_volume_set_cbk (struct cli_state *state, struct cli_cmd_word *word, + const char **words, int wordcount) +{ + int ret = -1; + rpc_clnt_procedure_t *proc = NULL; + call_frame_t *frame = NULL; + char *volname = NULL; + dict_t *dict = NULL; + + proc = &cli_rpc_prog->proctable[GF1_CLI_SET_VOLUME]; + + frame = create_frame (THIS, THIS->ctx->pool); + if (!frame) + goto out; + + volname = (char *)words[2]; + GF_ASSERT (volname); + + GF_ASSERT (words[3]); + + ret = cli_cmd_volume_set_parse (words, wordcount, &dict); + + if (ret) + goto out; + + //TODO: Build validation here + if (proc->fn) { + ret = proc->fn (frame, THIS, dict); + } + +out: + if (ret) { + if (dict) + dict_destroy (dict); + cli_out ("Changing option on Volume %s failed", volname); + } + + return 0; +} + + +int +cli_cmd_volume_add_brick_cbk (struct cli_state *state, + struct cli_cmd_word *word, const char **words, + int wordcount) +{ + int ret = -1; + rpc_clnt_procedure_t *proc = NULL; + call_frame_t *frame = NULL; + dict_t *options = NULL; + + proc = &cli_rpc_prog->proctable[GF1_CLI_ADD_BRICK]; + + frame = create_frame (THIS, THIS->ctx->pool); + if (!frame) + goto out; + + ret = cli_cmd_volume_add_brick_parse (words, wordcount, &options); + + if (ret) + goto out; + + if (proc->fn) { + ret = proc->fn (frame, THIS, options); + } + +out: + if (ret) { + char *volname = (char *) words[2]; + cli_out ("Adding brick to Volume %s failed",volname ); + } + return ret; +} + + +int +cli_cmd_volume_remove_brick_cbk (struct cli_state *state, + struct cli_cmd_word *word, const char **words, + int wordcount) +{ + int ret = -1; + rpc_clnt_procedure_t *proc = NULL; + call_frame_t *frame = NULL; + dict_t *options = NULL; + + proc = &cli_rpc_prog->proctable[GF1_CLI_REMOVE_BRICK]; + + frame = create_frame (THIS, THIS->ctx->pool); + if (!frame) + goto out; + + ret = cli_cmd_volume_remove_brick_parse (words, wordcount, &options); + + if (ret) + goto out; + + if (proc->fn) { + ret = proc->fn (frame, THIS, options); + } + +out: + if (ret) { + char *volname = (char *) words[2]; + cli_out ("Removing brick from Volume %s failed",volname ); + } + return ret; + +} + + + + +int +cli_cmd_volume_replace_brick_cbk (struct cli_state *state, + struct cli_cmd_word *word, + const char **words, + int wordcount) +{ + int ret = -1; + rpc_clnt_procedure_t *proc = NULL; + call_frame_t *frame = NULL; + dict_t *options = NULL; + + proc = &cli_rpc_prog->proctable[GF1_CLI_REPLACE_BRICK]; + + frame = create_frame (THIS, THIS->ctx->pool); + if (!frame) + goto out; + + ret = cli_cmd_volume_replace_brick_parse (words, wordcount, &options); + + if (ret) + goto out; + + if (proc->fn) { + ret = proc->fn (frame, THIS, options); + } + +out: + if (ret) { + char *volname = (char *) words[2]; + cli_out ("Replacing brick from Volume %s failed",volname ); + } + return ret; + +} + + +int +cli_cmd_volume_set_transport_cbk (struct cli_state *state, + struct cli_cmd_word *word, + const char **words, int wordcount) +{ + cli_out ("volume set-transport not implemented\n"); + return 0; +} + + +struct cli_cmd volume_cmds[] = { + { "volume info [all|<VOLNAME>]", + cli_cmd_volume_info_cbk }, + + { "volume create <NEW-VOLNAME> [stripe <COUNT>] [replicate <COUNT>] <NEW-BRICK> ...", + cli_cmd_volume_create_cbk }, + + { "volume delete <VOLNAME>", + cli_cmd_volume_delete_cbk }, + + { "volume start <VOLNAME>", + cli_cmd_volume_start_cbk }, + + { "volume stop <VOLNAME>", + cli_cmd_volume_stop_cbk }, + + { "volume rename <VOLNAME> <NEW-VOLNAME>", + cli_cmd_volume_rename_cbk }, + + { "volume add-brick <VOLNAME> [(replica <COUNT>)|(stripe <COUNT>)] <NEW-BRICK> ...", + cli_cmd_volume_add_brick_cbk }, + + { "volume remove-brick <VOLNAME> [(replica <COUNT>)|(stripe <COUNT>)] <BRICK> ...", + cli_cmd_volume_remove_brick_cbk }, + + { "volume defrag <VOLNAME>", + cli_cmd_volume_defrag_cbk }, + + { "volume replace-brick <VOLNAME> (<BRICK> <NEW-BRICK>)|pause|abort|start|status", + cli_cmd_volume_replace_brick_cbk }, + + { "volume set-transport <VOLNAME> <TRANSPORT-TYPE> [<TRANSPORT-TYPE>] ...", + cli_cmd_volume_set_transport_cbk }, + + { "volume set <VOLNAME> <KEY> <VALUE>", + cli_cmd_volume_set_cbk }, + + { NULL, NULL } +}; + + +int +cli_cmd_volume_register (struct cli_state *state) +{ + int ret = 0; + struct cli_cmd *cmd = NULL; + + for (cmd = volume_cmds; cmd->pattern; cmd++) { + ret = cli_cmd_register (&state->tree, cmd->pattern, cmd->cbk); + if (ret) + goto out; + } +out: + return ret; +} diff --git a/cli/src/cli-cmd.c b/cli/src/cli-cmd.c new file mode 100644 index 00000000000..a91dd77e23d --- /dev/null +++ b/cli/src/cli-cmd.c @@ -0,0 +1,199 @@ +/* + 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 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see + <http://www.gnu.org/licenses/>. +*/ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stdint.h> +#include <pthread.h> + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include "cli.h" +#include "cli-cmd.h" +#include "cli-mem-types.h" + +#include <fnmatch.h> + +static int cmd_done; +static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t cond_mutex = PTHREAD_MUTEX_INITIALIZER; + +int +cli_cmd_process (struct cli_state *state, int argc, char **argv) +{ + int ret = 0; + struct cli_cmd_word *word = NULL; + struct cli_cmd_word *next = NULL; + int i = 0; + + word = &state->tree.root; + + for (i = 0; i < argc; i++) { + next = cli_cmd_nextword (word, argv[i]); + + word = next; + if (!word) + break; + + if (word->cbkfn) + break; + } + + if (!word) { + cli_out ("unrecognized word: %s (position %d)\n", + argv[i], i); + return -1; + } + + if (!word->cbkfn) { + cli_out ("unrecognized command\n"); + return -1; + } + + ret = word->cbkfn (state, word, (const char **)argv, argc); + + return ret; +} + + +int +cli_cmd_input_token_count (const char *text) +{ + int count = 0; + const char *trav = NULL; + int is_spc = 1; + + for (trav = text; *trav; trav++) { + if (*trav == ' ') { + is_spc = 1; + } else { + if (is_spc) { + count++; + is_spc = 0; + } + } + } + + return count; +} + + +int +cli_cmd_process_line (struct cli_state *state, const char *text) +{ + int count = 0; + char **tokens = NULL; + char **tokenp = NULL; + char *token = NULL; + char *copy = NULL; + char *saveptr = NULL; + int i = 0; + int ret = -1; + + count = cli_cmd_input_token_count (text); + + tokens = calloc (count + 1, sizeof (*tokens)); + if (!tokens) + return -1; + + copy = strdup (text); + if (!copy) + goto out; + + tokenp = tokens; + + for (token = strtok_r (copy, " \t\r\n", &saveptr); token; + token = strtok_r (NULL, " \t\r\n", &saveptr)) { + *tokenp = strdup (token); + + if (!*tokenp) + goto out; + tokenp++; + i++; + + } + + ret = cli_cmd_process (state, count, tokens); +out: + if (copy) + free (copy); + + if (tokens) + cli_cmd_tokens_destroy (tokens); + + return ret; +} + + +int +cli_cmds_register (struct cli_state *state) +{ + int ret = 0; + + ret = cli_cmd_volume_register (state); + if (ret) + goto out; + + ret = cli_cmd_probe_register (state); + if (ret) + goto out; + +out: + return ret; +} + +int +cli_cmd_await_response () +{ + pthread_mutex_init (&cond_mutex, NULL); + pthread_cond_init (&cond, NULL); + cmd_done = 0; + + pthread_mutex_lock (&cond_mutex); + { + while (!cmd_done) { + pthread_cond_wait (&cond, &cond_mutex); + } + } + pthread_mutex_unlock (&cond_mutex); + + pthread_mutex_destroy (&cond_mutex); + pthread_cond_destroy (&cond); + + return 0; +} + +int +cli_cmd_broadcast_response () +{ + pthread_mutex_lock (&cond_mutex); + { + cmd_done = 1; + pthread_cond_broadcast (&cond); + } + + pthread_mutex_unlock (&cond_mutex); + + return 0; +} + diff --git a/cli/src/cli-cmd.h b/cli/src/cli-cmd.h new file mode 100644 index 00000000000..d1da3e2acd2 --- /dev/null +++ b/cli/src/cli-cmd.h @@ -0,0 +1,46 @@ +/* + Copyright (c) 2006-2009 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 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see + <http://www.gnu.org/licenses/>. +*/ + +#ifndef __CLI_CMD_H__ +#define __CLI_CMD_H__ + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include "cli.h" + +struct cli_cmd { + const char *pattern; + cli_cmd_cbk_t *cbk; +}; + +int cli_cmd_volume_register (struct cli_state *state); + +int cli_cmd_probe_register (struct cli_state *state); + +struct cli_cmd_word *cli_cmd_nextword (struct cli_cmd_word *word, + const char *text); +void cli_cmd_tokens_destroy (char **tokens); + +int cli_cmd_await_response (); + +int cli_cmd_broadcast_response (); +#endif /* __CLI_CMD_H__ */ diff --git a/cli/src/cli-mem-types.h b/cli/src/cli-mem-types.h new file mode 100644 index 00000000000..279e5e90826 --- /dev/null +++ b/cli/src/cli-mem-types.h @@ -0,0 +1,37 @@ +/* + 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 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see + <http://www.gnu.org/licenses/>. +*/ + +#ifndef __CLI_MEM_TYPES_H__ +#define __CLI_MEM_TYPES_H__ + +#include "mem-types.h" + +#define CLI_MEM_TYPE_START (gf_common_mt_end + 1) + +enum cli_mem_types_ { + cli_mt_xlator_list_t = CLI_MEM_TYPE_START, + cli_mt_xlator_t, + cli_mt_xlator_cmdline_option_t, + cli_mt_char, + cli_mt_call_pool_t, + cli_mt_end + +}; + +#endif diff --git a/cli/src/cli-rl.c b/cli/src/cli-rl.c new file mode 100644 index 00000000000..bc2e80eba04 --- /dev/null +++ b/cli/src/cli-rl.c @@ -0,0 +1,368 @@ +/* + 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 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see + <http://www.gnu.org/licenses/>. +*/ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stdint.h> +#include <pthread.h> + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include "cli.h" +#include "cli-cmd.h" +#include "cli-mem-types.h" + +#include "event.h" + +#include <fnmatch.h> + +#ifdef HAVE_READLINE + +#include <stdio.h> +#include <readline/readline.h> +#include <readline/history.h> + + +int +cli_rl_out (struct cli_state *state, const char *fmt, va_list ap) +{ + int tmp_rl_point = rl_point; + int n = rl_end; + int i = 0; + int ret = 0; + + if (rl_end >= 0 ) { + rl_kill_text (0, rl_end); + rl_redisplay (); + } + + printf ("\r"); + + for (i = 0; i <= strlen (state->prompt); i++) + printf (" "); + + printf ("\r"); + + ret = vprintf (fmt, ap); + + printf ("\n"); + fflush(stdout); + + if (n) { + rl_do_undo (); + rl_point = tmp_rl_point; + rl_reset_line_state (); + } + + return ret; +} + + +void +cli_rl_process_line (char *line) +{ + struct cli_state *state = NULL; + int ret = 0; + + state = global_state; + + state->rl_processing = 1; + { + ret = cli_cmd_process_line (state, line); + add_history (line); + } + state->rl_processing = 0; +} + + +int +cli_rl_stdin (int fd, int idx, void *data, + int poll_out, int poll_in, int poll_err) +{ + rl_callback_read_char (); + + return 0; +} + + +char * +cli_rl_autocomplete_entry (const char *text, int times) +{ + struct cli_state *state = NULL; + char *retp = NULL; + + state = global_state; + + if (!state->matchesp) + return NULL; + + retp = *state->matchesp; + + state->matchesp++; + + return retp ? strdup (retp) : NULL; +} + + +int +cli_rl_token_count (const char *text) +{ + int count = 0; + const char *trav = NULL; + int is_spc = 1; + + for (trav = text; *trav; trav++) { + if (*trav == ' ') { + is_spc = 1; + } else { + if (is_spc) { + count++; + is_spc = 0; + } + } + } + + if (is_spc) + /* what needs to be autocompleted is a full + new word, and not extend the last word + */ + count++; + + return count; +} + + +char ** +cli_rl_tokenize (const char *text) +{ + int count = 0; + char **tokens = NULL; + char **tokenp = NULL; + char *token = NULL; + char *copy = NULL; + char *saveptr = NULL; + int i = 0; + + count = cli_rl_token_count (text); + + tokens = calloc (count + 1, sizeof (*tokens)); + if (!tokens) + return NULL; + + copy = strdup (text); + if (!copy) + goto out; + + tokenp = tokens; + + for (token = strtok_r (copy, " \t\r\n", &saveptr); token; + token = strtok_r (NULL, " \t\r\n", &saveptr)) { + *tokenp = strdup (token); + + if (!*tokenp) + goto out; + tokenp++; + i++; + + } + + if (i < count) { + /* symoblize that what needs to be autocompleted is + the full set of possible nextwords, and not extend + the last word + */ + *tokenp = strdup (""); + if (!*tokenp) + goto out; + tokenp++; + i++; + } + +out: + if (copy) + free (copy); + + if (i < count) { + cli_cmd_tokens_destroy (tokens); + tokens = NULL; + } + + return tokens; +} + + +char ** +cli_rl_get_matches (struct cli_state *state, struct cli_cmd_word *word, + const char *text) +{ + char **matches = NULL; + char **matchesp = NULL; + struct cli_cmd_word **next = NULL; + int count = 0; + int len = 0; + + len = strlen (text); + + if (!word->nextwords) + return NULL; + + for (next = word->nextwords; *next; next++) + count++; + + matches = calloc (count + 1, sizeof (*matches)); + matchesp = matches; + + for (next = word->nextwords; *next; next++) { + if ((*next)->match) { + continue; + } + + if (strncmp ((*next)->word, text, len) == 0) { + *matchesp = strdup ((*next)->word); + matchesp++; + } + } + + return matches; +} + + +int +cli_rl_autocomplete_prepare (struct cli_state *state, const char *text) +{ + struct cli_cmd_word *word = NULL; + struct cli_cmd_word *next = NULL; + char **tokens = NULL; + char **tokenp = NULL; + char *token = NULL; + char **matches = NULL; + + tokens = cli_rl_tokenize (text); + if (!tokens) + return 0; + + word = &state->tree.root; + + for (tokenp = tokens; (token = *tokenp); tokenp++) { + if (!*(tokenp+1)) { + /* last word */ + break; + } + + next = cli_cmd_nextword (word, token); + word = next; + if (!word) + break; + } + + if (!word) + goto out; + + matches = cli_rl_get_matches (state, word, token); + + state->matches = matches; + state->matchesp = matches; + +out: + cli_cmd_tokens_destroy (tokens); + return 0; +} + + +int +cli_rl_autocomplete_cleanup (struct cli_state *state) +{ + if (state->matches) + cli_cmd_tokens_destroy (state->matches); + + state->matches = NULL; + state->matchesp = NULL; + + return 0; +} + + +char ** +cli_rl_autocomplete (const char *text, int start, int end) +{ + struct cli_state *state = NULL; + char **matches = NULL; + char save = 0; + + state = global_state; + + /* hack to make the autocompletion code neater */ + /* fake it as though the cursor is at the end of line */ + + save = rl_line_buffer[rl_point]; + rl_line_buffer[rl_point] = 0; + + cli_rl_autocomplete_prepare (state, rl_line_buffer); + + matches = rl_completion_matches (text, cli_rl_autocomplete_entry); + + cli_rl_autocomplete_cleanup (state); + + rl_line_buffer[rl_point] = save; + + return matches; +} + + +static char * +complete_none (const char *txt, int times) +{ + return NULL; +} + + +int +cli_rl_enable (struct cli_state *state) +{ + int ret = 0; + + rl_pre_input_hook = NULL; + rl_attempted_completion_function = cli_rl_autocomplete; + rl_completion_entry_function = complete_none; + + ret = event_register (state->ctx->event_pool, 0, cli_rl_stdin, state, + 1, 0); + if (ret == -1) + goto out; + + state->rl_enabled = 1; + rl_callback_handler_install (state->prompt, cli_rl_process_line); + +out: + return state->rl_enabled; +} + +#else /* HAVE_READLINE */ + +int +cli_rl_enable (struct cli_state *state) +{ + return 0; +} + +#endif /* HAVE_READLINE */ diff --git a/cli/src/cli.c b/cli/src/cli.c new file mode 100644 index 00000000000..970db712fe3 --- /dev/null +++ b/cli/src/cli.c @@ -0,0 +1,467 @@ +/* + 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 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see + <http://www.gnu.org/licenses/>. +*/ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <netinet/in.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <sys/resource.h> +#include <sys/file.h> +#include <netdb.h> +#include <signal.h> +#include <libgen.h> + +#include <sys/utsname.h> + +#include <stdint.h> +#include <pthread.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <time.h> +#include <semaphore.h> +#include <errno.h> + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_MALLOC_H +#include <malloc.h> +#endif + +#ifdef HAVE_MALLOC_STATS +#ifdef DEBUG +#include <mcheck.h> +#endif +#endif + +#include "cli.h" +#include "cli-cmd.h" +#include "cli-mem-types.h" + +#include "xlator.h" +#include "glusterfs.h" +#include "compat.h" +#include "logging.h" +#include "dict.h" +#include "list.h" +#include "timer.h" +#include "stack.h" +#include "revision.h" +#include "common-utils.h" +#include "event.h" +#include "globals.h" +#include "syscall.h" + +#include <fnmatch.h> + +/* using argp for command line parsing */ +static char gf_doc[] = ""; + +static char argp_doc[] = "COMMAND [PARAM ...]"; + +const char *argp_program_version = "" \ + PACKAGE_NAME" "PACKAGE_VERSION" built on "__DATE__" "__TIME__ \ + "\nRepository revision: " GLUSTERFS_REPOSITORY_REVISION "\n" \ + "Copyright (c) 2006-2010 Gluster Inc. " \ + "<http://www.gluster.com>\n" \ + "GlusterFS comes with ABSOLUTELY NO WARRANTY.\n" \ + "You may redistribute copies of GlusterFS under the terms of "\ + "the GNU General Public License."; + +const char *argp_program_bug_address = "<" PACKAGE_BUGREPORT ">"; + +static struct argp_option gf_options[] = { + {0, 0, 0, 0, "Basic options:"}, + {"debug", ARGP_DEBUG_KEY, 0, 0, + "Process runs in foreground and logs to console"}, + {0, } +}; + +struct rpc_clnt *global_rpc; + +rpc_clnt_prog_t *cli_rpc_prog; + + +extern struct rpc_clnt_program cli3_1_prog; + +static error_t +parse_opts (int key, char *arg, struct argp_state *argp_state) +{ + struct cli_state *state = NULL; + char **argv = NULL; + + state = argp_state->input; + + switch (key) { + case ARGP_DEBUG_KEY: + break; + case ARGP_KEY_ARG: + if (!state->argc) { + argv = calloc (state->argc + 2, + sizeof (*state->argv)); + } else { + argv = realloc (state->argv, (state->argc + 2) * + sizeof (*state->argv)); + } + if (!argv) + return -1; + + state->argv = argv; + + argv[state->argc] = strdup (arg); + if (!argv[state->argc]) + return -1; + state->argc++; + argv[state->argc] = NULL; + + break; + } + + return 0; +} + + +static char * +generate_uuid () +{ + char tmp_str[1024] = {0,}; + char hostname[256] = {0,}; + struct timeval tv = {0,}; + struct tm now = {0, }; + char now_str[32]; + + if (gettimeofday (&tv, NULL) == -1) { + gf_log ("glusterfsd", GF_LOG_ERROR, + "gettimeofday: failed %s", + strerror (errno)); + } + + if (gethostname (hostname, 256) == -1) { + gf_log ("glusterfsd", GF_LOG_ERROR, + "gethostname: failed %s", + strerror (errno)); + } + + localtime_r (&tv.tv_sec, &now); + strftime (now_str, 32, "%Y/%m/%d-%H:%M:%S", &now); + snprintf (tmp_str, 1024, "%s-%d-%s:%" +#ifdef GF_DARWIN_HOST_OS + PRId32, +#else + "ld", +#endif + hostname, getpid(), now_str, tv.tv_usec); + + return gf_strdup (tmp_str); +} + +static int +glusterfs_ctx_defaults_init (glusterfs_ctx_t *ctx) +{ + cmd_args_t *cmd_args = NULL; + struct rlimit lim = {0, }; + call_pool_t *pool = NULL; + + xlator_mem_acct_init (THIS, cli_mt_end); + + ctx->process_uuid = generate_uuid (); + if (!ctx->process_uuid) + return -1; + + ctx->page_size = 128 * GF_UNIT_KB; + + ctx->iobuf_pool = iobuf_pool_new (8 * GF_UNIT_MB, ctx->page_size); + if (!ctx->iobuf_pool) + return -1; + + ctx->event_pool = event_pool_new (DEFAULT_EVENT_POOL_SIZE); + if (!ctx->event_pool) + return -1; + + pool = GF_CALLOC (1, sizeof (call_pool_t), + cli_mt_call_pool_t); + if (!pool) + return -1; + INIT_LIST_HEAD (&pool->all_frames); + LOCK_INIT (&pool->lock); + ctx->pool = pool; + + pthread_mutex_init (&(ctx->lock), NULL); + + cmd_args = &ctx->cmd_args; + + /* parsing command line arguments */ + cmd_args->log_file = "/dev/stderr"; + cmd_args->log_level = GF_LOG_NORMAL; + + INIT_LIST_HEAD (&cmd_args->xlator_options); + + lim.rlim_cur = RLIM_INFINITY; + lim.rlim_max = RLIM_INFINITY; + setrlimit (RLIMIT_CORE, &lim); + + return 0; +} + + +static int +logging_init (glusterfs_ctx_t *ctx) +{ + cmd_args_t *cmd_args = NULL; + + cmd_args = &ctx->cmd_args; + + if (gf_log_init (cmd_args->log_file) == -1) { + fprintf (stderr, + "failed to open logfile %s. exiting\n", + cmd_args->log_file); + return -1; + } + + gf_log_set_loglevel (cmd_args->log_level); + + return 0; +} + +int +cli_submit_request (void *req, call_frame_t *frame, + rpc_clnt_prog_t *prog, + int procnum, struct iobref *iobref, + cli_serialize_t sfunc, xlator_t *this, + fop_cbk_fn_t cbkfn) +{ + int ret = -1; + int count = 0; + char start_ping = 0; + struct iovec iov = {0, }; + struct iobuf *iobuf = NULL; + char new_iobref = 0; + + GF_ASSERT (this); + + iobuf = iobuf_get (this->ctx->iobuf_pool); + if (!iobuf) { + goto out; + }; + + if (!iobref) { + iobref = iobref_new (); + if (!iobref) { + goto out; + } + + new_iobref = 1; + } + + iobref_add (iobref, iobuf); + + iov.iov_base = iobuf->ptr; + iov.iov_len = 128 * GF_UNIT_KB; + + + /* Create the xdr payload */ + if (req && sfunc) { + ret = sfunc (iov, req); + if (ret == -1) { + goto out; + } + iov.iov_len = ret; + count = 1; + } + + /* Send the msg */ + ret = rpc_clnt_submit (global_rpc, prog, procnum, cbkfn, + &iov, count, + NULL, 0, iobref, frame); + + if (ret == 0) { + pthread_mutex_lock (&global_rpc->conn.lock); + { + if (!global_rpc->conn.ping_started) { + start_ping = 1; + } + } + pthread_mutex_unlock (&global_rpc->conn.lock); + } + + if (start_ping) + //client_start_ping ((void *) this); + + ret = 0; + +out: + return ret; +} + +int +parse_cmdline (int argc, char *argv[], struct cli_state *state) +{ + int ret = 0; + struct argp argp = { 0,}; + + argp.options = gf_options; + argp.parser = parse_opts; + argp.args_doc = argp_doc; + argp.doc = gf_doc; + + ret = argp_parse (&argp, argc, argv, ARGP_IN_ORDER, NULL, state); + + return ret; +} + + +int +cli_cmd_tree_init (struct cli_cmd_tree *tree) +{ + struct cli_cmd_word *root = NULL; + int ret = 0; + + root = &tree->root; + root->tree = tree; + + return ret; +} + + +int +cli_state_init (struct cli_state *state) +{ + struct cli_cmd_tree *tree = NULL; + int ret = 0; + + tree = &state->tree; + tree->state = state; + + ret = cli_cmd_tree_init (tree); + + return ret; +} + + +int +cli_out (const char *fmt, ...) +{ + struct cli_state *state = NULL; + va_list ap; + + state = global_state; + + va_start (ap, fmt); + +#ifdef HAVE_READLINE + if (state->rl_enabled && !state->rl_processing) + return cli_rl_out(state, fmt, ap); +#endif + + return vprintf (fmt, ap); +} + +struct rpc_clnt * +cli_rpc_init (struct cli_state *state) +{ + struct rpc_clnt *rpc = NULL; + struct rpc_clnt_config rpc_cfg = {0,}; + dict_t *options = NULL; + int ret = -1; + + rpc_cfg.remote_host = "localhost"; + rpc_cfg.remote_port = CLI_GLUSTERD_PORT; + + cli_rpc_prog = &cli3_1_prog; + options = dict_new (); + if (!options) + goto out; + + ret = dict_set_str (options, "remote-host", "localhost"); + if (ret) + goto out; + + ret = dict_set_int32 (options, "remote-port", CLI_GLUSTERD_PORT); + if (ret) + goto out; + + ret = dict_set_str (options, "transport.address-family", "inet"); + if (ret) + goto out; + + rpc = rpc_clnt_init (&rpc_cfg, options, THIS->ctx, THIS->name); + +out: + return rpc; +} + +struct cli_state *global_state; + +int +main (int argc, char *argv[]) +{ + struct cli_state state = {0, }; + int ret = -1; + glusterfs_ctx_t *ctx = NULL; + + ret = glusterfs_globals_init (); + if (ret) + return ret; + + ctx = glusterfs_ctx_get (); + if (!ctx) + return ENOMEM; + + ret = glusterfs_ctx_defaults_init (ctx); + if (ret) + goto out; + + ret = cli_state_init (&state); + if (ret) + goto out; + + state.ctx = ctx; + global_state = &state; + + ret = parse_cmdline (argc, argv, &state); + if (ret) + goto out; + + ret = logging_init (ctx); + if (ret) + goto out; + + ret = cli_cmds_register (&state); + if (ret) + goto out; + + ret = cli_input_init (&state); + if (ret) + goto out; + + global_rpc = cli_rpc_init (&state); + if (!global_rpc) + goto out; + + ret = event_dispatch (ctx->event_pool); + +out: +// glusterfs_ctx_destroy (ctx); + + return ret; +} diff --git a/cli/src/cli.h b/cli/src/cli.h new file mode 100644 index 00000000000..c532babf4f5 --- /dev/null +++ b/cli/src/cli.h @@ -0,0 +1,139 @@ +/* + Copyright (c) 2006-2009 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 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see + <http://www.gnu.org/licenses/>. +*/ + +#ifndef __CLI_H__ +#define __CLI_H__ + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include "rpc-clnt.h" +#include "glusterfs.h" +#include "protocol-common.h" + +#define DEFAULT_EVENT_POOL_SIZE 16384 +#define CLI_GLUSTERD_PORT 6969 + +enum argp_option_keys { + ARGP_DEBUG_KEY = 133, +}; + +struct cli_state; +struct cli_cmd_word; +struct cli_cmd_tree; + +typedef int (cli_cmd_cbk_t)(struct cli_state *state, + struct cli_cmd_word *word, + const char **words, + int wordcount); +typedef int (cli_cmd_match_t)(struct cli_cmd_word *word); +typedef int (cli_cmd_filler_t)(struct cli_cmd_word *word); + +struct cli_cmd_word { + struct cli_cmd_tree *tree; + const char *word; + cli_cmd_filler_t *filler; + cli_cmd_match_t *match; + cli_cmd_cbk_t *cbkfn; + + int nextwords_cnt; + struct cli_cmd_word **nextwords; +}; + + +struct cli_cmd_tree { + struct cli_state *state; + struct cli_cmd_word root; +}; + + +struct cli_state { + int argc; + char **argv; + + char debug; + + /* for events dispatching */ + glusterfs_ctx_t *ctx; + + /* registry of known commands */ + struct cli_cmd_tree tree; + + /* the thread which "executes" the command in non-interactive mode */ + /* also the thread which reads from stdin in non-readline mode */ + pthread_t input; + + /* terminal I/O */ + const char *prompt; + int rl_enabled; + int rl_processing; + + /* autocompletion state */ + char **matches; + char **matchesp; +}; + + +typedef ssize_t (*cli_serialize_t) (struct iovec outmsg, void *args); + +extern struct cli_state *global_state; /* use only in readline callback */ + +int cli_cmd_register (struct cli_cmd_tree *tree, const char *template, + cli_cmd_cbk_t cbk); +int cli_cmds_register (struct cli_state *state); + +int cli_input_init (struct cli_state *state); + +int cli_cmd_process (struct cli_state *state, int argc, char *argv[]); +int cli_cmd_process_line (struct cli_state *state, const char *line); + +int cli_rl_enable (struct cli_state *state); +int cli_rl_out (struct cli_state *state, const char *fmt, va_list ap); + +int cli_out (const char *fmt, ...); + +int +cli_submit_request (void *req, call_frame_t *frame, + rpc_clnt_prog_t *prog, + int procnum, struct iobref *iobref, + cli_serialize_t sfunc, xlator_t *this, + fop_cbk_fn_t cbkfn); + +int32_t +cli_cmd_volume_create_parse (const char **words, int wordcount, + dict_t **options); + +int32_t +cli_cmd_volume_set_parse (const char **words, int wordcount, + dict_t **options); + +int32_t +cli_cmd_volume_add_brick_parse (const char **words, int wordcount, + dict_t **options); + +int32_t +cli_cmd_volume_remove_brick_parse (const char **words, int wordcount, + dict_t **options); + +int32_t +cli_cmd_volume_replace_brick_parse (const char **words, int wordcount, + dict_t **options); +#endif /* __CLI_H__ */ diff --git a/cli/src/cli3_1-cops.c b/cli/src/cli3_1-cops.c new file mode 100644 index 00000000000..a3d5ddd8950 --- /dev/null +++ b/cli/src/cli3_1-cops.c @@ -0,0 +1,805 @@ +/* + 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 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see + <http://www.gnu.org/licenses/>. +*/ + + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include "cli.h" +#include "gluster1.h" +#include "cli-xdr.h" +#include "compat-errno.h" +#include "protocol-common.h" +#include "cli-cmd.h" +#include <sys/uio.h> + +extern rpc_clnt_prog_t *cli_rpc_prog; + +int +gf_cli3_1_probe_cbk (struct rpc_req *req, struct iovec *iov, + int count, void *myframe) +{ + gf1_cli_probe_rsp rsp = {0,}; + int ret = 0; + + if (-1 == req->rpc_status) { + goto out; + } + + ret = gf_xdr_to_cli_probe_req (*iov, &rsp); + if (ret < 0) { + gf_log ("", GF_LOG_ERROR, "error"); + //rsp.op_ret = -1; + //rsp.op_errno = EINVAL; + goto out; + } + + gf_log ("cli", GF_LOG_NORMAL, "Received resp to probe"); + cli_out ("Probe %s", (rsp.op_ret) ? "Unsuccessful": "Successful"); + + cli_cmd_broadcast_response (); + + ret = 0; + +out: + return ret; +} + +int +gf_cli3_1_create_volume_cbk (struct rpc_req *req, struct iovec *iov, + int count, void *myframe) +{ + gf1_cli_create_vol_rsp rsp = {0,}; + int ret = 0; + + if (-1 == req->rpc_status) { + goto out; + } + + ret = gf_xdr_to_cli_create_vol_req (*iov, &rsp); + if (ret < 0) { + gf_log ("", GF_LOG_ERROR, "error"); + goto out; + } + + + gf_log ("cli", GF_LOG_NORMAL, "Received resp to create volume"); + cli_out ("Create Volume %s", (rsp.op_ret) ? "Unsuccessful": + "Successful"); + + ret = 0; + +out: + return ret; +} + +int +gf_cli3_1_delete_volume_cbk (struct rpc_req *req, struct iovec *iov, + int count, void *myframe) +{ + gf1_cli_delete_vol_rsp rsp = {0,}; + int ret = 0; + + if (-1 == req->rpc_status) { + goto out; + } + + ret = gf_xdr_to_cli_delete_vol_req (*iov, &rsp); + if (ret < 0) { + gf_log ("", GF_LOG_ERROR, "error"); + goto out; + } + + + gf_log ("cli", GF_LOG_NORMAL, "Received resp to delete volume"); + cli_out ("Delete Volume %s", (rsp.op_ret) ? "Unsuccessful": + "Successful"); + + ret = 0; + +out: + return ret; +} + +int +gf_cli3_1_start_volume_cbk (struct rpc_req *req, struct iovec *iov, + int count, void *myframe) +{ + gf1_cli_start_vol_rsp rsp = {0,}; + int ret = 0; + + if (-1 == req->rpc_status) { + goto out; + } + + ret = gf_xdr_to_cli_start_vol_req (*iov, &rsp); + if (ret < 0) { + gf_log ("", GF_LOG_ERROR, "error"); + goto out; + } + + + gf_log ("cli", GF_LOG_NORMAL, "Received resp to start volume"); + cli_out ("Start Volume %s", (rsp.op_ret) ? "Unsuccessful": + "Successful"); + + ret = 0; + +out: + return ret; +} + +int +gf_cli3_1_stop_volume_cbk (struct rpc_req *req, struct iovec *iov, + int count, void *myframe) +{ + gf1_cli_stop_vol_rsp rsp = {0,}; + int ret = 0; + + if (-1 == req->rpc_status) { + goto out; + } + + ret = gf_xdr_to_cli_stop_vol_req (*iov, &rsp); + if (ret < 0) { + gf_log ("", GF_LOG_ERROR, "error"); + goto out; + } + + + gf_log ("cli", GF_LOG_NORMAL, "Received resp to stop volume"); + cli_out ("Delete Volume %s", (rsp.op_ret) ? "Unsuccessful": + "Successful"); + + ret = 0; + +out: + return ret; +} + +int +gf_cli3_1_defrag_volume_cbk (struct rpc_req *req, struct iovec *iov, + int count, void *myframe) +{ + gf1_cli_defrag_vol_rsp rsp = {0,}; + int ret = 0; + + if (-1 == req->rpc_status) { + goto out; + } + + ret = gf_xdr_to_cli_defrag_vol_req (*iov, &rsp); + if (ret < 0) { + gf_log ("", GF_LOG_ERROR, "error"); + goto out; + } + + + gf_log ("cli", GF_LOG_NORMAL, "Received resp to probe"); + cli_out ("Defrag Volume %s", (rsp.op_ret) ? "Unsuccessful": + "Successful"); + + ret = 0; + +out: + return ret; +} + +int +gf_cli3_1_rename_volume_cbk (struct rpc_req *req, struct iovec *iov, + int count, void *myframe) +{ + gf1_cli_rename_vol_rsp rsp = {0,}; + int ret = 0; + + if (-1 == req->rpc_status) { + goto out; + } + + ret = gf_xdr_to_cli_rename_vol_req (*iov, &rsp); + if (ret < 0) { + gf_log ("", GF_LOG_ERROR, "error"); + goto out; + } + + + gf_log ("cli", GF_LOG_NORMAL, "Received resp to probe"); + cli_out ("Rename Volume %s", (rsp.op_ret) ? "Unsuccessful": + "Successful"); + + ret = 0; + +out: + return ret; +} + +int +gf_cli3_1_set_volume_cbk (struct rpc_req *req, struct iovec *iov, + int count, void *myframe) +{ + gf1_cli_set_vol_rsp rsp = {0,}; + int ret = 0; + + if (-1 == req->rpc_status) { + goto out; + } + + ret = gf_xdr_to_cli_set_vol_req (*iov, &rsp); + if (ret < 0) { + gf_log ("", GF_LOG_ERROR, "error"); + goto out; + } + + + gf_log ("cli", GF_LOG_NORMAL, "Received resp to set"); + cli_out ("Set Volume %s", (rsp.op_ret) ? "Unsuccessful": + "Successful"); + + ret = 0; + +out: + return ret; +} + +int +gf_cli3_1_add_brick_cbk (struct rpc_req *req, struct iovec *iov, + int count, void *myframe) +{ + gf1_cli_add_brick_rsp rsp = {0,}; + int ret = 0; + + if (-1 == req->rpc_status) { + goto out; + } + + ret = gf_xdr_to_cli_add_brick_req (*iov, &rsp); + if (ret < 0) { + gf_log ("", GF_LOG_ERROR, "error"); + goto out; + } + + + gf_log ("cli", GF_LOG_NORMAL, "Received resp to add brick"); + cli_out ("Add Brick %s", (rsp.op_ret) ? "Unsuccessful": + "Successful"); + + ret = 0; + +out: + return ret; +} + + +int +gf_cli3_1_remove_brick_cbk (struct rpc_req *req, struct iovec *iov, + int count, void *myframe) +{ + gf1_cli_remove_brick_rsp rsp = {0,}; + int ret = 0; + + if (-1 == req->rpc_status) { + goto out; + } + + ret = gf_xdr_to_cli_remove_brick_req (*iov, &rsp); + if (ret < 0) { + gf_log ("", GF_LOG_ERROR, "error"); + goto out; + } + + gf_log ("cli", GF_LOG_NORMAL, "Received resp to remove brick"); + cli_out ("Remove Brick %s", (rsp.op_ret) ? "Unsuccessful": + "Successful"); + + ret = 0; + +out: + return ret; +} + + +int +gf_cli3_1_replace_brick_cbk (struct rpc_req *req, struct iovec *iov, + int count, void *myframe) +{ + gf1_cli_replace_brick_rsp rsp = {0,}; + int ret = 0; + + if (-1 == req->rpc_status) { + goto out; + } + + ret = gf_xdr_to_cli_replace_brick_req (*iov, &rsp); + if (ret < 0) { + gf_log ("", GF_LOG_ERROR, "error"); + goto out; + } + + + gf_log ("cli", GF_LOG_NORMAL, "Received resp to replace brick"); + cli_out ("Replace Brick %s", (rsp.op_ret) ? "Unsuccessful": + "Successful"); + + ret = 0; + +out: + return ret; +} + +int32_t +gf_cli3_1_probe (call_frame_t *frame, xlator_t *this, + void *data) +{ + gf1_cli_probe_req req = {0,}; + int ret = 0; + char *hostname = NULL; + + if (!frame || !this || !data) { + ret = -1; + goto out; + } + + hostname = data; + + req.hostname = hostname; + + ret = cli_submit_request (&req, frame, cli_rpc_prog, + GD_MGMT_CLI_PROBE, NULL, gf_xdr_from_cli_probe_req, + this, gf_cli3_1_probe_cbk); + + if (!ret) { + //ret = cli_cmd_await_response (); + } +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int32_t +gf_cli3_1_create_volume (call_frame_t *frame, xlator_t *this, + void *data) +{ + gf1_cli_create_vol_req req = {0,}; + int ret = 0; + dict_t *dict = NULL; + + if (!frame || !this || !data) { + ret = -1; + goto out; + } + + dict = data; + + ret = dict_get_str (dict, "volname", &req.volname); + + if (ret) + goto out; + + ret = dict_get_int32 (dict, "type", (int32_t *)&req.type); + + if (ret) + goto out; + + ret = dict_get_int32 (dict, "count", &req.count); + + if (ret) + goto out; + + ret = dict_allocate_and_serialize (dict, + &req.bricks.bricks_val, + (size_t *)&req.bricks.bricks_len); + if (ret < 0) { + gf_log (this->name, GF_LOG_DEBUG, + "failed to get serialized length of dict"); + goto out; + } + + ret = cli_submit_request (&req, frame, cli_rpc_prog, + GD_MGMT_CLI_CREATE_VOLUME, NULL, + gf_xdr_from_cli_create_vol_req, + this, gf_cli3_1_create_volume_cbk); + + if (!ret) { + //ret = cli_cmd_await_response (); + } + + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + + if (req.bricks.bricks_val) { + GF_FREE (req.bricks.bricks_val); + } + + return ret; +} + +int32_t +gf_cli3_1_delete_volume (call_frame_t *frame, xlator_t *this, + void *data) +{ + gf1_cli_delete_vol_req req = {0,}; + int ret = 0; + + if (!frame || !this || !data) { + ret = -1; + goto out; + } + + req.volname = data; + + ret = cli_submit_request (&req, frame, cli_rpc_prog, + GD_MGMT_CLI_DELETE_VOLUME, NULL, + gf_xdr_from_cli_delete_vol_req, + this, gf_cli3_1_delete_volume_cbk); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + + return ret; +} + +int32_t +gf_cli3_1_start_volume (call_frame_t *frame, xlator_t *this, + void *data) +{ + gf1_cli_start_vol_req req = {0,}; + int ret = 0; + + if (!frame || !this || !data) { + ret = -1; + goto out; + } + + req.volname = data; + + ret = cli_submit_request (&req, frame, cli_rpc_prog, + GD_MGMT_CLI_START_VOLUME, NULL, + gf_xdr_from_cli_start_vol_req, + this, gf_cli3_1_start_volume_cbk); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + + return ret; +} + +int32_t +gf_cli3_1_stop_volume (call_frame_t *frame, xlator_t *this, + void *data) +{ + gf1_cli_stop_vol_req req = {0,}; + int ret = 0; + + if (!frame || !this || !data) { + ret = -1; + goto out; + } + + req.volname = data; + + ret = cli_submit_request (&req, frame, cli_rpc_prog, + GD_MGMT_CLI_STOP_VOLUME, NULL, + gf_xdr_from_cli_stop_vol_req, + this, gf_cli3_1_stop_volume_cbk); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + + return ret; +} + +int32_t +gf_cli3_1_defrag_volume (call_frame_t *frame, xlator_t *this, + void *data) +{ + gf1_cli_defrag_vol_req req = {0,}; + int ret = 0; + + if (!frame || !this || !data) { + ret = -1; + goto out; + } + + req.volname = data; + + ret = cli_submit_request (&req, frame, cli_rpc_prog, + GD_MGMT_CLI_DEFRAG_VOLUME, NULL, + gf_xdr_from_cli_defrag_vol_req, + this, gf_cli3_1_defrag_volume_cbk); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + + return ret; +} + +int32_t +gf_cli3_1_rename_volume (call_frame_t *frame, xlator_t *this, + void *data) +{ + gf1_cli_rename_vol_req req = {0,}; + int ret = 0; + dict_t *dict = NULL; + + if (!frame || !this || !data) { + ret = -1; + goto out; + } + + dict = data; + + ret = dict_get_str (dict, "old-volname", &req.old_volname); + + if (ret) + goto out; + + ret = dict_get_str (dict, "new-volname", &req.new_volname); + + if (ret) + goto out; + + ret = cli_submit_request (&req, frame, cli_rpc_prog, + GD_MGMT_CLI_RENAME_VOLUME, NULL, + gf_xdr_from_cli_rename_vol_req, + this, gf_cli3_1_rename_volume_cbk); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + + return ret; +} + +int32_t +gf_cli3_1_set_volume (call_frame_t *frame, xlator_t *this, + void *data) +{ + gf1_cli_set_vol_req req = {0,}; + int ret = 0; + dict_t *dict = NULL; + + if (!frame || !this || !data) { + ret = -1; + goto out; + } + + dict = data; + + ret = dict_get_str (dict, "volname", &req.volname); + + if (ret) + goto out; + + ret = dict_allocate_and_serialize (dict, + &req.dict.dict_val, + (size_t *)&req.dict.dict_len); + if (ret < 0) { + gf_log (this->name, GF_LOG_DEBUG, + "failed to get serialized length of dict"); + goto out; + } + + + ret = cli_submit_request (&req, frame, cli_rpc_prog, + GD_MGMT_CLI_SET_VOLUME, NULL, + gf_xdr_from_cli_set_vol_req, + this, gf_cli3_1_set_volume_cbk); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + + return ret; +} + +int32_t +gf_cli3_1_add_brick (call_frame_t *frame, xlator_t *this, + void *data) +{ + gf1_cli_add_brick_req req = {0,}; + int ret = 0; + dict_t *dict = NULL; + + if (!frame || !this || !data) { + ret = -1; + goto out; + } + + dict = data; + + ret = dict_get_str (dict, "volname", &req.volname); + + if (ret) + goto out; + + ret = dict_get_int32 (dict, "type", (int32_t *)&req.type); + + if (ret) + goto out; + + ret = dict_get_int32 (dict, "count", &req.count); + + if (ret) + goto out; + + ret = dict_allocate_and_serialize (dict, + &req.bricks.bricks_val, + (size_t *)&req.bricks.bricks_len); + if (ret < 0) { + gf_log (this->name, GF_LOG_DEBUG, + "failed to get serialized length of dict"); + goto out; + } + + ret = cli_submit_request (&req, frame, cli_rpc_prog, + GD_MGMT_CLI_ADD_BRICK, NULL, + gf_xdr_from_cli_add_brick_req, + this, gf_cli3_1_add_brick_cbk); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + + if (req.bricks.bricks_val) { + GF_FREE (req.bricks.bricks_val); + } + + return ret; +} + +int32_t +gf_cli3_1_remove_brick (call_frame_t *frame, xlator_t *this, + void *data) +{ + gf1_cli_remove_brick_req req = {0,}; + int ret = 0; + dict_t *dict = NULL; + + if (!frame || !this || !data) { + ret = -1; + goto out; + } + + dict = data; + + ret = dict_get_str (dict, "volname", &req.volname); + + if (ret) + goto out; + + ret = dict_get_int32 (dict, "type", (int32_t *)&req.type); + + if (ret) + goto out; + + ret = dict_get_int32 (dict, "count", &req.count); + + if (ret) + goto out; + + ret = dict_allocate_and_serialize (dict, + &req.bricks.bricks_val, + (size_t *)&req.bricks.bricks_len); + if (ret < 0) { + gf_log (this->name, GF_LOG_DEBUG, + "failed to get serialized length of dict"); + goto out; + } + + ret = cli_submit_request (&req, frame, cli_rpc_prog, + GD_MGMT_CLI_REMOVE_BRICK, NULL, + gf_xdr_from_cli_remove_brick_req, + this, gf_cli3_1_remove_brick_cbk); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + + if (req.bricks.bricks_val) { + GF_FREE (req.bricks.bricks_val); + } + + return ret; +} + +int32_t +gf_cli3_1_replace_brick (call_frame_t *frame, xlator_t *this, + void *data) +{ + gf1_cli_replace_brick_req req = {0,}; + int ret = 0; + dict_t *dict = NULL; + char *src_brick = NULL; + char *dst_brick = NULL; + + if (!frame || !this || !data) { + ret = -1; + goto out; + } + + dict = data; + + ret = dict_get_str (dict, "volname", &req.volname); + + if (ret) + goto out; + + ret = dict_get_int32 (dict, "operation", (int32_t *)&req.op); + + if (ret) + goto out; + + if (GF_REPLACE_OP_START == req.op) { + ret = dict_get_str (dict, "src-brick", &src_brick); + + if (ret) + goto out; + + req.src_brick.src_brick_len = strlen (src_brick); + req.src_brick.src_brick_val = src_brick; + + ret = dict_get_str (dict, "src-brick", &dst_brick); + + if (ret) + goto out; + + req.dst_brick.dst_brick_len = strlen (dst_brick); + req.dst_brick.dst_brick_val = dst_brick; + } + + ret = cli_submit_request (&req, frame, cli_rpc_prog, + GD_MGMT_CLI_REPLACE_BRICK, NULL, + gf_xdr_from_cli_replace_brick_req, + this, gf_cli3_1_replace_brick_cbk); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + + if (req.src_brick.src_brick_val) { + GF_FREE (req.src_brick.src_brick_val); + } + + if (req.dst_brick.dst_brick_val) { + GF_FREE (req.dst_brick.dst_brick_val); + } + + return ret; +} + +struct rpc_clnt_procedure gluster3_1_cli_actors[GF1_CLI_MAXVALUE] = { + [GF1_CLI_NULL] = {"NULL", NULL }, + [GF1_CLI_PROBE] = { "PROBE_QUERY", gf_cli3_1_probe}, + [GF1_CLI_CREATE_VOLUME] = {"CREATE_VOLUME", gf_cli3_1_create_volume}, + [GF1_CLI_DELETE_VOLUME] = {"DELETE_VOLUME", gf_cli3_1_delete_volume}, + [GF1_CLI_START_VOLUME] = {"START_VOLUME", gf_cli3_1_start_volume}, + [GF1_CLI_STOP_VOLUME] = {"STOP_VOLUME", gf_cli3_1_stop_volume}, + [GF1_CLI_RENAME_VOLUME] = {"RENAME_VOLUME", gf_cli3_1_rename_volume}, + [GF1_CLI_DEFRAG_VOLUME] = {"DEFRAG_VOLUME", gf_cli3_1_defrag_volume}, + [GF1_CLI_SET_VOLUME] = {"SET_VOLUME", gf_cli3_1_set_volume}, + [GF1_CLI_ADD_BRICK] = {"ADD_BRICK", gf_cli3_1_add_brick}, + [GF1_CLI_REMOVE_BRICK] = {"REMOVE_BRICK", gf_cli3_1_remove_brick}, + [GF1_CLI_REPLACE_BRICK] = {"REPLACE_BRICK", gf_cli3_1_replace_brick}, +}; + +struct rpc_clnt_program cli3_1_prog = { + .progname = "CLI 3.1", + .prognum = GLUSTER3_1_CLI_PROGRAM, + .progver = GLUSTER3_1_CLI_VERSION, + .proctable = gluster3_1_cli_actors, + .numproc = GLUSTER3_1_CLI_PROCCNT, +}; diff --git a/cli/src/input.c b/cli/src/input.c new file mode 100644 index 00000000000..62bd8c4063d --- /dev/null +++ b/cli/src/input.c @@ -0,0 +1,98 @@ +/* + 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 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see + <http://www.gnu.org/licenses/>. +*/ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stdint.h> +#include <pthread.h> + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include "cli.h" +#include "cli-mem-types.h" + +#define CMDBUFSIZ 1024 + +#define cli_out(fmt...) fprintf (stdout, ##fmt) + +void * +cli_batch (void *d) +{ + struct cli_state *state = NULL; + int ret = 0; + + state = d; + + ret = cli_cmd_process (state, state->argc, state->argv); + exit (ret); + + return NULL; +} + + +void * +cli_input (void *d) +{ + struct cli_state *state = NULL; + int ret = 0; + char cmdbuf[CMDBUFSIZ]; + char *cmd = NULL; + + state = d; + + for (;;) { + cli_out ("%s", state->prompt); + + cmd = fgets (cmdbuf, CMDBUFSIZ, stdin); + if (!cmd) + break; + + printf ("processing command: '%s'\n", cmd); + ret = cli_cmd_process_line (state, cmd); + } + + exit (ret); + + return NULL; +} + + +int +cli_input_init (struct cli_state *state) +{ + int ret = 0; + + if (state->argc) { + ret = pthread_create (&state->input, NULL, cli_batch, state); + return ret; + } + + state->prompt = "gluster> "; + + cli_rl_enable (state); + + if (!state->rl_enabled) + ret = pthread_create (&state->input, NULL, cli_input, state); + + return ret; +} diff --git a/cli/src/registry.c b/cli/src/registry.c new file mode 100644 index 00000000000..0ced00787c8 --- /dev/null +++ b/cli/src/registry.c @@ -0,0 +1,386 @@ +/* + 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 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see + <http://www.gnu.org/licenses/>. +*/ + + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#include "cli.h" +#include "cli-cmd.h" + + +static int +__is_spc (int ch) +{ + if (ch == ' ') + return 1; + return 0; +} + + +static int +__is_div (int ch) +{ + switch (ch) { + case '(': + case ')': + case '<': + case '>': + case '[': + case ']': + case '{': + case '}': + case '|': + return 1; + } + + return 0; +} + + +static int +__is_word (const char *word) +{ + return (!__is_div (*word) && !__is_spc (*word)); +} + + +int +counter_char (int ch) +{ + switch (ch) { + case '(': + return ')'; + case '<': + return '>'; + case '[': + return ']'; + case '{': + return '}'; + } + + return -1; +} + + +const char * +__is_template_balanced (const char *template) +{ + const char *trav = NULL; + int ch = 0; + + trav = template; + + while (*trav) { + ch = *trav; + + switch (ch) { + case '<': + case '(': + case '[': + trav = __is_template_balanced (trav+1); + if (!trav) + return NULL; + if (*trav != counter_char (ch)) + return NULL; + break; + case '>': + case ')': + case ']': + return trav; + } + + trav++; + } + + return trav; +} + + +int +is_template_balanced (const char *template) +{ + const char *trav = NULL; + + trav = __is_template_balanced (template); + if (!trav || *trav) + return -1; + + return 0; +} + + +int +cli_cmd_token_count (const char *template) +{ + int count = 0; + const char *trav = NULL; + int is_alnum = 0; + + for (trav = template; *trav; trav++) { + switch (*trav) { + case '<': + case '>': + case '(': + case ')': + case '[': + case ']': + case '{': + case '}': + case '|': + count++; + /* fall through */ + case ' ': + is_alnum = 0; + break; + default: + if (!is_alnum) { + is_alnum = 1; + count++; + } + } + } + + return count + 1; +} + + +void +cli_cmd_tokens_destroy (char **tokens) +{ + char **tokenp = NULL; + + if (!tokens) + return; + + tokenp = tokens; + while (*tokenp) { + free (*tokenp); + tokenp++; + } + + free (tokens); +} + + +int +cli_cmd_tokens_fill (char **tokens, const char *template) +{ + const char *trav = NULL; + char **tokenp = NULL; + char *token = NULL; + int ret = 0; + int ch = 0; + + tokenp = tokens; + + for (trav = template; *trav; trav++) { + ch = *trav; + + if (__is_spc (ch)) + continue; + + if (__is_div (ch)) { + token = calloc (2, 1); + if (!token) + return -1; + token[0] = ch; + + *tokenp = token; + tokenp++; + + continue; + } + + token = strdup (trav); + *tokenp = token; + tokenp++; + + for (token++; *token; token++) { + if (__is_spc (*token) || __is_div (*token)) { + *token = 0; + break; + } + trav++; + } + } + + return ret; +} + + +char ** +cli_cmd_tokenize (const char *template) +{ + char **tokens = NULL; + int ret = 0; + int count = 0; + + ret = is_template_balanced (template); + if (ret) + return NULL; + + count = cli_cmd_token_count (template); + if (count <= 0) + return NULL; + + tokens = calloc (count + 1, sizeof (char *)); + if (!tokens) + return NULL; + + ret = cli_cmd_tokens_fill (tokens, template); + if (ret) + goto err; + + return tokens; +err: + cli_cmd_tokens_destroy (tokens); + return NULL; +} + + +struct cli_cmd_word * +cli_cmd_nextword (struct cli_cmd_word *word, const char *token) +{ + struct cli_cmd_word *next = NULL; + struct cli_cmd_word **trav = NULL; + int ret = 0; + + if (!word->nextwords) + return NULL; + + for (trav = word->nextwords; (next = *trav); trav++) { + if (next->match) { +// ret = next->match (); + } else { + ret = strcmp (next->word, token); + } + + if (ret == 0) + break; + } + + return next; +} + + +struct cli_cmd_word * +cli_cmd_newword (struct cli_cmd_word *word, const char *token) +{ + struct cli_cmd_word **nextwords = NULL; + struct cli_cmd_word *nextword = NULL; + + nextwords = realloc (word->nextwords, + (word->nextwords_cnt + 2) * sizeof (*nextwords)); + if (!nextwords) + return NULL; + + word->nextwords = nextwords; + + nextword = calloc (1, sizeof (*nextword)); + if (!nextword) + return NULL; + + nextword->word = strdup (token); + if (!nextword->word) { + free (nextword); + return NULL; + } + + nextword->tree = word->tree; + nextwords[word->nextwords_cnt++] = nextword; + nextwords[word->nextwords_cnt] = NULL; + + return nextword; +} + + +int +cli_cmd_ingest (struct cli_cmd_tree *tree, char **tokens, cli_cmd_cbk_t *cbkfn) +{ + int ret = 0; + char **tokenp = NULL; + char *token = NULL; + struct cli_cmd_word *word = NULL; + struct cli_cmd_word *next = NULL; + + word = &tree->root; + + for (tokenp = tokens; (token = *tokenp); tokenp++) { + if (!__is_word (token)) + break; + + next = cli_cmd_nextword (word, token); + if (!next) + next = cli_cmd_newword (word, token); + + word = next; + if (!word) + break; + } + + if (!word) + return -1; + + if (word->cbkfn) { + /* warning - command already registered */ + } + + word->cbkfn = cbkfn; + + /* end of static strings in command template */ + + /* TODO: autocompletion beyond this point is just "nice to have" */ + + return ret; +} + + +int +cli_cmd_register (struct cli_cmd_tree *tree, const char *template, + cli_cmd_cbk_t cbk) +{ + char **tokens = NULL; + int ret = 0; + + if (!template) + return -1; + + tokens = cli_cmd_tokenize (template); + if (!tokens) + return -1; + + ret = cli_cmd_ingest (tree, tokens, cbk); + if (ret) + goto err; + + return 0; +err: + if (tokens) + cli_cmd_tokens_destroy (tokens); + + return ret; +} + |