diff options
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 000000000..8e1732603 --- /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 000000000..68c6a29c8 --- /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 000000000..dccdaedbe --- /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 000000000..227438db4 --- /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 000000000..a91dd77e2 --- /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 000000000..d1da3e2ac --- /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 000000000..279e5e908 --- /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 000000000..bc2e80eba --- /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 000000000..970db712f --- /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 000000000..c532babf4 --- /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 000000000..a3d5ddd89 --- /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 000000000..62bd8c406 --- /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 000000000..0ced00787 --- /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; +} +  | 
