diff options
Diffstat (limited to 'cli/src/cli.c')
| -rw-r--r-- | cli/src/cli.c | 666 |
1 files changed, 666 insertions, 0 deletions
diff --git a/cli/src/cli.c b/cli/src/cli.c new file mode 100644 index 000000000..91b315ff1 --- /dev/null +++ b/cli/src/cli.c @@ -0,0 +1,666 @@ +/* + Copyright (c) 2010-2012 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <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 "call-stub.h" +#include <fnmatch.h> + +#include "xdr-generic.h" + +extern int connected; +/* using argp for command line parsing */ + +const char *argp_program_version = "" \ + PACKAGE_NAME" "PACKAGE_VERSION" built on "__DATE__" "__TIME__ \ + "\nRepository revision: " GLUSTERFS_REPOSITORY_REVISION "\n" \ + "Copyright (c) 2006-2011 Gluster Inc. " \ + "<http://www.gluster.com>\n" \ + "GlusterFS comes with ABSOLUTELY NO WARRANTY.\n" \ + "You may redistribute copies of GlusterFS under the terms of "\ + "the GNU General Public License."; + +const char *argp_program_bug_address = "<" PACKAGE_BUGREPORT ">"; + + + +struct rpc_clnt *global_rpc; + +rpc_clnt_prog_t *cli_rpc_prog; + + +extern struct rpc_clnt_program cli_prog; + +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_glusterfs_ctx_id (); + if (!ctx->process_uuid) + return -1; + + ctx->page_size = 128 * GF_UNIT_KB; + + ctx->iobuf_pool = iobuf_pool_new (); + 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; + + /* frame_mem_pool size 112 * 64 */ + pool->frame_mem_pool = mem_pool_new (call_frame_t, 32); + if (!pool->frame_mem_pool) + return -1; + + /* stack_mem_pool size 256 * 128 */ + pool->stack_mem_pool = mem_pool_new (call_stack_t, 16); + + if (!pool->stack_mem_pool) + return -1; + + ctx->stub_mem_pool = mem_pool_new (call_stub_t, 16); + if (!ctx->stub_mem_pool) + return -1; + + ctx->dict_pool = mem_pool_new (dict_t, 32); + if (!ctx->dict_pool) + return -1; + + ctx->dict_pair_pool = mem_pool_new (data_pair_t, 512); + if (!ctx->dict_pair_pool) + return -1; + + ctx->dict_data_pool = mem_pool_new (data_t, 512); + if (!ctx->dict_data_pool) + return -1; + + INIT_LIST_HEAD (&pool->all_frames); + LOCK_INIT (&pool->lock); + ctx->pool = pool; + + pthread_mutex_init (&(ctx->lock), NULL); + + cmd_args = &ctx->cmd_args; + + 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, struct cli_state *state) +{ + char *log_file = state->log_file ? state->log_file : + DEFAULT_CLI_LOG_FILE_DIRECTORY "/cli.log"; + + /* passing ident as NULL means to use default ident for syslog */ + if (gf_log_init (ctx, log_file, NULL) == -1) { + fprintf (stderr, "ERROR: failed to open logfile %s\n", + log_file); + return -1; + } + + /* CLI should not have something to DEBUG after the release, + hence defaulting to INFO loglevel */ + gf_log_set_loglevel ((state->log_level == -1) ? GF_LOG_INFO : + state->log_level); + + return 0; +} + +int +cli_submit_request (void *req, call_frame_t *frame, + rpc_clnt_prog_t *prog, + int procnum, struct iobref *iobref, + xlator_t *this, fop_cbk_fn_t cbkfn, xdrproc_t xdrproc) +{ + int ret = -1; + int count = 0; + struct iovec iov = {0, }; + struct iobuf *iobuf = NULL; + char new_iobref = 0; + ssize_t xdr_size = 0; + + GF_ASSERT (this); + + if (req) { + xdr_size = xdr_sizeof (xdrproc, req); + iobuf = iobuf_get2 (this->ctx->iobuf_pool, xdr_size); + if (!iobuf) { + goto out; + }; + + if (!iobref) { + iobref = iobref_new (); + if (!iobref) { + goto out; + } + + new_iobref = 1; + } + + iobref_add (iobref, iobuf); + + iov.iov_base = iobuf->ptr; + iov.iov_len = iobuf_size (iobuf); + + + /* Create the xdr payload */ + ret = xdr_serialize_generic (iov, req, xdrproc); + 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, NULL, 0, NULL, 0, NULL); + ret = 0; + +out: + if (new_iobref) + iobref_unref (iobref); + if (iobuf) + iobuf_unref (iobuf); + return ret; +} + +int +cli_rpc_notify (struct rpc_clnt *rpc, void *mydata, rpc_clnt_event_t event, + void *data) +{ + xlator_t *this = NULL; + int ret = 0; + + this = mydata; + + switch (event) { + case RPC_CLNT_CONNECT: + { + + cli_cmd_broadcast_connected (); + gf_log (this->name, GF_LOG_TRACE, "got RPC_CLNT_CONNECT"); + break; + } + + case RPC_CLNT_DISCONNECT: + { + gf_log (this->name, GF_LOG_TRACE, "got RPC_CLNT_DISCONNECT"); + connected = 0; + if (!global_state->prompt && global_state->await_connected) { + ret = 1; + cli_out ("Connection failed. Please check if gluster " + "daemon is operational."); + exit (ret); + } + break; + } + + default: + gf_log (this->name, GF_LOG_TRACE, + "got some other RPC event %d", event); + ret = 0; + break; + } + + return ret; +} + + +/* + * ret: 0: option successfully processed + * 1: signalling end of option list + * -1: unknown option or other issue + */ +int +cli_opt_parse (char *opt, struct cli_state *state) +{ + char *oarg; + + if (strcmp (opt, "") == 0) + return 1; + + if (strcmp (opt, "version") == 0) { + cli_out ("%s", argp_program_version); + exit (0); + } + + if (strcmp (opt, "print-logdir") == 0) { + cli_out ("%s", DEFAULT_LOG_FILE_DIRECTORY); + exit (0); + } + + if (strcmp (opt, "print-statedumpdir") == 0) { + cli_out ("%s", DEFAULT_VAR_RUN_DIRECTORY); + exit (0); + } + + if (strcmp (opt, "xml") == 0) { +#if (HAVE_LIB_XML) + state->mode |= GLUSTER_MODE_XML; +#else + cli_err ("XML output not supported. Ignoring '--xml' option"); +#endif + return 0; + } + + oarg = strtail (opt, "mode="); + if (oarg) { + if (strcmp (oarg, "script") == 0) { + state->mode |= GLUSTER_MODE_SCRIPT; + return 0; + } + if (strcmp (oarg, "interactive") == 0) + return 0; + return -1; + } + + oarg = strtail (opt, "remote-host="); + if (oarg) { + state->remote_host = oarg; + return 0; + } + + oarg = strtail (opt, "log-file="); + if (oarg) { + state->log_file = oarg; + return 0; + } + + oarg = strtail (opt, "log-level="); + if (oarg) { + state->log_level = glusterd_check_log_level(oarg); + if (state->log_level == -1) + return -1; + return 0; + } + + oarg = strtail (opt, "glusterd-sock="); + if (oarg) { + state->glusterd_sock = oarg; + return 0; + } + + return -1; +} + +int +parse_cmdline (int argc, char *argv[], struct cli_state *state) +{ + int ret = 0; + int i = 0; + int j = 0; + char *opt = NULL; + + state->argc=argc-1; + state->argv=&argv[1]; + + for (i = 0; i < state->argc; i++) { + opt = strtail (state->argv[i], "--"); + if (opt) { + ret = cli_opt_parse (opt, state); + if (ret == -1) { + cli_out ("unrecognized option --%s", opt); + return ret; + } + for (j = i; j < state->argc - 1; j++) + state->argv[j] = state->argv[j + 1]; + state->argc--; + /* argv shifted, next check should be at i again */ + i--; + if (ret == 1) { + /* end of cli options */ + ret = 0; + break; + } + } + } + + state->argv[state->argc] = NULL; + + return ret; +} + + +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; + + + state->log_level = -1; + + tree = &state->tree; + tree->state = state; + + ret = cli_cmd_tree_init (tree); + + return ret; +} + +int +cli_usage_out (const char *usage) +{ + GF_ASSERT (usage); + GF_ASSERT (usage[0] != '\0'); + + if (!usage || usage[0] == '\0') + return -1; + + cli_err ("Usage: %s", usage); + return 0; +} + +int +_cli_err (const char *fmt, ...) +{ + struct cli_state *state = NULL; + va_list ap; + int ret = 0; + + state = global_state; + + va_start (ap, fmt); + +#ifdef HAVE_READLINE + if (state->rl_enabled && !state->rl_processing) + return cli_rl_err(state, fmt, ap); +#endif + + ret = vfprintf (stderr, fmt, ap); + fprintf (stderr, "\n"); + va_end (ap); + + return ret; +} + + +int +_cli_out (const char *fmt, ...) +{ + struct cli_state *state = NULL; + va_list ap; + int ret = 0; + + 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 + + ret = vprintf (fmt, ap); + printf ("\n"); + va_end (ap); + + return ret; +} + +struct rpc_clnt * +cli_rpc_init (struct cli_state *state) +{ + struct rpc_clnt *rpc = NULL; + dict_t *options = NULL; + int ret = -1; + int port = CLI_GLUSTERD_PORT; + xlator_t *this = NULL; + + + this = THIS; + cli_rpc_prog = &cli_prog; + options = dict_new (); + if (!options) + goto out; + + /* Connect using to glusterd using the specified method, giving + * preference to unix socket connection. If nothing is specified connect + * to the default glusterd socket + */ + if (state->glusterd_sock) { + gf_log ("cli", GF_LOG_INFO, "Connecting to glusterd using " + "sockfile %s", state->glusterd_sock); + ret = rpc_transport_unix_options_build (&options, + state->glusterd_sock, + 0); + if (ret) + goto out; + } else if (state->remote_host) { + gf_log ("cli", GF_LOG_INFO, "Connecting to remote glusterd at " + "%s", state->remote_host); + ret = dict_set_str (options, "remote-host", state->remote_host); + if (ret) + goto out; + + if (state->remote_port) + port = state->remote_port; + + ret = dict_set_int32 (options, "remote-port", port); + if (ret) + goto out; + + ret = dict_set_str (options, "transport.address-family", + "inet"); + if (ret) + goto out; + } else { + gf_log ("cli", GF_LOG_DEBUG, "Connecting to glusterd using " + "default socket"); + ret = rpc_transport_unix_options_build + (&options, DEFAULT_GLUSTERD_SOCKFILE, 0); + if (ret) + goto out; + } + + rpc = rpc_clnt_new (options, this->ctx, this->name, 16); + if (!rpc) + goto out; + + ret = rpc_clnt_register_notify (rpc, cli_rpc_notify, this); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "failed to register notify"); + goto out; + } + + ret = rpc_clnt_start (rpc); +out: + if (ret) { + if (rpc) + rpc_clnt_unref (rpc); + rpc = NULL; + } + return rpc; +} + +cli_local_t * +cli_local_get () +{ + cli_local_t *local = NULL; + + local = GF_CALLOC (1, sizeof (*local), cli_mt_cli_local_t); + + return local; +} + +void +cli_local_wipe (cli_local_t *local) +{ + if (local) { + GF_FREE (local->get_vol.volname); + if (local->dict) + dict_unref (local->dict); + GF_FREE (local); + } + + return; +} + +struct cli_state *global_state; + +int +main (int argc, char *argv[]) +{ + struct cli_state state = {0, }; + int ret = -1; + glusterfs_ctx_t *ctx = NULL; + + ctx = glusterfs_ctx_new (); + if (!ctx) + return ENOMEM; + +#ifdef DEBUG + gf_mem_acct_enable_set (ctx); +#endif + + ret = glusterfs_globals_init (ctx); + if (ret) + return ret; + + THIS->ctx = ctx; + + 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, &state); + if (ret) + goto out; + + global_rpc = cli_rpc_init (&state); + if (!global_rpc) + goto out; + + ret = cli_cmds_register (&state); + if (ret) + goto out; + + ret = cli_cmd_cond_init (); + if (ret) + goto out; + + ret = cli_input_init (&state); + if (ret) + goto out; + + ret = event_dispatch (ctx->event_pool); + +out: +// glusterfs_ctx_destroy (ctx); + + return ret; +} + +void +cli_print_line (int len) +{ + GF_ASSERT (len > 0); + + while (len--) + printf ("-"); + + printf ("\n"); +} |
