1# 1 "src/redis-cli.c"
2# 1 "<built-in>"
3# 1 "<command-line>"
4# 1 "src/redis-cli.c"
5# 31 "src/redis-cli.c"
6# 1 "src/fmacros.h" 1
7# 32 "src/redis-cli.c" 2
8# 1 "src/version.h" 1
9# 33 "src/redis-cli.c" 2
10
11# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdio.h" 1
12# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1
13# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdio.h" 2
14# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_typedefs.h" 1
15
16
17
18typedef int size_t;
19typedef int __builtin_va_list;
20typedef int __gnuc_va_list;
21typedef int va_list;
22typedef int __int8_t;
23typedef int __uint8_t;
24typedef int __int16_t;
25typedef int __uint16_t;
26typedef int __int_least16_t;
27typedef int __uint_least16_t;
28typedef int __int32_t;
29typedef int __uint32_t;
30typedef int __int64_t;
31typedef int __uint64_t;
32typedef int __int_least32_t;
33typedef int __uint_least32_t;
34typedef int __s8;
35typedef int __u8;
36typedef int __s16;
37typedef int __u16;
38typedef int __s32;
39typedef int __u32;
40typedef int __s64;
41typedef int __u64;
42typedef int _LOCK_T;
43typedef int _LOCK_RECURSIVE_T;
44typedef int _off_t;
45typedef int __dev_t;
46typedef int __uid_t;
47typedef int __gid_t;
48typedef int _off64_t;
49typedef int _fpos_t;
50typedef int _ssize_t;
51typedef int wint_t;
52typedef int _mbstate_t;
53typedef int _flock_t;
54typedef int _iconv_t;
55typedef int __ULong;
56typedef int __FILE;
57typedef int ptrdiff_t;
58typedef int wchar_t;
59typedef int __off_t;
60typedef int __pid_t;
61typedef int __loff_t;
62typedef int u_char;
63typedef int u_short;
64typedef int u_int;
65typedef int u_long;
66typedef int ushort;
67typedef int uint;
68typedef int clock_t;
69typedef int time_t;
70typedef int daddr_t;
71typedef int caddr_t;
72typedef int ino_t;
73typedef int off_t;
74typedef int dev_t;
75typedef int uid_t;
76typedef int gid_t;
77typedef int pid_t;
78typedef int key_t;
79typedef int ssize_t;
80typedef int mode_t;
81typedef int nlink_t;
82typedef int fd_mask;
83typedef int _types_fd_set;
84typedef int clockid_t;
85typedef int timer_t;
86typedef int useconds_t;
87typedef int suseconds_t;
88typedef int FILE;
89typedef int fpos_t;
90typedef int cookie_read_function_t;
91typedef int cookie_write_function_t;
92typedef int cookie_seek_function_t;
93typedef int cookie_close_function_t;
94typedef int cookie_io_functions_t;
95typedef int div_t;
96typedef int ldiv_t;
97typedef int lldiv_t;
98typedef int sigset_t;
99typedef int __sigset_t;
100typedef int _sig_func_ptr;
101typedef int sig_atomic_t;
102typedef int __tzrule_type;
103typedef int __tzinfo_type;
104typedef int mbstate_t;
105typedef int sem_t;
106typedef int pthread_t;
107typedef int pthread_attr_t;
108typedef int pthread_mutex_t;
109typedef int pthread_mutexattr_t;
110typedef int pthread_cond_t;
111typedef int pthread_condattr_t;
112typedef int pthread_key_t;
113typedef int pthread_once_t;
114typedef int pthread_rwlock_t;
115typedef int pthread_rwlockattr_t;
116typedef int pthread_spinlock_t;
117typedef int pthread_barrier_t;
118typedef int pthread_barrierattr_t;
119typedef int jmp_buf;
120typedef int rlim_t;
121typedef int sa_family_t;
122typedef int sigjmp_buf;
123typedef int stack_t;
124typedef int siginfo_t;
125typedef int z_stream;
126
127
128typedef int int8_t;
129typedef int uint8_t;
130typedef int int16_t;
131typedef int uint16_t;
132typedef int int32_t;
133typedef int uint32_t;
134typedef int int64_t;
135typedef int uint64_t;
136
137
138typedef int int_least8_t;
139typedef int uint_least8_t;
140typedef int int_least16_t;
141typedef int uint_least16_t;
142typedef int int_least32_t;
143typedef int uint_least32_t;
144typedef int int_least64_t;
145typedef int uint_least64_t;
146
147
148typedef int int_fast8_t;
149typedef int uint_fast8_t;
150typedef int int_fast16_t;
151typedef int uint_fast16_t;
152typedef int int_fast32_t;
153typedef int uint_fast32_t;
154typedef int int_fast64_t;
155typedef int uint_fast64_t;
156
157
158typedef int intptr_t;
159typedef int uintptr_t;
160
161
162typedef int intmax_t;
163typedef int uintmax_t;
164
165
166typedef _Bool bool;
167
168
169typedef void* MirEGLNativeWindowType;
170typedef void* MirEGLNativeDisplayType;
171typedef struct MirConnection MirConnection;
172typedef struct MirSurface MirSurface;
173typedef struct MirSurfaceSpec MirSurfaceSpec;
174typedef struct MirScreencast MirScreencast;
175typedef struct MirPromptSession MirPromptSession;
176typedef struct MirBufferStream MirBufferStream;
177typedef struct MirPersistentId MirPersistentId;
178typedef struct MirBlob MirBlob;
179typedef struct MirDisplayConfig MirDisplayConfig;
180
181
182typedef struct xcb_connection_t xcb_connection_t;
183typedef uint32_t xcb_window_t;
184typedef uint32_t xcb_visualid_t;
185# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdio.h" 2
186# 35 "src/redis-cli.c" 2
187# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/string.h" 1
188# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1
189# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/string.h" 2
190# 36 "src/redis-cli.c" 2
191# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdlib.h" 1
192# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1
193# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdlib.h" 2
194# 37 "src/redis-cli.c" 2
195# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/signal.h" 1
196# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1
197# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/signal.h" 2
198# 38 "src/redis-cli.c" 2
199# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/unistd.h" 1
200# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1
201# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/unistd.h" 2
202# 39 "src/redis-cli.c" 2
203# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/time.h" 1
204# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1
205# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/time.h" 2
206# 40 "src/redis-cli.c" 2
207# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/ctype.h" 1
208# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1
209# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/ctype.h" 2
210# 41 "src/redis-cli.c" 2
211# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/errno.h" 1
212# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1
213# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/errno.h" 2
214# 42 "src/redis-cli.c" 2
215# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/sys/stat.h" 1
216# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1
217# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/sys/stat.h" 2
218# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_typedefs.h" 1
219# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/sys/stat.h" 2
220# 43 "src/redis-cli.c" 2
221# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/sys/time.h" 1
222# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1
223# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/sys/time.h" 2
224# 44 "src/redis-cli.c" 2
225# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/assert.h" 1
226# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1
227# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/assert.h" 2
228# 45 "src/redis-cli.c" 2
229# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/fcntl.h" 1
230# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1
231# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/fcntl.h" 2
232# 46 "src/redis-cli.c" 2
233# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/limits.h" 1
234# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1
235# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/limits.h" 2
236# 47 "src/redis-cli.c" 2
237# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/math.h" 1
238# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1
239# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/math.h" 2
240# 48 "src/redis-cli.c" 2
241
242# 1 "deps/hiredis/hiredis.h" 1
243# 36 "deps/hiredis/hiredis.h"
244# 1 "deps/hiredis/read.h" 1
245# 35 "deps/hiredis/read.h"
246# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdio.h" 1
247# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1
248# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdio.h" 2
249# 36 "deps/hiredis/read.h" 2
250# 63 "deps/hiredis/read.h"
251typedef struct redisReadTask {
252    int type;
253    int elements;
254    int idx;
255    void *obj;
256    struct redisReadTask *parent;
257    void *privdata;
258} redisReadTask;
259
260typedef struct redisReplyObjectFunctions {
261    void *(*createString)(const redisReadTask*, char*, size_t);
262    void *(*createArray)(const redisReadTask*, int);
263    void *(*createInteger)(const redisReadTask*, long long);
264    void *(*createNil)(const redisReadTask*);
265    void (*freeObject)(void*);
266} redisReplyObjectFunctions;
267
268typedef struct redisReader {
269    int err;
270    char errstr[128];
271
272    char *buf;
273    size_t pos;
274    size_t len;
275    size_t maxbuf;
276
277    redisReadTask rstack[9];
278    int ridx;
279    void *reply;
280
281    redisReplyObjectFunctions *fn;
282    void *privdata;
283} redisReader;
284
285
286redisReader *redisReaderCreateWithFunctions(redisReplyObjectFunctions *fn);
287void redisReaderFree(redisReader *r);
288int redisReaderFeed(redisReader *r, const char *buf, size_t len);
289int redisReaderGetReply(redisReader *r, void **reply);
290# 37 "deps/hiredis/hiredis.h" 2
291# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdarg.h" 1
292# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1
293# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdarg.h" 2
294# 38 "deps/hiredis/hiredis.h" 2
295# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/sys/time.h" 1
296# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1
297# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/sys/time.h" 2
298# 39 "deps/hiredis/hiredis.h" 2
299# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdint.h" 1
300# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1
301# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdint.h" 2
302# 40 "deps/hiredis/hiredis.h" 2
303# 1 "deps/hiredis/sds.h" 1
304# 38 "deps/hiredis/sds.h"
305# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/sys/types.h" 1
306# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1
307# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/sys/types.h" 2
308# 39 "deps/hiredis/sds.h" 2
309# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdarg.h" 1
310# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1
311# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdarg.h" 2
312# 40 "deps/hiredis/sds.h" 2
313# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdint.h" 1
314# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1
315# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdint.h" 2
316# 41 "deps/hiredis/sds.h" 2
317
318typedef char *sds;
319
320
321
322struct sdshdr5 {
323    unsigned char flags;
324    char buf[];
325};
326struct sdshdr8 {
327    uint8_t len;
328    uint8_t alloc;
329    unsigned char flags;
330    char buf[];
331};
332struct sdshdr16 {
333    uint16_t len;
334    uint16_t alloc;
335    unsigned char flags;
336    char buf[];
337};
338struct sdshdr32 {
339    uint32_t len;
340    uint32_t alloc;
341    unsigned char flags;
342    char buf[];
343};
344struct sdshdr64 {
345    uint64_t len;
346    uint64_t alloc;
347    unsigned char flags;
348    char buf[];
349};
350# 86 "deps/hiredis/sds.h"
351static inline size_t sdslen(const sds s) {
352    unsigned char flags = s[-1];
353    switch(flags&7) {
354        case 0:
355            return ((flags)>>3);
356        case 1:
357            return ((struct sdshdr8 *)((s)-(sizeof(struct sdshdr8))))->len;
358        case 2:
359            return ((struct sdshdr16 *)((s)-(sizeof(struct sdshdr16))))->len;
360        case 3:
361            return ((struct sdshdr32 *)((s)-(sizeof(struct sdshdr32))))->len;
362        case 4:
363            return ((struct sdshdr64 *)((s)-(sizeof(struct sdshdr64))))->len;
364    }
365    return 0;
366}
367
368static inline size_t sdsavail(const sds s) {
369    unsigned char flags = s[-1];
370    switch(flags&7) {
371        case 0: {
372            return 0;
373        }
374        case 1: {
375            struct sdshdr8 *sh = (struct sdshdr8 *)((s)-(sizeof(struct sdshdr8)));;
376            return sh->alloc - sh->len;
377        }
378        case 2: {
379            struct sdshdr16 *sh = (struct sdshdr16 *)((s)-(sizeof(struct sdshdr16)));;
380            return sh->alloc - sh->len;
381        }
382        case 3: {
383            struct sdshdr32 *sh = (struct sdshdr32 *)((s)-(sizeof(struct sdshdr32)));;
384            return sh->alloc - sh->len;
385        }
386        case 4: {
387            struct sdshdr64 *sh = (struct sdshdr64 *)((s)-(sizeof(struct sdshdr64)));;
388            return sh->alloc - sh->len;
389        }
390    }
391    return 0;
392}
393
394static inline void sdssetlen(sds s, size_t newlen) {
395    unsigned char flags = s[-1];
396    switch(flags&7) {
397        case 0:
398            {
399                unsigned char *fp = ((unsigned char*)s)-1;
400                *fp = 0 | (newlen << 3);
401            }
402            break;
403        case 1:
404            ((struct sdshdr8 *)((s)-(sizeof(struct sdshdr8))))->len = newlen;
405            break;
406        case 2:
407            ((struct sdshdr16 *)((s)-(sizeof(struct sdshdr16))))->len = newlen;
408            break;
409        case 3:
410            ((struct sdshdr32 *)((s)-(sizeof(struct sdshdr32))))->len = newlen;
411            break;
412        case 4:
413            ((struct sdshdr64 *)((s)-(sizeof(struct sdshdr64))))->len = newlen;
414            break;
415    }
416}
417
418static inline void sdsinclen(sds s, size_t inc) {
419    unsigned char flags = s[-1];
420    switch(flags&7) {
421        case 0:
422            {
423                unsigned char *fp = ((unsigned char*)s)-1;
424                unsigned char newlen = ((flags)>>3)+inc;
425                *fp = 0 | (newlen << 3);
426            }
427            break;
428        case 1:
429            ((struct sdshdr8 *)((s)-(sizeof(struct sdshdr8))))->len += inc;
430            break;
431        case 2:
432            ((struct sdshdr16 *)((s)-(sizeof(struct sdshdr16))))->len += inc;
433            break;
434        case 3:
435            ((struct sdshdr32 *)((s)-(sizeof(struct sdshdr32))))->len += inc;
436            break;
437        case 4:
438            ((struct sdshdr64 *)((s)-(sizeof(struct sdshdr64))))->len += inc;
439            break;
440    }
441}
442
443
444static inline size_t sdsalloc(const sds s) {
445    unsigned char flags = s[-1];
446    switch(flags&7) {
447        case 0:
448            return ((flags)>>3);
449        case 1:
450            return ((struct sdshdr8 *)((s)-(sizeof(struct sdshdr8))))->alloc;
451        case 2:
452            return ((struct sdshdr16 *)((s)-(sizeof(struct sdshdr16))))->alloc;
453        case 3:
454            return ((struct sdshdr32 *)((s)-(sizeof(struct sdshdr32))))->alloc;
455        case 4:
456            return ((struct sdshdr64 *)((s)-(sizeof(struct sdshdr64))))->alloc;
457    }
458    return 0;
459}
460
461static inline void sdssetalloc(sds s, size_t newlen) {
462    unsigned char flags = s[-1];
463    switch(flags&7) {
464        case 0:
465
466            break;
467        case 1:
468            ((struct sdshdr8 *)((s)-(sizeof(struct sdshdr8))))->alloc = newlen;
469            break;
470        case 2:
471            ((struct sdshdr16 *)((s)-(sizeof(struct sdshdr16))))->alloc = newlen;
472            break;
473        case 3:
474            ((struct sdshdr32 *)((s)-(sizeof(struct sdshdr32))))->alloc = newlen;
475            break;
476        case 4:
477            ((struct sdshdr64 *)((s)-(sizeof(struct sdshdr64))))->alloc = newlen;
478            break;
479    }
480}
481
482sds sdsnewlen(const void *init, size_t initlen);
483sds sdsnew(const char *init);
484sds sdsempty(void);
485sds sdsdup(const sds s);
486void sdsfree(sds s);
487sds sdsgrowzero(sds s, size_t len);
488sds sdscatlen(sds s, const void *t, size_t len);
489sds sdscat(sds s, const char *t);
490sds sdscatsds(sds s, const sds t);
491sds sdscpylen(sds s, const char *t, size_t len);
492sds sdscpy(sds s, const char *t);
493
494sds sdscatvprintf(sds s, const char *fmt, va_list ap);
495
496sds sdscatprintf(sds s, const char *fmt, ...)
497    ;
498
499
500
501
502sds sdscatfmt(sds s, char const *fmt, ...);
503sds sdstrim(sds s, const char *cset);
504void sdsrange(sds s, int start, int end);
505void sdsupdatelen(sds s);
506void sdsclear(sds s);
507int sdscmp(const sds s1, const sds s2);
508sds *sdssplitlen(const char *s, int len, const char *sep, int seplen, int *count);
509void sdsfreesplitres(sds *tokens, int count);
510void sdstolower(sds s);
511void sdstoupper(sds s);
512sds sdsfromlonglong(long long value);
513sds sdscatrepr(sds s, const char *p, size_t len);
514sds *sdssplitargs(const char *line, int *argc);
515sds sdsmapchars(sds s, const char *from, const char *to, size_t setlen);
516sds sdsjoin(char **argv, int argc, char *sep);
517sds sdsjoinsds(sds *argv, int argc, const char *sep, size_t seplen);
518
519
520sds sdsMakeRoomFor(sds s, size_t addlen);
521void sdsIncrLen(sds s, int incr);
522sds sdsRemoveFreeSpace(sds s);
523size_t sdsAllocSize(sds s);
524void *sdsAllocPtr(sds s);
525
526
527
528
529
530void *sds_malloc(size_t size);
531void *sds_realloc(void *ptr, size_t size);
532void sds_free(void *ptr);
533# 41 "deps/hiredis/hiredis.h" 2
534# 112 "deps/hiredis/hiredis.h"
535typedef struct redisReply {
536    int type;
537    long long integer;
538    size_t len;
539    char *str;
540    size_t elements;
541    struct redisReply **element;
542} redisReply;
543
544redisReader *redisReaderCreate(void);
545
546
547void freeReplyObject(void *reply);
548
549
550int redisvFormatCommand(char **target, const char *format, va_list ap);
551int redisFormatCommand(char **target, const char *format, ...);
552int redisFormatCommandArgv(char **target, int argc, const char **argv, const size_t *argvlen);
553int redisFormatSdsCommandArgv(sds *target, int argc, const char ** argv, const size_t *argvlen);
554void redisFreeCommand(char *cmd);
555void redisFreeSdsCommand(sds cmd);
556
557enum redisConnectionType {
558    REDIS_CONN_TCP,
559    REDIS_CONN_UNIX
560};
561
562
563typedef struct redisContext {
564    int err;
565    char errstr[128];
566    int fd;
567    int flags;
568    char *obuf;
569    redisReader *reader;
570
571    enum redisConnectionType connection_type;
572    struct timeval *timeout;
573
574    struct {
575        char *host;
576        char *source_addr;
577        int port;
578    } tcp;
579
580    struct {
581        char *path;
582    } unix_sock;
583
584} redisContext;
585
586redisContext *redisConnect(const char *ip, int port);
587redisContext *redisConnectWithTimeout(const char *ip, int port, const struct timeval tv);
588redisContext *redisConnectNonBlock(const char *ip, int port);
589redisContext *redisConnectBindNonBlock(const char *ip, int port,
590                                       const char *source_addr);
591redisContext *redisConnectBindNonBlockWithReuse(const char *ip, int port,
592                                                const char *source_addr);
593redisContext *redisConnectUnix(const char *path);
594redisContext *redisConnectUnixWithTimeout(const char *path, const struct timeval tv);
595redisContext *redisConnectUnixNonBlock(const char *path);
596redisContext *redisConnectFd(int fd);
597# 184 "deps/hiredis/hiredis.h"
598int redisReconnect(redisContext *c);
599
600int redisSetTimeout(redisContext *c, const struct timeval tv);
601int redisEnableKeepAlive(redisContext *c);
602void redisFree(redisContext *c);
603int redisFreeKeepFd(redisContext *c);
604int redisBufferRead(redisContext *c);
605int redisBufferWrite(redisContext *c, int *done);
606
607
608
609
610
611int redisGetReply(redisContext *c, void **reply);
612int redisGetReplyFromReader(redisContext *c, void **reply);
613
614
615
616int redisAppendFormattedCommand(redisContext *c, const char *cmd, size_t len);
617
618
619
620int redisvAppendCommand(redisContext *c, const char *format, va_list ap);
621int redisAppendCommand(redisContext *c, const char *format, ...);
622int redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen);
623
624
625
626
627
628
629void *redisvCommand(redisContext *c, const char *format, va_list ap);
630void *redisCommand(redisContext *c, const char *format, ...);
631void *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen);
632# 50 "src/redis-cli.c" 2
633# 1 "src/sds.h" 1
634# 51 "src/redis-cli.c" 2
635# 1 "src/zmalloc.h" 1
636# 75 "src/zmalloc.h"
637void *zmalloc(size_t size);
638void *zcalloc(size_t size);
639void *zrealloc(void *ptr, size_t size);
640void zfree(void *ptr);
641char *zstrdup(const char *s);
642size_t zmalloc_used_memory(void);
643void zmalloc_set_oom_handler(void (*oom_handler)(size_t));
644float zmalloc_get_fragmentation_ratio(size_t rss);
645size_t zmalloc_get_rss(void);
646size_t zmalloc_get_private_dirty(long pid);
647size_t zmalloc_get_smap_bytes_by_field(char *field, long pid);
648size_t zmalloc_get_memory_size(void);
649void zlibc_free(void *ptr);
650
651
652
653
654
655
656
657size_t zmalloc_size(void *ptr);
658# 52 "src/redis-cli.c" 2
659# 1 "deps/linenoise/linenoise.h" 1
660# 46 "deps/linenoise/linenoise.h"
661typedef struct linenoiseCompletions {
662  size_t len;
663  char **cvec;
664} linenoiseCompletions;
665
666typedef void(linenoiseCompletionCallback)(const char *, linenoiseCompletions *);
667typedef char*(linenoiseHintsCallback)(const char *, int *color, int *bold);
668typedef void(linenoiseFreeHintsCallback)(void *);
669void linenoiseSetCompletionCallback(linenoiseCompletionCallback *);
670void linenoiseSetHintsCallback(linenoiseHintsCallback *);
671void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *);
672void linenoiseAddCompletion(linenoiseCompletions *, const char *);
673
674char *linenoise(const char *prompt);
675void linenoiseFree(void *ptr);
676int linenoiseHistoryAdd(const char *line);
677int linenoiseHistorySetMaxLen(int len);
678int linenoiseHistorySave(const char *filename);
679int linenoiseHistoryLoad(const char *filename);
680void linenoiseClearScreen(void);
681void linenoiseSetMultiLine(int ml);
682void linenoisePrintKeyCodes(void);
683# 53 "src/redis-cli.c" 2
684# 1 "src/help.h" 1
685
686
687
688
689
690static char *commandGroups[] = {
691    "generic",
692    "string",
693    "list",
694    "set",
695    "sorted_set",
696    "hash",
697    "pubsub",
698    "transactions",
699    "connection",
700    "server",
701    "scripting",
702    "hyperloglog",
703    "cluster",
704    "geo"
705};
706
707struct commandHelp {
708  char *name;
709  char *params;
710  char *summary;
711  int group;
712  char *since;
713} commandHelp[] = {
714    { "APPEND",
715    "key value",
716    "Append a value to a key",
717    1,
718    "2.0.0" },
719    { "AUTH",
720    "password",
721    "Authenticate to the server",
722    8,
723    "1.0.0" },
724    { "BGREWRITEAOF",
725    "-",
726    "Asynchronously rewrite the append-only file",
727    9,
728    "1.0.0" },
729    { "BGSAVE",
730    "-",
731    "Asynchronously save the dataset to disk",
732    9,
733    "1.0.0" },
734    { "BITCOUNT",
735    "key [start end]",
736    "Count set bits in a string",
737    1,
738    "2.6.0" },
739    { "BITFIELD",
740    "key [GET type offset] [SET type offset value] [INCRBY type offset increment] [OVERFLOW WRAP|SAT|FAIL]",
741    "Perform arbitrary bitfield integer operations on strings",
742    1,
743    "3.2.0" },
744    { "BITOP",
745    "operation destkey key [key ...]",
746    "Perform bitwise operations between strings",
747    1,
748    "2.6.0" },
749    { "BITPOS",
750    "key bit [start] [end]",
751    "Find first bit set or clear in a string",
752    1,
753    "2.8.7" },
754    { "BLPOP",
755    "key [key ...] timeout",
756    "Remove and get the first element in a list, or block until one is available",
757    2,
758    "2.0.0" },
759    { "BRPOP",
760    "key [key ...] timeout",
761    "Remove and get the last element in a list, or block until one is available",
762    2,
763    "2.0.0" },
764    { "BRPOPLPUSH",
765    "source destination timeout",
766    "Pop a value from a list, push it to another list and return it; or block until one is available",
767    2,
768    "2.2.0" },
769    { "CLIENT GETNAME",
770    "-",
771    "Get the current connection name",
772    9,
773    "2.6.9" },
774    { "CLIENT KILL",
775    "[ip:port] [ID client-id] [TYPE normal|master|slave|pubsub] [ADDR ip:port] [SKIPME yes/no]",
776    "Kill the connection of a client",
777    9,
778    "2.4.0" },
779    { "CLIENT LIST",
780    "-",
781    "Get the list of client connections",
782    9,
783    "2.4.0" },
784    { "CLIENT PAUSE",
785    "timeout",
786    "Stop processing commands from clients for some time",
787    9,
788    "2.9.50" },
789    { "CLIENT REPLY",
790    "ON|OFF|SKIP",
791    "Instruct the server whether to reply to commands",
792    9,
793    "3.2" },
794    { "CLIENT SETNAME",
795    "connection-name",
796    "Set the current connection name",
797    9,
798    "2.6.9" },
799    { "CLUSTER ADDSLOTS",
800    "slot [slot ...]",
801    "Assign new hash slots to receiving node",
802    12,
803    "3.0.0" },
804    { "CLUSTER COUNT-FAILURE-REPORTS",
805    "node-id",
806    "Return the number of failure reports active for a given node",
807    12,
808    "3.0.0" },
809    { "CLUSTER COUNTKEYSINSLOT",
810    "slot",
811    "Return the number of local keys in the specified hash slot",
812    12,
813    "3.0.0" },
814    { "CLUSTER DELSLOTS",
815    "slot [slot ...]",
816    "Set hash slots as unbound in receiving node",
817    12,
818    "3.0.0" },
819    { "CLUSTER FAILOVER",
820    "[FORCE|TAKEOVER]",
821    "Forces a slave to perform a manual failover of its master.",
822    12,
823    "3.0.0" },
824    { "CLUSTER FORGET",
825    "node-id",
826    "Remove a node from the nodes table",
827    12,
828    "3.0.0" },
829    { "CLUSTER GETKEYSINSLOT",
830    "slot count",
831    "Return local key names in the specified hash slot",
832    12,
833    "3.0.0" },
834    { "CLUSTER INFO",
835    "-",
836    "Provides info about Redis Cluster node state",
837    12,
838    "3.0.0" },
839    { "CLUSTER KEYSLOT",
840    "key",
841    "Returns the hash slot of the specified key",
842    12,
843    "3.0.0" },
844    { "CLUSTER MEET",
845    "ip port",
846    "Force a node cluster to handshake with another node",
847    12,
848    "3.0.0" },
849    { "CLUSTER NODES",
850    "-",
851    "Get Cluster config for the node",
852    12,
853    "3.0.0" },
854    { "CLUSTER REPLICATE",
855    "node-id",
856    "Reconfigure a node as a slave of the specified master node",
857    12,
858    "3.0.0" },
859    { "CLUSTER RESET",
860    "[HARD|SOFT]",
861    "Reset a Redis Cluster node",
862    12,
863    "3.0.0" },
864    { "CLUSTER SAVECONFIG",
865    "-",
866    "Forces the node to save cluster state on disk",
867    12,
868    "3.0.0" },
869    { "CLUSTER SET-CONFIG-EPOCH",
870    "config-epoch",
871    "Set the configuration epoch in a new node",
872    12,
873    "3.0.0" },
874    { "CLUSTER SETSLOT",
875    "slot IMPORTING|MIGRATING|STABLE|NODE [node-id]",
876    "Bind a hash slot to a specific node",
877    12,
878    "3.0.0" },
879    { "CLUSTER SLAVES",
880    "node-id",
881    "List slave nodes of the specified master node",
882    12,
883    "3.0.0" },
884    { "CLUSTER SLOTS",
885    "-",
886    "Get array of Cluster slot to node mappings",
887    12,
888    "3.0.0" },
889    { "COMMAND",
890    "-",
891    "Get array of Redis command details",
892    9,
893    "2.8.13" },
894    { "COMMAND COUNT",
895    "-",
896    "Get total number of Redis commands",
897    9,
898    "2.8.13" },
899    { "COMMAND GETKEYS",
900    "-",
901    "Extract keys given a full Redis command",
902    9,
903    "2.8.13" },
904    { "COMMAND INFO",
905    "command-name [command-name ...]",
906    "Get array of specific Redis command details",
907    9,
908    "2.8.13" },
909    { "CONFIG GET",
910    "parameter",
911    "Get the value of a configuration parameter",
912    9,
913    "2.0.0" },
914    { "CONFIG RESETSTAT",
915    "-",
916    "Reset the stats returned by INFO",
917    9,
918    "2.0.0" },
919    { "CONFIG REWRITE",
920    "-",
921    "Rewrite the configuration file with the in memory configuration",
922    9,
923    "2.8.0" },
924    { "CONFIG SET",
925    "parameter value",
926    "Set a configuration parameter to the given value",
927    9,
928    "2.0.0" },
929    { "DBSIZE",
930    "-",
931    "Return the number of keys in the selected database",
932    9,
933    "1.0.0" },
934    { "DEBUG OBJECT",
935    "key",
936    "Get debugging information about a key",
937    9,
938    "1.0.0" },
939    { "DEBUG SEGFAULT",
940    "-",
941    "Make the server crash",
942    9,
943    "1.0.0" },
944    { "DECR",
945    "key",
946    "Decrement the integer value of a key by one",
947    1,
948    "1.0.0" },
949    { "DECRBY",
950    "key decrement",
951    "Decrement the integer value of a key by the given number",
952    1,
953    "1.0.0" },
954    { "DEL",
955    "key [key ...]",
956    "Delete a key",
957    0,
958    "1.0.0" },
959    { "DISCARD",
960    "-",
961    "Discard all commands issued after MULTI",
962    7,
963    "2.0.0" },
964    { "DUMP",
965    "key",
966    "Return a serialized version of the value stored at the specified key.",
967    0,
968    "2.6.0" },
969    { "ECHO",
970    "message",
971    "Echo the given string",
972    8,
973    "1.0.0" },
974    { "EVAL",
975    "script numkeys key [key ...] arg [arg ...]",
976    "Execute a Lua script server side",
977    10,
978    "2.6.0" },
979    { "EVALSHA",
980    "sha1 numkeys key [key ...] arg [arg ...]",
981    "Execute a Lua script server side",
982    10,
983    "2.6.0" },
984    { "EXEC",
985    "-",
986    "Execute all commands issued after MULTI",
987    7,
988    "1.2.0" },
989    { "EXISTS",
990    "key [key ...]",
991    "Determine if a key exists",
992    0,
993    "1.0.0" },
994    { "EXPIRE",
995    "key seconds",
996    "Set a key's time to live in seconds",
997    0,
998    "1.0.0" },
999    { "EXPIREAT",
1000    "key timestamp",
1001    "Set the expiration for a key as a UNIX timestamp",
1002    0,
1003    "1.2.0" },
1004    { "FLUSHALL",
1005    "-",
1006    "Remove all keys from all databases",
1007    9,
1008    "1.0.0" },
1009    { "FLUSHDB",
1010    "-",
1011    "Remove all keys from the current database",
1012    9,
1013    "1.0.0" },
1014    { "GEOADD",
1015    "key longitude latitude member [longitude latitude member ...]",
1016    "Add one or more geospatial items in the geospatial index represented using a sorted set",
1017    13,
1018    "3.2.0" },
1019    { "GEODIST",
1020    "key member1 member2 [unit]",
1021    "Returns the distance between two members of a geospatial index",
1022    13,
1023    "3.2.0" },
1024    { "GEOHASH",
1025    "key member [member ...]",
1026    "Returns members of a geospatial index as standard geohash strings",
1027    13,
1028    "3.2.0" },
1029    { "GEOPOS",
1030    "key member [member ...]",
1031    "Returns longitude and latitude of members of a geospatial index",
1032    13,
1033    "3.2.0" },
1034    { "GEORADIUS",
1035    "key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key]",
1036    "Query a sorted set representing a geospatial index to fetch members matching a given maximum distance from a point",
1037    13,
1038    "3.2.0" },
1039    { "GEORADIUSBYMEMBER",
1040    "key member radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key]",
1041    "Query a sorted set representing a geospatial index to fetch members matching a given maximum distance from a member",
1042    13,
1043    "3.2.0" },
1044    { "GET",
1045    "key",
1046    "Get the value of a key",
1047    1,
1048    "1.0.0" },
1049    { "GETBIT",
1050    "key offset",
1051    "Returns the bit value at offset in the string value stored at key",
1052    1,
1053    "2.2.0" },
1054    { "GETRANGE",
1055    "key start end",
1056    "Get a substring of the string stored at a key",
1057    1,
1058    "2.4.0" },
1059    { "GETSET",
1060    "key value",
1061    "Set the string value of a key and return its old value",
1062    1,
1063    "1.0.0" },
1064    { "HDEL",
1065    "key field [field ...]",
1066    "Delete one or more hash fields",
1067    5,
1068    "2.0.0" },
1069    { "HEXISTS",
1070    "key field",
1071    "Determine if a hash field exists",
1072    5,
1073    "2.0.0" },
1074    { "HGET",
1075    "key field",
1076    "Get the value of a hash field",
1077    5,
1078    "2.0.0" },
1079    { "HGETALL",
1080    "key",
1081    "Get all the fields and values in a hash",
1082    5,
1083    "2.0.0" },
1084    { "HINCRBY",
1085    "key field increment",
1086    "Increment the integer value of a hash field by the given number",
1087    5,
1088    "2.0.0" },
1089    { "HINCRBYFLOAT",
1090    "key field increment",
1091    "Increment the float value of a hash field by the given amount",
1092    5,
1093    "2.6.0" },
1094    { "HKEYS",
1095    "key",
1096    "Get all the fields in a hash",
1097    5,
1098    "2.0.0" },
1099    { "HLEN",
1100    "key",
1101    "Get the number of fields in a hash",
1102    5,
1103    "2.0.0" },
1104    { "HMGET",
1105    "key field [field ...]",
1106    "Get the values of all the given hash fields",
1107    5,
1108    "2.0.0" },
1109    { "HMSET",
1110    "key field value [field value ...]",
1111    "Set multiple hash fields to multiple values",
1112    5,
1113    "2.0.0" },
1114    { "HSCAN",
1115    "key cursor [MATCH pattern] [COUNT count]",
1116    "Incrementally iterate hash fields and associated values",
1117    5,
1118    "2.8.0" },
1119    { "HSET",
1120    "key field value",
1121    "Set the string value of a hash field",
1122    5,
1123    "2.0.0" },
1124    { "HSETNX",
1125    "key field value",
1126    "Set the value of a hash field, only if the field does not exist",
1127    5,
1128    "2.0.0" },
1129    { "HSTRLEN",
1130    "key field",
1131    "Get the length of the value of a hash field",
1132    5,
1133    "3.2.0" },
1134    { "HVALS",
1135    "key",
1136    "Get all the values in a hash",
1137    5,
1138    "2.0.0" },
1139    { "INCR",
1140    "key",
1141    "Increment the integer value of a key by one",
1142    1,
1143    "1.0.0" },
1144    { "INCRBY",
1145    "key increment",
1146    "Increment the integer value of a key by the given amount",
1147    1,
1148    "1.0.0" },
1149    { "INCRBYFLOAT",
1150    "key increment",
1151    "Increment the float value of a key by the given amount",
1152    1,
1153    "2.6.0" },
1154    { "INFO",
1155    "[section]",
1156    "Get information and statistics about the server",
1157    9,
1158    "1.0.0" },
1159    { "KEYS",
1160    "pattern",
1161    "Find all keys matching the given pattern",
1162    0,
1163    "1.0.0" },
1164    { "LASTSAVE",
1165    "-",
1166    "Get the UNIX time stamp of the last successful save to disk",
1167    9,
1168    "1.0.0" },
1169    { "LINDEX",
1170    "key index",
1171    "Get an element from a list by its index",
1172    2,
1173    "1.0.0" },
1174    { "LINSERT",
1175    "key BEFORE|AFTER pivot value",
1176    "Insert an element before or after another element in a list",
1177    2,
1178    "2.2.0" },
1179    { "LLEN",
1180    "key",
1181    "Get the length of a list",
1182    2,
1183    "1.0.0" },
1184    { "LPOP",
1185    "key",
1186    "Remove and get the first element in a list",
1187    2,
1188    "1.0.0" },
1189    { "LPUSH",
1190    "key value [value ...]",
1191    "Prepend one or multiple values to a list",
1192    2,
1193    "1.0.0" },
1194    { "LPUSHX",
1195    "key value",
1196    "Prepend a value to a list, only if the list exists",
1197    2,
1198    "2.2.0" },
1199    { "LRANGE",
1200    "key start stop",
1201    "Get a range of elements from a list",
1202    2,
1203    "1.0.0" },
1204    { "LREM",
1205    "key count value",
1206    "Remove elements from a list",
1207    2,
1208    "1.0.0" },
1209    { "LSET",
1210    "key index value",
1211    "Set the value of an element in a list by its index",
1212    2,
1213    "1.0.0" },
1214    { "LTRIM",
1215    "key start stop",
1216    "Trim a list to the specified range",
1217    2,
1218    "1.0.0" },
1219    { "MGET",
1220    "key [key ...]",
1221    "Get the values of all the given keys",
1222    1,
1223    "1.0.0" },
1224    { "MIGRATE",
1225    "host port key|"" destination-db timeout [COPY] [REPLACE] [KEYS key]",
1226    "Atomically transfer a key from a Redis instance to another one.",
1227    0,
1228    "2.6.0" },
1229    { "MONITOR",
1230    "-",
1231    "Listen for all requests received by the server in real time",
1232    9,
1233    "1.0.0" },
1234    { "MOVE",
1235    "key db",
1236    "Move a key to another database",
1237    0,
1238    "1.0.0" },
1239    { "MSET",
1240    "key value [key value ...]",
1241    "Set multiple keys to multiple values",
1242    1,
1243    "1.0.1" },
1244    { "MSETNX",
1245    "key value [key value ...]",
1246    "Set multiple keys to multiple values, only if none of the keys exist",
1247    1,
1248    "1.0.1" },
1249    { "MULTI",
1250    "-",
1251    "Mark the start of a transaction block",
1252    7,
1253    "1.2.0" },
1254    { "OBJECT",
1255    "subcommand [arguments [arguments ...]]",
1256    "Inspect the internals of Redis objects",
1257    0,
1258    "2.2.3" },
1259    { "PERSIST",
1260    "key",
1261    "Remove the expiration from a key",
1262    0,
1263    "2.2.0" },
1264    { "PEXPIRE",
1265    "key milliseconds",
1266    "Set a key's time to live in milliseconds",
1267    0,
1268    "2.6.0" },
1269    { "PEXPIREAT",
1270    "key milliseconds-timestamp",
1271    "Set the expiration for a key as a UNIX timestamp specified in milliseconds",
1272    0,
1273    "2.6.0" },
1274    { "PFADD",
1275    "key element [element ...]",
1276    "Adds the specified elements to the specified HyperLogLog.",
1277    11,
1278    "2.8.9" },
1279    { "PFCOUNT",
1280    "key [key ...]",
1281    "Return the approximated cardinality of the set(s) observed by the HyperLogLog at key(s).",
1282    11,
1283    "2.8.9" },
1284    { "PFMERGE",
1285    "destkey sourcekey [sourcekey ...]",
1286    "Merge N different HyperLogLogs into a single one.",
1287    11,
1288    "2.8.9" },
1289    { "PING",
1290    "[message]",
1291    "Ping the server",
1292    8,
1293    "1.0.0" },
1294    { "PSETEX",
1295    "key milliseconds value",
1296    "Set the value and expiration in milliseconds of a key",
1297    1,
1298    "2.6.0" },
1299    { "PSUBSCRIBE",
1300    "pattern [pattern ...]",
1301    "Listen for messages published to channels matching the given patterns",
1302    6,
1303    "2.0.0" },
1304    { "PTTL",
1305    "key",
1306    "Get the time to live for a key in milliseconds",
1307    0,
1308    "2.6.0" },
1309    { "PUBLISH",
1310    "channel message",
1311    "Post a message to a channel",
1312    6,
1313    "2.0.0" },
1314    { "PUBSUB",
1315    "subcommand [argument [argument ...]]",
1316    "Inspect the state of the Pub/Sub subsystem",
1317    6,
1318    "2.8.0" },
1319    { "PUNSUBSCRIBE",
1320    "[pattern [pattern ...]]",
1321    "Stop listening for messages posted to channels matching the given patterns",
1322    6,
1323    "2.0.0" },
1324    { "QUIT",
1325    "-",
1326    "Close the connection",
1327    8,
1328    "1.0.0" },
1329    { "RANDOMKEY",
1330    "-",
1331    "Return a random key from the keyspace",
1332    0,
1333    "1.0.0" },
1334    { "READONLY",
1335    "-",
1336    "Enables read queries for a connection to a cluster slave node",
1337    12,
1338    "3.0.0" },
1339    { "READWRITE",
1340    "-",
1341    "Disables read queries for a connection to a cluster slave node",
1342    12,
1343    "3.0.0" },
1344    { "RENAME",
1345    "key newkey",
1346    "Rename a key",
1347    0,
1348    "1.0.0" },
1349    { "RENAMENX",
1350    "key newkey",
1351    "Rename a key, only if the new key does not exist",
1352    0,
1353    "1.0.0" },
1354    { "RESTORE",
1355    "key ttl serialized-value [REPLACE]",
1356    "Create a key using the provided serialized value, previously obtained using DUMP.",
1357    0,
1358    "2.6.0" },
1359    { "ROLE",
1360    "-",
1361    "Return the role of the instance in the context of replication",
1362    9,
1363    "2.8.12" },
1364    { "RPOP",
1365    "key",
1366    "Remove and get the last element in a list",
1367    2,
1368    "1.0.0" },
1369    { "RPOPLPUSH",
1370    "source destination",
1371    "Remove the last element in a list, prepend it to another list and return it",
1372    2,
1373    "1.2.0" },
1374    { "RPUSH",
1375    "key value [value ...]",
1376    "Append one or multiple values to a list",
1377    2,
1378    "1.0.0" },
1379    { "RPUSHX",
1380    "key value",
1381    "Append a value to a list, only if the list exists",
1382    2,
1383    "2.2.0" },
1384    { "SADD",
1385    "key member [member ...]",
1386    "Add one or more members to a set",
1387    3,
1388    "1.0.0" },
1389    { "SAVE",
1390    "-",
1391    "Synchronously save the dataset to disk",
1392    9,
1393    "1.0.0" },
1394    { "SCAN",
1395    "cursor [MATCH pattern] [COUNT count]",
1396    "Incrementally iterate the keys space",
1397    0,
1398    "2.8.0" },
1399    { "SCARD",
1400    "key",
1401    "Get the number of members in a set",
1402    3,
1403    "1.0.0" },
1404    { "SCRIPT DEBUG",
1405    "YES|SYNC|NO",
1406    "Set the debug mode for executed scripts.",
1407    10,
1408    "3.2.0" },
1409    { "SCRIPT EXISTS",
1410    "script [script ...]",
1411    "Check existence of scripts in the script cache.",
1412    10,
1413    "2.6.0" },
1414    { "SCRIPT FLUSH",
1415    "-",
1416    "Remove all the scripts from the script cache.",
1417    10,
1418    "2.6.0" },
1419    { "SCRIPT KILL",
1420    "-",
1421    "Kill the script currently in execution.",
1422    10,
1423    "2.6.0" },
1424    { "SCRIPT LOAD",
1425    "script",
1426    "Load the specified Lua script into the script cache.",
1427    10,
1428    "2.6.0" },
1429    { "SDIFF",
1430    "key [key ...]",
1431    "Subtract multiple sets",
1432    3,
1433    "1.0.0" },
1434    { "SDIFFSTORE",
1435    "destination key [key ...]",
1436    "Subtract multiple sets and store the resulting set in a key",
1437    3,
1438    "1.0.0" },
1439    { "SELECT",
1440    "index",
1441    "Change the selected database for the current connection",
1442    8,
1443    "1.0.0" },
1444    { "SET",
1445    "key value [EX seconds] [PX milliseconds] [NX|XX]",
1446    "Set the string value of a key",
1447    1,
1448    "1.0.0" },
1449    { "SETBIT",
1450    "key offset value",
1451    "Sets or clears the bit at offset in the string value stored at key",
1452    1,
1453    "2.2.0" },
1454    { "SETEX",
1455    "key seconds value",
1456    "Set the value and expiration of a key",
1457    1,
1458    "2.0.0" },
1459    { "SETNX",
1460    "key value",
1461    "Set the value of a key, only if the key does not exist",
1462    1,
1463    "1.0.0" },
1464    { "SETRANGE",
1465    "key offset value",
1466    "Overwrite part of a string at key starting at the specified offset",
1467    1,
1468    "2.2.0" },
1469    { "SHUTDOWN",
1470    "[NOSAVE|SAVE]",
1471    "Synchronously save the dataset to disk and then shut down the server",
1472    9,
1473    "1.0.0" },
1474    { "SINTER",
1475    "key [key ...]",
1476    "Intersect multiple sets",
1477    3,
1478    "1.0.0" },
1479    { "SINTERSTORE",
1480    "destination key [key ...]",
1481    "Intersect multiple sets and store the resulting set in a key",
1482    3,
1483    "1.0.0" },
1484    { "SISMEMBER",
1485    "key member",
1486    "Determine if a given value is a member of a set",
1487    3,
1488    "1.0.0" },
1489    { "SLAVEOF",
1490    "host port",
1491    "Make the server a slave of another instance, or promote it as master",
1492    9,
1493    "1.0.0" },
1494    { "SLOWLOG",
1495    "subcommand [argument]",
1496    "Manages the Redis slow queries log",
1497    9,
1498    "2.2.12" },
1499    { "SMEMBERS",
1500    "key",
1501    "Get all the members in a set",
1502    3,
1503    "1.0.0" },
1504    { "SMOVE",
1505    "source destination member",
1506    "Move a member from one set to another",
1507    3,
1508    "1.0.0" },
1509    { "SORT",
1510    "key [BY pattern] [LIMIT offset count] [GET pattern [GET pattern ...]] [ASC|DESC] [ALPHA] [STORE destination]",
1511    "Sort the elements in a list, set or sorted set",
1512    0,
1513    "1.0.0" },
1514    { "SPOP",
1515    "key [count]",
1516    "Remove and return one or multiple random members from a set",
1517    3,
1518    "1.0.0" },
1519    { "SRANDMEMBER",
1520    "key [count]",
1521    "Get one or multiple random members from a set",
1522    3,
1523    "1.0.0" },
1524    { "SREM",
1525    "key member [member ...]",
1526    "Remove one or more members from a set",
1527    3,
1528    "1.0.0" },
1529    { "SSCAN",
1530    "key cursor [MATCH pattern] [COUNT count]",
1531    "Incrementally iterate Set elements",
1532    3,
1533    "2.8.0" },
1534    { "STRLEN",
1535    "key",
1536    "Get the length of the value stored in a key",
1537    1,
1538    "2.2.0" },
1539    { "SUBSCRIBE",
1540    "channel [channel ...]",
1541    "Listen for messages published to the given channels",
1542    6,
1543    "2.0.0" },
1544    { "SUNION",
1545    "key [key ...]",
1546    "Add multiple sets",
1547    3,
1548    "1.0.0" },
1549    { "SUNIONSTORE",
1550    "destination key [key ...]",
1551    "Add multiple sets and store the resulting set in a key",
1552    3,
1553    "1.0.0" },
1554    { "SYNC",
1555    "-",
1556    "Internal command used for replication",
1557    9,
1558    "1.0.0" },
1559    { "TIME",
1560    "-",
1561    "Return the current server time",
1562    9,
1563    "2.6.0" },
1564    { "TTL",
1565    "key",
1566    "Get the time to live for a key",
1567    0,
1568    "1.0.0" },
1569    { "TYPE",
1570    "key",
1571    "Determine the type stored at key",
1572    0,
1573    "1.0.0" },
1574    { "UNSUBSCRIBE",
1575    "[channel [channel ...]]",
1576    "Stop listening for messages posted to the given channels",
1577    6,
1578    "2.0.0" },
1579    { "UNWATCH",
1580    "-",
1581    "Forget about all watched keys",
1582    7,
1583    "2.2.0" },
1584    { "WAIT",
1585    "numslaves timeout",
1586    "Wait for the synchronous replication of all the write commands sent in the context of the current connection",
1587    0,
1588    "3.0.0" },
1589    { "WATCH",
1590    "key [key ...]",
1591    "Watch the given keys to determine execution of the MULTI/EXEC block",
1592    7,
1593    "2.2.0" },
1594    { "ZADD",
1595    "key [NX|XX] [CH] [INCR] score member [score member ...]",
1596    "Add one or more members to a sorted set, or update its score if it already exists",
1597    4,
1598    "1.2.0" },
1599    { "ZCARD",
1600    "key",
1601    "Get the number of members in a sorted set",
1602    4,
1603    "1.2.0" },
1604    { "ZCOUNT",
1605    "key min max",
1606    "Count the members in a sorted set with scores within the given values",
1607    4,
1608    "2.0.0" },
1609    { "ZINCRBY",
1610    "key increment member",
1611    "Increment the score of a member in a sorted set",
1612    4,
1613    "1.2.0" },
1614    { "ZINTERSTORE",
1615    "destination numkeys key [key ...] [WEIGHTS weight] [AGGREGATE SUM|MIN|MAX]",
1616    "Intersect multiple sorted sets and store the resulting sorted set in a new key",
1617    4,
1618    "2.0.0" },
1619    { "ZLEXCOUNT",
1620    "key min max",
1621    "Count the number of members in a sorted set between a given lexicographical range",
1622    4,
1623    "2.8.9" },
1624    { "ZRANGE",
1625    "key start stop [WITHSCORES]",
1626    "Return a range of members in a sorted set, by index",
1627    4,
1628    "1.2.0" },
1629    { "ZRANGEBYLEX",
1630    "key min max [LIMIT offset count]",
1631    "Return a range of members in a sorted set, by lexicographical range",
1632    4,
1633    "2.8.9" },
1634    { "ZRANGEBYSCORE",
1635    "key min max [WITHSCORES] [LIMIT offset count]",
1636    "Return a range of members in a sorted set, by score",
1637    4,
1638    "1.0.5" },
1639    { "ZRANK",
1640    "key member",
1641    "Determine the index of a member in a sorted set",
1642    4,
1643    "2.0.0" },
1644    { "ZREM",
1645    "key member [member ...]",
1646    "Remove one or more members from a sorted set",
1647    4,
1648    "1.2.0" },
1649    { "ZREMRANGEBYLEX",
1650    "key min max",
1651    "Remove all members in a sorted set between the given lexicographical range",
1652    4,
1653    "2.8.9" },
1654    { "ZREMRANGEBYRANK",
1655    "key start stop",
1656    "Remove all members in a sorted set within the given indexes",
1657    4,
1658    "2.0.0" },
1659    { "ZREMRANGEBYSCORE",
1660    "key min max",
1661    "Remove all members in a sorted set within the given scores",
1662    4,
1663    "1.2.0" },
1664    { "ZREVRANGE",
1665    "key start stop [WITHSCORES]",
1666    "Return a range of members in a sorted set, by index, with scores ordered from high to low",
1667    4,
1668    "1.2.0" },
1669    { "ZREVRANGEBYLEX",
1670    "key max min [LIMIT offset count]",
1671    "Return a range of members in a sorted set, by lexicographical range, ordered from higher to lower strings.",
1672    4,
1673    "2.8.9" },
1674    { "ZREVRANGEBYSCORE",
1675    "key max min [WITHSCORES] [LIMIT offset count]",
1676    "Return a range of members in a sorted set, by score, with scores ordered from high to low",
1677    4,
1678    "2.2.0" },
1679    { "ZREVRANK",
1680    "key member",
1681    "Determine the index of a member in a sorted set, with scores ordered from high to low",
1682    4,
1683    "2.0.0" },
1684    { "ZSCAN",
1685    "key cursor [MATCH pattern] [COUNT count]",
1686    "Incrementally iterate sorted sets elements and associated scores",
1687    4,
1688    "2.8.0" },
1689    { "ZSCORE",
1690    "key member",
1691    "Get the score associated with the given member in a sorted set",
1692    4,
1693    "1.2.0" },
1694    { "ZUNIONSTORE",
1695    "destination numkeys key [key ...] [WEIGHTS weight] [AGGREGATE SUM|MIN|MAX]",
1696    "Add multiple sorted sets and store the resulting sorted set in a new key",
1697    4,
1698    "2.0.0" }
1699};
1700# 54 "src/redis-cli.c" 2
1701# 1 "src/anet.h" 1
1702# 34 "src/anet.h"
1703# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/sys/types.h" 1
1704# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1
1705# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/sys/types.h" 2
1706# 35 "src/anet.h" 2
1707# 52 "src/anet.h"
1708int anetTcpConnect(char *err, char *addr, int port);
1709int anetTcpNonBlockConnect(char *err, char *addr, int port);
1710int anetTcpNonBlockBindConnect(char *err, char *addr, int port, char *source_addr);
1711int anetTcpNonBlockBestEffortBindConnect(char *err, char *addr, int port, char *source_addr);
1712int anetUnixConnect(char *err, char *path);
1713int anetUnixNonBlockConnect(char *err, char *path);
1714int anetRead(int fd, char *buf, int count);
1715int anetResolve(char *err, char *host, char *ipbuf, size_t ipbuf_len);
1716int anetResolveIP(char *err, char *host, char *ipbuf, size_t ipbuf_len);
1717int anetTcpServer(char *err, int port, char *bindaddr, int backlog);
1718int anetTcp6Server(char *err, int port, char *bindaddr, int backlog);
1719int anetUnixServer(char *err, char *path, mode_t perm, int backlog);
1720int anetTcpAccept(char *err, int serversock, char *ip, size_t ip_len, int *port);
1721int anetUnixAccept(char *err, int serversock);
1722int anetWrite(int fd, char *buf, int count);
1723int anetNonBlock(char *err, int fd);
1724int anetBlock(char *err, int fd);
1725int anetEnableTcpNoDelay(char *err, int fd);
1726int anetDisableTcpNoDelay(char *err, int fd);
1727int anetTcpKeepAlive(char *err, int fd);
1728int anetSendTimeout(char *err, int fd, long long ms);
1729int anetPeerToString(int fd, char *ip, size_t ip_len, int *port);
1730int anetKeepAlive(char *err, int fd, int interval);
1731int anetSockName(int fd, char *ip, size_t ip_len, int *port);
1732int anetFormatAddr(char *fmt, size_t fmt_len, char *ip, int port);
1733int anetFormatPeer(int fd, char *fmt, size_t fmt_len);
1734int anetFormatSock(int fd, char *fmt, size_t fmt_len);
1735# 55 "src/redis-cli.c" 2
1736# 1 "src/ae.h" 1
1737# 36 "src/ae.h"
1738# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/time.h" 1
1739# 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1
1740# 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/time.h" 2
1741# 37 "src/ae.h" 2
1742# 57 "src/ae.h"
1743struct aeEventLoop;
1744
1745
1746typedef void aeFileProc(struct aeEventLoop *eventLoop, int fd, void *clientData, int mask);
1747typedef int aeTimeProc(struct aeEventLoop *eventLoop, long long id, void *clientData);
1748typedef void aeEventFinalizerProc(struct aeEventLoop *eventLoop, void *clientData);
1749typedef void aeBeforeSleepProc(struct aeEventLoop *eventLoop);
1750
1751
1752typedef struct aeFileEvent {
1753    int mask;
1754    aeFileProc *rfileProc;
1755    aeFileProc *wfileProc;
1756    void *clientData;
1757} aeFileEvent;
1758
1759
1760typedef struct aeTimeEvent {
1761    long long id;
1762    long when_sec;
1763    long when_ms;
1764    aeTimeProc *timeProc;
1765    aeEventFinalizerProc *finalizerProc;
1766    void *clientData;
1767    struct aeTimeEvent *next;
1768} aeTimeEvent;
1769
1770
1771typedef struct aeFiredEvent {
1772    int fd;
1773    int mask;
1774} aeFiredEvent;
1775
1776
1777typedef struct aeEventLoop {
1778    int maxfd;
1779    int setsize;
1780    long long timeEventNextId;
1781    time_t lastTime;
1782    aeFileEvent *events;
1783    aeFiredEvent *fired;
1784    aeTimeEvent *timeEventHead;
1785    int stop;
1786    void *apidata;
1787    aeBeforeSleepProc *beforesleep;
1788    aeBeforeSleepProc *aftersleep;
1789} aeEventLoop;
1790
1791
1792aeEventLoop *aeCreateEventLoop(int setsize);
1793void aeDeleteEventLoop(aeEventLoop *eventLoop);
1794void aeStop(aeEventLoop *eventLoop);
1795int aeCreateFileEvent(aeEventLoop *eventLoop, int fd, int mask,
1796        aeFileProc *proc, void *clientData);
1797void aeDeleteFileEvent(aeEventLoop *eventLoop, int fd, int mask);
1798int aeGetFileEvents(aeEventLoop *eventLoop, int fd);
1799long long aeCreateTimeEvent(aeEventLoop *eventLoop, long long milliseconds,
1800        aeTimeProc *proc, void *clientData,
1801        aeEventFinalizerProc *finalizerProc);
1802int aeDeleteTimeEvent(aeEventLoop *eventLoop, long long id);
1803int aeProcessEvents(aeEventLoop *eventLoop, int flags);
1804int aeWait(int fd, int mask, long long milliseconds);
1805void aeMain(aeEventLoop *eventLoop);
1806char *aeGetApiName(void);
1807void aeSetBeforeSleepProc(aeEventLoop *eventLoop, aeBeforeSleepProc *beforesleep);
1808void aeSetAfterSleepProc(aeEventLoop *eventLoop, aeBeforeSleepProc *aftersleep);
1809int aeGetSetSize(aeEventLoop *eventLoop);
1810int aeResizeSetSize(aeEventLoop *eventLoop, int setsize);
1811# 56 "src/redis-cli.c" 2
1812# 70 "src/redis-cli.c"
1813int spectrum_palette_color_size = 19;
1814int spectrum_palette_color[] = {0,233,234,235,237,239,241,243,245,247,144,143,142,184,226,214,208,202,196};
1815
1816int spectrum_palette_mono_size = 13;
1817int spectrum_palette_mono[] = {0,233,234,235,237,239,241,243,245,247,249,251,253};
1818
1819
1820int *spectrum_palette;
1821int spectrum_palette_size;
1822
1823static redisContext *context;
1824static struct config {
1825    char *hostip;
1826    int hostport;
1827    char *hostsocket;
1828    long repeat;
1829    long interval;
1830    int dbnum;
1831    int interactive;
1832    int shutdown;
1833    int monitor_mode;
1834    int pubsub_mode;
1835    int latency_mode;
1836    int latency_dist_mode;
1837    int latency_history;
1838    int lru_test_mode;
1839    long long lru_test_sample_size;
1840    int cluster_mode;
1841    int cluster_reissue_command;
1842    int slave_mode;
1843    int pipe_mode;
1844    int pipe_timeout;
1845    int getrdb_mode;
1846    int stat_mode;
1847    int scan_mode;
1848    int intrinsic_latency_mode;
1849    int intrinsic_latency_duration;
1850    char *pattern;
1851    char *rdb_filename;
1852    int bigkeys;
1853    int hotkeys;
1854    int stdinarg;
1855    char *auth;
1856    int output;
1857    sds mb_delim;
1858    char prompt[128];
1859    char *eval;
1860    int eval_ldb;
1861    int eval_ldb_sync;
1862    int eval_ldb_end;
1863    int enable_ldb_on_eval;
1864    int last_cmd_type;
1865} config;
1866
1867
1868static struct pref {
1869    int hints;
1870} pref;
1871
1872static volatile sig_atomic_t force_cancel_loop = 0;
1873static void usage(void);
1874static void slaveMode(void);
1875char *redisGitSHA1(void);
1876char *redisGitDirty(void);
1877static int cliConnect(int force);
1878
1879
1880
1881
1882
1883static long long ustime(void) {
1884    struct timeval tv;
1885    long long ust;
1886
1887    gettimeofday(&tv, 0);
1888    ust = ((long long)tv.tv_sec)*1000000;
1889    ust += tv.tv_usec;
1890    return ust;
1891}
1892
1893static long long mstime(void) {
1894    return ustime()/1000;
1895}
1896
1897static void cliRefreshPrompt(void) {
1898    int len;
1899
1900    if (config.eval_ldb) return;
1901    if (config.hostsocket != 0)
1902        len = snprintf(config.prompt,sizeof(config.prompt),"redis %s",
1903                       config.hostsocket);
1904    else
1905        len = anetFormatAddr(config.prompt, sizeof(config.prompt),
1906                           config.hostip, config.hostport);
1907
1908    if (config.dbnum != 0)
1909        len += snprintf(config.prompt+len,sizeof(config.prompt)-len,"[%d]",
1910            config.dbnum);
1911    snprintf(config.prompt+len,sizeof(config.prompt)-len,"> ");
1912}
1913# 179 "src/redis-cli.c"
1914static sds getDotfilePath(char *envoverride, char *dotfilename) {
1915    char *path = 0;
1916    sds dotPath = 0;
1917
1918
1919    path = getenv(envoverride);
1920    if (path != 0 && *path != '\0') {
1921        if (!strcmp("/dev/null", path)) {
1922            return 0;
1923        }
1924
1925
1926        dotPath = sdsnew(path);
1927    } else {
1928        char *home = getenv("HOME");
1929        if (home != 0 && *home != '\0') {
1930
1931            dotPath = sdscatprintf(sdsempty(), "%s/%s", home, dotfilename);
1932        }
1933    }
1934    return dotPath;
1935}
1936
1937
1938
1939
1940
1941
1942static sds percentDecode(const char *pe, size_t len) {
1943    const char *end = pe + len;
1944    sds ret = sdsempty();
1945    const char *curr = pe;
1946
1947    while (curr < end) {
1948        if (*curr == '%') {
1949            if ((end - curr) < 2) {
1950                fprintf(stderr, "Incomplete URI encoding\n");
1951                exit(1);
1952            }
1953
1954            char h = tolower(*(++curr));
1955            char l = tolower(*(++curr));
1956            if (!(isdigit(h) || (h >= 'a' && h <= 'f')) || !(isdigit(l) || (l >= 'a' && l <= 'f'))) {
1957                fprintf(stderr, "Illegal character in URI encoding\n");
1958                exit(1);
1959            }
1960            char c = (((isdigit(h) ? h - '0' : h - 'a' + 10) << 4) + (isdigit(l) ? l - '0' : l - 'a' + 10));
1961            ret = sdscatlen(ret, &c, 1);
1962            curr++;
1963        } else {
1964            ret = sdscatlen(ret, curr++, 1);
1965        }
1966    }
1967
1968    return ret;
1969}
1970# 244 "src/redis-cli.c"
1971static void parseRedisUri(const char *uri) {
1972
1973    const char *scheme = "redis://";
1974    const char *curr = uri;
1975    const char *end = uri + strlen(uri);
1976    const char *userinfo, *username, *port, *host, *path;
1977
1978
1979    if (strncasecmp(scheme, curr, strlen(scheme))) {
1980        fprintf(stderr,"Invalid URI scheme\n");
1981        exit(1);
1982    }
1983    curr += strlen(scheme);
1984    if (curr == end) return;
1985
1986
1987    if ((userinfo = strchr(curr,'@'))) {
1988        if ((username = strchr(curr, ':')) && username < userinfo) {
1989
1990            curr = username + 1;
1991        }
1992
1993        config.auth = percentDecode(curr, userinfo - curr);
1994        curr = userinfo + 1;
1995    }
1996    if (curr == end) return;
1997
1998
1999    path = strchr(curr, '/');
2000    if (*curr != '/') {
2001        host = path ? path - 1 : end;
2002        if ((port = strchr(curr, ':'))) {
2003            config.hostport = atoi(port + 1);
2004            host = port - 1;
2005        }
2006        config.hostip = sdsnewlen(curr, host - curr + 1);
2007    }
2008    curr = path ? path + 1 : end;
2009    if (curr == end) return;
2010
2011
2012    config.dbnum = atoi(curr);
2013}
2014# 295 "src/redis-cli.c"
2015typedef struct {
2016    int type;
2017    int argc;
2018    sds *argv;
2019    sds full;
2020
2021
2022    struct commandHelp *org;
2023} helpEntry;
2024
2025static helpEntry *helpEntries;
2026static int helpEntriesLen;
2027
2028static sds cliVersion(void) {
2029    sds version;
2030    version = sdscatprintf(sdsempty(), "%s", "4.0.8");
2031
2032
2033    if (strtoll(redisGitSHA1(),0,16)) {
2034        version = sdscatprintf(version, " (git:%s", redisGitSHA1());
2035        if (strtoll(redisGitDirty(),0,10))
2036            version = sdscatprintf(version, "-dirty");
2037        version = sdscat(version, ")");
2038    }
2039    return version;
2040}
2041
2042static void cliInitHelp(void) {
2043    int commandslen = sizeof(commandHelp)/sizeof(struct commandHelp);
2044    int groupslen = sizeof(commandGroups)/sizeof(char*);
2045    int i, len, pos = 0;
2046    helpEntry tmp;
2047
2048    helpEntriesLen = len = commandslen+groupslen;
2049    helpEntries = zmalloc(sizeof(helpEntry)*len);
2050
2051    for (i = 0; i < groupslen; i++) {
2052        tmp.argc = 1;
2053        tmp.argv = zmalloc(sizeof(sds));
2054        tmp.argv[0] = sdscatprintf(sdsempty(),"@%s",commandGroups[i]);
2055        tmp.full = tmp.argv[0];
2056        tmp.type = 2;
2057        tmp.org = 0;
2058        helpEntries[pos++] = tmp;
2059    }
2060
2061    for (i = 0; i < commandslen; i++) {
2062        tmp.argv = sdssplitargs(commandHelp[i].name,&tmp.argc);
2063        tmp.full = sdsnew(commandHelp[i].name);
2064        tmp.type = 1;
2065        tmp.org = &commandHelp[i];
2066        helpEntries[pos++] = tmp;
2067    }
2068}
2069
2070
2071
2072
2073
2074
2075static void cliIntegrateHelp(void) {
2076    if (cliConnect(0) == -1) return;
2077
2078    redisReply *reply = redisCommand(context, "COMMAND");
2079    if(reply == 0 || reply->type != 2) return;
2080
2081
2082
2083    for (size_t j = 0; j < reply->elements; j++) {
2084        redisReply *entry = reply->element[j];
2085        if (entry->type != 2 || entry->elements < 4 ||
2086            entry->element[0]->type != 1 ||
2087            entry->element[1]->type != 3 ||
2088            entry->element[3]->type != 3) return;
2089        char *cmdname = entry->element[0]->str;
2090        int i;
2091
2092        for (i = 0; i < helpEntriesLen; i++) {
2093            helpEntry *he = helpEntries+i;
2094            if (!strcasecmp(he->argv[0],cmdname))
2095                break;
2096        }
2097        if (i != helpEntriesLen) continue;
2098
2099        helpEntriesLen++;
2100        helpEntries = zrealloc(helpEntries,sizeof(helpEntry)*helpEntriesLen);
2101        helpEntry *new = helpEntries+(helpEntriesLen-1);
2102
2103        new->argc = 1;
2104        new->argv = zmalloc(sizeof(sds));
2105        new->argv[0] = sdsnew(cmdname);
2106        new->full = new->argv[0];
2107        new->type = 1;
2108        sdstoupper(new->argv[0]);
2109
2110        struct commandHelp *ch = zmalloc(sizeof(*ch));
2111        ch->name = new->argv[0];
2112        ch->params = sdsempty();
2113        int args = llabs(entry->element[1]->integer);
2114        if (entry->element[3]->integer == 1) {
2115            ch->params = sdscat(ch->params,"key ");
2116            args--;
2117        }
2118        while(args--) ch->params = sdscat(ch->params,"arg ");
2119        if (entry->element[1]->integer < 0)
2120            ch->params = sdscat(ch->params,"...options...");
2121        ch->summary = "Help not available";
2122        ch->group = 0;
2123        ch->since = "not known";
2124        new->org = ch;
2125    }
2126    freeReplyObject(reply);
2127}
2128
2129
2130static void cliOutputCommandHelp(struct commandHelp *help, int group) {
2131    printf("\r\n  \x1b[1m%s\x1b[0m \x1b[90m%s\x1b[0m\r\n", help->name, help->params);
2132    printf("  \x1b[33msummary:\x1b[0m %s\r\n", help->summary);
2133    printf("  \x1b[33msince:\x1b[0m %s\r\n", help->since);
2134    if (group) {
2135        printf("  \x1b[33mgroup:\x1b[0m %s\r\n", commandGroups[help->group]);
2136    }
2137}
2138
2139
2140static void cliOutputGenericHelp(void) {
2141    sds version = cliVersion();
2142    printf(
2143        "redis-cli %s\n"
2144        "To get help about Redis commands type:\n"
2145        "      \"help @<group>\" to get a list of commands in <group>\n"
2146        "      \"help <command>\" for help on <command>\n"
2147        "      \"help <tab>\" to get a list of possible help topics\n"
2148        "      \"quit\" to exit\n"
2149        "\n"
2150        "To set redis-cli preferences:\n"
2151        "      \":set hints\" enable online hints\n"
2152        "      \":set nohints\" disable online hints\n"
2153        "Set your preferences in ~/.redisclirc\n",
2154        version
2155    );
2156    sdsfree(version);
2157}
2158
2159
2160static void cliOutputHelp(int argc, char **argv) {
2161    int i, j, len;
2162    int group = -1;
2163    helpEntry *entry;
2164    struct commandHelp *help;
2165
2166    if (argc == 0) {
2167        cliOutputGenericHelp();
2168        return;
2169    } else if (argc > 0 && argv[0][0] == '@') {
2170        len = sizeof(commandGroups)/sizeof(char*);
2171        for (i = 0; i < len; i++) {
2172            if (strcasecmp(argv[0]+1,commandGroups[i]) == 0) {
2173                group = i;
2174                break;
2175            }
2176        }
2177    }
2178
2179    assert(argc > 0);
2180    for (i = 0; i < helpEntriesLen; i++) {
2181        entry = &helpEntries[i];
2182        if (entry->type != 1) continue;
2183
2184        help = entry->org;
2185        if (group == -1) {
2186
2187            if (argc == entry->argc) {
2188                for (j = 0; j < argc; j++) {
2189                    if (strcasecmp(argv[j],entry->argv[j]) != 0) break;
2190                }
2191                if (j == argc) {
2192                    cliOutputCommandHelp(help,1);
2193                }
2194            }
2195        } else {
2196            if (group == help->group) {
2197                cliOutputCommandHelp(help,0);
2198            }
2199        }
2200    }
2201    printf("\r\n");
2202}
2203
2204
2205static void completionCallback(const char *buf, linenoiseCompletions *lc) {
2206    size_t startpos = 0;
2207    int mask;
2208    int i;
2209    size_t matchlen;
2210    sds tmp;
2211
2212    if (strncasecmp(buf,"help ",5) == 0) {
2213        startpos = 5;
2214        while (isspace(buf[startpos])) startpos++;
2215        mask = 1 | 2;
2216    } else {
2217        mask = 1;
2218    }
2219
2220    for (i = 0; i < helpEntriesLen; i++) {
2221        if (!(helpEntries[i].type & mask)) continue;
2222
2223        matchlen = strlen(buf+startpos);
2224        if (strncasecmp(buf+startpos,helpEntries[i].full,matchlen) == 0) {
2225            tmp = sdsnewlen(buf,startpos);
2226            tmp = sdscat(tmp,helpEntries[i].full);
2227            linenoiseAddCompletion(lc,tmp);
2228            sdsfree(tmp);
2229        }
2230    }
2231}
2232
2233
2234static char *hintsCallback(const char *buf, int *color, int *bold) {
2235    if (!pref.hints) return 0;
2236
2237    int i, argc, buflen = strlen(buf);
2238    sds *argv = sdssplitargs(buf,&argc);
2239    int endspace = buflen && isspace(buf[buflen-1]);
2240
2241
2242    if (argc == 0) {
2243        sdsfreesplitres(argv,argc);
2244        return 0;
2245    }
2246
2247    for (i = 0; i < helpEntriesLen; i++) {
2248        if (!(helpEntries[i].type & 1)) continue;
2249
2250        if (strcasecmp(argv[0],helpEntries[i].full) == 0)
2251        {
2252            *color = 90;
2253            *bold = 0;
2254            sds hint = sdsnew(helpEntries[i].org->params);
2255
2256
2257
2258            int toremove = argc-1;
2259            while(toremove > 0 && sdslen(hint)) {
2260                if (hint[0] == '[') break;
2261                if (hint[0] == ' ') toremove--;
2262                sdsrange(hint,1,-1);
2263            }
2264
2265
2266            if (!endspace) {
2267                sds newhint = sdsnewlen(" ",1);
2268                newhint = sdscatsds(newhint,hint);
2269                sdsfree(hint);
2270                hint = newhint;
2271            }
2272
2273            sdsfreesplitres(argv,argc);
2274            return hint;
2275        }
2276    }
2277    sdsfreesplitres(argv,argc);
2278    return 0;
2279}
2280
2281static void freeHintsCallback(void *ptr) {
2282    sdsfree(ptr);
2283}
2284
2285
2286
2287
2288
2289
2290static int cliAuth(void) {
2291    redisReply *reply;
2292    if (config.auth == 0) return 0;
2293
2294    reply = redisCommand(context,"AUTH %s",config.auth);
2295    if (reply != 0) {
2296        freeReplyObject(reply);
2297        return 0;
2298    }
2299    return -1;
2300}
2301
2302
2303static int cliSelect(void) {
2304    redisReply *reply;
2305    if (config.dbnum == 0) return 0;
2306
2307    reply = redisCommand(context,"SELECT %d",config.dbnum);
2308    if (reply != 0) {
2309        int result = 0;
2310        if (reply->type == 6) result = -1;
2311        freeReplyObject(reply);
2312        return result;
2313    }
2314    return -1;
2315}
2316
2317
2318
2319static int cliConnect(int force) {
2320    if (context == 0 || force) {
2321        if (context != 0) {
2322            redisFree(context);
2323        }
2324
2325        if (config.hostsocket == 0) {
2326            context = redisConnect(config.hostip,config.hostport);
2327        } else {
2328            context = redisConnectUnix(config.hostsocket);
2329        }
2330
2331        if (context->err) {
2332            fprintf(stderr,"Could not connect to Redis at ");
2333            if (config.hostsocket == 0)
2334                fprintf(stderr,"%s:%d: %s\n",config.hostip,config.hostport,context->errstr);
2335            else
2336                fprintf(stderr,"%s: %s\n",config.hostsocket,context->errstr);
2337            redisFree(context);
2338            context = 0;
2339            return -1;
2340        }
2341
2342
2343
2344
2345
2346        anetKeepAlive(0, context->fd, 15);
2347
2348
2349        if (cliAuth() != 0)
2350            return -1;
2351        if (cliSelect() != 0)
2352            return -1;
2353    }
2354    return 0;
2355}
2356
2357static void cliPrintContextError(void) {
2358    if (context == 0) return;
2359    fprintf(stderr,"Error: %s\n",context->errstr);
2360}
2361
2362static sds cliFormatReplyTTY(redisReply *r, char *prefix) {
2363    sds out = sdsempty();
2364    switch (r->type) {
2365    case 6:
2366        out = sdscatprintf(out,"(error) %s\n", r->str);
2367    break;
2368    case 5:
2369        out = sdscat(out,r->str);
2370        out = sdscat(out,"\n");
2371    break;
2372    case 3:
2373        out = sdscatprintf(out,"(integer) %lld\n",r->integer);
2374    break;
2375    case 1:
2376
2377
2378        out = sdscatrepr(out,r->str,r->len);
2379        out = sdscat(out,"\n");
2380    break;
2381    case 4:
2382        out = sdscat(out,"(nil)\n");
2383    break;
2384    case 2:
2385        if (r->elements == 0) {
2386            out = sdscat(out,"(empty list or set)\n");
2387        } else {
2388            unsigned int i, idxlen = 0;
2389            char _prefixlen[16];
2390            char _prefixfmt[16];
2391            sds _prefix;
2392            sds tmp;
2393
2394
2395            i = r->elements;
2396            do {
2397                idxlen++;
2398                i /= 10;
2399            } while(i);
2400
2401
2402            memset(_prefixlen,' ',idxlen+2);
2403            _prefixlen[idxlen+2] = '\0';
2404            _prefix = sdscat(sdsnew(prefix),_prefixlen);
2405
2406
2407            snprintf(_prefixfmt,sizeof(_prefixfmt),"%%s%%%ud) ",idxlen);
2408
2409            for (i = 0; i < r->elements; i++) {
2410
2411
2412                out = sdscatprintf(out,_prefixfmt,i == 0 ? "" : prefix,i+1);
2413
2414
2415                tmp = cliFormatReplyTTY(r->element[i],_prefix);
2416                out = sdscatlen(out,tmp,sdslen(tmp));
2417                sdsfree(tmp);
2418            }
2419            sdsfree(_prefix);
2420        }
2421    break;
2422    default:
2423        fprintf(stderr,"Unknown reply type: %d\n", r->type);
2424        exit(1);
2425    }
2426    return out;
2427}
2428
2429int isColorTerm(void) {
2430    char *t = getenv("TERM");
2431    return t != 0 && strstr(t,"xterm") != 0;
2432}
2433
2434
2435
2436sds sdscatcolor(sds o, char *s, size_t len, char *color) {
2437    if (!isColorTerm()) return sdscatlen(o,s,len);
2438
2439    int bold = strstr(color,"bold") != 0;
2440    int ccode = 37;
2441    if (strstr(color,"red")) ccode = 31;
2442    else if (strstr(color,"green")) ccode = 32;
2443    else if (strstr(color,"yellow")) ccode = 33;
2444    else if (strstr(color,"blue")) ccode = 34;
2445    else if (strstr(color,"magenta")) ccode = 35;
2446    else if (strstr(color,"cyan")) ccode = 36;
2447    else if (strstr(color,"white")) ccode = 37;
2448
2449    o = sdscatfmt(o,"\033[%i;%i;49m",bold,ccode);
2450    o = sdscatlen(o,s,len);
2451    o = sdscat(o,"\033[0m");
2452    return o;
2453}
2454
2455
2456
2457sds sdsCatColorizedLdbReply(sds o, char *s, size_t len) {
2458    char *color = "white";
2459
2460    if (strstr(s,"<debug>")) color = "bold";
2461    if (strstr(s,"<redis>")) color = "green";
2462    if (strstr(s,"<reply>")) color = "cyan";
2463    if (strstr(s,"<error>")) color = "red";
2464    if (strstr(s,"<hint>")) color = "bold";
2465    if (strstr(s,"<value>") || strstr(s,"<retval>")) color = "magenta";
2466    if (len > 4 && isdigit(s[3])) {
2467        if (s[1] == '>') color = "yellow";
2468        else if (s[2] == '#') color = "bold";
2469    }
2470    return sdscatcolor(o,s,len,color);
2471}
2472
2473static sds cliFormatReplyRaw(redisReply *r) {
2474    sds out = sdsempty(), tmp;
2475    size_t i;
2476
2477    switch (r->type) {
2478    case 4:
2479
2480        break;
2481    case 6:
2482        out = sdscatlen(out,r->str,r->len);
2483        out = sdscatlen(out,"\n",1);
2484        break;
2485    case 5:
2486    case 1:
2487        if (r->type == 5 && config.eval_ldb) {
2488
2489
2490
2491
2492
2493            if (strstr(r->str,"<endsession>") == r->str) {
2494                config.enable_ldb_on_eval = 0;
2495                config.eval_ldb = 0;
2496                config.eval_ldb_end = 1;
2497                config.output = 0;
2498                cliRefreshPrompt();
2499            } else {
2500                out = sdsCatColorizedLdbReply(out,r->str,r->len);
2501            }
2502        } else {
2503            out = sdscatlen(out,r->str,r->len);
2504        }
2505        break;
2506    case 3:
2507        out = sdscatprintf(out,"%lld",r->integer);
2508        break;
2509    case 2:
2510        for (i = 0; i < r->elements; i++) {
2511            if (i > 0) out = sdscat(out,config.mb_delim);
2512            tmp = cliFormatReplyRaw(r->element[i]);
2513            out = sdscatlen(out,tmp,sdslen(tmp));
2514            sdsfree(tmp);
2515        }
2516        break;
2517    default:
2518        fprintf(stderr,"Unknown reply type: %d\n", r->type);
2519        exit(1);
2520    }
2521    return out;
2522}
2523
2524static sds cliFormatReplyCSV(redisReply *r) {
2525    unsigned int i;
2526
2527    sds out = sdsempty();
2528    switch (r->type) {
2529    case 6:
2530        out = sdscat(out,"ERROR,");
2531        out = sdscatrepr(out,r->str,strlen(r->str));
2532    break;
2533    case 5:
2534        out = sdscatrepr(out,r->str,r->len);
2535    break;
2536    case 3:
2537        out = sdscatprintf(out,"%lld",r->integer);
2538    break;
2539    case 1:
2540        out = sdscatrepr(out,r->str,r->len);
2541    break;
2542    case 4:
2543        out = sdscat(out,"NIL");
2544    break;
2545    case 2:
2546        for (i = 0; i < r->elements; i++) {
2547            sds tmp = cliFormatReplyCSV(r->element[i]);
2548            out = sdscatlen(out,tmp,sdslen(tmp));
2549            if (i != r->elements-1) out = sdscat(out,",");
2550            sdsfree(tmp);
2551        }
2552    break;
2553    default:
2554        fprintf(stderr,"Unknown reply type: %d\n", r->type);
2555        exit(1);
2556    }
2557    return out;
2558}
2559
2560static int cliReadReply(int output_raw_strings) {
2561    void *_reply;
2562    redisReply *reply;
2563    sds out = 0;
2564    int output = 1;
2565
2566    if (redisGetReply(context,&_reply) != 0) {
2567        if (config.shutdown) {
2568            redisFree(context);
2569            context = 0;
2570            return 0;
2571        }
2572        if (config.interactive) {
2573
2574            if (context->err == 1 &&
2575                (errno == ECONNRESET || errno == EPIPE))
2576                return -1;
2577            if (context->err == 3)
2578                return -1;
2579        }
2580        cliPrintContextError();
2581        exit(1);
2582        return -1;
2583    }
2584
2585    reply = (redisReply*)_reply;
2586
2587    config.last_cmd_type = reply->type;
2588
2589
2590
2591    if (config.cluster_mode && reply->type == 6 &&
2592        (!strncmp(reply->str,"MOVED",5) || !strcmp(reply->str,"ASK")))
2593    {
2594        char *p = reply->str, *s;
2595        int slot;
2596
2597        output = 0;
2598
2599
2600
2601
2602
2603        s = strchr(p,' ');
2604        p = strchr(s+1,' ');
2605        *p = '\0';
2606        slot = atoi(s+1);
2607        s = strrchr(p+1,':');
2608        *s = '\0';
2609        sdsfree(config.hostip);
2610        config.hostip = sdsnew(p+1);
2611        config.hostport = atoi(s+1);
2612        if (config.interactive)
2613            printf("-> Redirected to slot [%d] located at %s:%d\n",
2614                slot, config.hostip, config.hostport);
2615        config.cluster_reissue_command = 1;
2616        cliRefreshPrompt();
2617    }
2618
2619    if (output) {
2620        if (output_raw_strings) {
2621            out = cliFormatReplyRaw(reply);
2622        } else {
2623            if (config.output == 1) {
2624                out = cliFormatReplyRaw(reply);
2625                out = sdscat(out,"\n");
2626            } else if (config.output == 0) {
2627                out = cliFormatReplyTTY(reply,"");
2628            } else if (config.output == 2) {
2629                out = cliFormatReplyCSV(reply);
2630                out = sdscat(out,"\n");
2631            }
2632        }
2633        fwrite(out,sdslen(out),1,stdout);
2634        sdsfree(out);
2635    }
2636    freeReplyObject(reply);
2637    return 0;
2638}
2639
2640static int cliSendCommand(int argc, char **argv, int repeat) {
2641    char *command = argv[0];
2642    size_t *argvlen;
2643    int j, output_raw;
2644
2645    if (!config.eval_ldb &&
2646        (!strcasecmp(command,"help") || !strcasecmp(command,"?"))) {
2647        cliOutputHelp(--argc, ++argv);
2648        return 0;
2649    }
2650
2651    if (context == 0) return -1;
2652
2653    output_raw = 0;
2654    if (!strcasecmp(command,"info") ||
2655        (argc >= 2 && !strcasecmp(command,"debug") &&
2656                       !strcasecmp(argv[1],"htstats")) ||
2657        (argc >= 2 && !strcasecmp(command,"memory") &&
2658                      (!strcasecmp(argv[1],"malloc-stats") ||
2659                       !strcasecmp(argv[1],"doctor"))) ||
2660        (argc == 2 && !strcasecmp(command,"cluster") &&
2661                      (!strcasecmp(argv[1],"nodes") ||
2662                       !strcasecmp(argv[1],"info"))) ||
2663        (argc == 2 && !strcasecmp(command,"client") &&
2664                       !strcasecmp(argv[1],"list")) ||
2665        (argc == 3 && !strcasecmp(command,"latency") &&
2666                       !strcasecmp(argv[1],"graph")) ||
2667        (argc == 2 && !strcasecmp(command,"latency") &&
2668                       !strcasecmp(argv[1],"doctor")))
2669    {
2670        output_raw = 1;
2671    }
2672
2673    if (!strcasecmp(command,"shutdown")) config.shutdown = 1;
2674    if (!strcasecmp(command,"monitor")) config.monitor_mode = 1;
2675    if (!strcasecmp(command,"subscribe") ||
2676        !strcasecmp(command,"psubscribe")) config.pubsub_mode = 1;
2677    if (!strcasecmp(command,"sync") ||
2678        !strcasecmp(command,"psync")) config.slave_mode = 1;
2679
2680
2681
2682    if (argc == 3 && !strcasecmp(argv[0],"script") &&
2683                     !strcasecmp(argv[1],"debug"))
2684    {
2685        if (!strcasecmp(argv[2],"yes") || !strcasecmp(argv[2],"sync")) {
2686            config.enable_ldb_on_eval = 1;
2687        } else {
2688            config.enable_ldb_on_eval = 0;
2689        }
2690    }
2691
2692
2693    if (!strcasecmp(command,"eval") && config.enable_ldb_on_eval) {
2694        config.eval_ldb = 1;
2695        config.output = 1;
2696    }
2697
2698
2699    argvlen = zmalloc(argc*sizeof(size_t));
2700    for (j = 0; j < argc; j++)
2701        argvlen[j] = sdslen(argv[j]);
2702
2703    while(repeat--) {
2704        redisAppendCommandArgv(context,argc,(const char**)argv,argvlen);
2705        while (config.monitor_mode) {
2706            if (cliReadReply(output_raw) != 0) exit(1);
2707            fflush(stdout);
2708        }
2709
2710        if (config.pubsub_mode) {
2711            if (config.output != 1)
2712                printf("Reading messages... (press Ctrl-C to quit)\n");
2713            while (1) {
2714                if (cliReadReply(output_raw) != 0) exit(1);
2715            }
2716        }
2717
2718        if (config.slave_mode) {
2719            printf("Entering slave output mode...  (press Ctrl-C to quit)\n");
2720            slaveMode();
2721            config.slave_mode = 0;
2722            zfree(argvlen);
2723            return -1;
2724        }
2725
2726        if (cliReadReply(output_raw) != 0) {
2727            zfree(argvlen);
2728            return -1;
2729        } else {
2730
2731            if (!strcasecmp(command,"select") && argc == 2 && config.last_cmd_type != 6) {
2732                config.dbnum = atoi(argv[1]);
2733                cliRefreshPrompt();
2734            } else if (!strcasecmp(command,"auth") && argc == 2) {
2735                cliSelect();
2736            }
2737        }
2738        if (config.interval) usleep(config.interval);
2739        fflush(stdout);
2740    }
2741
2742    zfree(argvlen);
2743    return 0;
2744}
2745
2746
2747static redisReply *reconnectingRedisCommand(redisContext *c, const char *fmt, ...) {
2748    redisReply *reply = 0;
2749    int tries = 0;
2750    va_list ap;
2751
2752    assert(!c->err);
2753    while(reply == 0) {
2754        while (c->err & (1 | 3)) {
2755            printf("\r\x1b[0K");
2756            printf("Reconnecting... %d\r", ++tries);
2757            fflush(stdout);
2758
2759            redisFree(c);
2760            c = redisConnect(config.hostip,config.hostport);
2761            usleep(1000000);
2762        }
2763
2764        __builtin_va_start((ap));
2765        reply = redisvCommand(c,fmt,ap);
2766        ;
2767
2768        if (c->err && !(c->err & (1 | 3))) {
2769            fprintf(stderr, "Error: %s\n", c->errstr);
2770            exit(1);
2771        } else if (tries > 0) {
2772            printf("\r\x1b[0K");
2773        }
2774    }
2775
2776    context = c;
2777    return reply;
2778}
2779
2780
2781
2782
2783
2784static int parseOptions(int argc, char **argv) {
2785    int i;
2786
2787    for (i = 1; i < argc; i++) {
2788        int lastarg = i==argc-1;
2789
2790        if (!strcmp(argv[i],"-h") && !lastarg) {
2791            sdsfree(config.hostip);
2792            config.hostip = sdsnew(argv[++i]);
2793        } else if (!strcmp(argv[i],"-h") && lastarg) {
2794            usage();
2795        } else if (!strcmp(argv[i],"--help")) {
2796            usage();
2797        } else if (!strcmp(argv[i],"-x")) {
2798            config.stdinarg = 1;
2799        } else if (!strcmp(argv[i],"-p") && !lastarg) {
2800            config.hostport = atoi(argv[++i]);
2801        } else if (!strcmp(argv[i],"-s") && !lastarg) {
2802            config.hostsocket = argv[++i];
2803        } else if (!strcmp(argv[i],"-r") && !lastarg) {
2804            config.repeat = strtoll(argv[++i],0,10);
2805        } else if (!strcmp(argv[i],"-i") && !lastarg) {
2806            double seconds = atof(argv[++i]);
2807            config.interval = seconds*1000000;
2808        } else if (!strcmp(argv[i],"-n") && !lastarg) {
2809            config.dbnum = atoi(argv[++i]);
2810        } else if (!strcmp(argv[i],"-a") && !lastarg) {
2811            config.auth = argv[++i];
2812        } else if (!strcmp(argv[i],"-u") && !lastarg) {
2813            parseRedisUri(argv[++i]);
2814        } else if (!strcmp(argv[i],"--raw")) {
2815            config.output = 1;
2816        } else if (!strcmp(argv[i],"--no-raw")) {
2817            config.output = 0;
2818        } else if (!strcmp(argv[i],"--csv")) {
2819            config.output = 2;
2820        } else if (!strcmp(argv[i],"--latency")) {
2821            config.latency_mode = 1;
2822        } else if (!strcmp(argv[i],"--latency-dist")) {
2823            config.latency_dist_mode = 1;
2824        } else if (!strcmp(argv[i],"--mono")) {
2825            spectrum_palette = spectrum_palette_mono;
2826            spectrum_palette_size = spectrum_palette_mono_size;
2827        } else if (!strcmp(argv[i],"--latency-history")) {
2828            config.latency_mode = 1;
2829            config.latency_history = 1;
2830        } else if (!strcmp(argv[i],"--lru-test") && !lastarg) {
2831            config.lru_test_mode = 1;
2832            config.lru_test_sample_size = strtoll(argv[++i],0,10);
2833        } else if (!strcmp(argv[i],"--slave")) {
2834            config.slave_mode = 1;
2835        } else if (!strcmp(argv[i],"--stat")) {
2836            config.stat_mode = 1;
2837        } else if (!strcmp(argv[i],"--scan")) {
2838            config.scan_mode = 1;
2839        } else if (!strcmp(argv[i],"--pattern") && !lastarg) {
2840            config.pattern = argv[++i];
2841        } else if (!strcmp(argv[i],"--intrinsic-latency") && !lastarg) {
2842            config.intrinsic_latency_mode = 1;
2843            config.intrinsic_latency_duration = atoi(argv[++i]);
2844        } else if (!strcmp(argv[i],"--rdb") && !lastarg) {
2845            config.getrdb_mode = 1;
2846            config.rdb_filename = argv[++i];
2847        } else if (!strcmp(argv[i],"--pipe")) {
2848            config.pipe_mode = 1;
2849        } else if (!strcmp(argv[i],"--pipe-timeout") && !lastarg) {
2850            config.pipe_timeout = atoi(argv[++i]);
2851        } else if (!strcmp(argv[i],"--bigkeys")) {
2852            config.bigkeys = 1;
2853        } else if (!strcmp(argv[i],"--hotkeys")) {
2854            config.hotkeys = 1;
2855        } else if (!strcmp(argv[i],"--eval") && !lastarg) {
2856            config.eval = argv[++i];
2857        } else if (!strcmp(argv[i],"--ldb")) {
2858            config.eval_ldb = 1;
2859            config.output = 1;
2860        } else if (!strcmp(argv[i],"--ldb-sync-mode")) {
2861            config.eval_ldb = 1;
2862            config.eval_ldb_sync = 1;
2863            config.output = 1;
2864        } else if (!strcmp(argv[i],"-c")) {
2865            config.cluster_mode = 1;
2866        } else if (!strcmp(argv[i],"-d") && !lastarg) {
2867            sdsfree(config.mb_delim);
2868            config.mb_delim = sdsnew(argv[++i]);
2869        } else if (!strcmp(argv[i],"-v") || !strcmp(argv[i], "--version")) {
2870            sds version = cliVersion();
2871            printf("redis-cli %s\n", version);
2872            sdsfree(version);
2873            exit(0);
2874        } else {
2875            if (argv[i][0] == '-') {
2876                fprintf(stderr,
2877                    "Unrecognized option or bad number of args for: '%s'\n",
2878                    argv[i]);
2879                exit(1);
2880            } else {
2881
2882                break;
2883            }
2884        }
2885    }
2886
2887
2888    if (config.eval_ldb && config.eval == 0) {
2889        fprintf(stderr,"Options --ldb and --ldb-sync-mode require --eval.\n");
2890        fprintf(stderr,"Try %s --help for more information.\n", argv[0]);
2891        exit(1);
2892    }
2893    return i;
2894}
2895
2896static sds readArgFromStdin(void) {
2897    char buf[1024];
2898    sds arg = sdsempty();
2899
2900    while(1) {
2901        int nread = read(fileno(stdin),buf,1024);
2902
2903        if (nread == 0) break;
2904        else if (nread == -1) {
2905            perror("Reading from standard input");
2906            exit(1);
2907        }
2908        arg = sdscatlen(arg,buf,nread);
2909    }
2910    return arg;
2911}
2912
2913static void usage(void) {
2914    sds version = cliVersion();
2915    fprintf(stderr,
2916"redis-cli %s\n"
2917"\n"
2918"Usage: redis-cli [OPTIONS] [cmd [arg [arg ...]]]\n"
2919"  -h <hostname>      Server hostname (default: 127.0.0.1).\n"
2920"  -p <port>          Server port (default: 6379).\n"
2921"  -s <socket>        Server socket (overrides hostname and port).\n"
2922"  -a <password>      Password to use when connecting to the server.\n"
2923"  -u <uri>           Server URI.\n"
2924"  -r <repeat>        Execute specified command N times.\n"
2925"  -i <interval>      When -r is used, waits <interval> seconds per command.\n"
2926"                     It is possible to specify sub-second times like -i 0.1.\n"
2927"  -n <db>            Database number.\n"
2928"  -x                 Read last argument from STDIN.\n"
2929"  -d <delimiter>     Multi-bulk delimiter in for raw formatting (default: \\n).\n"
2930"  -c                 Enable cluster mode (follow -ASK and -MOVED redirections).\n"
2931"  --raw              Use raw formatting for replies (default when STDOUT is\n"
2932"                     not a tty).\n"
2933"  --no-raw           Force formatted output even when STDOUT is not a tty.\n"
2934"  --csv              Output in CSV format.\n"
2935"  --stat             Print rolling stats about server: mem, clients, ...\n"
2936"  --latency          Enter a special mode continuously sampling latency.\n"
2937"                     If you use this mode in an interactive session it runs\n"
2938"                     forever displaying real-time stats. Otherwise if --raw or\n"
2939"                     --csv is specified, or if you redirect the output to a non\n"
2940"                     TTY, it samples the latency for 1 second (you can use\n"
2941"                     -i to change the interval), then produces a single output\n"
2942"                     and exits.\n"
2943"  --latency-history  Like --latency but tracking latency changes over time.\n"
2944"                     Default time interval is 15 sec. Change it using -i.\n"
2945"  --latency-dist     Shows latency as a spectrum, requires xterm 256 colors.\n"
2946"                     Default time interval is 1 sec. Change it using -i.\n"
2947"  --lru-test <keys>  Simulate a cache workload with an 80-20 distribution.\n"
2948"  --slave            Simulate a slave showing commands received from the master.\n"
2949"  --rdb <filename>   Transfer an RDB dump from remote server to local file.\n"
2950"  --pipe             Transfer raw Redis protocol from stdin to server.\n"
2951"  --pipe-timeout <n> In --pipe mode, abort with error if after sending all data.\n"
2952"                     no reply is received within <n> seconds.\n"
2953"                     Default timeout: %d. Use 0 to wait forever.\n"
2954"  --bigkeys          Sample Redis keys looking for big keys.\n"
2955"  --hotkeys          Sample Redis keys looking for hot keys.\n"
2956"                     only works when maxmemory-policy is *lfu.\n"
2957"  --scan             List all keys using the SCAN command.\n"
2958"  --pattern <pat>    Useful with --scan to specify a SCAN pattern.\n"
2959"  --intrinsic-latency <sec> Run a test to measure intrinsic system latency.\n"
2960"                     The test will run for the specified amount of seconds.\n"
2961"  --eval <file>      Send an EVAL command using the Lua script at <file>.\n"
2962"  --ldb              Used with --eval enable the Redis Lua debugger.\n"
2963"  --ldb-sync-mode    Like --ldb but uses the synchronous Lua debugger, in\n"
2964"                     this mode the server is blocked and script changes are\n"
2965"                     are not rolled back from the server memory.\n"
2966"  --help             Output this help and exit.\n"
2967"  --version          Output version and exit.\n"
2968"\n"
2969"Examples:\n"
2970"  cat /etc/passwd | redis-cli -x set mypasswd\n"
2971"  redis-cli get mypasswd\n"
2972"  redis-cli -r 100 lpush mylist x\n"
2973"  redis-cli -r 100 -i 1 info | grep used_memory_human:\n"
2974"  redis-cli --eval myscript.lua key1 key2 , arg1 arg2 arg3\n"
2975"  redis-cli --scan --pattern '*:12345*'\n"
2976"\n"
2977"  (Note: when using --eval the comma separates KEYS[] from ARGV[] items)\n"
2978"\n"
2979"When no command is given, redis-cli starts in interactive mode.\n"
2980"Type \"help\" in interactive mode for information on available commands\n"
2981"and settings.\n"
2982"\n",
2983        version, 30);
2984    sdsfree(version);
2985    exit(1);
2986}
2987
2988
2989static char **convertToSds(int count, char** args) {
2990  int j;
2991  char **sds = zmalloc(sizeof(char*)*count);
2992
2993  for(j = 0; j < count; j++)
2994    sds[j] = sdsnew(args[j]);
2995
2996  return sds;
2997}
2998
2999static int issueCommandRepeat(int argc, char **argv, long repeat) {
3000    while (1) {
3001        config.cluster_reissue_command = 0;
3002        if (cliSendCommand(argc,argv,repeat) != 0) {
3003            cliConnect(1);
3004
3005
3006
3007            if (cliSendCommand(argc,argv,repeat) != 0) {
3008                cliPrintContextError();
3009                return -1;
3010            }
3011         }
3012
3013         if (config.cluster_mode && config.cluster_reissue_command) {
3014            cliConnect(1);
3015         } else {
3016             break;
3017        }
3018    }
3019    return 0;
3020}
3021
3022static int issueCommand(int argc, char **argv) {
3023    return issueCommandRepeat(argc, argv, config.repeat);
3024}
3025
3026
3027
3028
3029
3030
3031
3032static sds *cliSplitArgs(char *line, int *argc) {
3033    if (config.eval_ldb && (strstr(line,"eval ") == line ||
3034                            strstr(line,"e ") == line))
3035    {
3036        sds *argv = sds_malloc(sizeof(sds)*2);
3037        *argc = 2;
3038        int len = strlen(line);
3039        int elen = line[1] == ' ' ? 2 : 5;
3040        argv[0] = sdsnewlen(line,elen-1);
3041        argv[1] = sdsnewlen(line+elen,len-elen);
3042        return argv;
3043    } else {
3044        return sdssplitargs(line,argc);
3045    }
3046}
3047
3048
3049
3050
3051void cliSetPreferences(char **argv, int argc, int interactive) {
3052    if (!strcasecmp(argv[0],":set") && argc >= 2) {
3053        if (!strcasecmp(argv[1],"hints")) pref.hints = 1;
3054        else if (!strcasecmp(argv[1],"nohints")) pref.hints = 0;
3055        else {
3056            printf("%sunknown redis-cli preference '%s'\n",
3057                interactive ? "" : ".redisclirc: ",
3058                argv[1]);
3059        }
3060    } else {
3061        printf("%sunknown redis-cli internal command '%s'\n",
3062            interactive ? "" : ".redisclirc: ",
3063            argv[0]);
3064    }
3065}
3066
3067
3068void cliLoadPreferences(void) {
3069    sds rcfile = getDotfilePath("REDISCLI_RCFILE",".redisclirc");
3070    if (rcfile == 0) return;
3071    FILE *fp = fopen(rcfile,"r");
3072    char buf[1024];
3073
3074    if (fp) {
3075        while(fgets(buf,sizeof(buf),fp) != 0) {
3076            sds *argv;
3077            int argc;
3078
3079            argv = sdssplitargs(buf,&argc);
3080            if (argc > 0) cliSetPreferences(argv,argc,0);
3081            sdsfreesplitres(argv,argc);
3082        }
3083        fclose(fp);
3084    }
3085    sdsfree(rcfile);
3086}
3087
3088static void repl(void) {
3089    sds historyfile = 0;
3090    int history = 0;
3091    char *line;
3092    int argc;
3093    sds *argv;
3094
3095
3096
3097    cliInitHelp();
3098    cliIntegrateHelp();
3099
3100    config.interactive = 1;
3101    linenoiseSetMultiLine(1);
3102    linenoiseSetCompletionCallback(completionCallback);
3103    linenoiseSetHintsCallback(hintsCallback);
3104    linenoiseSetFreeHintsCallback(freeHintsCallback);
3105
3106
3107    if (isatty(fileno(stdin))) {
3108        historyfile = getDotfilePath("REDISCLI_HISTFILE",".rediscli_history");
3109
3110        history = 1;
3111        if (historyfile != 0) {
3112            linenoiseHistoryLoad(historyfile);
3113        }
3114        cliLoadPreferences();
3115    }
3116
3117    cliRefreshPrompt();
3118    while((line = linenoise(context ? config.prompt : "not connected> ")) != 0) {
3119        if (line[0] != '\0') {
3120            argv = cliSplitArgs(line,&argc);
3121            if (history) linenoiseHistoryAdd(line);
3122            if (historyfile) linenoiseHistorySave(historyfile);
3123
3124            if (argv == 0) {
3125                printf("Invalid argument(s)\n");
3126                linenoiseFree(line);
3127                continue;
3128            } else if (argc > 0) {
3129                if (strcasecmp(argv[0],"quit") == 0 ||
3130                    strcasecmp(argv[0],"exit") == 0)
3131                {
3132                    exit(0);
3133                } else if (argv[0][0] == ':') {
3134                    cliSetPreferences(argv,argc,1);
3135                    continue;
3136                } else if (strcasecmp(argv[0],"restart") == 0) {
3137                    if (config.eval) {
3138                        config.eval_ldb = 1;
3139                        config.output = 1;
3140                        return;
3141                    } else {
3142                        printf("Use 'restart' only in Lua debugging mode.");
3143                    }
3144                } else if (argc == 3 && !strcasecmp(argv[0],"connect")) {
3145                    sdsfree(config.hostip);
3146                    config.hostip = sdsnew(argv[1]);
3147                    config.hostport = atoi(argv[2]);
3148                    cliRefreshPrompt();
3149                    cliConnect(1);
3150                } else if (argc == 1 && !strcasecmp(argv[0],"clear")) {
3151                    linenoiseClearScreen();
3152                } else {
3153                    long long start_time = mstime(), elapsed;
3154                    int repeat, skipargs = 0;
3155                    char *endptr;
3156
3157                    repeat = strtol(argv[0], &endptr, 10);
3158                    if (argc > 1 && *endptr == '\0' && repeat) {
3159                        skipargs = 1;
3160                    } else {
3161                        repeat = 1;
3162                    }
3163
3164                    issueCommandRepeat(argc-skipargs, argv+skipargs, repeat);
3165
3166
3167
3168                    if (config.eval_ldb_end) {
3169                        config.eval_ldb_end = 0;
3170                        cliReadReply(0);
3171                        printf("\n(Lua debugging session ended%s)\n\n",
3172                            config.eval_ldb_sync ? "" :
3173                            " -- dataset changes rolled back");
3174                    }
3175
3176                    elapsed = mstime()-start_time;
3177                    if (elapsed >= 500 &&
3178                        config.output == 0)
3179                    {
3180                        printf("(%.2fs)\n",(double)elapsed/1000);
3181                    }
3182                }
3183            }
3184
3185            sdsfreesplitres(argv,argc);
3186        }
3187
3188        linenoiseFree(line);
3189    }
3190    exit(0);
3191}
3192
3193static int noninteractive(int argc, char **argv) {
3194    int retval = 0;
3195    if (config.stdinarg) {
3196        argv = zrealloc(argv, (argc+1)*sizeof(char*));
3197        argv[argc] = readArgFromStdin();
3198        retval = issueCommand(argc+1, argv);
3199    } else {
3200        retval = issueCommand(argc, argv);
3201    }
3202    return retval;
3203}
3204
3205
3206
3207
3208
3209static int evalMode(int argc, char **argv) {
3210    sds script = 0;
3211    FILE *fp;
3212    char buf[1024];
3213    size_t nread;
3214    char **argv2;
3215    int j, got_comma, keys;
3216    int retval = 0;
3217
3218    while(1) {
3219        if (config.eval_ldb) {
3220            printf(
3221            "Lua debugging session started, please use:\n"
3222            "quit    -- End the session.\n"
3223            "restart -- Restart the script in debug mode again.\n"
3224            "help    -- Show Lua script debugging commands.\n\n"
3225            );
3226        }
3227
3228        sdsfree(script);
3229        script = sdsempty();
3230        got_comma = 0;
3231        keys = 0;
3232
3233
3234        fp = fopen(config.eval,"r");
3235        if (!fp) {
3236            fprintf(stderr,
3237                "Can't open file '%s': %s\n", config.eval, strerror(errno));
3238            exit(1);
3239        }
3240        while((nread = fread(buf,1,sizeof(buf),fp)) != 0) {
3241            script = sdscatlen(script,buf,nread);
3242        }
3243        fclose(fp);
3244
3245
3246        if (config.eval_ldb) {
3247            redisReply *reply = redisCommand(context,
3248                    config.eval_ldb_sync ?
3249                    "SCRIPT DEBUG sync": "SCRIPT DEBUG yes");
3250            if (reply) freeReplyObject(reply);
3251        }
3252
3253
3254        argv2 = zmalloc(sizeof(sds)*(argc+3));
3255        argv2[0] = sdsnew("EVAL");
3256        argv2[1] = script;
3257        for (j = 0; j < argc; j++) {
3258            if (!got_comma && argv[j][0] == ',' && argv[j][1] == 0) {
3259                got_comma = 1;
3260                continue;
3261            }
3262            argv2[j+3-got_comma] = sdsnew(argv[j]);
3263            if (!got_comma) keys++;
3264        }
3265        argv2[2] = sdscatprintf(sdsempty(),"%d",keys);
3266
3267
3268        int eval_ldb = config.eval_ldb;
3269        retval = issueCommand(argc+3-got_comma, argv2);
3270        if (eval_ldb) {
3271            if (!config.eval_ldb) {
3272
3273
3274
3275                printf("Eval debugging session can't start:\n");
3276                cliReadReply(0);
3277                break;
3278            } else {
3279                strncpy(config.prompt,"lua debugger> ",sizeof(config.prompt));
3280                repl();
3281
3282                cliConnect(1);
3283                printf("\n");
3284            }
3285        } else {
3286            break;
3287        }
3288    }
3289    return retval;
3290}
3291
3292
3293
3294
3295
3296static void latencyModePrint(long long min, long long max, double avg, long long count) {
3297    if (config.output == 0) {
3298        printf("min: %lld, max: %lld, avg: %.2f (%lld samples)",
3299                min, max, avg, count);
3300        fflush(stdout);
3301    } else if (config.output == 2) {
3302        printf("%lld,%lld,%.2f,%lld\n", min, max, avg, count);
3303    } else if (config.output == 1) {
3304        printf("%lld %lld %.2f %lld\n", min, max, avg, count);
3305    }
3306}
3307
3308
3309
3310static void latencyMode(void) {
3311    redisReply *reply;
3312    long long start, latency, min = 0, max = 0, tot = 0, count = 0;
3313    long long history_interval =
3314        config.interval ? config.interval/1000 :
3315                          15000;
3316    double avg;
3317    long long history_start = mstime();
3318
3319
3320
3321    if (config.interval == 0) {
3322        config.interval = 1000;
3323    } else {
3324        config.interval /= 1000;
3325    }
3326
3327    if (!context) exit(1);
3328    while(1) {
3329        start = mstime();
3330        reply = reconnectingRedisCommand(context,"PING");
3331        if (reply == 0) {
3332            fprintf(stderr,"\nI/O error\n");
3333            exit(1);
3334        }
3335        latency = mstime()-start;
3336        freeReplyObject(reply);
3337        count++;
3338        if (count == 1) {
3339            min = max = tot = latency;
3340            avg = (double) latency;
3341        } else {
3342            if (latency < min) min = latency;
3343            if (latency > max) max = latency;
3344            tot += latency;
3345            avg = (double) tot/count;
3346        }
3347
3348        if (config.output == 0) {
3349            printf("\x1b[0G\x1b[2K");
3350            latencyModePrint(min,max,avg,count);
3351        } else {
3352            if (config.latency_history) {
3353                latencyModePrint(min,max,avg,count);
3354            } else if (mstime()-history_start > config.interval) {
3355                latencyModePrint(min,max,avg,count);
3356                exit(0);
3357            }
3358        }
3359
3360        if (config.latency_history && mstime()-history_start > history_interval)
3361        {
3362            printf(" -- %.2f seconds range\n", (float)(mstime()-history_start)/1000);
3363            history_start = mstime();
3364            min = max = tot = count = 0;
3365        }
3366        usleep(10 * 1000);
3367    }
3368}
3369# 1657 "src/redis-cli.c"
3370struct distsamples {
3371    long long max;
3372    long long count;
3373    int character;
3374};
3375# 1674 "src/redis-cli.c"
3376void showLatencyDistSamples(struct distsamples *samples, long long tot) {
3377    int j;
3378
3379
3380
3381
3382
3383
3384    printf("\033[38;5;0m");
3385    for (j = 0; ; j++) {
3386        int coloridx =
3387            ceil((float) samples[j].count / tot * (spectrum_palette_size-1));
3388        int color = spectrum_palette[coloridx];
3389        printf("\033[48;5;%dm%c", (int)color, samples[j].character);
3390        samples[j].count = 0;
3391        if (samples[j].max == 0) break;
3392    }
3393    printf("\033[0m\n");
3394    fflush(stdout);
3395}
3396
3397
3398
3399void showLatencyDistLegend(void) {
3400    int j;
3401
3402    printf("---------------------------------------------\n");
3403    printf(". - * #          .01 .125 .25 .5 milliseconds\n");
3404    printf("1,2,3,...,9      from 1 to 9     milliseconds\n");
3405    printf("A,B,C,D,E        10,20,30,40,50  milliseconds\n");
3406    printf("F,G,H,I,J        .1,.2,.3,.4,.5       seconds\n");
3407    printf("K,L,M,N,O,P,Q,?  1,2,4,8,16,30,60,>60 seconds\n");
3408    printf("From 0 to 100%%: ");
3409    for (j = 0; j < spectrum_palette_size; j++) {
3410        printf("\033[48;5;%dm ", spectrum_palette[j]);
3411    }
3412    printf("\033[0m\n");
3413    printf("---------------------------------------------\n");
3414}
3415
3416static void latencyDistMode(void) {
3417    redisReply *reply;
3418    long long start, latency, count = 0;
3419    long long history_interval =
3420        config.interval ? config.interval/1000 :
3421                          1000;
3422    long long history_start = ustime();
3423    int j, outputs = 0;
3424
3425    struct distsamples samples[] = {
3426
3427
3428
3429        {10,0,'.'},
3430        {125,0,'-'},
3431        {250,0,'*'},
3432        {500,0,'#'},
3433        {1000,0,'1'},
3434        {2000,0,'2'},
3435        {3000,0,'3'},
3436        {4000,0,'4'},
3437        {5000,0,'5'},
3438        {6000,0,'6'},
3439        {7000,0,'7'},
3440        {8000,0,'8'},
3441        {9000,0,'9'},
3442        {10000,0,'A'},
3443        {20000,0,'B'},
3444        {30000,0,'C'},
3445        {40000,0,'D'},
3446        {50000,0,'E'},
3447        {100000,0,'F'},
3448        {200000,0,'G'},
3449        {300000,0,'H'},
3450        {400000,0,'I'},
3451        {500000,0,'J'},
3452        {1000000,0,'K'},
3453        {2000000,0,'L'},
3454        {4000000,0,'M'},
3455        {8000000,0,'N'},
3456        {16000000,0,'O'},
3457        {30000000,0,'P'},
3458        {60000000,0,'Q'},
3459        {0,0,'?'},
3460    };
3461
3462    if (!context) exit(1);
3463    while(1) {
3464        start = ustime();
3465        reply = reconnectingRedisCommand(context,"PING");
3466        if (reply == 0) {
3467            fprintf(stderr,"\nI/O error\n");
3468            exit(1);
3469        }
3470        latency = ustime()-start;
3471        freeReplyObject(reply);
3472        count++;
3473
3474
3475        for (j = 0; ; j++) {
3476            if (samples[j].max == 0 || latency <= samples[j].max) {
3477                samples[j].count++;
3478                break;
3479            }
3480        }
3481
3482
3483        if (count && (ustime()-history_start)/1000 > history_interval) {
3484            if ((outputs++ % 20) == 0)
3485                showLatencyDistLegend();
3486            showLatencyDistSamples(samples,count);
3487            history_start = ustime();
3488            count = 0;
3489        }
3490        usleep(10 * 1000);
3491    }
3492}
3493
3494
3495
3496
3497
3498
3499
3500unsigned long long sendSync(int fd) {
3501
3502
3503
3504
3505    char buf[4096], *p;
3506    ssize_t nread;
3507
3508
3509    if (write(fd,"SYNC\r\n",6) != 6) {
3510        fprintf(stderr,"Error writing to master\n");
3511        exit(1);
3512    }
3513
3514
3515    p = buf;
3516    while(1) {
3517        nread = read(fd,p,1);
3518        if (nread <= 0) {
3519            fprintf(stderr,"Error reading bulk length while SYNCing\n");
3520            exit(1);
3521        }
3522        if (*p == '\n' && p != buf) break;
3523        if (*p != '\n') p++;
3524    }
3525    *p = '\0';
3526    if (buf[0] == '-') {
3527        printf("SYNC with master failed: %s\n", buf);
3528        exit(1);
3529    }
3530    return strtoull(buf+1,0,10);
3531}
3532
3533static void slaveMode(void) {
3534    int fd = context->fd;
3535    unsigned long long payload = sendSync(fd);
3536    char buf[1024];
3537    int original_output = config.output;
3538
3539    fprintf(stderr,"SYNC with master, discarding %llu "
3540                   "bytes of bulk transfer...\n", payload);
3541
3542
3543    while(payload) {
3544        ssize_t nread;
3545
3546        nread = read(fd,buf,(payload > sizeof(buf)) ? sizeof(buf) : payload);
3547        if (nread <= 0) {
3548            fprintf(stderr,"Error reading RDB payload while SYNCing\n");
3549            exit(1);
3550        }
3551        payload -= nread;
3552    }
3553    fprintf(stderr,"SYNC done. Logging commands from master.\n");
3554
3555
3556    config.output = 2;
3557    while (cliReadReply(0) == 0);
3558    config.output = original_output;
3559}
3560
3561
3562
3563
3564
3565
3566
3567static void getRDB(void) {
3568    int s = context->fd;
3569    int fd;
3570    unsigned long long payload = sendSync(s);
3571    char buf[4096];
3572
3573    fprintf(stderr,"SYNC sent to master, writing %llu bytes to '%s'\n",
3574        payload, config.rdb_filename);
3575
3576
3577    if (!strcmp(config.rdb_filename,"-")) {
3578        fd = STDOUT_FILENO;
3579    } else {
3580        fd = open(config.rdb_filename, O_CREAT|O_WRONLY, 0644);
3581        if (fd == -1) {
3582            fprintf(stderr, "Error opening '%s': %s\n", config.rdb_filename,
3583                strerror(errno));
3584            exit(1);
3585        }
3586    }
3587
3588    while(payload) {
3589        ssize_t nread, nwritten;
3590
3591        nread = read(s,buf,(payload > sizeof(buf)) ? sizeof(buf) : payload);
3592        if (nread <= 0) {
3593            fprintf(stderr,"I/O Error reading RDB payload from socket\n");
3594            exit(1);
3595        }
3596        nwritten = write(fd, buf, nread);
3597        if (nwritten != nread) {
3598            fprintf(stderr,"Error writing data to file: %s\n",
3599                strerror(errno));
3600            exit(1);
3601        }
3602        payload -= nread;
3603    }
3604    close(s);
3605    fsync(fd);
3606    fprintf(stderr,"Transfer finished with success.\n");
3607    exit(0);
3608}
3609
3610
3611
3612
3613
3614
3615static void pipeMode(void) {
3616    int fd = context->fd;
3617    long long errors = 0, replies = 0, obuf_len = 0, obuf_pos = 0;
3618    char ibuf[1024*16], obuf[1024*16];
3619    char aneterr[256];
3620    redisReader *reader = redisReaderCreate();
3621    redisReply *reply;
3622    int eof = 0;
3623    int done = 0;
3624    char magic[20];
3625    time_t last_read_time = time(0);
3626
3627    srand(time(0));
3628
3629
3630    if (anetNonBlock(aneterr,fd) == -1) {
3631        fprintf(stderr, "Can't set the socket in non blocking mode: %s\n",
3632            aneterr);
3633        exit(1);
3634    }
3635
3636
3637
3638    while(!done) {
3639        int mask = 1;
3640
3641        if (!eof || obuf_len != 0) mask |= 2;
3642        mask = aeWait(fd,mask,1000);
3643
3644
3645        if (mask & 1) {
3646            ssize_t nread;
3647
3648
3649            do {
3650                nread = read(fd,ibuf,sizeof(ibuf));
3651                if (nread == -1 && errno != EAGAIN && errno != EINTR) {
3652                    fprintf(stderr, "Error reading from the server: %s\n",
3653                        strerror(errno));
3654                    exit(1);
3655                }
3656                if (nread > 0) {
3657                    redisReaderFeed(reader,ibuf,nread);
3658                    last_read_time = time(0);
3659                }
3660            } while(nread > 0);
3661
3662
3663            do {
3664                if (redisReaderGetReply(reader,(void**)&reply) == -1) {
3665                    fprintf(stderr, "Error reading replies from server\n");
3666                    exit(1);
3667                }
3668                if (reply) {
3669                    if (reply->type == 6) {
3670                        fprintf(stderr,"%s\n", reply->str);
3671                        errors++;
3672                    } else if (eof && reply->type == 1 &&
3673                                      reply->len == 20) {
3674
3675
3676
3677                        if (memcmp(reply->str,magic,20) == 0) {
3678                            printf("Last reply received from server.\n");
3679                            done = 1;
3680                            replies--;
3681                        }
3682                    }
3683                    replies++;
3684                    freeReplyObject(reply);
3685                }
3686            } while(reply);
3687        }
3688
3689
3690        if (mask & 2) {
3691            ssize_t loop_nwritten = 0;
3692
3693            while(1) {
3694
3695                if (obuf_len != 0) {
3696                    ssize_t nwritten = write(fd,obuf+obuf_pos,obuf_len);
3697
3698                    if (nwritten == -1) {
3699                        if (errno != EAGAIN && errno != EINTR) {
3700                            fprintf(stderr, "Error writing to the server: %s\n",
3701                                strerror(errno));
3702                            exit(1);
3703                        } else {
3704                            nwritten = 0;
3705                        }
3706                    }
3707                    obuf_len -= nwritten;
3708                    obuf_pos += nwritten;
3709                    loop_nwritten += nwritten;
3710                    if (obuf_len != 0) break;
3711                }
3712
3713                if (obuf_len == 0 && !eof) {
3714                    ssize_t nread = read(STDIN_FILENO,obuf,sizeof(obuf));
3715
3716                    if (nread == 0) {
3717
3718
3719
3720
3721                        char echo[] =
3722                        "\r\n*2\r\n$4\r\nECHO\r\n$20\r\n01234567890123456789\r\n";
3723                        int j;
3724
3725                        eof = 1;
3726
3727
3728
3729                        for (j = 0; j < 20; j++)
3730                            magic[j] = rand() & 0xff;
3731                        memcpy(echo+21,magic,20);
3732                        memcpy(obuf,echo,sizeof(echo)-1);
3733                        obuf_len = sizeof(echo)-1;
3734                        obuf_pos = 0;
3735                        printf("All data transferred. Waiting for the last reply...\n");
3736                    } else if (nread == -1) {
3737                        fprintf(stderr, "Error reading from stdin: %s\n",
3738                            strerror(errno));
3739                        exit(1);
3740                    } else {
3741                        obuf_len = nread;
3742                        obuf_pos = 0;
3743                    }
3744                }
3745                if ((obuf_len == 0 && eof) ||
3746                    loop_nwritten > (128*1024)) break;
3747            }
3748        }
3749
3750
3751
3752
3753        if (eof && config.pipe_timeout > 0 &&
3754            time(0)-last_read_time > config.pipe_timeout)
3755        {
3756            fprintf(stderr,"No replies for %d seconds: exiting.\n",
3757                config.pipe_timeout);
3758            errors++;
3759            break;
3760        }
3761    }
3762    redisReaderFree(reader);
3763    printf("errors: %lld, replies: %lld\n", errors, replies);
3764    if (errors)
3765        exit(1);
3766    else
3767        exit(0);
3768}
3769# 2079 "src/redis-cli.c"
3770static redisReply *sendScan(unsigned long long *it) {
3771    redisReply *reply = redisCommand(context, "SCAN %llu", *it);
3772
3773
3774    if(reply == 0) {
3775        fprintf(stderr, "\nI/O error\n");
3776        exit(1);
3777    } else if(reply->type == 6) {
3778        fprintf(stderr, "SCAN error: %s\n", reply->str);
3779        exit(1);
3780    } else if(reply->type != 2) {
3781        fprintf(stderr, "Non ARRAY response from SCAN!\n");
3782        exit(1);
3783    } else if(reply->elements != 2) {
3784        fprintf(stderr, "Invalid element count from SCAN!\n");
3785        exit(1);
3786    }
3787
3788
3789    assert(reply->element[0]->type == 1);
3790    assert(reply->element[1]->type == 2);
3791
3792
3793    *it = strtoull(reply->element[0]->str, 0, 10);
3794
3795    return reply;
3796}
3797
3798static int getDbSize(void) {
3799    redisReply *reply;
3800    int size;
3801
3802    reply = redisCommand(context, "DBSIZE");
3803
3804    if(reply == 0 || reply->type != 3) {
3805        fprintf(stderr, "Couldn't determine DBSIZE!\n");
3806        exit(1);
3807    }
3808
3809
3810    size = reply->integer;
3811    freeReplyObject(reply);
3812
3813    return size;
3814}
3815
3816static int toIntType(char *key, char *type) {
3817    if(!strcmp(type, "string")) {
3818        return 0;
3819    } else if(!strcmp(type, "list")) {
3820        return 1;
3821    } else if(!strcmp(type, "set")) {
3822        return 2;
3823    } else if(!strcmp(type, "hash")) {
3824        return 3;
3825    } else if(!strcmp(type, "zset")) {
3826        return 4;
3827    } else if(!strcmp(type, "none")) {
3828        return 5;
3829    } else {
3830        fprintf(stderr, "Unknown type '%s' for key '%s'\n", type, key);
3831        exit(1);
3832    }
3833}
3834
3835static void getKeyTypes(redisReply *keys, int *types) {
3836    redisReply *reply;
3837    unsigned int i;
3838
3839
3840    for(i=0;i<keys->elements;i++) {
3841        redisAppendCommand(context, "TYPE %s", keys->element[i]->str);
3842    }
3843
3844
3845    for(i=0;i<keys->elements;i++) {
3846        if(redisGetReply(context, (void**)&reply)!=0) {
3847            fprintf(stderr, "Error getting type for key '%s' (%d: %s)\n",
3848                keys->element[i]->str, context->err, context->errstr);
3849            exit(1);
3850        } else if(reply->type != 5) {
3851            if(reply->type == 6) {
3852                fprintf(stderr, "TYPE returned an error: %s\n", reply->str);
3853            } else {
3854                fprintf(stderr,
3855                    "Invalid reply type (%d) for TYPE on key '%s'!\n",
3856                    reply->type, keys->element[i]->str);
3857            }
3858            exit(1);
3859        }
3860
3861        types[i] = toIntType(keys->element[i]->str, reply->str);
3862        freeReplyObject(reply);
3863    }
3864}
3865
3866static void getKeySizes(redisReply *keys, int *types,
3867                        unsigned long long *sizes)
3868{
3869    redisReply *reply;
3870    char *sizecmds[] = {"STRLEN","LLEN","SCARD","HLEN","ZCARD"};
3871    unsigned int i;
3872
3873
3874    for(i=0;i<keys->elements;i++) {
3875
3876        if(types[i]==5)
3877            continue;
3878
3879        redisAppendCommand(context, "%s %s", sizecmds[types[i]],
3880            keys->element[i]->str);
3881    }
3882
3883
3884    for(i=0;i<keys->elements;i++) {
3885
3886        if(types[i] == 5) {
3887            sizes[i] = 0;
3888            continue;
3889        }
3890
3891
3892        if(redisGetReply(context, (void**)&reply)!=0) {
3893            fprintf(stderr, "Error getting size for key '%s' (%d: %s)\n",
3894                keys->element[i]->str, context->err, context->errstr);
3895            exit(1);
3896        } else if(reply->type != 3) {
3897
3898
3899            fprintf(stderr,
3900                "Warning:  %s on '%s' failed (may have changed type)\n",
3901                 sizecmds[types[i]], keys->element[i]->str);
3902            sizes[i] = 0;
3903        } else {
3904            sizes[i] = reply->integer;
3905        }
3906
3907        freeReplyObject(reply);
3908    }
3909}
3910
3911static void findBigKeys(void) {
3912    unsigned long long biggest[5] = {0}, counts[5] = {0}, totalsize[5] = {0};
3913    unsigned long long sampled = 0, total_keys, totlen=0, *sizes=0, it=0;
3914    sds maxkeys[5] = {0};
3915    char *typename[] = {"string","list","set","hash","zset"};
3916    char *typeunit[] = {"bytes","items","members","fields","members"};
3917    redisReply *reply, *keys;
3918    unsigned int arrsize=0, i;
3919    int type, *types=0;
3920    double pct;
3921
3922
3923    total_keys = getDbSize();
3924
3925
3926    printf("\n# Scanning the entire keyspace to find biggest keys as well as\n");
3927    printf("# average sizes per key type.  You can use -i 0.1 to sleep 0.1 sec\n");
3928    printf("# per 100 SCAN commands (not usually needed).\n\n");
3929
3930
3931    for(i=0;i<5; i++) {
3932        maxkeys[i] = sdsempty();
3933        if(!maxkeys[i]) {
3934            fprintf(stderr, "Failed to allocate memory for largest key names!\n");
3935            exit(1);
3936        }
3937    }
3938
3939
3940    do {
3941
3942        pct = 100 * (double)sampled/total_keys;
3943
3944
3945        reply = sendScan(&it);
3946        keys = reply->element[1];
3947
3948
3949        if(keys->elements > arrsize) {
3950            types = zrealloc(types, sizeof(int)*keys->elements);
3951            sizes = zrealloc(sizes, sizeof(unsigned long long)*keys->elements);
3952
3953            if(!types || !sizes) {
3954                fprintf(stderr, "Failed to allocate storage for keys!\n");
3955                exit(1);
3956            }
3957
3958            arrsize = keys->elements;
3959        }
3960
3961
3962        getKeyTypes(keys, types);
3963        getKeySizes(keys, types, sizes);
3964
3965
3966        for(i=0;i<keys->elements;i++) {
3967            if((type = types[i]) == 5)
3968                continue;
3969
3970            totalsize[type] += sizes[i];
3971            counts[type]++;
3972            totlen += keys->element[i]->len;
3973            sampled++;
3974
3975            if(biggest[type]<sizes[i]) {
3976                printf(
3977                   "[%05.2f%%] Biggest %-6s found so far '%s' with %llu %s\n",
3978                   pct, typename[type], keys->element[i]->str, sizes[i],
3979                   typeunit[type]);
3980
3981
3982                maxkeys[type] = sdscpy(maxkeys[type], keys->element[i]->str);
3983                if(!maxkeys[type]) {
3984                    fprintf(stderr, "Failed to allocate memory for key!\n");
3985                    exit(1);
3986                }
3987
3988
3989                biggest[type] = sizes[i];
3990            }
3991
3992
3993            if(sampled % 1000000 == 0) {
3994                printf("[%05.2f%%] Sampled %llu keys so far\n", pct, sampled);
3995            }
3996        }
3997
3998
3999        if(sampled && (sampled %100) == 0 && config.interval) {
4000            usleep(config.interval);
4001        }
4002
4003        freeReplyObject(reply);
4004    } while(it != 0);
4005
4006    if(types) zfree(types);
4007    if(sizes) zfree(sizes);
4008
4009
4010    printf("\n-------- summary -------\n\n");
4011
4012    printf("Sampled %llu keys in the keyspace!\n", sampled);
4013    printf("Total key length in bytes is %llu (avg len %.2f)\n\n",
4014       totlen, totlen ? (double)totlen/sampled : 0);
4015
4016
4017    for(i=0;i<5;i++) {
4018        if(sdslen(maxkeys[i])>0) {
4019            printf("Biggest %6s found '%s' has %llu %s\n", typename[i], maxkeys[i],
4020               biggest[i], typeunit[i]);
4021        }
4022    }
4023
4024    printf("\n");
4025
4026    for(i=0;i<5;i++) {
4027        printf("%llu %ss with %llu %s (%05.2f%% of keys, avg size %.2f)\n",
4028           counts[i], typename[i], totalsize[i], typeunit[i],
4029           sampled ? 100 * (double)counts[i]/sampled : 0,
4030           counts[i] ? (double)totalsize[i]/counts[i] : 0);
4031    }
4032
4033
4034    for(i=0;i<5;i++) {
4035        sdsfree(maxkeys[i]);
4036    }
4037
4038
4039    exit(0);
4040}
4041
4042static void getKeyFreqs(redisReply *keys, unsigned long long *freqs) {
4043    redisReply *reply;
4044    unsigned int i;
4045
4046
4047    for(i=0;i<keys->elements;i++) {
4048        redisAppendCommand(context, "OBJECT freq %s", keys->element[i]->str);
4049    }
4050
4051
4052    for(i=0;i<keys->elements;i++) {
4053        if(redisGetReply(context, (void**)&reply)!=0) {
4054            fprintf(stderr, "Error getting freq for key '%s' (%d: %s)\n",
4055                keys->element[i]->str, context->err, context->errstr);
4056            exit(1);
4057        } else if(reply->type != 3) {
4058            if(reply->type == 6) {
4059                fprintf(stderr, "Error: %s\n", reply->str);
4060                exit(1);
4061            } else {
4062                fprintf(stderr, "Warning: OBJECT freq on '%s' failed (may have been deleted)\n", keys->element[i]->str);
4063                freqs[i] = 0;
4064            }
4065        } else {
4066            freqs[i] = reply->integer;
4067        }
4068        freeReplyObject(reply);
4069    }
4070}
4071
4072
4073static void findHotKeys(void) {
4074    redisReply *keys, *reply;
4075    unsigned long long counters[16] = {0};
4076    sds hotkeys[16] = {0};
4077    unsigned long long sampled = 0, total_keys, *freqs = 0, it = 0;
4078    unsigned int arrsize = 0, i, k;
4079    double pct;
4080
4081
4082    total_keys = getDbSize();
4083
4084
4085    printf("\n# Scanning the entire keyspace to find hot keys as well as\n");
4086    printf("# average sizes per key type.  You can use -i 0.1 to sleep 0.1 sec\n");
4087    printf("# per 100 SCAN commands (not usually needed).\n\n");
4088
4089
4090    do {
4091
4092        pct = 100 * (double)sampled/total_keys;
4093
4094
4095        reply = sendScan(&it);
4096        keys = reply->element[1];
4097
4098
4099        if(keys->elements > arrsize) {
4100            freqs = zrealloc(freqs, sizeof(unsigned long long)*keys->elements);
4101
4102            if(!freqs) {
4103                fprintf(stderr, "Failed to allocate storage for keys!\n");
4104                exit(1);
4105            }
4106
4107            arrsize = keys->elements;
4108        }
4109
4110        getKeyFreqs(keys, freqs);
4111
4112
4113        for(i=0;i<keys->elements;i++) {
4114            sampled++;
4115
4116            if(sampled % 1000000 == 0) {
4117                printf("[%05.2f%%] Sampled %llu keys so far\n", pct, sampled);
4118            }
4119
4120
4121            k = 0;
4122            while (k < 16 && freqs[i] > counters[k]) k++;
4123            if (k == 0) continue;
4124            k--;
4125            if (k == 0 || counters[k] == 0) {
4126                sdsfree(hotkeys[k]);
4127            } else {
4128                sdsfree(hotkeys[0]);
4129                memmove(counters,counters+1,sizeof(counters[0])*k);
4130                memmove(hotkeys,hotkeys+1,sizeof(hotkeys[0])*k);
4131            }
4132            counters[k] = freqs[i];
4133            hotkeys[k] = sdsnew(keys->element[i]->str);
4134            printf(
4135               "[%05.2f%%] Hot key '%s' found so far with counter %llu\n",
4136               pct, keys->element[i]->str, freqs[i]);
4137        }
4138
4139
4140        if(sampled && (sampled %100) == 0 && config.interval) {
4141            usleep(config.interval);
4142        }
4143
4144        freeReplyObject(reply);
4145    } while(it != 0);
4146
4147    if (freqs) zfree(freqs);
4148
4149
4150    printf("\n-------- summary -------\n\n");
4151
4152    printf("Sampled %llu keys in the keyspace!\n", sampled);
4153
4154    for (i=1; i<= 16; i++) {
4155        k = 16 - i;
4156        if(counters[k]>0) {
4157            printf("hot key found with counter: %llu\tkeyname: %s\n", counters[k], hotkeys[k]);
4158            sdsfree(hotkeys[k]);
4159        }
4160    }
4161
4162    exit(0);
4163}
4164# 2481 "src/redis-cli.c"
4165static char *getInfoField(char *info, char *field) {
4166    char *p = strstr(info,field);
4167    char *n1, *n2;
4168    char *result;
4169
4170    if (!p) return 0;
4171    p += strlen(field)+1;
4172    n1 = strchr(p,'\r');
4173    n2 = strchr(p,',');
4174    if (n2 && n2 < n1) n1 = n2;
4175    result = zmalloc(sizeof(char)*(n1-p)+1);
4176    memcpy(result,p,(n1-p));
4177    result[n1-p] = '\0';
4178    return result;
4179}
4180
4181
4182
4183static long getLongInfoField(char *info, char *field) {
4184    char *value = getInfoField(info,field);
4185    long l;
4186
4187    if (!value) return LONG_MIN;
4188    l = strtol(value,0,10);
4189    zfree(value);
4190    return l;
4191}
4192
4193
4194
4195void bytesToHuman(char *s, long long n) {
4196    double d;
4197
4198    if (n < 0) {
4199        *s = '-';
4200        s++;
4201        n = -n;
4202    }
4203    if (n < 1024) {
4204
4205        sprintf(s,"%lldB",n);
4206        return;
4207    } else if (n < (1024*1024)) {
4208        d = (double)n/(1024);
4209        sprintf(s,"%.2fK",d);
4210    } else if (n < (1024LL*1024*1024)) {
4211        d = (double)n/(1024*1024);
4212        sprintf(s,"%.2fM",d);
4213    } else if (n < (1024LL*1024*1024*1024)) {
4214        d = (double)n/(1024LL*1024*1024);
4215        sprintf(s,"%.2fG",d);
4216    }
4217}
4218
4219static void statMode(void) {
4220    redisReply *reply;
4221    long aux, requests = 0;
4222    int i = 0;
4223
4224    while(1) {
4225        char buf[64];
4226        int j;
4227
4228        reply = reconnectingRedisCommand(context,"INFO");
4229        if (reply->type == 6) {
4230            printf("ERROR: %s\n", reply->str);
4231            exit(1);
4232        }
4233
4234        if ((i++ % 20) == 0) {
4235            printf(
4236"------- data ------ --------------------- load -------------------- - child -\n"
4237"keys       mem      clients blocked requests            connections          \n");
4238        }
4239
4240
4241        aux = 0;
4242        for (j = 0; j < 20; j++) {
4243            long k;
4244
4245            sprintf(buf,"db%d:keys",j);
4246            k = getLongInfoField(reply->str,buf);
4247            if (k == LONG_MIN) continue;
4248            aux += k;
4249        }
4250        sprintf(buf,"%ld",aux);
4251        printf("%-11s",buf);
4252
4253
4254        aux = getLongInfoField(reply->str,"used_memory");
4255        bytesToHuman(buf,aux);
4256        printf("%-8s",buf);
4257
4258
4259        aux = getLongInfoField(reply->str,"connected_clients");
4260        sprintf(buf,"%ld",aux);
4261        printf(" %-8s",buf);
4262
4263
4264        aux = getLongInfoField(reply->str,"blocked_clients");
4265        sprintf(buf,"%ld",aux);
4266        printf("%-8s",buf);
4267
4268
4269        aux = getLongInfoField(reply->str,"total_commands_processed");
4270        sprintf(buf,"%ld (+%ld)",aux,requests == 0 ? 0 : aux-requests);
4271        printf("%-19s",buf);
4272        requests = aux;
4273
4274
4275        aux = getLongInfoField(reply->str,"total_connections_received");
4276        sprintf(buf,"%ld",aux);
4277        printf(" %-12s",buf);
4278
4279
4280        aux = getLongInfoField(reply->str,"bgsave_in_progress");
4281        aux |= getLongInfoField(reply->str,"aof_rewrite_in_progress") << 1;
4282        aux |= getLongInfoField(reply->str,"loading") << 2;
4283        switch(aux) {
4284        case 0: break;
4285        case 1:
4286            printf("SAVE");
4287            break;
4288        case 2:
4289            printf("AOF");
4290            break;
4291        case 3:
4292            printf("SAVE+AOF");
4293            break;
4294        case 4:
4295            printf("LOAD");
4296            break;
4297        }
4298
4299        printf("\n");
4300        freeReplyObject(reply);
4301        usleep(config.interval);
4302    }
4303}
4304
4305
4306
4307
4308
4309static void scanMode(void) {
4310    redisReply *reply;
4311    unsigned long long cur = 0;
4312
4313    do {
4314        if (config.pattern)
4315            reply = redisCommand(context,"SCAN %llu MATCH %s",
4316                cur,config.pattern);
4317        else
4318            reply = redisCommand(context,"SCAN %llu",cur);
4319        if (reply == 0) {
4320            printf("I/O error\n");
4321            exit(1);
4322        } else if (reply->type == 6) {
4323            printf("ERROR: %s\n", reply->str);
4324            exit(1);
4325        } else {
4326            unsigned int j;
4327
4328            cur = strtoull(reply->element[0]->str,0,10);
4329            for (j = 0; j < reply->element[1]->elements; j++)
4330                printf("%s\n", reply->element[1]->element[j]->str);
4331        }
4332        freeReplyObject(reply);
4333    } while(cur != 0);
4334
4335    exit(0);
4336}
4337# 2664 "src/redis-cli.c"
4338long long powerLawRand(long long min, long long max, double alpha) {
4339    double pl, r;
4340
4341    max += 1;
4342    r = ((double)rand()) / 32767;
4343    pl = pow(
4344        ((pow(max,alpha+1) - pow(min,alpha+1))*r + pow(min,alpha+1)),
4345        (1.0/(alpha+1)));
4346    return (max-1-(long long)pl)+min;
4347}
4348
4349
4350
4351void LRUTestGenKey(char *buf, size_t buflen) {
4352    snprintf(buf, buflen, "lru:%lld",
4353        powerLawRand(1, config.lru_test_sample_size, 6.2));
4354}
4355
4356
4357
4358static void LRUTestMode(void) {
4359    redisReply *reply;
4360    char key[128];
4361    long long start_cycle;
4362    int j;
4363
4364    srand(time(0)^getpid());
4365    while(1) {
4366
4367
4368
4369        start_cycle = mstime();
4370        long long hits = 0, misses = 0;
4371        while(mstime() - start_cycle < 1000) {
4372
4373            for (j = 0; j < 250; j++) {
4374                char val[6];
4375                val[5] = '\0';
4376                for (int i = 0; i < 5; i++) val[i] = 'A'+rand()%('z'-'A');
4377                LRUTestGenKey(key,sizeof(key));
4378                redisAppendCommand(context, "SET %s %s",key,val);
4379            }
4380            for (j = 0; j < 250; j++)
4381                redisGetReply(context, (void**)&reply);
4382
4383
4384            for (j = 0; j < 250; j++) {
4385                LRUTestGenKey(key,sizeof(key));
4386                redisAppendCommand(context, "GET %s",key);
4387            }
4388            for (j = 0; j < 250; j++) {
4389                if (redisGetReply(context, (void**)&reply) == 0) {
4390                    switch(reply->type) {
4391                        case 6:
4392                            printf("%s\n", reply->str);
4393                            break;
4394                        case 4:
4395                            misses++;
4396                            break;
4397                        default:
4398                            hits++;
4399                            break;
4400                    }
4401                }
4402            }
4403
4404            if (context->err) {
4405                fprintf(stderr,"I/O error during LRU test\n");
4406                exit(1);
4407            }
4408        }
4409
4410        printf(
4411            "%lld Gets/sec | Hits: %lld (%.2f%%) | Misses: %lld (%.2f%%)\n",
4412            hits+misses,
4413            hits, (double)hits/(hits+misses)*100,
4414            misses, (double)misses/(hits+misses)*100);
4415    }
4416    exit(0);
4417}
4418# 2756 "src/redis-cli.c"
4419unsigned long compute_something_fast(void) {
4420    unsigned char s[256], i, j, t;
4421    int count = 1000, k;
4422    unsigned long output = 0;
4423
4424    for (k = 0; k < 256; k++) s[k] = k;
4425
4426    i = 0;
4427    j = 0;
4428    while(count--) {
4429        i++;
4430        j = j + s[i];
4431        t = s[i];
4432        s[i] = s[j];
4433        s[j] = t;
4434        output += s[(s[i]+s[j])&255];
4435    }
4436    return output;
4437}
4438
4439static void intrinsicLatencyModeStop(int s) {
4440    ((void) s);
4441    force_cancel_loop = 1;
4442}
4443
4444static void intrinsicLatencyMode(void) {
4445    long long test_end, run_time, max_latency = 0, runs = 0;
4446
4447    run_time = config.intrinsic_latency_duration*1000000;
4448    test_end = ustime() + run_time;
4449    signal(SIGINT, intrinsicLatencyModeStop);
4450
4451    while(1) {
4452        long long start, end, latency;
4453
4454        start = ustime();
4455        compute_something_fast();
4456        end = ustime();
4457        latency = end-start;
4458        runs++;
4459        if (latency <= 0) continue;
4460
4461
4462        if (latency > max_latency) {
4463            max_latency = latency;
4464            printf("Max latency so far: %lld microseconds.\n", max_latency);
4465        }
4466
4467        double avg_us = (double)run_time/runs;
4468        double avg_ns = avg_us * 1e3;
4469        if (force_cancel_loop || end > test_end) {
4470            printf("\n%lld total runs "
4471                "(avg latency: "
4472                "%.4f microseconds / %.2f nanoseconds per run).\n",
4473                runs, avg_us, avg_ns);
4474            printf("Worst run took %.0fx longer than the average latency.\n",
4475                max_latency / avg_us);
4476            exit(0);
4477        }
4478    }
4479}
4480
4481
4482
4483
4484
4485int main(int argc, char **argv) {
4486    int firstarg;
4487
4488    config.hostip = sdsnew("127.0.0.1");
4489    config.hostport = 6379;
4490    config.hostsocket = 0;
4491    config.repeat = 1;
4492    config.interval = 0;
4493    config.dbnum = 0;
4494    config.interactive = 0;
4495    config.shutdown = 0;
4496    config.monitor_mode = 0;
4497    config.pubsub_mode = 0;
4498    config.latency_mode = 0;
4499    config.latency_dist_mode = 0;
4500    config.latency_history = 0;
4501    config.lru_test_mode = 0;
4502    config.lru_test_sample_size = 0;
4503    config.cluster_mode = 0;
4504    config.slave_mode = 0;
4505    config.getrdb_mode = 0;
4506    config.stat_mode = 0;
4507    config.scan_mode = 0;
4508    config.intrinsic_latency_mode = 0;
4509    config.pattern = 0;
4510    config.rdb_filename = 0;
4511    config.pipe_mode = 0;
4512    config.pipe_timeout = 30;
4513    config.bigkeys = 0;
4514    config.hotkeys = 0;
4515    config.stdinarg = 0;
4516    config.auth = 0;
4517    config.eval = 0;
4518    config.eval_ldb = 0;
4519    config.eval_ldb_end = 0;
4520    config.eval_ldb_sync = 0;
4521    config.enable_ldb_on_eval = 0;
4522    config.last_cmd_type = -1;
4523
4524    pref.hints = 1;
4525
4526    spectrum_palette = spectrum_palette_color;
4527    spectrum_palette_size = spectrum_palette_color_size;
4528
4529    if (!isatty(fileno(stdout)) && (getenv("FAKETTY") == 0))
4530        config.output = 1;
4531    else
4532        config.output = 0;
4533    config.mb_delim = sdsnew("\n");
4534
4535    firstarg = parseOptions(argc,argv);
4536    argc -= firstarg;
4537    argv += firstarg;
4538
4539
4540    if (config.latency_mode) {
4541        if (cliConnect(0) == -1) exit(1);
4542        latencyMode();
4543    }
4544
4545
4546    if (config.latency_dist_mode) {
4547        if (cliConnect(0) == -1) exit(1);
4548        latencyDistMode();
4549    }
4550
4551
4552    if (config.slave_mode) {
4553        if (cliConnect(0) == -1) exit(1);
4554        slaveMode();
4555    }
4556
4557
4558    if (config.getrdb_mode) {
4559        if (cliConnect(0) == -1) exit(1);
4560        getRDB();
4561    }
4562
4563
4564    if (config.pipe_mode) {
4565        if (cliConnect(0) == -1) exit(1);
4566        pipeMode();
4567    }
4568
4569
4570    if (config.bigkeys) {
4571        if (cliConnect(0) == -1) exit(1);
4572        findBigKeys();
4573    }
4574
4575
4576    if (config.hotkeys) {
4577        if (cliConnect(0) == -1) exit(1);
4578        findHotKeys();
4579    }
4580
4581
4582    if (config.stat_mode) {
4583        if (cliConnect(0) == -1) exit(1);
4584        if (config.interval == 0) config.interval = 1000000;
4585        statMode();
4586    }
4587
4588
4589    if (config.scan_mode) {
4590        if (cliConnect(0) == -1) exit(1);
4591        scanMode();
4592    }
4593
4594
4595    if (config.lru_test_mode) {
4596        if (cliConnect(0) == -1) exit(1);
4597        LRUTestMode();
4598    }
4599
4600
4601    if (config.intrinsic_latency_mode) intrinsicLatencyMode();
4602
4603
4604    if (argc == 0 && !config.eval) {
4605
4606        signal(SIGPIPE, SIG_IGN);
4607
4608
4609
4610        cliConnect(0);
4611        repl();
4612    }
4613
4614
4615    if (cliConnect(0) != 0) exit(1);
4616    if (config.eval) {
4617        return evalMode(argc,argv);
4618    } else {
4619        return noninteractive(argc,convertToSds(argc,argv));
4620    }
4621}
4622