X-Git-Url: https://git.saurik.com/redis.git/blobdiff_plain/5d15b5207d3fb83b4815df596251f553b7a811d5..30d31cc8bb416f67183a218f1511ef517eb9ae3b:/src/redis-cli.c diff --git a/src/redis-cli.c b/src/redis-cli.c index 33919758..0e6edbe7 100644 --- a/src/redis-cli.c +++ b/src/redis-cli.c @@ -37,6 +37,7 @@ #include #include #include +#include #include "anet.h" #include "sds.h" @@ -55,13 +56,13 @@ static struct config { int hostport; long repeat; int dbnum; - int argn_from_stdin; int interactive; int shutdown; int monitor_mode; int pubsub_mode; int raw_output; /* output mode per command */ int tty; /* flag for default output format */ + int stdinarg; /* get last arg from stdin. (-x option) */ char mb_sep; char *auth; char *historyfile; @@ -96,7 +97,7 @@ static sds cliReadLine(int fd) { ssize_t ret; ret = read(fd,&c,1); - if (ret == -1) { + if (ret <= 0) { sdsfree(line); return NULL; } else if ((ret == 0) || (c == '\n')) { @@ -226,7 +227,7 @@ static int cliReadReply(int fd) { case '*': return cliReadMultiBulkReply(fd); default: - printf("protocol error, got '%c' as reply type byte\n", type); + printf("protocol error, got '%c' as reply type byte", type); return 1; } } @@ -251,12 +252,32 @@ static int selectDb(int fd) { return 0; } +static void showInteractiveHelp(void) { + printf( + "\n" + "Welcome to redis-cli " REDIS_VERSION "!\n" + "Just type any valid Redis command to see a pretty printed output.\n" + "\n" + "It is possible to quote strings, like in:\n" + " set \"my key\" \"some string \\xff\\n\"\n" + "\n" + "You can find a list of valid Redis commands at\n" + " http://code.google.com/p/redis/wiki/CommandReference\n" + "\n" + "Note: redis-cli supports line editing, use up/down arrows for history." + "\n\n"); +} + static int cliSendCommand(int argc, char **argv, int repeat) { char *command = argv[0]; int fd, j, retval = 0; sds cmd; config.raw_output = !strcasecmp(command,"info"); + if (!strcasecmp(command,"help")) { + showInteractiveHelp(); + return 0; + } if (!strcasecmp(command,"shutdown")) config.shutdown = 1; if (!strcasecmp(command,"monitor")) config.monitor_mode = 1; if (!strcasecmp(command,"subscribe") || @@ -282,7 +303,8 @@ static int cliSendCommand(int argc, char **argv, int repeat) { while(repeat--) { anetWrite(fd,cmd,sdslen(cmd)); while (config.monitor_mode) { - cliReadSingleLineReply(fd,0); + if (cliReadSingleLineReply(fd,0)) exit(1); + printf("\n"); } if (config.pubsub_mode) { @@ -294,12 +316,8 @@ static int cliSendCommand(int argc, char **argv, int repeat) { } retval = cliReadReply(fd); - if (retval) { - return retval; - } - if (!config.raw_output && config.tty) { - printf("\n"); - } + if (!config.raw_output && config.tty) printf("\n"); + if (retval) return retval; } return 0; } @@ -320,6 +338,8 @@ static int parseOptions(int argc, char **argv) { i++; } else if (!strcmp(argv[i],"-h") && lastarg) { usage(); + } else if (!strcmp(argv[i],"-x")) { + config.stdinarg = 1; } else if (!strcmp(argv[i],"-p") && !lastarg) { config.hostport = atoi(argv[i+1]); i++; @@ -338,7 +358,11 @@ static int parseOptions(int argc, char **argv) { "by default when redis-cli is executed without a command to execute.\n" ); } else if (!strcmp(argv[i],"-c")) { - config.argn_from_stdin = 1; + fprintf(stderr, +"Reading last argument from standard input using -c is deprecated.\n" +"When standard input is connected to a pipe or regular file, it is\n" +"automatically used as last argument.\n" + ); } else if (!strcmp(argv[i],"-v")) { printf("redis-cli shipped with Redis verison %s\n", REDIS_VERSION); exit(0); @@ -368,9 +392,8 @@ static sds readArgFromStdin(void) { static void usage() { fprintf(stderr, "usage: redis-cli [-iv] [-h host] [-p port] [-a authpw] [-r repeat_times] [-n db_num] cmd arg1 arg2 arg3 ... argN\n"); - fprintf(stderr, "usage: echo \"argN\" | redis-cli -c [-h host] [-p port] [-a authpw] [-r repeat_times] [-n db_num] cmd arg1 arg2 ... arg(N-1)\n"); - fprintf(stderr, "\nIf a pipe from standard input is detected this data is used as last argument.\n\n"); - fprintf(stderr, "example: cat /etc/passwd | redis-cli set my_passwd\n"); + fprintf(stderr, "usage: echo \"argN\" | redis-cli -x [options] cmd arg1 arg2 ... arg(N-1)\n\n"); + fprintf(stderr, "example: cat /etc/passwd | redis-cli -x set my_passwd\n"); fprintf(stderr, "example: redis-cli get my_passwd\n"); fprintf(stderr, "example: redis-cli -r 100 lpush mylist x\n"); fprintf(stderr, "\nRun in interactive mode: redis-cli -i or just don't pass any command\n"); @@ -433,20 +456,32 @@ static void repl() { exit(0); } +static int noninteractive(int argc, char **argv) { + int retval = 0; + if (config.stdinarg) { + argv = zrealloc(argv, (argc+1)*sizeof(char*)); + argv[argc] = readArgFromStdin(); + retval = cliSendCommand(argc+1, argv, config.repeat); + } else { + /* stdin is probably a tty, can be tested with S_ISCHR(s.st_mode) */ + retval = cliSendCommand(argc, argv, config.repeat); + } + return retval; +} + int main(int argc, char **argv) { int firstarg; - char **argvcopy; config.hostip = "127.0.0.1"; config.hostport = 6379; config.repeat = 1; config.dbnum = 0; - config.argn_from_stdin = 0; config.interactive = 0; config.shutdown = 0; config.monitor_mode = 0; config.pubsub_mode = 0; config.raw_output = 0; + config.stdinarg = 0; config.auth = NULL; config.historyfile = NULL; config.tty = isatty(fileno(stdout)) || (getenv("FAKETTY") != NULL); @@ -464,20 +499,20 @@ int main(int argc, char **argv) { if (config.auth != NULL) { char *authargv[2]; + int dbnum = config.dbnum; + /* We need to save the real configured database number and set it to + * zero here, otherwise cliSendCommand() will try to perform the + * SELECT command before the authentication, and it will fail. */ + config.dbnum = 0; authargv[0] = "AUTH"; authargv[1] = config.auth; cliSendCommand(2, convertToSds(2, authargv), 1); + config.dbnum = dbnum; /* restore the right DB number */ } /* Start interactive mode when no command is provided */ if (argc == 0) repl(); - - argvcopy = convertToSds(argc+1, argv); - if (config.argn_from_stdin) { - sds lastarg = readArgFromStdin(); - argvcopy[argc] = lastarg; - argc++; - } - return cliSendCommand(argc, argvcopy, config.repeat); + /* Otherwise, we have some arguments to execute */ + return noninteractive(argc,convertToSds(argc,argv)); }