xref: /f-stack/app/redis-5.0.5/src/scripting.c (revision 572c4311)
1*572c4311Sfengbojiang /*
2*572c4311Sfengbojiang  * Copyright (c) 2009-2012, Salvatore Sanfilippo <antirez at gmail dot com>
3*572c4311Sfengbojiang  * All rights reserved.
4*572c4311Sfengbojiang  *
5*572c4311Sfengbojiang  * Redistribution and use in source and binary forms, with or without
6*572c4311Sfengbojiang  * modification, are permitted provided that the following conditions are met:
7*572c4311Sfengbojiang  *
8*572c4311Sfengbojiang  *   * Redistributions of source code must retain the above copyright notice,
9*572c4311Sfengbojiang  *     this list of conditions and the following disclaimer.
10*572c4311Sfengbojiang  *   * Redistributions in binary form must reproduce the above copyright
11*572c4311Sfengbojiang  *     notice, this list of conditions and the following disclaimer in the
12*572c4311Sfengbojiang  *     documentation and/or other materials provided with the distribution.
13*572c4311Sfengbojiang  *   * Neither the name of Redis nor the names of its contributors may be used
14*572c4311Sfengbojiang  *     to endorse or promote products derived from this software without
15*572c4311Sfengbojiang  *     specific prior written permission.
16*572c4311Sfengbojiang  *
17*572c4311Sfengbojiang  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18*572c4311Sfengbojiang  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19*572c4311Sfengbojiang  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20*572c4311Sfengbojiang  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21*572c4311Sfengbojiang  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22*572c4311Sfengbojiang  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23*572c4311Sfengbojiang  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24*572c4311Sfengbojiang  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25*572c4311Sfengbojiang  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26*572c4311Sfengbojiang  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27*572c4311Sfengbojiang  * POSSIBILITY OF SUCH DAMAGE.
28*572c4311Sfengbojiang  */
29*572c4311Sfengbojiang 
30*572c4311Sfengbojiang #include "server.h"
31*572c4311Sfengbojiang #include "sha1.h"
32*572c4311Sfengbojiang #include "rand.h"
33*572c4311Sfengbojiang #include "cluster.h"
34*572c4311Sfengbojiang 
35*572c4311Sfengbojiang #include <lua.h>
36*572c4311Sfengbojiang #include <lauxlib.h>
37*572c4311Sfengbojiang #include <lualib.h>
38*572c4311Sfengbojiang #include <ctype.h>
39*572c4311Sfengbojiang #include <math.h>
40*572c4311Sfengbojiang 
41*572c4311Sfengbojiang char *redisProtocolToLuaType_Int(lua_State *lua, char *reply);
42*572c4311Sfengbojiang char *redisProtocolToLuaType_Bulk(lua_State *lua, char *reply);
43*572c4311Sfengbojiang char *redisProtocolToLuaType_Status(lua_State *lua, char *reply);
44*572c4311Sfengbojiang char *redisProtocolToLuaType_Error(lua_State *lua, char *reply);
45*572c4311Sfengbojiang char *redisProtocolToLuaType_MultiBulk(lua_State *lua, char *reply);
46*572c4311Sfengbojiang int redis_math_random (lua_State *L);
47*572c4311Sfengbojiang int redis_math_randomseed (lua_State *L);
48*572c4311Sfengbojiang void ldbInit(void);
49*572c4311Sfengbojiang void ldbDisable(client *c);
50*572c4311Sfengbojiang void ldbEnable(client *c);
51*572c4311Sfengbojiang void evalGenericCommandWithDebugging(client *c, int evalsha);
52*572c4311Sfengbojiang void luaLdbLineHook(lua_State *lua, lua_Debug *ar);
53*572c4311Sfengbojiang void ldbLog(sds entry);
54*572c4311Sfengbojiang void ldbLogRedisReply(char *reply);
55*572c4311Sfengbojiang sds ldbCatStackValue(sds s, lua_State *lua, int idx);
56*572c4311Sfengbojiang 
57*572c4311Sfengbojiang /* Debugger shared state is stored inside this global structure. */
58*572c4311Sfengbojiang #define LDB_BREAKPOINTS_MAX 64  /* Max number of breakpoints. */
59*572c4311Sfengbojiang #define LDB_MAX_LEN_DEFAULT 256 /* Default len limit for replies / var dumps. */
60*572c4311Sfengbojiang struct ldbState {
61*572c4311Sfengbojiang     int fd;     /* Socket of the debugging client. */
62*572c4311Sfengbojiang     int active; /* Are we debugging EVAL right now? */
63*572c4311Sfengbojiang     int forked; /* Is this a fork()ed debugging session? */
64*572c4311Sfengbojiang     list *logs; /* List of messages to send to the client. */
65*572c4311Sfengbojiang     list *traces; /* Messages about Redis commands executed since last stop.*/
66*572c4311Sfengbojiang     list *children; /* All forked debugging sessions pids. */
67*572c4311Sfengbojiang     int bp[LDB_BREAKPOINTS_MAX]; /* An array of breakpoints line numbers. */
68*572c4311Sfengbojiang     int bpcount; /* Number of valid entries inside bp. */
69*572c4311Sfengbojiang     int step;   /* Stop at next line ragardless of breakpoints. */
70*572c4311Sfengbojiang     int luabp;  /* Stop at next line because redis.breakpoint() was called. */
71*572c4311Sfengbojiang     sds *src;   /* Lua script source code split by line. */
72*572c4311Sfengbojiang     int lines;  /* Number of lines in 'src'. */
73*572c4311Sfengbojiang     int currentline;    /* Current line number. */
74*572c4311Sfengbojiang     sds cbuf;   /* Debugger client command buffer. */
75*572c4311Sfengbojiang     size_t maxlen;  /* Max var dump / reply length. */
76*572c4311Sfengbojiang     int maxlen_hint_sent; /* Did we already hint about "set maxlen"? */
77*572c4311Sfengbojiang } ldb;
78*572c4311Sfengbojiang 
79*572c4311Sfengbojiang /* ---------------------------------------------------------------------------
80*572c4311Sfengbojiang  * Utility functions.
81*572c4311Sfengbojiang  * ------------------------------------------------------------------------- */
82*572c4311Sfengbojiang 
83*572c4311Sfengbojiang /* Perform the SHA1 of the input string. We use this both for hashing script
84*572c4311Sfengbojiang  * bodies in order to obtain the Lua function name, and in the implementation
85*572c4311Sfengbojiang  * of redis.sha1().
86*572c4311Sfengbojiang  *
87*572c4311Sfengbojiang  * 'digest' should point to a 41 bytes buffer: 40 for SHA1 converted into an
88*572c4311Sfengbojiang  * hexadecimal number, plus 1 byte for null term. */
sha1hex(char * digest,char * script,size_t len)89*572c4311Sfengbojiang void sha1hex(char *digest, char *script, size_t len) {
90*572c4311Sfengbojiang     SHA1_CTX ctx;
91*572c4311Sfengbojiang     unsigned char hash[20];
92*572c4311Sfengbojiang     char *cset = "0123456789abcdef";
93*572c4311Sfengbojiang     int j;
94*572c4311Sfengbojiang 
95*572c4311Sfengbojiang     SHA1Init(&ctx);
96*572c4311Sfengbojiang     SHA1Update(&ctx,(unsigned char*)script,len);
97*572c4311Sfengbojiang     SHA1Final(hash,&ctx);
98*572c4311Sfengbojiang 
99*572c4311Sfengbojiang     for (j = 0; j < 20; j++) {
100*572c4311Sfengbojiang         digest[j*2] = cset[((hash[j]&0xF0)>>4)];
101*572c4311Sfengbojiang         digest[j*2+1] = cset[(hash[j]&0xF)];
102*572c4311Sfengbojiang     }
103*572c4311Sfengbojiang     digest[40] = '\0';
104*572c4311Sfengbojiang }
105*572c4311Sfengbojiang 
106*572c4311Sfengbojiang /* ---------------------------------------------------------------------------
107*572c4311Sfengbojiang  * Redis reply to Lua type conversion functions.
108*572c4311Sfengbojiang  * ------------------------------------------------------------------------- */
109*572c4311Sfengbojiang 
110*572c4311Sfengbojiang /* Take a Redis reply in the Redis protocol format and convert it into a
111*572c4311Sfengbojiang  * Lua type. Thanks to this function, and the introduction of not connected
112*572c4311Sfengbojiang  * clients, it is trivial to implement the redis() lua function.
113*572c4311Sfengbojiang  *
114*572c4311Sfengbojiang  * Basically we take the arguments, execute the Redis command in the context
115*572c4311Sfengbojiang  * of a non connected client, then take the generated reply and convert it
116*572c4311Sfengbojiang  * into a suitable Lua type. With this trick the scripting feature does not
117*572c4311Sfengbojiang  * need the introduction of a full Redis internals API. The script
118*572c4311Sfengbojiang  * is like a normal client that bypasses all the slow I/O paths.
119*572c4311Sfengbojiang  *
120*572c4311Sfengbojiang  * Note: in this function we do not do any sanity check as the reply is
121*572c4311Sfengbojiang  * generated by Redis directly. This allows us to go faster.
122*572c4311Sfengbojiang  *
123*572c4311Sfengbojiang  * Errors are returned as a table with a single 'err' field set to the
124*572c4311Sfengbojiang  * error string.
125*572c4311Sfengbojiang  */
126*572c4311Sfengbojiang 
redisProtocolToLuaType(lua_State * lua,char * reply)127*572c4311Sfengbojiang char *redisProtocolToLuaType(lua_State *lua, char* reply) {
128*572c4311Sfengbojiang     char *p = reply;
129*572c4311Sfengbojiang 
130*572c4311Sfengbojiang     switch(*p) {
131*572c4311Sfengbojiang     case ':': p = redisProtocolToLuaType_Int(lua,reply); break;
132*572c4311Sfengbojiang     case '$': p = redisProtocolToLuaType_Bulk(lua,reply); break;
133*572c4311Sfengbojiang     case '+': p = redisProtocolToLuaType_Status(lua,reply); break;
134*572c4311Sfengbojiang     case '-': p = redisProtocolToLuaType_Error(lua,reply); break;
135*572c4311Sfengbojiang     case '*': p = redisProtocolToLuaType_MultiBulk(lua,reply); break;
136*572c4311Sfengbojiang     }
137*572c4311Sfengbojiang     return p;
138*572c4311Sfengbojiang }
139*572c4311Sfengbojiang 
redisProtocolToLuaType_Int(lua_State * lua,char * reply)140*572c4311Sfengbojiang char *redisProtocolToLuaType_Int(lua_State *lua, char *reply) {
141*572c4311Sfengbojiang     char *p = strchr(reply+1,'\r');
142*572c4311Sfengbojiang     long long value;
143*572c4311Sfengbojiang 
144*572c4311Sfengbojiang     string2ll(reply+1,p-reply-1,&value);
145*572c4311Sfengbojiang     lua_pushnumber(lua,(lua_Number)value);
146*572c4311Sfengbojiang     return p+2;
147*572c4311Sfengbojiang }
148*572c4311Sfengbojiang 
redisProtocolToLuaType_Bulk(lua_State * lua,char * reply)149*572c4311Sfengbojiang char *redisProtocolToLuaType_Bulk(lua_State *lua, char *reply) {
150*572c4311Sfengbojiang     char *p = strchr(reply+1,'\r');
151*572c4311Sfengbojiang     long long bulklen;
152*572c4311Sfengbojiang 
153*572c4311Sfengbojiang     string2ll(reply+1,p-reply-1,&bulklen);
154*572c4311Sfengbojiang     if (bulklen == -1) {
155*572c4311Sfengbojiang         lua_pushboolean(lua,0);
156*572c4311Sfengbojiang         return p+2;
157*572c4311Sfengbojiang     } else {
158*572c4311Sfengbojiang         lua_pushlstring(lua,p+2,bulklen);
159*572c4311Sfengbojiang         return p+2+bulklen+2;
160*572c4311Sfengbojiang     }
161*572c4311Sfengbojiang }
162*572c4311Sfengbojiang 
redisProtocolToLuaType_Status(lua_State * lua,char * reply)163*572c4311Sfengbojiang char *redisProtocolToLuaType_Status(lua_State *lua, char *reply) {
164*572c4311Sfengbojiang     char *p = strchr(reply+1,'\r');
165*572c4311Sfengbojiang 
166*572c4311Sfengbojiang     lua_newtable(lua);
167*572c4311Sfengbojiang     lua_pushstring(lua,"ok");
168*572c4311Sfengbojiang     lua_pushlstring(lua,reply+1,p-reply-1);
169*572c4311Sfengbojiang     lua_settable(lua,-3);
170*572c4311Sfengbojiang     return p+2;
171*572c4311Sfengbojiang }
172*572c4311Sfengbojiang 
redisProtocolToLuaType_Error(lua_State * lua,char * reply)173*572c4311Sfengbojiang char *redisProtocolToLuaType_Error(lua_State *lua, char *reply) {
174*572c4311Sfengbojiang     char *p = strchr(reply+1,'\r');
175*572c4311Sfengbojiang 
176*572c4311Sfengbojiang     lua_newtable(lua);
177*572c4311Sfengbojiang     lua_pushstring(lua,"err");
178*572c4311Sfengbojiang     lua_pushlstring(lua,reply+1,p-reply-1);
179*572c4311Sfengbojiang     lua_settable(lua,-3);
180*572c4311Sfengbojiang     return p+2;
181*572c4311Sfengbojiang }
182*572c4311Sfengbojiang 
redisProtocolToLuaType_MultiBulk(lua_State * lua,char * reply)183*572c4311Sfengbojiang char *redisProtocolToLuaType_MultiBulk(lua_State *lua, char *reply) {
184*572c4311Sfengbojiang     char *p = strchr(reply+1,'\r');
185*572c4311Sfengbojiang     long long mbulklen;
186*572c4311Sfengbojiang     int j = 0;
187*572c4311Sfengbojiang 
188*572c4311Sfengbojiang     string2ll(reply+1,p-reply-1,&mbulklen);
189*572c4311Sfengbojiang     p += 2;
190*572c4311Sfengbojiang     if (mbulklen == -1) {
191*572c4311Sfengbojiang         lua_pushboolean(lua,0);
192*572c4311Sfengbojiang         return p;
193*572c4311Sfengbojiang     }
194*572c4311Sfengbojiang     lua_newtable(lua);
195*572c4311Sfengbojiang     for (j = 0; j < mbulklen; j++) {
196*572c4311Sfengbojiang         lua_pushnumber(lua,j+1);
197*572c4311Sfengbojiang         p = redisProtocolToLuaType(lua,p);
198*572c4311Sfengbojiang         lua_settable(lua,-3);
199*572c4311Sfengbojiang     }
200*572c4311Sfengbojiang     return p;
201*572c4311Sfengbojiang }
202*572c4311Sfengbojiang 
203*572c4311Sfengbojiang /* This function is used in order to push an error on the Lua stack in the
204*572c4311Sfengbojiang  * format used by redis.pcall to return errors, which is a lua table
205*572c4311Sfengbojiang  * with a single "err" field set to the error string. Note that this
206*572c4311Sfengbojiang  * table is never a valid reply by proper commands, since the returned
207*572c4311Sfengbojiang  * tables are otherwise always indexed by integers, never by strings. */
luaPushError(lua_State * lua,char * error)208*572c4311Sfengbojiang void luaPushError(lua_State *lua, char *error) {
209*572c4311Sfengbojiang     lua_Debug dbg;
210*572c4311Sfengbojiang 
211*572c4311Sfengbojiang     /* If debugging is active and in step mode, log errors resulting from
212*572c4311Sfengbojiang      * Redis commands. */
213*572c4311Sfengbojiang     if (ldb.active && ldb.step) {
214*572c4311Sfengbojiang         ldbLog(sdscatprintf(sdsempty(),"<error> %s",error));
215*572c4311Sfengbojiang     }
216*572c4311Sfengbojiang 
217*572c4311Sfengbojiang     lua_newtable(lua);
218*572c4311Sfengbojiang     lua_pushstring(lua,"err");
219*572c4311Sfengbojiang 
220*572c4311Sfengbojiang     /* Attempt to figure out where this function was called, if possible */
221*572c4311Sfengbojiang     if(lua_getstack(lua, 1, &dbg) && lua_getinfo(lua, "nSl", &dbg)) {
222*572c4311Sfengbojiang         sds msg = sdscatprintf(sdsempty(), "%s: %d: %s",
223*572c4311Sfengbojiang             dbg.source, dbg.currentline, error);
224*572c4311Sfengbojiang         lua_pushstring(lua, msg);
225*572c4311Sfengbojiang         sdsfree(msg);
226*572c4311Sfengbojiang     } else {
227*572c4311Sfengbojiang         lua_pushstring(lua, error);
228*572c4311Sfengbojiang     }
229*572c4311Sfengbojiang     lua_settable(lua,-3);
230*572c4311Sfengbojiang }
231*572c4311Sfengbojiang 
232*572c4311Sfengbojiang /* In case the error set into the Lua stack by luaPushError() was generated
233*572c4311Sfengbojiang  * by the non-error-trapping version of redis.pcall(), which is redis.call(),
234*572c4311Sfengbojiang  * this function will raise the Lua error so that the execution of the
235*572c4311Sfengbojiang  * script will be halted. */
luaRaiseError(lua_State * lua)236*572c4311Sfengbojiang int luaRaiseError(lua_State *lua) {
237*572c4311Sfengbojiang     lua_pushstring(lua,"err");
238*572c4311Sfengbojiang     lua_gettable(lua,-2);
239*572c4311Sfengbojiang     return lua_error(lua);
240*572c4311Sfengbojiang }
241*572c4311Sfengbojiang 
242*572c4311Sfengbojiang /* Sort the array currently in the stack. We do this to make the output
243*572c4311Sfengbojiang  * of commands like KEYS or SMEMBERS something deterministic when called
244*572c4311Sfengbojiang  * from Lua (to play well with AOf/replication).
245*572c4311Sfengbojiang  *
246*572c4311Sfengbojiang  * The array is sorted using table.sort itself, and assuming all the
247*572c4311Sfengbojiang  * list elements are strings. */
luaSortArray(lua_State * lua)248*572c4311Sfengbojiang void luaSortArray(lua_State *lua) {
249*572c4311Sfengbojiang     /* Initial Stack: array */
250*572c4311Sfengbojiang     lua_getglobal(lua,"table");
251*572c4311Sfengbojiang     lua_pushstring(lua,"sort");
252*572c4311Sfengbojiang     lua_gettable(lua,-2);       /* Stack: array, table, table.sort */
253*572c4311Sfengbojiang     lua_pushvalue(lua,-3);      /* Stack: array, table, table.sort, array */
254*572c4311Sfengbojiang     if (lua_pcall(lua,1,0,0)) {
255*572c4311Sfengbojiang         /* Stack: array, table, error */
256*572c4311Sfengbojiang 
257*572c4311Sfengbojiang         /* We are not interested in the error, we assume that the problem is
258*572c4311Sfengbojiang          * that there are 'false' elements inside the array, so we try
259*572c4311Sfengbojiang          * again with a slower function but able to handle this case, that
260*572c4311Sfengbojiang          * is: table.sort(table, __redis__compare_helper) */
261*572c4311Sfengbojiang         lua_pop(lua,1);             /* Stack: array, table */
262*572c4311Sfengbojiang         lua_pushstring(lua,"sort"); /* Stack: array, table, sort */
263*572c4311Sfengbojiang         lua_gettable(lua,-2);       /* Stack: array, table, table.sort */
264*572c4311Sfengbojiang         lua_pushvalue(lua,-3);      /* Stack: array, table, table.sort, array */
265*572c4311Sfengbojiang         lua_getglobal(lua,"__redis__compare_helper");
266*572c4311Sfengbojiang         /* Stack: array, table, table.sort, array, __redis__compare_helper */
267*572c4311Sfengbojiang         lua_call(lua,2,0);
268*572c4311Sfengbojiang     }
269*572c4311Sfengbojiang     /* Stack: array (sorted), table */
270*572c4311Sfengbojiang     lua_pop(lua,1);             /* Stack: array (sorted) */
271*572c4311Sfengbojiang }
272*572c4311Sfengbojiang 
273*572c4311Sfengbojiang /* ---------------------------------------------------------------------------
274*572c4311Sfengbojiang  * Lua reply to Redis reply conversion functions.
275*572c4311Sfengbojiang  * ------------------------------------------------------------------------- */
276*572c4311Sfengbojiang 
luaReplyToRedisReply(client * c,lua_State * lua)277*572c4311Sfengbojiang void luaReplyToRedisReply(client *c, lua_State *lua) {
278*572c4311Sfengbojiang     int t = lua_type(lua,-1);
279*572c4311Sfengbojiang 
280*572c4311Sfengbojiang     switch(t) {
281*572c4311Sfengbojiang     case LUA_TSTRING:
282*572c4311Sfengbojiang         addReplyBulkCBuffer(c,(char*)lua_tostring(lua,-1),lua_strlen(lua,-1));
283*572c4311Sfengbojiang         break;
284*572c4311Sfengbojiang     case LUA_TBOOLEAN:
285*572c4311Sfengbojiang         addReply(c,lua_toboolean(lua,-1) ? shared.cone : shared.nullbulk);
286*572c4311Sfengbojiang         break;
287*572c4311Sfengbojiang     case LUA_TNUMBER:
288*572c4311Sfengbojiang         addReplyLongLong(c,(long long)lua_tonumber(lua,-1));
289*572c4311Sfengbojiang         break;
290*572c4311Sfengbojiang     case LUA_TTABLE:
291*572c4311Sfengbojiang         /* We need to check if it is an array, an error, or a status reply.
292*572c4311Sfengbojiang          * Error are returned as a single element table with 'err' field.
293*572c4311Sfengbojiang          * Status replies are returned as single element table with 'ok'
294*572c4311Sfengbojiang          * field. */
295*572c4311Sfengbojiang         lua_pushstring(lua,"err");
296*572c4311Sfengbojiang         lua_gettable(lua,-2);
297*572c4311Sfengbojiang         t = lua_type(lua,-1);
298*572c4311Sfengbojiang         if (t == LUA_TSTRING) {
299*572c4311Sfengbojiang             sds err = sdsnew(lua_tostring(lua,-1));
300*572c4311Sfengbojiang             sdsmapchars(err,"\r\n","  ",2);
301*572c4311Sfengbojiang             addReplySds(c,sdscatprintf(sdsempty(),"-%s\r\n",err));
302*572c4311Sfengbojiang             sdsfree(err);
303*572c4311Sfengbojiang             lua_pop(lua,2);
304*572c4311Sfengbojiang             return;
305*572c4311Sfengbojiang         }
306*572c4311Sfengbojiang 
307*572c4311Sfengbojiang         lua_pop(lua,1);
308*572c4311Sfengbojiang         lua_pushstring(lua,"ok");
309*572c4311Sfengbojiang         lua_gettable(lua,-2);
310*572c4311Sfengbojiang         t = lua_type(lua,-1);
311*572c4311Sfengbojiang         if (t == LUA_TSTRING) {
312*572c4311Sfengbojiang             sds ok = sdsnew(lua_tostring(lua,-1));
313*572c4311Sfengbojiang             sdsmapchars(ok,"\r\n","  ",2);
314*572c4311Sfengbojiang             addReplySds(c,sdscatprintf(sdsempty(),"+%s\r\n",ok));
315*572c4311Sfengbojiang             sdsfree(ok);
316*572c4311Sfengbojiang             lua_pop(lua,1);
317*572c4311Sfengbojiang         } else {
318*572c4311Sfengbojiang             void *replylen = addDeferredMultiBulkLength(c);
319*572c4311Sfengbojiang             int j = 1, mbulklen = 0;
320*572c4311Sfengbojiang 
321*572c4311Sfengbojiang             lua_pop(lua,1); /* Discard the 'ok' field value we popped */
322*572c4311Sfengbojiang             while(1) {
323*572c4311Sfengbojiang                 lua_pushnumber(lua,j++);
324*572c4311Sfengbojiang                 lua_gettable(lua,-2);
325*572c4311Sfengbojiang                 t = lua_type(lua,-1);
326*572c4311Sfengbojiang                 if (t == LUA_TNIL) {
327*572c4311Sfengbojiang                     lua_pop(lua,1);
328*572c4311Sfengbojiang                     break;
329*572c4311Sfengbojiang                 }
330*572c4311Sfengbojiang                 luaReplyToRedisReply(c, lua);
331*572c4311Sfengbojiang                 mbulklen++;
332*572c4311Sfengbojiang             }
333*572c4311Sfengbojiang             setDeferredMultiBulkLength(c,replylen,mbulklen);
334*572c4311Sfengbojiang         }
335*572c4311Sfengbojiang         break;
336*572c4311Sfengbojiang     default:
337*572c4311Sfengbojiang         addReply(c,shared.nullbulk);
338*572c4311Sfengbojiang     }
339*572c4311Sfengbojiang     lua_pop(lua,1);
340*572c4311Sfengbojiang }
341*572c4311Sfengbojiang 
342*572c4311Sfengbojiang /* ---------------------------------------------------------------------------
343*572c4311Sfengbojiang  * Lua redis.* functions implementations.
344*572c4311Sfengbojiang  * ------------------------------------------------------------------------- */
345*572c4311Sfengbojiang 
346*572c4311Sfengbojiang #define LUA_CMD_OBJCACHE_SIZE 32
347*572c4311Sfengbojiang #define LUA_CMD_OBJCACHE_MAX_LEN 64
luaRedisGenericCommand(lua_State * lua,int raise_error)348*572c4311Sfengbojiang int luaRedisGenericCommand(lua_State *lua, int raise_error) {
349*572c4311Sfengbojiang     int j, argc = lua_gettop(lua);
350*572c4311Sfengbojiang     struct redisCommand *cmd;
351*572c4311Sfengbojiang     client *c = server.lua_client;
352*572c4311Sfengbojiang     sds reply;
353*572c4311Sfengbojiang 
354*572c4311Sfengbojiang     /* Cached across calls. */
355*572c4311Sfengbojiang     static robj **argv = NULL;
356*572c4311Sfengbojiang     static int argv_size = 0;
357*572c4311Sfengbojiang     static robj *cached_objects[LUA_CMD_OBJCACHE_SIZE];
358*572c4311Sfengbojiang     static size_t cached_objects_len[LUA_CMD_OBJCACHE_SIZE];
359*572c4311Sfengbojiang     static int inuse = 0;   /* Recursive calls detection. */
360*572c4311Sfengbojiang 
361*572c4311Sfengbojiang     /* Reflect MULTI state */
362*572c4311Sfengbojiang     if (server.lua_multi_emitted || (server.lua_caller->flags & CLIENT_MULTI)) {
363*572c4311Sfengbojiang         c->flags |= CLIENT_MULTI;
364*572c4311Sfengbojiang     } else {
365*572c4311Sfengbojiang         c->flags &= ~CLIENT_MULTI;
366*572c4311Sfengbojiang     }
367*572c4311Sfengbojiang 
368*572c4311Sfengbojiang     /* By using Lua debug hooks it is possible to trigger a recursive call
369*572c4311Sfengbojiang      * to luaRedisGenericCommand(), which normally should never happen.
370*572c4311Sfengbojiang      * To make this function reentrant is futile and makes it slower, but
371*572c4311Sfengbojiang      * we should at least detect such a misuse, and abort. */
372*572c4311Sfengbojiang     if (inuse) {
373*572c4311Sfengbojiang         char *recursion_warning =
374*572c4311Sfengbojiang             "luaRedisGenericCommand() recursive call detected. "
375*572c4311Sfengbojiang             "Are you doing funny stuff with Lua debug hooks?";
376*572c4311Sfengbojiang         serverLog(LL_WARNING,"%s",recursion_warning);
377*572c4311Sfengbojiang         luaPushError(lua,recursion_warning);
378*572c4311Sfengbojiang         return 1;
379*572c4311Sfengbojiang     }
380*572c4311Sfengbojiang     inuse++;
381*572c4311Sfengbojiang 
382*572c4311Sfengbojiang     /* Require at least one argument */
383*572c4311Sfengbojiang     if (argc == 0) {
384*572c4311Sfengbojiang         luaPushError(lua,
385*572c4311Sfengbojiang             "Please specify at least one argument for redis.call()");
386*572c4311Sfengbojiang         inuse--;
387*572c4311Sfengbojiang         return raise_error ? luaRaiseError(lua) : 1;
388*572c4311Sfengbojiang     }
389*572c4311Sfengbojiang 
390*572c4311Sfengbojiang     /* Build the arguments vector */
391*572c4311Sfengbojiang     if (argv_size < argc) {
392*572c4311Sfengbojiang         argv = zrealloc(argv,sizeof(robj*)*argc);
393*572c4311Sfengbojiang         argv_size = argc;
394*572c4311Sfengbojiang     }
395*572c4311Sfengbojiang 
396*572c4311Sfengbojiang     for (j = 0; j < argc; j++) {
397*572c4311Sfengbojiang         char *obj_s;
398*572c4311Sfengbojiang         size_t obj_len;
399*572c4311Sfengbojiang         char dbuf[64];
400*572c4311Sfengbojiang 
401*572c4311Sfengbojiang         if (lua_type(lua,j+1) == LUA_TNUMBER) {
402*572c4311Sfengbojiang             /* We can't use lua_tolstring() for number -> string conversion
403*572c4311Sfengbojiang              * since Lua uses a format specifier that loses precision. */
404*572c4311Sfengbojiang             lua_Number num = lua_tonumber(lua,j+1);
405*572c4311Sfengbojiang 
406*572c4311Sfengbojiang             obj_len = snprintf(dbuf,sizeof(dbuf),"%.17g",(double)num);
407*572c4311Sfengbojiang             obj_s = dbuf;
408*572c4311Sfengbojiang         } else {
409*572c4311Sfengbojiang             obj_s = (char*)lua_tolstring(lua,j+1,&obj_len);
410*572c4311Sfengbojiang             if (obj_s == NULL) break; /* Not a string. */
411*572c4311Sfengbojiang         }
412*572c4311Sfengbojiang 
413*572c4311Sfengbojiang         /* Try to use a cached object. */
414*572c4311Sfengbojiang         if (j < LUA_CMD_OBJCACHE_SIZE && cached_objects[j] &&
415*572c4311Sfengbojiang             cached_objects_len[j] >= obj_len)
416*572c4311Sfengbojiang         {
417*572c4311Sfengbojiang             sds s = cached_objects[j]->ptr;
418*572c4311Sfengbojiang             argv[j] = cached_objects[j];
419*572c4311Sfengbojiang             cached_objects[j] = NULL;
420*572c4311Sfengbojiang             memcpy(s,obj_s,obj_len+1);
421*572c4311Sfengbojiang             sdssetlen(s, obj_len);
422*572c4311Sfengbojiang         } else {
423*572c4311Sfengbojiang             argv[j] = createStringObject(obj_s, obj_len);
424*572c4311Sfengbojiang         }
425*572c4311Sfengbojiang     }
426*572c4311Sfengbojiang 
427*572c4311Sfengbojiang     /* Check if one of the arguments passed by the Lua script
428*572c4311Sfengbojiang      * is not a string or an integer (lua_isstring() return true for
429*572c4311Sfengbojiang      * integers as well). */
430*572c4311Sfengbojiang     if (j != argc) {
431*572c4311Sfengbojiang         j--;
432*572c4311Sfengbojiang         while (j >= 0) {
433*572c4311Sfengbojiang             decrRefCount(argv[j]);
434*572c4311Sfengbojiang             j--;
435*572c4311Sfengbojiang         }
436*572c4311Sfengbojiang         luaPushError(lua,
437*572c4311Sfengbojiang             "Lua redis() command arguments must be strings or integers");
438*572c4311Sfengbojiang         inuse--;
439*572c4311Sfengbojiang         return raise_error ? luaRaiseError(lua) : 1;
440*572c4311Sfengbojiang     }
441*572c4311Sfengbojiang 
442*572c4311Sfengbojiang     /* Setup our fake client for command execution */
443*572c4311Sfengbojiang     c->argv = argv;
444*572c4311Sfengbojiang     c->argc = argc;
445*572c4311Sfengbojiang 
446*572c4311Sfengbojiang     /* Process module hooks */
447*572c4311Sfengbojiang     moduleCallCommandFilters(c);
448*572c4311Sfengbojiang     argv = c->argv;
449*572c4311Sfengbojiang     argc = c->argc;
450*572c4311Sfengbojiang 
451*572c4311Sfengbojiang     /* Log the command if debugging is active. */
452*572c4311Sfengbojiang     if (ldb.active && ldb.step) {
453*572c4311Sfengbojiang         sds cmdlog = sdsnew("<redis>");
454*572c4311Sfengbojiang         for (j = 0; j < c->argc; j++) {
455*572c4311Sfengbojiang             if (j == 10) {
456*572c4311Sfengbojiang                 cmdlog = sdscatprintf(cmdlog," ... (%d more)",
457*572c4311Sfengbojiang                     c->argc-j-1);
458*572c4311Sfengbojiang                 break;
459*572c4311Sfengbojiang             } else {
460*572c4311Sfengbojiang                 cmdlog = sdscatlen(cmdlog," ",1);
461*572c4311Sfengbojiang                 cmdlog = sdscatsds(cmdlog,c->argv[j]->ptr);
462*572c4311Sfengbojiang             }
463*572c4311Sfengbojiang         }
464*572c4311Sfengbojiang         ldbLog(cmdlog);
465*572c4311Sfengbojiang     }
466*572c4311Sfengbojiang 
467*572c4311Sfengbojiang     /* Command lookup */
468*572c4311Sfengbojiang     cmd = lookupCommand(argv[0]->ptr);
469*572c4311Sfengbojiang     if (!cmd || ((cmd->arity > 0 && cmd->arity != argc) ||
470*572c4311Sfengbojiang                    (argc < -cmd->arity)))
471*572c4311Sfengbojiang     {
472*572c4311Sfengbojiang         if (cmd)
473*572c4311Sfengbojiang             luaPushError(lua,
474*572c4311Sfengbojiang                 "Wrong number of args calling Redis command From Lua script");
475*572c4311Sfengbojiang         else
476*572c4311Sfengbojiang             luaPushError(lua,"Unknown Redis command called from Lua script");
477*572c4311Sfengbojiang         goto cleanup;
478*572c4311Sfengbojiang     }
479*572c4311Sfengbojiang     c->cmd = c->lastcmd = cmd;
480*572c4311Sfengbojiang 
481*572c4311Sfengbojiang     /* There are commands that are not allowed inside scripts. */
482*572c4311Sfengbojiang     if (cmd->flags & CMD_NOSCRIPT) {
483*572c4311Sfengbojiang         luaPushError(lua, "This Redis command is not allowed from scripts");
484*572c4311Sfengbojiang         goto cleanup;
485*572c4311Sfengbojiang     }
486*572c4311Sfengbojiang 
487*572c4311Sfengbojiang     /* Write commands are forbidden against read-only slaves, or if a
488*572c4311Sfengbojiang      * command marked as non-deterministic was already called in the context
489*572c4311Sfengbojiang      * of this script. */
490*572c4311Sfengbojiang     if (cmd->flags & CMD_WRITE) {
491*572c4311Sfengbojiang         int deny_write_type = writeCommandsDeniedByDiskError();
492*572c4311Sfengbojiang         if (server.lua_random_dirty && !server.lua_replicate_commands) {
493*572c4311Sfengbojiang             luaPushError(lua,
494*572c4311Sfengbojiang                 "Write commands not allowed after non deterministic commands. Call redis.replicate_commands() at the start of your script in order to switch to single commands replication mode.");
495*572c4311Sfengbojiang             goto cleanup;
496*572c4311Sfengbojiang         } else if (server.masterhost && server.repl_slave_ro &&
497*572c4311Sfengbojiang                    !server.loading &&
498*572c4311Sfengbojiang                    !(server.lua_caller->flags & CLIENT_MASTER))
499*572c4311Sfengbojiang         {
500*572c4311Sfengbojiang             luaPushError(lua, shared.roslaveerr->ptr);
501*572c4311Sfengbojiang             goto cleanup;
502*572c4311Sfengbojiang         } else if (deny_write_type != DISK_ERROR_TYPE_NONE) {
503*572c4311Sfengbojiang             if (deny_write_type == DISK_ERROR_TYPE_RDB) {
504*572c4311Sfengbojiang                 luaPushError(lua, shared.bgsaveerr->ptr);
505*572c4311Sfengbojiang             } else {
506*572c4311Sfengbojiang                 sds aof_write_err = sdscatfmt(sdsempty(),
507*572c4311Sfengbojiang                     "-MISCONF Errors writing to the AOF file: %s\r\n",
508*572c4311Sfengbojiang                     strerror(server.aof_last_write_errno));
509*572c4311Sfengbojiang                 luaPushError(lua, aof_write_err);
510*572c4311Sfengbojiang                 sdsfree(aof_write_err);
511*572c4311Sfengbojiang             }
512*572c4311Sfengbojiang             goto cleanup;
513*572c4311Sfengbojiang         }
514*572c4311Sfengbojiang     }
515*572c4311Sfengbojiang 
516*572c4311Sfengbojiang     /* If we reached the memory limit configured via maxmemory, commands that
517*572c4311Sfengbojiang      * could enlarge the memory usage are not allowed, but only if this is the
518*572c4311Sfengbojiang      * first write in the context of this script, otherwise we can't stop
519*572c4311Sfengbojiang      * in the middle. */
520*572c4311Sfengbojiang     if (server.maxmemory &&             /* Maxmemory is actually enabled. */
521*572c4311Sfengbojiang         !server.loading &&              /* Don't care about mem if loading. */
522*572c4311Sfengbojiang         !server.masterhost &&           /* Slave must execute the script. */
523*572c4311Sfengbojiang         server.lua_write_dirty == 0 &&  /* Script had no side effects so far. */
524*572c4311Sfengbojiang         (cmd->flags & CMD_DENYOOM))
525*572c4311Sfengbojiang     {
526*572c4311Sfengbojiang         if (getMaxmemoryState(NULL,NULL,NULL,NULL) != C_OK) {
527*572c4311Sfengbojiang             luaPushError(lua, shared.oomerr->ptr);
528*572c4311Sfengbojiang             goto cleanup;
529*572c4311Sfengbojiang         }
530*572c4311Sfengbojiang     }
531*572c4311Sfengbojiang 
532*572c4311Sfengbojiang     if (cmd->flags & CMD_RANDOM) server.lua_random_dirty = 1;
533*572c4311Sfengbojiang     if (cmd->flags & CMD_WRITE) server.lua_write_dirty = 1;
534*572c4311Sfengbojiang 
535*572c4311Sfengbojiang     /* If this is a Redis Cluster node, we need to make sure Lua is not
536*572c4311Sfengbojiang      * trying to access non-local keys, with the exception of commands
537*572c4311Sfengbojiang      * received from our master or when loading the AOF back in memory. */
538*572c4311Sfengbojiang     if (server.cluster_enabled && !server.loading &&
539*572c4311Sfengbojiang         !(server.lua_caller->flags & CLIENT_MASTER))
540*572c4311Sfengbojiang     {
541*572c4311Sfengbojiang         /* Duplicate relevant flags in the lua client. */
542*572c4311Sfengbojiang         c->flags &= ~(CLIENT_READONLY|CLIENT_ASKING);
543*572c4311Sfengbojiang         c->flags |= server.lua_caller->flags & (CLIENT_READONLY|CLIENT_ASKING);
544*572c4311Sfengbojiang         if (getNodeByQuery(c,c->cmd,c->argv,c->argc,NULL,NULL) !=
545*572c4311Sfengbojiang                            server.cluster->myself)
546*572c4311Sfengbojiang         {
547*572c4311Sfengbojiang             luaPushError(lua,
548*572c4311Sfengbojiang                 "Lua script attempted to access a non local key in a "
549*572c4311Sfengbojiang                 "cluster node");
550*572c4311Sfengbojiang             goto cleanup;
551*572c4311Sfengbojiang         }
552*572c4311Sfengbojiang     }
553*572c4311Sfengbojiang 
554*572c4311Sfengbojiang     /* If we are using single commands replication, we need to wrap what
555*572c4311Sfengbojiang      * we propagate into a MULTI/EXEC block, so that it will be atomic like
556*572c4311Sfengbojiang      * a Lua script in the context of AOF and slaves. */
557*572c4311Sfengbojiang     if (server.lua_replicate_commands &&
558*572c4311Sfengbojiang         !server.lua_multi_emitted &&
559*572c4311Sfengbojiang         !(server.lua_caller->flags & CLIENT_MULTI) &&
560*572c4311Sfengbojiang         server.lua_write_dirty &&
561*572c4311Sfengbojiang         server.lua_repl != PROPAGATE_NONE)
562*572c4311Sfengbojiang     {
563*572c4311Sfengbojiang         execCommandPropagateMulti(server.lua_caller);
564*572c4311Sfengbojiang         server.lua_multi_emitted = 1;
565*572c4311Sfengbojiang     }
566*572c4311Sfengbojiang 
567*572c4311Sfengbojiang     /* Run the command */
568*572c4311Sfengbojiang     int call_flags = CMD_CALL_SLOWLOG | CMD_CALL_STATS;
569*572c4311Sfengbojiang     if (server.lua_replicate_commands) {
570*572c4311Sfengbojiang         /* Set flags according to redis.set_repl() settings. */
571*572c4311Sfengbojiang         if (server.lua_repl & PROPAGATE_AOF)
572*572c4311Sfengbojiang             call_flags |= CMD_CALL_PROPAGATE_AOF;
573*572c4311Sfengbojiang         if (server.lua_repl & PROPAGATE_REPL)
574*572c4311Sfengbojiang             call_flags |= CMD_CALL_PROPAGATE_REPL;
575*572c4311Sfengbojiang     }
576*572c4311Sfengbojiang     call(c,call_flags);
577*572c4311Sfengbojiang 
578*572c4311Sfengbojiang     /* Convert the result of the Redis command into a suitable Lua type.
579*572c4311Sfengbojiang      * The first thing we need is to create a single string from the client
580*572c4311Sfengbojiang      * output buffers. */
581*572c4311Sfengbojiang     if (listLength(c->reply) == 0 && c->bufpos < PROTO_REPLY_CHUNK_BYTES) {
582*572c4311Sfengbojiang         /* This is a fast path for the common case of a reply inside the
583*572c4311Sfengbojiang          * client static buffer. Don't create an SDS string but just use
584*572c4311Sfengbojiang          * the client buffer directly. */
585*572c4311Sfengbojiang         c->buf[c->bufpos] = '\0';
586*572c4311Sfengbojiang         reply = c->buf;
587*572c4311Sfengbojiang         c->bufpos = 0;
588*572c4311Sfengbojiang     } else {
589*572c4311Sfengbojiang         reply = sdsnewlen(c->buf,c->bufpos);
590*572c4311Sfengbojiang         c->bufpos = 0;
591*572c4311Sfengbojiang         while(listLength(c->reply)) {
592*572c4311Sfengbojiang             clientReplyBlock *o = listNodeValue(listFirst(c->reply));
593*572c4311Sfengbojiang 
594*572c4311Sfengbojiang             reply = sdscatlen(reply,o->buf,o->used);
595*572c4311Sfengbojiang             listDelNode(c->reply,listFirst(c->reply));
596*572c4311Sfengbojiang         }
597*572c4311Sfengbojiang     }
598*572c4311Sfengbojiang     if (raise_error && reply[0] != '-') raise_error = 0;
599*572c4311Sfengbojiang     redisProtocolToLuaType(lua,reply);
600*572c4311Sfengbojiang 
601*572c4311Sfengbojiang     /* If the debugger is active, log the reply from Redis. */
602*572c4311Sfengbojiang     if (ldb.active && ldb.step)
603*572c4311Sfengbojiang         ldbLogRedisReply(reply);
604*572c4311Sfengbojiang 
605*572c4311Sfengbojiang     /* Sort the output array if needed, assuming it is a non-null multi bulk
606*572c4311Sfengbojiang      * reply as expected. */
607*572c4311Sfengbojiang     if ((cmd->flags & CMD_SORT_FOR_SCRIPT) &&
608*572c4311Sfengbojiang         (server.lua_replicate_commands == 0) &&
609*572c4311Sfengbojiang         (reply[0] == '*' && reply[1] != '-')) {
610*572c4311Sfengbojiang             luaSortArray(lua);
611*572c4311Sfengbojiang     }
612*572c4311Sfengbojiang     if (reply != c->buf) sdsfree(reply);
613*572c4311Sfengbojiang     c->reply_bytes = 0;
614*572c4311Sfengbojiang 
615*572c4311Sfengbojiang cleanup:
616*572c4311Sfengbojiang     /* Clean up. Command code may have changed argv/argc so we use the
617*572c4311Sfengbojiang      * argv/argc of the client instead of the local variables. */
618*572c4311Sfengbojiang     for (j = 0; j < c->argc; j++) {
619*572c4311Sfengbojiang         robj *o = c->argv[j];
620*572c4311Sfengbojiang 
621*572c4311Sfengbojiang         /* Try to cache the object in the cached_objects array.
622*572c4311Sfengbojiang          * The object must be small, SDS-encoded, and with refcount = 1
623*572c4311Sfengbojiang          * (we must be the only owner) for us to cache it. */
624*572c4311Sfengbojiang         if (j < LUA_CMD_OBJCACHE_SIZE &&
625*572c4311Sfengbojiang             o->refcount == 1 &&
626*572c4311Sfengbojiang             (o->encoding == OBJ_ENCODING_RAW ||
627*572c4311Sfengbojiang              o->encoding == OBJ_ENCODING_EMBSTR) &&
628*572c4311Sfengbojiang             sdslen(o->ptr) <= LUA_CMD_OBJCACHE_MAX_LEN)
629*572c4311Sfengbojiang         {
630*572c4311Sfengbojiang             sds s = o->ptr;
631*572c4311Sfengbojiang             if (cached_objects[j]) decrRefCount(cached_objects[j]);
632*572c4311Sfengbojiang             cached_objects[j] = o;
633*572c4311Sfengbojiang             cached_objects_len[j] = sdsalloc(s);
634*572c4311Sfengbojiang         } else {
635*572c4311Sfengbojiang             decrRefCount(o);
636*572c4311Sfengbojiang         }
637*572c4311Sfengbojiang     }
638*572c4311Sfengbojiang 
639*572c4311Sfengbojiang     if (c->argv != argv) {
640*572c4311Sfengbojiang         zfree(c->argv);
641*572c4311Sfengbojiang         argv = NULL;
642*572c4311Sfengbojiang         argv_size = 0;
643*572c4311Sfengbojiang     }
644*572c4311Sfengbojiang 
645*572c4311Sfengbojiang     if (raise_error) {
646*572c4311Sfengbojiang         /* If we are here we should have an error in the stack, in the
647*572c4311Sfengbojiang          * form of a table with an "err" field. Extract the string to
648*572c4311Sfengbojiang          * return the plain error. */
649*572c4311Sfengbojiang         inuse--;
650*572c4311Sfengbojiang         return luaRaiseError(lua);
651*572c4311Sfengbojiang     }
652*572c4311Sfengbojiang     inuse--;
653*572c4311Sfengbojiang     return 1;
654*572c4311Sfengbojiang }
655*572c4311Sfengbojiang 
656*572c4311Sfengbojiang /* redis.call() */
luaRedisCallCommand(lua_State * lua)657*572c4311Sfengbojiang int luaRedisCallCommand(lua_State *lua) {
658*572c4311Sfengbojiang     return luaRedisGenericCommand(lua,1);
659*572c4311Sfengbojiang }
660*572c4311Sfengbojiang 
661*572c4311Sfengbojiang /* redis.pcall() */
luaRedisPCallCommand(lua_State * lua)662*572c4311Sfengbojiang int luaRedisPCallCommand(lua_State *lua) {
663*572c4311Sfengbojiang     return luaRedisGenericCommand(lua,0);
664*572c4311Sfengbojiang }
665*572c4311Sfengbojiang 
666*572c4311Sfengbojiang /* This adds redis.sha1hex(string) to Lua scripts using the same hashing
667*572c4311Sfengbojiang  * function used for sha1ing lua scripts. */
luaRedisSha1hexCommand(lua_State * lua)668*572c4311Sfengbojiang int luaRedisSha1hexCommand(lua_State *lua) {
669*572c4311Sfengbojiang     int argc = lua_gettop(lua);
670*572c4311Sfengbojiang     char digest[41];
671*572c4311Sfengbojiang     size_t len;
672*572c4311Sfengbojiang     char *s;
673*572c4311Sfengbojiang 
674*572c4311Sfengbojiang     if (argc != 1) {
675*572c4311Sfengbojiang         lua_pushstring(lua, "wrong number of arguments");
676*572c4311Sfengbojiang         return lua_error(lua);
677*572c4311Sfengbojiang     }
678*572c4311Sfengbojiang 
679*572c4311Sfengbojiang     s = (char*)lua_tolstring(lua,1,&len);
680*572c4311Sfengbojiang     sha1hex(digest,s,len);
681*572c4311Sfengbojiang     lua_pushstring(lua,digest);
682*572c4311Sfengbojiang     return 1;
683*572c4311Sfengbojiang }
684*572c4311Sfengbojiang 
685*572c4311Sfengbojiang /* Returns a table with a single field 'field' set to the string value
686*572c4311Sfengbojiang  * passed as argument. This helper function is handy when returning
687*572c4311Sfengbojiang  * a Redis Protocol error or status reply from Lua:
688*572c4311Sfengbojiang  *
689*572c4311Sfengbojiang  * return redis.error_reply("ERR Some Error")
690*572c4311Sfengbojiang  * return redis.status_reply("ERR Some Error")
691*572c4311Sfengbojiang  */
luaRedisReturnSingleFieldTable(lua_State * lua,char * field)692*572c4311Sfengbojiang int luaRedisReturnSingleFieldTable(lua_State *lua, char *field) {
693*572c4311Sfengbojiang     if (lua_gettop(lua) != 1 || lua_type(lua,-1) != LUA_TSTRING) {
694*572c4311Sfengbojiang         luaPushError(lua, "wrong number or type of arguments");
695*572c4311Sfengbojiang         return 1;
696*572c4311Sfengbojiang     }
697*572c4311Sfengbojiang 
698*572c4311Sfengbojiang     lua_newtable(lua);
699*572c4311Sfengbojiang     lua_pushstring(lua, field);
700*572c4311Sfengbojiang     lua_pushvalue(lua, -3);
701*572c4311Sfengbojiang     lua_settable(lua, -3);
702*572c4311Sfengbojiang     return 1;
703*572c4311Sfengbojiang }
704*572c4311Sfengbojiang 
705*572c4311Sfengbojiang /* redis.error_reply() */
luaRedisErrorReplyCommand(lua_State * lua)706*572c4311Sfengbojiang int luaRedisErrorReplyCommand(lua_State *lua) {
707*572c4311Sfengbojiang     return luaRedisReturnSingleFieldTable(lua,"err");
708*572c4311Sfengbojiang }
709*572c4311Sfengbojiang 
710*572c4311Sfengbojiang /* redis.status_reply() */
luaRedisStatusReplyCommand(lua_State * lua)711*572c4311Sfengbojiang int luaRedisStatusReplyCommand(lua_State *lua) {
712*572c4311Sfengbojiang     return luaRedisReturnSingleFieldTable(lua,"ok");
713*572c4311Sfengbojiang }
714*572c4311Sfengbojiang 
715*572c4311Sfengbojiang /* redis.replicate_commands()
716*572c4311Sfengbojiang  *
717*572c4311Sfengbojiang  * Turn on single commands replication if the script never called
718*572c4311Sfengbojiang  * a write command so far, and returns true. Otherwise if the script
719*572c4311Sfengbojiang  * already started to write, returns false and stick to whole scripts
720*572c4311Sfengbojiang  * replication, which is our default. */
luaRedisReplicateCommandsCommand(lua_State * lua)721*572c4311Sfengbojiang int luaRedisReplicateCommandsCommand(lua_State *lua) {
722*572c4311Sfengbojiang     if (server.lua_write_dirty) {
723*572c4311Sfengbojiang         lua_pushboolean(lua,0);
724*572c4311Sfengbojiang     } else {
725*572c4311Sfengbojiang         server.lua_replicate_commands = 1;
726*572c4311Sfengbojiang         /* When we switch to single commands replication, we can provide
727*572c4311Sfengbojiang          * different math.random() sequences at every call, which is what
728*572c4311Sfengbojiang          * the user normally expects. */
729*572c4311Sfengbojiang         redisSrand48(rand());
730*572c4311Sfengbojiang         lua_pushboolean(lua,1);
731*572c4311Sfengbojiang     }
732*572c4311Sfengbojiang     return 1;
733*572c4311Sfengbojiang }
734*572c4311Sfengbojiang 
735*572c4311Sfengbojiang /* redis.breakpoint()
736*572c4311Sfengbojiang  *
737*572c4311Sfengbojiang  * Allows to stop execution during a debuggign session from within
738*572c4311Sfengbojiang  * the Lua code implementation, like if a breakpoint was set in the code
739*572c4311Sfengbojiang  * immediately after the function. */
luaRedisBreakpointCommand(lua_State * lua)740*572c4311Sfengbojiang int luaRedisBreakpointCommand(lua_State *lua) {
741*572c4311Sfengbojiang     if (ldb.active) {
742*572c4311Sfengbojiang         ldb.luabp = 1;
743*572c4311Sfengbojiang         lua_pushboolean(lua,1);
744*572c4311Sfengbojiang     } else {
745*572c4311Sfengbojiang         lua_pushboolean(lua,0);
746*572c4311Sfengbojiang     }
747*572c4311Sfengbojiang     return 1;
748*572c4311Sfengbojiang }
749*572c4311Sfengbojiang 
750*572c4311Sfengbojiang /* redis.debug()
751*572c4311Sfengbojiang  *
752*572c4311Sfengbojiang  * Log a string message into the output console.
753*572c4311Sfengbojiang  * Can take multiple arguments that will be separated by commas.
754*572c4311Sfengbojiang  * Nothing is returned to the caller. */
luaRedisDebugCommand(lua_State * lua)755*572c4311Sfengbojiang int luaRedisDebugCommand(lua_State *lua) {
756*572c4311Sfengbojiang     if (!ldb.active) return 0;
757*572c4311Sfengbojiang     int argc = lua_gettop(lua);
758*572c4311Sfengbojiang     sds log = sdscatprintf(sdsempty(),"<debug> line %d: ", ldb.currentline);
759*572c4311Sfengbojiang     while(argc--) {
760*572c4311Sfengbojiang         log = ldbCatStackValue(log,lua,-1 - argc);
761*572c4311Sfengbojiang         if (argc != 0) log = sdscatlen(log,", ",2);
762*572c4311Sfengbojiang     }
763*572c4311Sfengbojiang     ldbLog(log);
764*572c4311Sfengbojiang     return 0;
765*572c4311Sfengbojiang }
766*572c4311Sfengbojiang 
767*572c4311Sfengbojiang /* redis.set_repl()
768*572c4311Sfengbojiang  *
769*572c4311Sfengbojiang  * Set the propagation of write commands executed in the context of the
770*572c4311Sfengbojiang  * script to on/off for AOF and slaves. */
luaRedisSetReplCommand(lua_State * lua)771*572c4311Sfengbojiang int luaRedisSetReplCommand(lua_State *lua) {
772*572c4311Sfengbojiang     int argc = lua_gettop(lua);
773*572c4311Sfengbojiang     int flags;
774*572c4311Sfengbojiang 
775*572c4311Sfengbojiang     if (server.lua_replicate_commands == 0) {
776*572c4311Sfengbojiang         lua_pushstring(lua, "You can set the replication behavior only after turning on single commands replication with redis.replicate_commands().");
777*572c4311Sfengbojiang         return lua_error(lua);
778*572c4311Sfengbojiang     } else if (argc != 1) {
779*572c4311Sfengbojiang         lua_pushstring(lua, "redis.set_repl() requires two arguments.");
780*572c4311Sfengbojiang         return lua_error(lua);
781*572c4311Sfengbojiang     }
782*572c4311Sfengbojiang 
783*572c4311Sfengbojiang     flags = lua_tonumber(lua,-1);
784*572c4311Sfengbojiang     if ((flags & ~(PROPAGATE_AOF|PROPAGATE_REPL)) != 0) {
785*572c4311Sfengbojiang         lua_pushstring(lua, "Invalid replication flags. Use REPL_AOF, REPL_REPLICA, REPL_ALL or REPL_NONE.");
786*572c4311Sfengbojiang         return lua_error(lua);
787*572c4311Sfengbojiang     }
788*572c4311Sfengbojiang     server.lua_repl = flags;
789*572c4311Sfengbojiang     return 0;
790*572c4311Sfengbojiang }
791*572c4311Sfengbojiang 
792*572c4311Sfengbojiang /* redis.log() */
luaLogCommand(lua_State * lua)793*572c4311Sfengbojiang int luaLogCommand(lua_State *lua) {
794*572c4311Sfengbojiang     int j, argc = lua_gettop(lua);
795*572c4311Sfengbojiang     int level;
796*572c4311Sfengbojiang     sds log;
797*572c4311Sfengbojiang 
798*572c4311Sfengbojiang     if (argc < 2) {
799*572c4311Sfengbojiang         lua_pushstring(lua, "redis.log() requires two arguments or more.");
800*572c4311Sfengbojiang         return lua_error(lua);
801*572c4311Sfengbojiang     } else if (!lua_isnumber(lua,-argc)) {
802*572c4311Sfengbojiang         lua_pushstring(lua, "First argument must be a number (log level).");
803*572c4311Sfengbojiang         return lua_error(lua);
804*572c4311Sfengbojiang     }
805*572c4311Sfengbojiang     level = lua_tonumber(lua,-argc);
806*572c4311Sfengbojiang     if (level < LL_DEBUG || level > LL_WARNING) {
807*572c4311Sfengbojiang         lua_pushstring(lua, "Invalid debug level.");
808*572c4311Sfengbojiang         return lua_error(lua);
809*572c4311Sfengbojiang     }
810*572c4311Sfengbojiang 
811*572c4311Sfengbojiang     /* Glue together all the arguments */
812*572c4311Sfengbojiang     log = sdsempty();
813*572c4311Sfengbojiang     for (j = 1; j < argc; j++) {
814*572c4311Sfengbojiang         size_t len;
815*572c4311Sfengbojiang         char *s;
816*572c4311Sfengbojiang 
817*572c4311Sfengbojiang         s = (char*)lua_tolstring(lua,(-argc)+j,&len);
818*572c4311Sfengbojiang         if (s) {
819*572c4311Sfengbojiang             if (j != 1) log = sdscatlen(log," ",1);
820*572c4311Sfengbojiang             log = sdscatlen(log,s,len);
821*572c4311Sfengbojiang         }
822*572c4311Sfengbojiang     }
823*572c4311Sfengbojiang     serverLogRaw(level,log);
824*572c4311Sfengbojiang     sdsfree(log);
825*572c4311Sfengbojiang     return 0;
826*572c4311Sfengbojiang }
827*572c4311Sfengbojiang 
828*572c4311Sfengbojiang /* ---------------------------------------------------------------------------
829*572c4311Sfengbojiang  * Lua engine initialization and reset.
830*572c4311Sfengbojiang  * ------------------------------------------------------------------------- */
831*572c4311Sfengbojiang 
luaLoadLib(lua_State * lua,const char * libname,lua_CFunction luafunc)832*572c4311Sfengbojiang void luaLoadLib(lua_State *lua, const char *libname, lua_CFunction luafunc) {
833*572c4311Sfengbojiang   lua_pushcfunction(lua, luafunc);
834*572c4311Sfengbojiang   lua_pushstring(lua, libname);
835*572c4311Sfengbojiang   lua_call(lua, 1, 0);
836*572c4311Sfengbojiang }
837*572c4311Sfengbojiang 
838*572c4311Sfengbojiang LUALIB_API int (luaopen_cjson) (lua_State *L);
839*572c4311Sfengbojiang LUALIB_API int (luaopen_struct) (lua_State *L);
840*572c4311Sfengbojiang LUALIB_API int (luaopen_cmsgpack) (lua_State *L);
841*572c4311Sfengbojiang LUALIB_API int (luaopen_bit) (lua_State *L);
842*572c4311Sfengbojiang 
luaLoadLibraries(lua_State * lua)843*572c4311Sfengbojiang void luaLoadLibraries(lua_State *lua) {
844*572c4311Sfengbojiang     luaLoadLib(lua, "", luaopen_base);
845*572c4311Sfengbojiang     luaLoadLib(lua, LUA_TABLIBNAME, luaopen_table);
846*572c4311Sfengbojiang     luaLoadLib(lua, LUA_STRLIBNAME, luaopen_string);
847*572c4311Sfengbojiang     luaLoadLib(lua, LUA_MATHLIBNAME, luaopen_math);
848*572c4311Sfengbojiang     luaLoadLib(lua, LUA_DBLIBNAME, luaopen_debug);
849*572c4311Sfengbojiang     luaLoadLib(lua, "cjson", luaopen_cjson);
850*572c4311Sfengbojiang     luaLoadLib(lua, "struct", luaopen_struct);
851*572c4311Sfengbojiang     luaLoadLib(lua, "cmsgpack", luaopen_cmsgpack);
852*572c4311Sfengbojiang     luaLoadLib(lua, "bit", luaopen_bit);
853*572c4311Sfengbojiang 
854*572c4311Sfengbojiang #if 0 /* Stuff that we don't load currently, for sandboxing concerns. */
855*572c4311Sfengbojiang     luaLoadLib(lua, LUA_LOADLIBNAME, luaopen_package);
856*572c4311Sfengbojiang     luaLoadLib(lua, LUA_OSLIBNAME, luaopen_os);
857*572c4311Sfengbojiang #endif
858*572c4311Sfengbojiang }
859*572c4311Sfengbojiang 
860*572c4311Sfengbojiang /* Remove a functions that we don't want to expose to the Redis scripting
861*572c4311Sfengbojiang  * environment. */
luaRemoveUnsupportedFunctions(lua_State * lua)862*572c4311Sfengbojiang void luaRemoveUnsupportedFunctions(lua_State *lua) {
863*572c4311Sfengbojiang     lua_pushnil(lua);
864*572c4311Sfengbojiang     lua_setglobal(lua,"loadfile");
865*572c4311Sfengbojiang     lua_pushnil(lua);
866*572c4311Sfengbojiang     lua_setglobal(lua,"dofile");
867*572c4311Sfengbojiang }
868*572c4311Sfengbojiang 
869*572c4311Sfengbojiang /* This function installs metamethods in the global table _G that prevent
870*572c4311Sfengbojiang  * the creation of globals accidentally.
871*572c4311Sfengbojiang  *
872*572c4311Sfengbojiang  * It should be the last to be called in the scripting engine initialization
873*572c4311Sfengbojiang  * sequence, because it may interact with creation of globals. */
scriptingEnableGlobalsProtection(lua_State * lua)874*572c4311Sfengbojiang void scriptingEnableGlobalsProtection(lua_State *lua) {
875*572c4311Sfengbojiang     char *s[32];
876*572c4311Sfengbojiang     sds code = sdsempty();
877*572c4311Sfengbojiang     int j = 0;
878*572c4311Sfengbojiang 
879*572c4311Sfengbojiang     /* strict.lua from: http://metalua.luaforge.net/src/lib/strict.lua.html.
880*572c4311Sfengbojiang      * Modified to be adapted to Redis. */
881*572c4311Sfengbojiang     s[j++]="local dbg=debug\n";
882*572c4311Sfengbojiang     s[j++]="local mt = {}\n";
883*572c4311Sfengbojiang     s[j++]="setmetatable(_G, mt)\n";
884*572c4311Sfengbojiang     s[j++]="mt.__newindex = function (t, n, v)\n";
885*572c4311Sfengbojiang     s[j++]="  if dbg.getinfo(2) then\n";
886*572c4311Sfengbojiang     s[j++]="    local w = dbg.getinfo(2, \"S\").what\n";
887*572c4311Sfengbojiang     s[j++]="    if w ~= \"main\" and w ~= \"C\" then\n";
888*572c4311Sfengbojiang     s[j++]="      error(\"Script attempted to create global variable '\"..tostring(n)..\"'\", 2)\n";
889*572c4311Sfengbojiang     s[j++]="    end\n";
890*572c4311Sfengbojiang     s[j++]="  end\n";
891*572c4311Sfengbojiang     s[j++]="  rawset(t, n, v)\n";
892*572c4311Sfengbojiang     s[j++]="end\n";
893*572c4311Sfengbojiang     s[j++]="mt.__index = function (t, n)\n";
894*572c4311Sfengbojiang     s[j++]="  if dbg.getinfo(2) and dbg.getinfo(2, \"S\").what ~= \"C\" then\n";
895*572c4311Sfengbojiang     s[j++]="    error(\"Script attempted to access nonexistent global variable '\"..tostring(n)..\"'\", 2)\n";
896*572c4311Sfengbojiang     s[j++]="  end\n";
897*572c4311Sfengbojiang     s[j++]="  return rawget(t, n)\n";
898*572c4311Sfengbojiang     s[j++]="end\n";
899*572c4311Sfengbojiang     s[j++]="debug = nil\n";
900*572c4311Sfengbojiang     s[j++]=NULL;
901*572c4311Sfengbojiang 
902*572c4311Sfengbojiang     for (j = 0; s[j] != NULL; j++) code = sdscatlen(code,s[j],strlen(s[j]));
903*572c4311Sfengbojiang     luaL_loadbuffer(lua,code,sdslen(code),"@enable_strict_lua");
904*572c4311Sfengbojiang     lua_pcall(lua,0,0,0);
905*572c4311Sfengbojiang     sdsfree(code);
906*572c4311Sfengbojiang }
907*572c4311Sfengbojiang 
908*572c4311Sfengbojiang /* Initialize the scripting environment.
909*572c4311Sfengbojiang  *
910*572c4311Sfengbojiang  * This function is called the first time at server startup with
911*572c4311Sfengbojiang  * the 'setup' argument set to 1.
912*572c4311Sfengbojiang  *
913*572c4311Sfengbojiang  * It can be called again multiple times during the lifetime of the Redis
914*572c4311Sfengbojiang  * process, with 'setup' set to 0, and following a scriptingRelease() call,
915*572c4311Sfengbojiang  * in order to reset the Lua scripting environment.
916*572c4311Sfengbojiang  *
917*572c4311Sfengbojiang  * However it is simpler to just call scriptingReset() that does just that. */
scriptingInit(int setup)918*572c4311Sfengbojiang void scriptingInit(int setup) {
919*572c4311Sfengbojiang     lua_State *lua = lua_open();
920*572c4311Sfengbojiang 
921*572c4311Sfengbojiang     if (setup) {
922*572c4311Sfengbojiang         server.lua_client = NULL;
923*572c4311Sfengbojiang         server.lua_caller = NULL;
924*572c4311Sfengbojiang         server.lua_timedout = 0;
925*572c4311Sfengbojiang         ldbInit();
926*572c4311Sfengbojiang     }
927*572c4311Sfengbojiang 
928*572c4311Sfengbojiang     luaLoadLibraries(lua);
929*572c4311Sfengbojiang     luaRemoveUnsupportedFunctions(lua);
930*572c4311Sfengbojiang 
931*572c4311Sfengbojiang     /* Initialize a dictionary we use to map SHAs to scripts.
932*572c4311Sfengbojiang      * This is useful for replication, as we need to replicate EVALSHA
933*572c4311Sfengbojiang      * as EVAL, so we need to remember the associated script. */
934*572c4311Sfengbojiang     server.lua_scripts = dictCreate(&shaScriptObjectDictType,NULL);
935*572c4311Sfengbojiang     server.lua_scripts_mem = 0;
936*572c4311Sfengbojiang 
937*572c4311Sfengbojiang     /* Register the redis commands table and fields */
938*572c4311Sfengbojiang     lua_newtable(lua);
939*572c4311Sfengbojiang 
940*572c4311Sfengbojiang     /* redis.call */
941*572c4311Sfengbojiang     lua_pushstring(lua,"call");
942*572c4311Sfengbojiang     lua_pushcfunction(lua,luaRedisCallCommand);
943*572c4311Sfengbojiang     lua_settable(lua,-3);
944*572c4311Sfengbojiang 
945*572c4311Sfengbojiang     /* redis.pcall */
946*572c4311Sfengbojiang     lua_pushstring(lua,"pcall");
947*572c4311Sfengbojiang     lua_pushcfunction(lua,luaRedisPCallCommand);
948*572c4311Sfengbojiang     lua_settable(lua,-3);
949*572c4311Sfengbojiang 
950*572c4311Sfengbojiang     /* redis.log and log levels. */
951*572c4311Sfengbojiang     lua_pushstring(lua,"log");
952*572c4311Sfengbojiang     lua_pushcfunction(lua,luaLogCommand);
953*572c4311Sfengbojiang     lua_settable(lua,-3);
954*572c4311Sfengbojiang 
955*572c4311Sfengbojiang     lua_pushstring(lua,"LOG_DEBUG");
956*572c4311Sfengbojiang     lua_pushnumber(lua,LL_DEBUG);
957*572c4311Sfengbojiang     lua_settable(lua,-3);
958*572c4311Sfengbojiang 
959*572c4311Sfengbojiang     lua_pushstring(lua,"LOG_VERBOSE");
960*572c4311Sfengbojiang     lua_pushnumber(lua,LL_VERBOSE);
961*572c4311Sfengbojiang     lua_settable(lua,-3);
962*572c4311Sfengbojiang 
963*572c4311Sfengbojiang     lua_pushstring(lua,"LOG_NOTICE");
964*572c4311Sfengbojiang     lua_pushnumber(lua,LL_NOTICE);
965*572c4311Sfengbojiang     lua_settable(lua,-3);
966*572c4311Sfengbojiang 
967*572c4311Sfengbojiang     lua_pushstring(lua,"LOG_WARNING");
968*572c4311Sfengbojiang     lua_pushnumber(lua,LL_WARNING);
969*572c4311Sfengbojiang     lua_settable(lua,-3);
970*572c4311Sfengbojiang 
971*572c4311Sfengbojiang     /* redis.sha1hex */
972*572c4311Sfengbojiang     lua_pushstring(lua, "sha1hex");
973*572c4311Sfengbojiang     lua_pushcfunction(lua, luaRedisSha1hexCommand);
974*572c4311Sfengbojiang     lua_settable(lua, -3);
975*572c4311Sfengbojiang 
976*572c4311Sfengbojiang     /* redis.error_reply and redis.status_reply */
977*572c4311Sfengbojiang     lua_pushstring(lua, "error_reply");
978*572c4311Sfengbojiang     lua_pushcfunction(lua, luaRedisErrorReplyCommand);
979*572c4311Sfengbojiang     lua_settable(lua, -3);
980*572c4311Sfengbojiang     lua_pushstring(lua, "status_reply");
981*572c4311Sfengbojiang     lua_pushcfunction(lua, luaRedisStatusReplyCommand);
982*572c4311Sfengbojiang     lua_settable(lua, -3);
983*572c4311Sfengbojiang 
984*572c4311Sfengbojiang     /* redis.replicate_commands */
985*572c4311Sfengbojiang     lua_pushstring(lua, "replicate_commands");
986*572c4311Sfengbojiang     lua_pushcfunction(lua, luaRedisReplicateCommandsCommand);
987*572c4311Sfengbojiang     lua_settable(lua, -3);
988*572c4311Sfengbojiang 
989*572c4311Sfengbojiang     /* redis.set_repl and associated flags. */
990*572c4311Sfengbojiang     lua_pushstring(lua,"set_repl");
991*572c4311Sfengbojiang     lua_pushcfunction(lua,luaRedisSetReplCommand);
992*572c4311Sfengbojiang     lua_settable(lua,-3);
993*572c4311Sfengbojiang 
994*572c4311Sfengbojiang     lua_pushstring(lua,"REPL_NONE");
995*572c4311Sfengbojiang     lua_pushnumber(lua,PROPAGATE_NONE);
996*572c4311Sfengbojiang     lua_settable(lua,-3);
997*572c4311Sfengbojiang 
998*572c4311Sfengbojiang     lua_pushstring(lua,"REPL_AOF");
999*572c4311Sfengbojiang     lua_pushnumber(lua,PROPAGATE_AOF);
1000*572c4311Sfengbojiang     lua_settable(lua,-3);
1001*572c4311Sfengbojiang 
1002*572c4311Sfengbojiang     lua_pushstring(lua,"REPL_SLAVE");
1003*572c4311Sfengbojiang     lua_pushnumber(lua,PROPAGATE_REPL);
1004*572c4311Sfengbojiang     lua_settable(lua,-3);
1005*572c4311Sfengbojiang 
1006*572c4311Sfengbojiang     lua_pushstring(lua,"REPL_REPLICA");
1007*572c4311Sfengbojiang     lua_pushnumber(lua,PROPAGATE_REPL);
1008*572c4311Sfengbojiang     lua_settable(lua,-3);
1009*572c4311Sfengbojiang 
1010*572c4311Sfengbojiang     lua_pushstring(lua,"REPL_ALL");
1011*572c4311Sfengbojiang     lua_pushnumber(lua,PROPAGATE_AOF|PROPAGATE_REPL);
1012*572c4311Sfengbojiang     lua_settable(lua,-3);
1013*572c4311Sfengbojiang 
1014*572c4311Sfengbojiang     /* redis.breakpoint */
1015*572c4311Sfengbojiang     lua_pushstring(lua,"breakpoint");
1016*572c4311Sfengbojiang     lua_pushcfunction(lua,luaRedisBreakpointCommand);
1017*572c4311Sfengbojiang     lua_settable(lua,-3);
1018*572c4311Sfengbojiang 
1019*572c4311Sfengbojiang     /* redis.debug */
1020*572c4311Sfengbojiang     lua_pushstring(lua,"debug");
1021*572c4311Sfengbojiang     lua_pushcfunction(lua,luaRedisDebugCommand);
1022*572c4311Sfengbojiang     lua_settable(lua,-3);
1023*572c4311Sfengbojiang 
1024*572c4311Sfengbojiang     /* Finally set the table as 'redis' global var. */
1025*572c4311Sfengbojiang     lua_setglobal(lua,"redis");
1026*572c4311Sfengbojiang 
1027*572c4311Sfengbojiang     /* Replace math.random and math.randomseed with our implementations. */
1028*572c4311Sfengbojiang     lua_getglobal(lua,"math");
1029*572c4311Sfengbojiang 
1030*572c4311Sfengbojiang     lua_pushstring(lua,"random");
1031*572c4311Sfengbojiang     lua_pushcfunction(lua,redis_math_random);
1032*572c4311Sfengbojiang     lua_settable(lua,-3);
1033*572c4311Sfengbojiang 
1034*572c4311Sfengbojiang     lua_pushstring(lua,"randomseed");
1035*572c4311Sfengbojiang     lua_pushcfunction(lua,redis_math_randomseed);
1036*572c4311Sfengbojiang     lua_settable(lua,-3);
1037*572c4311Sfengbojiang 
1038*572c4311Sfengbojiang     lua_setglobal(lua,"math");
1039*572c4311Sfengbojiang 
1040*572c4311Sfengbojiang     /* Add a helper function that we use to sort the multi bulk output of non
1041*572c4311Sfengbojiang      * deterministic commands, when containing 'false' elements. */
1042*572c4311Sfengbojiang     {
1043*572c4311Sfengbojiang         char *compare_func =    "function __redis__compare_helper(a,b)\n"
1044*572c4311Sfengbojiang                                 "  if a == false then a = '' end\n"
1045*572c4311Sfengbojiang                                 "  if b == false then b = '' end\n"
1046*572c4311Sfengbojiang                                 "  return a<b\n"
1047*572c4311Sfengbojiang                                 "end\n";
1048*572c4311Sfengbojiang         luaL_loadbuffer(lua,compare_func,strlen(compare_func),"@cmp_func_def");
1049*572c4311Sfengbojiang         lua_pcall(lua,0,0,0);
1050*572c4311Sfengbojiang     }
1051*572c4311Sfengbojiang 
1052*572c4311Sfengbojiang     /* Add a helper function we use for pcall error reporting.
1053*572c4311Sfengbojiang      * Note that when the error is in the C function we want to report the
1054*572c4311Sfengbojiang      * information about the caller, that's what makes sense from the point
1055*572c4311Sfengbojiang      * of view of the user debugging a script. */
1056*572c4311Sfengbojiang     {
1057*572c4311Sfengbojiang         char *errh_func =       "local dbg = debug\n"
1058*572c4311Sfengbojiang                                 "function __redis__err__handler(err)\n"
1059*572c4311Sfengbojiang                                 "  local i = dbg.getinfo(2,'nSl')\n"
1060*572c4311Sfengbojiang                                 "  if i and i.what == 'C' then\n"
1061*572c4311Sfengbojiang                                 "    i = dbg.getinfo(3,'nSl')\n"
1062*572c4311Sfengbojiang                                 "  end\n"
1063*572c4311Sfengbojiang                                 "  if i then\n"
1064*572c4311Sfengbojiang                                 "    return i.source .. ':' .. i.currentline .. ': ' .. err\n"
1065*572c4311Sfengbojiang                                 "  else\n"
1066*572c4311Sfengbojiang                                 "    return err\n"
1067*572c4311Sfengbojiang                                 "  end\n"
1068*572c4311Sfengbojiang                                 "end\n";
1069*572c4311Sfengbojiang         luaL_loadbuffer(lua,errh_func,strlen(errh_func),"@err_handler_def");
1070*572c4311Sfengbojiang         lua_pcall(lua,0,0,0);
1071*572c4311Sfengbojiang     }
1072*572c4311Sfengbojiang 
1073*572c4311Sfengbojiang     /* Create the (non connected) client that we use to execute Redis commands
1074*572c4311Sfengbojiang      * inside the Lua interpreter.
1075*572c4311Sfengbojiang      * Note: there is no need to create it again when this function is called
1076*572c4311Sfengbojiang      * by scriptingReset(). */
1077*572c4311Sfengbojiang     if (server.lua_client == NULL) {
1078*572c4311Sfengbojiang         server.lua_client = createClient(-1);
1079*572c4311Sfengbojiang         server.lua_client->flags |= CLIENT_LUA;
1080*572c4311Sfengbojiang     }
1081*572c4311Sfengbojiang 
1082*572c4311Sfengbojiang     /* Lua beginners often don't use "local", this is likely to introduce
1083*572c4311Sfengbojiang      * subtle bugs in their code. To prevent problems we protect accesses
1084*572c4311Sfengbojiang      * to global variables. */
1085*572c4311Sfengbojiang     scriptingEnableGlobalsProtection(lua);
1086*572c4311Sfengbojiang 
1087*572c4311Sfengbojiang     server.lua = lua;
1088*572c4311Sfengbojiang }
1089*572c4311Sfengbojiang 
1090*572c4311Sfengbojiang /* Release resources related to Lua scripting.
1091*572c4311Sfengbojiang  * This function is used in order to reset the scripting environment. */
scriptingRelease(void)1092*572c4311Sfengbojiang void scriptingRelease(void) {
1093*572c4311Sfengbojiang     dictRelease(server.lua_scripts);
1094*572c4311Sfengbojiang     server.lua_scripts_mem = 0;
1095*572c4311Sfengbojiang     lua_close(server.lua);
1096*572c4311Sfengbojiang }
1097*572c4311Sfengbojiang 
scriptingReset(void)1098*572c4311Sfengbojiang void scriptingReset(void) {
1099*572c4311Sfengbojiang     scriptingRelease();
1100*572c4311Sfengbojiang     scriptingInit(0);
1101*572c4311Sfengbojiang }
1102*572c4311Sfengbojiang 
1103*572c4311Sfengbojiang /* Set an array of Redis String Objects as a Lua array (table) stored into a
1104*572c4311Sfengbojiang  * global variable. */
luaSetGlobalArray(lua_State * lua,char * var,robj ** elev,int elec)1105*572c4311Sfengbojiang void luaSetGlobalArray(lua_State *lua, char *var, robj **elev, int elec) {
1106*572c4311Sfengbojiang     int j;
1107*572c4311Sfengbojiang 
1108*572c4311Sfengbojiang     lua_newtable(lua);
1109*572c4311Sfengbojiang     for (j = 0; j < elec; j++) {
1110*572c4311Sfengbojiang         lua_pushlstring(lua,(char*)elev[j]->ptr,sdslen(elev[j]->ptr));
1111*572c4311Sfengbojiang         lua_rawseti(lua,-2,j+1);
1112*572c4311Sfengbojiang     }
1113*572c4311Sfengbojiang     lua_setglobal(lua,var);
1114*572c4311Sfengbojiang }
1115*572c4311Sfengbojiang 
1116*572c4311Sfengbojiang /* ---------------------------------------------------------------------------
1117*572c4311Sfengbojiang  * Redis provided math.random
1118*572c4311Sfengbojiang  * ------------------------------------------------------------------------- */
1119*572c4311Sfengbojiang 
1120*572c4311Sfengbojiang /* We replace math.random() with our implementation that is not affected
1121*572c4311Sfengbojiang  * by specific libc random() implementations and will output the same sequence
1122*572c4311Sfengbojiang  * (for the same seed) in every arch. */
1123*572c4311Sfengbojiang 
1124*572c4311Sfengbojiang /* The following implementation is the one shipped with Lua itself but with
1125*572c4311Sfengbojiang  * rand() replaced by redisLrand48(). */
redis_math_random(lua_State * L)1126*572c4311Sfengbojiang int redis_math_random (lua_State *L) {
1127*572c4311Sfengbojiang   /* the `%' avoids the (rare) case of r==1, and is needed also because on
1128*572c4311Sfengbojiang      some systems (SunOS!) `rand()' may return a value larger than RAND_MAX */
1129*572c4311Sfengbojiang   lua_Number r = (lua_Number)(redisLrand48()%REDIS_LRAND48_MAX) /
1130*572c4311Sfengbojiang                                 (lua_Number)REDIS_LRAND48_MAX;
1131*572c4311Sfengbojiang   switch (lua_gettop(L)) {  /* check number of arguments */
1132*572c4311Sfengbojiang     case 0: {  /* no arguments */
1133*572c4311Sfengbojiang       lua_pushnumber(L, r);  /* Number between 0 and 1 */
1134*572c4311Sfengbojiang       break;
1135*572c4311Sfengbojiang     }
1136*572c4311Sfengbojiang     case 1: {  /* only upper limit */
1137*572c4311Sfengbojiang       int u = luaL_checkint(L, 1);
1138*572c4311Sfengbojiang       luaL_argcheck(L, 1<=u, 1, "interval is empty");
1139*572c4311Sfengbojiang       lua_pushnumber(L, floor(r*u)+1);  /* int between 1 and `u' */
1140*572c4311Sfengbojiang       break;
1141*572c4311Sfengbojiang     }
1142*572c4311Sfengbojiang     case 2: {  /* lower and upper limits */
1143*572c4311Sfengbojiang       int l = luaL_checkint(L, 1);
1144*572c4311Sfengbojiang       int u = luaL_checkint(L, 2);
1145*572c4311Sfengbojiang       luaL_argcheck(L, l<=u, 2, "interval is empty");
1146*572c4311Sfengbojiang       lua_pushnumber(L, floor(r*(u-l+1))+l);  /* int between `l' and `u' */
1147*572c4311Sfengbojiang       break;
1148*572c4311Sfengbojiang     }
1149*572c4311Sfengbojiang     default: return luaL_error(L, "wrong number of arguments");
1150*572c4311Sfengbojiang   }
1151*572c4311Sfengbojiang   return 1;
1152*572c4311Sfengbojiang }
1153*572c4311Sfengbojiang 
redis_math_randomseed(lua_State * L)1154*572c4311Sfengbojiang int redis_math_randomseed (lua_State *L) {
1155*572c4311Sfengbojiang   redisSrand48(luaL_checkint(L, 1));
1156*572c4311Sfengbojiang   return 0;
1157*572c4311Sfengbojiang }
1158*572c4311Sfengbojiang 
1159*572c4311Sfengbojiang /* ---------------------------------------------------------------------------
1160*572c4311Sfengbojiang  * EVAL and SCRIPT commands implementation
1161*572c4311Sfengbojiang  * ------------------------------------------------------------------------- */
1162*572c4311Sfengbojiang 
1163*572c4311Sfengbojiang /* Define a Lua function with the specified body.
1164*572c4311Sfengbojiang  * The function name will be generated in the following form:
1165*572c4311Sfengbojiang  *
1166*572c4311Sfengbojiang  *   f_<hex sha1 sum>
1167*572c4311Sfengbojiang  *
1168*572c4311Sfengbojiang  * The function increments the reference count of the 'body' object as a
1169*572c4311Sfengbojiang  * side effect of a successful call.
1170*572c4311Sfengbojiang  *
1171*572c4311Sfengbojiang  * On success a pointer to an SDS string representing the function SHA1 of the
1172*572c4311Sfengbojiang  * just added function is returned (and will be valid until the next call
1173*572c4311Sfengbojiang  * to scriptingReset() function), otherwise NULL is returned.
1174*572c4311Sfengbojiang  *
1175*572c4311Sfengbojiang  * The function handles the fact of being called with a script that already
1176*572c4311Sfengbojiang  * exists, and in such a case, it behaves like in the success case.
1177*572c4311Sfengbojiang  *
1178*572c4311Sfengbojiang  * If 'c' is not NULL, on error the client is informed with an appropriate
1179*572c4311Sfengbojiang  * error describing the nature of the problem and the Lua interpreter error. */
luaCreateFunction(client * c,lua_State * lua,robj * body)1180*572c4311Sfengbojiang sds luaCreateFunction(client *c, lua_State *lua, robj *body) {
1181*572c4311Sfengbojiang     char funcname[43];
1182*572c4311Sfengbojiang     dictEntry *de;
1183*572c4311Sfengbojiang 
1184*572c4311Sfengbojiang     funcname[0] = 'f';
1185*572c4311Sfengbojiang     funcname[1] = '_';
1186*572c4311Sfengbojiang     sha1hex(funcname+2,body->ptr,sdslen(body->ptr));
1187*572c4311Sfengbojiang 
1188*572c4311Sfengbojiang     sds sha = sdsnewlen(funcname+2,40);
1189*572c4311Sfengbojiang     if ((de = dictFind(server.lua_scripts,sha)) != NULL) {
1190*572c4311Sfengbojiang         sdsfree(sha);
1191*572c4311Sfengbojiang         return dictGetKey(de);
1192*572c4311Sfengbojiang     }
1193*572c4311Sfengbojiang 
1194*572c4311Sfengbojiang     sds funcdef = sdsempty();
1195*572c4311Sfengbojiang     funcdef = sdscat(funcdef,"function ");
1196*572c4311Sfengbojiang     funcdef = sdscatlen(funcdef,funcname,42);
1197*572c4311Sfengbojiang     funcdef = sdscatlen(funcdef,"() ",3);
1198*572c4311Sfengbojiang     funcdef = sdscatlen(funcdef,body->ptr,sdslen(body->ptr));
1199*572c4311Sfengbojiang     funcdef = sdscatlen(funcdef,"\nend",4);
1200*572c4311Sfengbojiang 
1201*572c4311Sfengbojiang     if (luaL_loadbuffer(lua,funcdef,sdslen(funcdef),"@user_script")) {
1202*572c4311Sfengbojiang         if (c != NULL) {
1203*572c4311Sfengbojiang             addReplyErrorFormat(c,
1204*572c4311Sfengbojiang                 "Error compiling script (new function): %s\n",
1205*572c4311Sfengbojiang                 lua_tostring(lua,-1));
1206*572c4311Sfengbojiang         }
1207*572c4311Sfengbojiang         lua_pop(lua,1);
1208*572c4311Sfengbojiang         sdsfree(sha);
1209*572c4311Sfengbojiang         sdsfree(funcdef);
1210*572c4311Sfengbojiang         return NULL;
1211*572c4311Sfengbojiang     }
1212*572c4311Sfengbojiang     sdsfree(funcdef);
1213*572c4311Sfengbojiang 
1214*572c4311Sfengbojiang     if (lua_pcall(lua,0,0,0)) {
1215*572c4311Sfengbojiang         if (c != NULL) {
1216*572c4311Sfengbojiang             addReplyErrorFormat(c,"Error running script (new function): %s\n",
1217*572c4311Sfengbojiang                 lua_tostring(lua,-1));
1218*572c4311Sfengbojiang         }
1219*572c4311Sfengbojiang         lua_pop(lua,1);
1220*572c4311Sfengbojiang         sdsfree(sha);
1221*572c4311Sfengbojiang         return NULL;
1222*572c4311Sfengbojiang     }
1223*572c4311Sfengbojiang 
1224*572c4311Sfengbojiang     /* We also save a SHA1 -> Original script map in a dictionary
1225*572c4311Sfengbojiang      * so that we can replicate / write in the AOF all the
1226*572c4311Sfengbojiang      * EVALSHA commands as EVAL using the original script. */
1227*572c4311Sfengbojiang     int retval = dictAdd(server.lua_scripts,sha,body);
1228*572c4311Sfengbojiang     serverAssertWithInfo(c ? c : server.lua_client,NULL,retval == DICT_OK);
1229*572c4311Sfengbojiang     server.lua_scripts_mem += sdsZmallocSize(sha) + getStringObjectSdsUsedMemory(body);
1230*572c4311Sfengbojiang     incrRefCount(body);
1231*572c4311Sfengbojiang     return sha;
1232*572c4311Sfengbojiang }
1233*572c4311Sfengbojiang 
1234*572c4311Sfengbojiang /* This is the Lua script "count" hook that we use to detect scripts timeout. */
luaMaskCountHook(lua_State * lua,lua_Debug * ar)1235*572c4311Sfengbojiang void luaMaskCountHook(lua_State *lua, lua_Debug *ar) {
1236*572c4311Sfengbojiang     long long elapsed = mstime() - server.lua_time_start;
1237*572c4311Sfengbojiang     UNUSED(ar);
1238*572c4311Sfengbojiang     UNUSED(lua);
1239*572c4311Sfengbojiang 
1240*572c4311Sfengbojiang     /* Set the timeout condition if not already set and the maximum
1241*572c4311Sfengbojiang      * execution time was reached. */
1242*572c4311Sfengbojiang     if (elapsed >= server.lua_time_limit && server.lua_timedout == 0) {
1243*572c4311Sfengbojiang         serverLog(LL_WARNING,"Lua slow script detected: still in execution after %lld milliseconds. You can try killing the script using the SCRIPT KILL command.",elapsed);
1244*572c4311Sfengbojiang         server.lua_timedout = 1;
1245*572c4311Sfengbojiang         /* Once the script timeouts we reenter the event loop to permit others
1246*572c4311Sfengbojiang          * to call SCRIPT KILL or SHUTDOWN NOSAVE if needed. For this reason
1247*572c4311Sfengbojiang          * we need to mask the client executing the script from the event loop.
1248*572c4311Sfengbojiang          * If we don't do that the client may disconnect and could no longer be
1249*572c4311Sfengbojiang          * here when the EVAL command will return. */
1250*572c4311Sfengbojiang         protectClient(server.lua_caller);
1251*572c4311Sfengbojiang     }
1252*572c4311Sfengbojiang     if (server.lua_timedout) processEventsWhileBlocked();
1253*572c4311Sfengbojiang     if (server.lua_kill) {
1254*572c4311Sfengbojiang         serverLog(LL_WARNING,"Lua script killed by user with SCRIPT KILL.");
1255*572c4311Sfengbojiang         lua_pushstring(lua,"Script killed by user with SCRIPT KILL...");
1256*572c4311Sfengbojiang         lua_error(lua);
1257*572c4311Sfengbojiang     }
1258*572c4311Sfengbojiang }
1259*572c4311Sfengbojiang 
evalGenericCommand(client * c,int evalsha)1260*572c4311Sfengbojiang void evalGenericCommand(client *c, int evalsha) {
1261*572c4311Sfengbojiang     lua_State *lua = server.lua;
1262*572c4311Sfengbojiang     char funcname[43];
1263*572c4311Sfengbojiang     long long numkeys;
1264*572c4311Sfengbojiang     long long initial_server_dirty = server.dirty;
1265*572c4311Sfengbojiang     int delhook = 0, err;
1266*572c4311Sfengbojiang 
1267*572c4311Sfengbojiang     /* When we replicate whole scripts, we want the same PRNG sequence at
1268*572c4311Sfengbojiang      * every call so that our PRNG is not affected by external state. */
1269*572c4311Sfengbojiang     redisSrand48(0);
1270*572c4311Sfengbojiang 
1271*572c4311Sfengbojiang     /* We set this flag to zero to remember that so far no random command
1272*572c4311Sfengbojiang      * was called. This way we can allow the user to call commands like
1273*572c4311Sfengbojiang      * SRANDMEMBER or RANDOMKEY from Lua scripts as far as no write command
1274*572c4311Sfengbojiang      * is called (otherwise the replication and AOF would end with non
1275*572c4311Sfengbojiang      * deterministic sequences).
1276*572c4311Sfengbojiang      *
1277*572c4311Sfengbojiang      * Thanks to this flag we'll raise an error every time a write command
1278*572c4311Sfengbojiang      * is called after a random command was used. */
1279*572c4311Sfengbojiang     server.lua_random_dirty = 0;
1280*572c4311Sfengbojiang     server.lua_write_dirty = 0;
1281*572c4311Sfengbojiang     server.lua_replicate_commands = server.lua_always_replicate_commands;
1282*572c4311Sfengbojiang     server.lua_multi_emitted = 0;
1283*572c4311Sfengbojiang     server.lua_repl = PROPAGATE_AOF|PROPAGATE_REPL;
1284*572c4311Sfengbojiang 
1285*572c4311Sfengbojiang     /* Get the number of arguments that are keys */
1286*572c4311Sfengbojiang     if (getLongLongFromObjectOrReply(c,c->argv[2],&numkeys,NULL) != C_OK)
1287*572c4311Sfengbojiang         return;
1288*572c4311Sfengbojiang     if (numkeys > (c->argc - 3)) {
1289*572c4311Sfengbojiang         addReplyError(c,"Number of keys can't be greater than number of args");
1290*572c4311Sfengbojiang         return;
1291*572c4311Sfengbojiang     } else if (numkeys < 0) {
1292*572c4311Sfengbojiang         addReplyError(c,"Number of keys can't be negative");
1293*572c4311Sfengbojiang         return;
1294*572c4311Sfengbojiang     }
1295*572c4311Sfengbojiang 
1296*572c4311Sfengbojiang     /* We obtain the script SHA1, then check if this function is already
1297*572c4311Sfengbojiang      * defined into the Lua state */
1298*572c4311Sfengbojiang     funcname[0] = 'f';
1299*572c4311Sfengbojiang     funcname[1] = '_';
1300*572c4311Sfengbojiang     if (!evalsha) {
1301*572c4311Sfengbojiang         /* Hash the code if this is an EVAL call */
1302*572c4311Sfengbojiang         sha1hex(funcname+2,c->argv[1]->ptr,sdslen(c->argv[1]->ptr));
1303*572c4311Sfengbojiang     } else {
1304*572c4311Sfengbojiang         /* We already have the SHA if it is a EVALSHA */
1305*572c4311Sfengbojiang         int j;
1306*572c4311Sfengbojiang         char *sha = c->argv[1]->ptr;
1307*572c4311Sfengbojiang 
1308*572c4311Sfengbojiang         /* Convert to lowercase. We don't use tolower since the function
1309*572c4311Sfengbojiang          * managed to always show up in the profiler output consuming
1310*572c4311Sfengbojiang          * a non trivial amount of time. */
1311*572c4311Sfengbojiang         for (j = 0; j < 40; j++)
1312*572c4311Sfengbojiang             funcname[j+2] = (sha[j] >= 'A' && sha[j] <= 'Z') ?
1313*572c4311Sfengbojiang                 sha[j]+('a'-'A') : sha[j];
1314*572c4311Sfengbojiang         funcname[42] = '\0';
1315*572c4311Sfengbojiang     }
1316*572c4311Sfengbojiang 
1317*572c4311Sfengbojiang     /* Push the pcall error handler function on the stack. */
1318*572c4311Sfengbojiang     lua_getglobal(lua, "__redis__err__handler");
1319*572c4311Sfengbojiang 
1320*572c4311Sfengbojiang     /* Try to lookup the Lua function */
1321*572c4311Sfengbojiang     lua_getglobal(lua, funcname);
1322*572c4311Sfengbojiang     if (lua_isnil(lua,-1)) {
1323*572c4311Sfengbojiang         lua_pop(lua,1); /* remove the nil from the stack */
1324*572c4311Sfengbojiang         /* Function not defined... let's define it if we have the
1325*572c4311Sfengbojiang          * body of the function. If this is an EVALSHA call we can just
1326*572c4311Sfengbojiang          * return an error. */
1327*572c4311Sfengbojiang         if (evalsha) {
1328*572c4311Sfengbojiang             lua_pop(lua,1); /* remove the error handler from the stack. */
1329*572c4311Sfengbojiang             addReply(c, shared.noscripterr);
1330*572c4311Sfengbojiang             return;
1331*572c4311Sfengbojiang         }
1332*572c4311Sfengbojiang         if (luaCreateFunction(c,lua,c->argv[1]) == NULL) {
1333*572c4311Sfengbojiang             lua_pop(lua,1); /* remove the error handler from the stack. */
1334*572c4311Sfengbojiang             /* The error is sent to the client by luaCreateFunction()
1335*572c4311Sfengbojiang              * itself when it returns NULL. */
1336*572c4311Sfengbojiang             return;
1337*572c4311Sfengbojiang         }
1338*572c4311Sfengbojiang         /* Now the following is guaranteed to return non nil */
1339*572c4311Sfengbojiang         lua_getglobal(lua, funcname);
1340*572c4311Sfengbojiang         serverAssert(!lua_isnil(lua,-1));
1341*572c4311Sfengbojiang     }
1342*572c4311Sfengbojiang 
1343*572c4311Sfengbojiang     /* Populate the argv and keys table accordingly to the arguments that
1344*572c4311Sfengbojiang      * EVAL received. */
1345*572c4311Sfengbojiang     luaSetGlobalArray(lua,"KEYS",c->argv+3,numkeys);
1346*572c4311Sfengbojiang     luaSetGlobalArray(lua,"ARGV",c->argv+3+numkeys,c->argc-3-numkeys);
1347*572c4311Sfengbojiang 
1348*572c4311Sfengbojiang     /* Select the right DB in the context of the Lua client */
1349*572c4311Sfengbojiang     selectDb(server.lua_client,c->db->id);
1350*572c4311Sfengbojiang 
1351*572c4311Sfengbojiang     /* Set a hook in order to be able to stop the script execution if it
1352*572c4311Sfengbojiang      * is running for too much time.
1353*572c4311Sfengbojiang      * We set the hook only if the time limit is enabled as the hook will
1354*572c4311Sfengbojiang      * make the Lua script execution slower.
1355*572c4311Sfengbojiang      *
1356*572c4311Sfengbojiang      * If we are debugging, we set instead a "line" hook so that the
1357*572c4311Sfengbojiang      * debugger is call-back at every line executed by the script. */
1358*572c4311Sfengbojiang     server.lua_caller = c;
1359*572c4311Sfengbojiang     server.lua_time_start = mstime();
1360*572c4311Sfengbojiang     server.lua_kill = 0;
1361*572c4311Sfengbojiang     if (server.lua_time_limit > 0 && ldb.active == 0) {
1362*572c4311Sfengbojiang         lua_sethook(lua,luaMaskCountHook,LUA_MASKCOUNT,100000);
1363*572c4311Sfengbojiang         delhook = 1;
1364*572c4311Sfengbojiang     } else if (ldb.active) {
1365*572c4311Sfengbojiang         lua_sethook(server.lua,luaLdbLineHook,LUA_MASKLINE|LUA_MASKCOUNT,100000);
1366*572c4311Sfengbojiang         delhook = 1;
1367*572c4311Sfengbojiang     }
1368*572c4311Sfengbojiang 
1369*572c4311Sfengbojiang     /* At this point whether this script was never seen before or if it was
1370*572c4311Sfengbojiang      * already defined, we can call it. We have zero arguments and expect
1371*572c4311Sfengbojiang      * a single return value. */
1372*572c4311Sfengbojiang     err = lua_pcall(lua,0,1,-2);
1373*572c4311Sfengbojiang 
1374*572c4311Sfengbojiang     /* Perform some cleanup that we need to do both on error and success. */
1375*572c4311Sfengbojiang     if (delhook) lua_sethook(lua,NULL,0,0); /* Disable hook */
1376*572c4311Sfengbojiang     if (server.lua_timedout) {
1377*572c4311Sfengbojiang         server.lua_timedout = 0;
1378*572c4311Sfengbojiang         /* Restore the client that was protected when the script timeout
1379*572c4311Sfengbojiang          * was detected. */
1380*572c4311Sfengbojiang         unprotectClient(c);
1381*572c4311Sfengbojiang         if (server.masterhost && server.master)
1382*572c4311Sfengbojiang             queueClientForReprocessing(server.master);
1383*572c4311Sfengbojiang     }
1384*572c4311Sfengbojiang     server.lua_caller = NULL;
1385*572c4311Sfengbojiang 
1386*572c4311Sfengbojiang     /* Call the Lua garbage collector from time to time to avoid a
1387*572c4311Sfengbojiang      * full cycle performed by Lua, which adds too latency.
1388*572c4311Sfengbojiang      *
1389*572c4311Sfengbojiang      * The call is performed every LUA_GC_CYCLE_PERIOD executed commands
1390*572c4311Sfengbojiang      * (and for LUA_GC_CYCLE_PERIOD collection steps) because calling it
1391*572c4311Sfengbojiang      * for every command uses too much CPU. */
1392*572c4311Sfengbojiang     #define LUA_GC_CYCLE_PERIOD 50
1393*572c4311Sfengbojiang     {
1394*572c4311Sfengbojiang         static long gc_count = 0;
1395*572c4311Sfengbojiang 
1396*572c4311Sfengbojiang         gc_count++;
1397*572c4311Sfengbojiang         if (gc_count == LUA_GC_CYCLE_PERIOD) {
1398*572c4311Sfengbojiang             lua_gc(lua,LUA_GCSTEP,LUA_GC_CYCLE_PERIOD);
1399*572c4311Sfengbojiang             gc_count = 0;
1400*572c4311Sfengbojiang         }
1401*572c4311Sfengbojiang     }
1402*572c4311Sfengbojiang 
1403*572c4311Sfengbojiang     if (err) {
1404*572c4311Sfengbojiang         addReplyErrorFormat(c,"Error running script (call to %s): %s\n",
1405*572c4311Sfengbojiang             funcname, lua_tostring(lua,-1));
1406*572c4311Sfengbojiang         lua_pop(lua,2); /* Consume the Lua reply and remove error handler. */
1407*572c4311Sfengbojiang     } else {
1408*572c4311Sfengbojiang         /* On success convert the Lua return value into Redis protocol, and
1409*572c4311Sfengbojiang          * send it to * the client. */
1410*572c4311Sfengbojiang         luaReplyToRedisReply(c,lua); /* Convert and consume the reply. */
1411*572c4311Sfengbojiang         lua_pop(lua,1); /* Remove the error handler. */
1412*572c4311Sfengbojiang     }
1413*572c4311Sfengbojiang 
1414*572c4311Sfengbojiang     /* If we are using single commands replication, emit EXEC if there
1415*572c4311Sfengbojiang      * was at least a write. */
1416*572c4311Sfengbojiang     if (server.lua_replicate_commands) {
1417*572c4311Sfengbojiang         preventCommandPropagation(c);
1418*572c4311Sfengbojiang         if (server.lua_multi_emitted) {
1419*572c4311Sfengbojiang             robj *propargv[1];
1420*572c4311Sfengbojiang             propargv[0] = createStringObject("EXEC",4);
1421*572c4311Sfengbojiang             alsoPropagate(server.execCommand,c->db->id,propargv,1,
1422*572c4311Sfengbojiang                 PROPAGATE_AOF|PROPAGATE_REPL);
1423*572c4311Sfengbojiang             decrRefCount(propargv[0]);
1424*572c4311Sfengbojiang         }
1425*572c4311Sfengbojiang     }
1426*572c4311Sfengbojiang 
1427*572c4311Sfengbojiang     /* EVALSHA should be propagated to Slave and AOF file as full EVAL, unless
1428*572c4311Sfengbojiang      * we are sure that the script was already in the context of all the
1429*572c4311Sfengbojiang      * attached slaves *and* the current AOF file if enabled.
1430*572c4311Sfengbojiang      *
1431*572c4311Sfengbojiang      * To do so we use a cache of SHA1s of scripts that we already propagated
1432*572c4311Sfengbojiang      * as full EVAL, that's called the Replication Script Cache.
1433*572c4311Sfengbojiang      *
1434*572c4311Sfengbojiang      * For repliation, everytime a new slave attaches to the master, we need to
1435*572c4311Sfengbojiang      * flush our cache of scripts that can be replicated as EVALSHA, while
1436*572c4311Sfengbojiang      * for AOF we need to do so every time we rewrite the AOF file. */
1437*572c4311Sfengbojiang     if (evalsha && !server.lua_replicate_commands) {
1438*572c4311Sfengbojiang         if (!replicationScriptCacheExists(c->argv[1]->ptr)) {
1439*572c4311Sfengbojiang             /* This script is not in our script cache, replicate it as
1440*572c4311Sfengbojiang              * EVAL, then add it into the script cache, as from now on
1441*572c4311Sfengbojiang              * slaves and AOF know about it. */
1442*572c4311Sfengbojiang             robj *script = dictFetchValue(server.lua_scripts,c->argv[1]->ptr);
1443*572c4311Sfengbojiang 
1444*572c4311Sfengbojiang             replicationScriptCacheAdd(c->argv[1]->ptr);
1445*572c4311Sfengbojiang             serverAssertWithInfo(c,NULL,script != NULL);
1446*572c4311Sfengbojiang 
1447*572c4311Sfengbojiang             /* If the script did not produce any changes in the dataset we want
1448*572c4311Sfengbojiang              * just to replicate it as SCRIPT LOAD, otherwise we risk running
1449*572c4311Sfengbojiang              * an aborted script on slaves (that may then produce results there)
1450*572c4311Sfengbojiang              * or just running a CPU costly read-only script on the slaves. */
1451*572c4311Sfengbojiang             if (server.dirty == initial_server_dirty) {
1452*572c4311Sfengbojiang                 rewriteClientCommandVector(c,3,
1453*572c4311Sfengbojiang                     resetRefCount(createStringObject("SCRIPT",6)),
1454*572c4311Sfengbojiang                     resetRefCount(createStringObject("LOAD",4)),
1455*572c4311Sfengbojiang                     script);
1456*572c4311Sfengbojiang             } else {
1457*572c4311Sfengbojiang                 rewriteClientCommandArgument(c,0,
1458*572c4311Sfengbojiang                     resetRefCount(createStringObject("EVAL",4)));
1459*572c4311Sfengbojiang                 rewriteClientCommandArgument(c,1,script);
1460*572c4311Sfengbojiang             }
1461*572c4311Sfengbojiang             forceCommandPropagation(c,PROPAGATE_REPL|PROPAGATE_AOF);
1462*572c4311Sfengbojiang         }
1463*572c4311Sfengbojiang     }
1464*572c4311Sfengbojiang }
1465*572c4311Sfengbojiang 
evalCommand(client * c)1466*572c4311Sfengbojiang void evalCommand(client *c) {
1467*572c4311Sfengbojiang     if (!(c->flags & CLIENT_LUA_DEBUG))
1468*572c4311Sfengbojiang         evalGenericCommand(c,0);
1469*572c4311Sfengbojiang     else
1470*572c4311Sfengbojiang         evalGenericCommandWithDebugging(c,0);
1471*572c4311Sfengbojiang }
1472*572c4311Sfengbojiang 
evalShaCommand(client * c)1473*572c4311Sfengbojiang void evalShaCommand(client *c) {
1474*572c4311Sfengbojiang     if (sdslen(c->argv[1]->ptr) != 40) {
1475*572c4311Sfengbojiang         /* We know that a match is not possible if the provided SHA is
1476*572c4311Sfengbojiang          * not the right length. So we return an error ASAP, this way
1477*572c4311Sfengbojiang          * evalGenericCommand() can be implemented without string length
1478*572c4311Sfengbojiang          * sanity check */
1479*572c4311Sfengbojiang         addReply(c, shared.noscripterr);
1480*572c4311Sfengbojiang         return;
1481*572c4311Sfengbojiang     }
1482*572c4311Sfengbojiang     if (!(c->flags & CLIENT_LUA_DEBUG))
1483*572c4311Sfengbojiang         evalGenericCommand(c,1);
1484*572c4311Sfengbojiang     else {
1485*572c4311Sfengbojiang         addReplyError(c,"Please use EVAL instead of EVALSHA for debugging");
1486*572c4311Sfengbojiang         return;
1487*572c4311Sfengbojiang     }
1488*572c4311Sfengbojiang }
1489*572c4311Sfengbojiang 
scriptCommand(client * c)1490*572c4311Sfengbojiang void scriptCommand(client *c) {
1491*572c4311Sfengbojiang     if (c->argc == 2 && !strcasecmp(c->argv[1]->ptr,"help")) {
1492*572c4311Sfengbojiang         const char *help[] = {
1493*572c4311Sfengbojiang "DEBUG (yes|sync|no) -- Set the debug mode for subsequent scripts executed.",
1494*572c4311Sfengbojiang "EXISTS <sha1> [<sha1> ...] -- Return information about the existence of the scripts in the script cache.",
1495*572c4311Sfengbojiang "FLUSH -- Flush the Lua scripts cache. Very dangerous on replicas.",
1496*572c4311Sfengbojiang "KILL -- Kill the currently executing Lua script.",
1497*572c4311Sfengbojiang "LOAD <script> -- Load a script into the scripts cache, without executing it.",
1498*572c4311Sfengbojiang NULL
1499*572c4311Sfengbojiang         };
1500*572c4311Sfengbojiang         addReplyHelp(c, help);
1501*572c4311Sfengbojiang     } else if (c->argc == 2 && !strcasecmp(c->argv[1]->ptr,"flush")) {
1502*572c4311Sfengbojiang         scriptingReset();
1503*572c4311Sfengbojiang         addReply(c,shared.ok);
1504*572c4311Sfengbojiang         replicationScriptCacheFlush();
1505*572c4311Sfengbojiang         server.dirty++; /* Propagating this command is a good idea. */
1506*572c4311Sfengbojiang     } else if (c->argc >= 2 && !strcasecmp(c->argv[1]->ptr,"exists")) {
1507*572c4311Sfengbojiang         int j;
1508*572c4311Sfengbojiang 
1509*572c4311Sfengbojiang         addReplyMultiBulkLen(c, c->argc-2);
1510*572c4311Sfengbojiang         for (j = 2; j < c->argc; j++) {
1511*572c4311Sfengbojiang             if (dictFind(server.lua_scripts,c->argv[j]->ptr))
1512*572c4311Sfengbojiang                 addReply(c,shared.cone);
1513*572c4311Sfengbojiang             else
1514*572c4311Sfengbojiang                 addReply(c,shared.czero);
1515*572c4311Sfengbojiang         }
1516*572c4311Sfengbojiang     } else if (c->argc == 3 && !strcasecmp(c->argv[1]->ptr,"load")) {
1517*572c4311Sfengbojiang         sds sha = luaCreateFunction(c,server.lua,c->argv[2]);
1518*572c4311Sfengbojiang         if (sha == NULL) return; /* The error was sent by luaCreateFunction(). */
1519*572c4311Sfengbojiang         addReplyBulkCBuffer(c,sha,40);
1520*572c4311Sfengbojiang         forceCommandPropagation(c,PROPAGATE_REPL|PROPAGATE_AOF);
1521*572c4311Sfengbojiang     } else if (c->argc == 2 && !strcasecmp(c->argv[1]->ptr,"kill")) {
1522*572c4311Sfengbojiang         if (server.lua_caller == NULL) {
1523*572c4311Sfengbojiang             addReplySds(c,sdsnew("-NOTBUSY No scripts in execution right now.\r\n"));
1524*572c4311Sfengbojiang         } else if (server.lua_caller->flags & CLIENT_MASTER) {
1525*572c4311Sfengbojiang             addReplySds(c,sdsnew("-UNKILLABLE The busy script was sent by a master instance in the context of replication and cannot be killed.\r\n"));
1526*572c4311Sfengbojiang         } else if (server.lua_write_dirty) {
1527*572c4311Sfengbojiang             addReplySds(c,sdsnew("-UNKILLABLE Sorry the script already executed write commands against the dataset. You can either wait the script termination or kill the server in a hard way using the SHUTDOWN NOSAVE command.\r\n"));
1528*572c4311Sfengbojiang         } else {
1529*572c4311Sfengbojiang             server.lua_kill = 1;
1530*572c4311Sfengbojiang             addReply(c,shared.ok);
1531*572c4311Sfengbojiang         }
1532*572c4311Sfengbojiang     } else if (c->argc == 3 && !strcasecmp(c->argv[1]->ptr,"debug")) {
1533*572c4311Sfengbojiang         if (clientHasPendingReplies(c)) {
1534*572c4311Sfengbojiang             addReplyError(c,"SCRIPT DEBUG must be called outside a pipeline");
1535*572c4311Sfengbojiang             return;
1536*572c4311Sfengbojiang         }
1537*572c4311Sfengbojiang         if (!strcasecmp(c->argv[2]->ptr,"no")) {
1538*572c4311Sfengbojiang             ldbDisable(c);
1539*572c4311Sfengbojiang             addReply(c,shared.ok);
1540*572c4311Sfengbojiang         } else if (!strcasecmp(c->argv[2]->ptr,"yes")) {
1541*572c4311Sfengbojiang             ldbEnable(c);
1542*572c4311Sfengbojiang             addReply(c,shared.ok);
1543*572c4311Sfengbojiang         } else if (!strcasecmp(c->argv[2]->ptr,"sync")) {
1544*572c4311Sfengbojiang             ldbEnable(c);
1545*572c4311Sfengbojiang             addReply(c,shared.ok);
1546*572c4311Sfengbojiang             c->flags |= CLIENT_LUA_DEBUG_SYNC;
1547*572c4311Sfengbojiang         } else {
1548*572c4311Sfengbojiang             addReplyError(c,"Use SCRIPT DEBUG yes/sync/no");
1549*572c4311Sfengbojiang             return;
1550*572c4311Sfengbojiang         }
1551*572c4311Sfengbojiang     } else {
1552*572c4311Sfengbojiang         addReplySubcommandSyntaxError(c);
1553*572c4311Sfengbojiang     }
1554*572c4311Sfengbojiang }
1555*572c4311Sfengbojiang 
1556*572c4311Sfengbojiang /* ---------------------------------------------------------------------------
1557*572c4311Sfengbojiang  * LDB: Redis Lua debugging facilities
1558*572c4311Sfengbojiang  * ------------------------------------------------------------------------- */
1559*572c4311Sfengbojiang 
1560*572c4311Sfengbojiang /* Initialize Lua debugger data structures. */
ldbInit(void)1561*572c4311Sfengbojiang void ldbInit(void) {
1562*572c4311Sfengbojiang     ldb.fd = -1;
1563*572c4311Sfengbojiang     ldb.active = 0;
1564*572c4311Sfengbojiang     ldb.logs = listCreate();
1565*572c4311Sfengbojiang     listSetFreeMethod(ldb.logs,(void (*)(void*))sdsfree);
1566*572c4311Sfengbojiang     ldb.children = listCreate();
1567*572c4311Sfengbojiang     ldb.src = NULL;
1568*572c4311Sfengbojiang     ldb.lines = 0;
1569*572c4311Sfengbojiang     ldb.cbuf = sdsempty();
1570*572c4311Sfengbojiang }
1571*572c4311Sfengbojiang 
1572*572c4311Sfengbojiang /* Remove all the pending messages in the specified list. */
ldbFlushLog(list * log)1573*572c4311Sfengbojiang void ldbFlushLog(list *log) {
1574*572c4311Sfengbojiang     listNode *ln;
1575*572c4311Sfengbojiang 
1576*572c4311Sfengbojiang     while((ln = listFirst(log)) != NULL)
1577*572c4311Sfengbojiang         listDelNode(log,ln);
1578*572c4311Sfengbojiang }
1579*572c4311Sfengbojiang 
1580*572c4311Sfengbojiang /* Enable debug mode of Lua scripts for this client. */
ldbEnable(client * c)1581*572c4311Sfengbojiang void ldbEnable(client *c) {
1582*572c4311Sfengbojiang     c->flags |= CLIENT_LUA_DEBUG;
1583*572c4311Sfengbojiang     ldbFlushLog(ldb.logs);
1584*572c4311Sfengbojiang     ldb.fd = c->fd;
1585*572c4311Sfengbojiang     ldb.step = 1;
1586*572c4311Sfengbojiang     ldb.bpcount = 0;
1587*572c4311Sfengbojiang     ldb.luabp = 0;
1588*572c4311Sfengbojiang     sdsfree(ldb.cbuf);
1589*572c4311Sfengbojiang     ldb.cbuf = sdsempty();
1590*572c4311Sfengbojiang     ldb.maxlen = LDB_MAX_LEN_DEFAULT;
1591*572c4311Sfengbojiang     ldb.maxlen_hint_sent = 0;
1592*572c4311Sfengbojiang }
1593*572c4311Sfengbojiang 
1594*572c4311Sfengbojiang /* Exit debugging mode from the POV of client. This function is not enough
1595*572c4311Sfengbojiang  * to properly shut down a client debugging session, see ldbEndSession()
1596*572c4311Sfengbojiang  * for more information. */
ldbDisable(client * c)1597*572c4311Sfengbojiang void ldbDisable(client *c) {
1598*572c4311Sfengbojiang     c->flags &= ~(CLIENT_LUA_DEBUG|CLIENT_LUA_DEBUG_SYNC);
1599*572c4311Sfengbojiang }
1600*572c4311Sfengbojiang 
1601*572c4311Sfengbojiang /* Append a log entry to the specified LDB log. */
ldbLog(sds entry)1602*572c4311Sfengbojiang void ldbLog(sds entry) {
1603*572c4311Sfengbojiang     listAddNodeTail(ldb.logs,entry);
1604*572c4311Sfengbojiang }
1605*572c4311Sfengbojiang 
1606*572c4311Sfengbojiang /* A version of ldbLog() which prevents producing logs greater than
1607*572c4311Sfengbojiang  * ldb.maxlen. The first time the limit is reached an hint is generated
1608*572c4311Sfengbojiang  * to inform the user that reply trimming can be disabled using the
1609*572c4311Sfengbojiang  * debugger "maxlen" command. */
ldbLogWithMaxLen(sds entry)1610*572c4311Sfengbojiang void ldbLogWithMaxLen(sds entry) {
1611*572c4311Sfengbojiang     int trimmed = 0;
1612*572c4311Sfengbojiang     if (ldb.maxlen && sdslen(entry) > ldb.maxlen) {
1613*572c4311Sfengbojiang         sdsrange(entry,0,ldb.maxlen-1);
1614*572c4311Sfengbojiang         entry = sdscatlen(entry," ...",4);
1615*572c4311Sfengbojiang         trimmed = 1;
1616*572c4311Sfengbojiang     }
1617*572c4311Sfengbojiang     ldbLog(entry);
1618*572c4311Sfengbojiang     if (trimmed && ldb.maxlen_hint_sent == 0) {
1619*572c4311Sfengbojiang         ldb.maxlen_hint_sent = 1;
1620*572c4311Sfengbojiang         ldbLog(sdsnew(
1621*572c4311Sfengbojiang         "<hint> The above reply was trimmed. Use 'maxlen 0' to disable trimming."));
1622*572c4311Sfengbojiang     }
1623*572c4311Sfengbojiang }
1624*572c4311Sfengbojiang 
1625*572c4311Sfengbojiang /* Send ldb.logs to the debugging client as a multi-bulk reply
1626*572c4311Sfengbojiang  * consisting of simple strings. Log entries which include newlines have them
1627*572c4311Sfengbojiang  * replaced with spaces. The entries sent are also consumed. */
ldbSendLogs(void)1628*572c4311Sfengbojiang void ldbSendLogs(void) {
1629*572c4311Sfengbojiang     sds proto = sdsempty();
1630*572c4311Sfengbojiang     proto = sdscatfmt(proto,"*%i\r\n", (int)listLength(ldb.logs));
1631*572c4311Sfengbojiang     while(listLength(ldb.logs)) {
1632*572c4311Sfengbojiang         listNode *ln = listFirst(ldb.logs);
1633*572c4311Sfengbojiang         proto = sdscatlen(proto,"+",1);
1634*572c4311Sfengbojiang         sdsmapchars(ln->value,"\r\n","  ",2);
1635*572c4311Sfengbojiang         proto = sdscatsds(proto,ln->value);
1636*572c4311Sfengbojiang         proto = sdscatlen(proto,"\r\n",2);
1637*572c4311Sfengbojiang         listDelNode(ldb.logs,ln);
1638*572c4311Sfengbojiang     }
1639*572c4311Sfengbojiang     if (write(ldb.fd,proto,sdslen(proto)) == -1) {
1640*572c4311Sfengbojiang         /* Avoid warning. We don't check the return value of write()
1641*572c4311Sfengbojiang          * since the next read() will catch the I/O error and will
1642*572c4311Sfengbojiang          * close the debugging session. */
1643*572c4311Sfengbojiang     }
1644*572c4311Sfengbojiang     sdsfree(proto);
1645*572c4311Sfengbojiang }
1646*572c4311Sfengbojiang 
1647*572c4311Sfengbojiang /* Start a debugging session before calling EVAL implementation.
1648*572c4311Sfengbojiang  * The techique we use is to capture the client socket file descriptor,
1649*572c4311Sfengbojiang  * in order to perform direct I/O with it from within Lua hooks. This
1650*572c4311Sfengbojiang  * way we don't have to re-enter Redis in order to handle I/O.
1651*572c4311Sfengbojiang  *
1652*572c4311Sfengbojiang  * The function returns 1 if the caller should proceed to call EVAL,
1653*572c4311Sfengbojiang  * and 0 if instead the caller should abort the operation (this happens
1654*572c4311Sfengbojiang  * for the parent in a forked session, since it's up to the children
1655*572c4311Sfengbojiang  * to continue, or when fork returned an error).
1656*572c4311Sfengbojiang  *
1657*572c4311Sfengbojiang  * The caller should call ldbEndSession() only if ldbStartSession()
1658*572c4311Sfengbojiang  * returned 1. */
ldbStartSession(client * c)1659*572c4311Sfengbojiang int ldbStartSession(client *c) {
1660*572c4311Sfengbojiang     ldb.forked = (c->flags & CLIENT_LUA_DEBUG_SYNC) == 0;
1661*572c4311Sfengbojiang     if (ldb.forked) {
1662*572c4311Sfengbojiang         pid_t cp = fork();
1663*572c4311Sfengbojiang         if (cp == -1) {
1664*572c4311Sfengbojiang             addReplyError(c,"Fork() failed: can't run EVAL in debugging mode.");
1665*572c4311Sfengbojiang             return 0;
1666*572c4311Sfengbojiang         } else if (cp == 0) {
1667*572c4311Sfengbojiang             /* Child. Let's ignore important signals handled by the parent. */
1668*572c4311Sfengbojiang             struct sigaction act;
1669*572c4311Sfengbojiang             sigemptyset(&act.sa_mask);
1670*572c4311Sfengbojiang             act.sa_flags = 0;
1671*572c4311Sfengbojiang             act.sa_handler = SIG_IGN;
1672*572c4311Sfengbojiang             sigaction(SIGTERM, &act, NULL);
1673*572c4311Sfengbojiang             sigaction(SIGINT, &act, NULL);
1674*572c4311Sfengbojiang 
1675*572c4311Sfengbojiang             /* Log the creation of the child and close the listening
1676*572c4311Sfengbojiang              * socket to make sure if the parent crashes a reset is sent
1677*572c4311Sfengbojiang              * to the clients. */
1678*572c4311Sfengbojiang             serverLog(LL_WARNING,"Redis forked for debugging eval");
1679*572c4311Sfengbojiang             closeListeningSockets(0);
1680*572c4311Sfengbojiang             resetCpuAffinity("redis-dbg");
1681*572c4311Sfengbojiang         } else {
1682*572c4311Sfengbojiang             /* Parent */
1683*572c4311Sfengbojiang             listAddNodeTail(ldb.children,(void*)(unsigned long)cp);
1684*572c4311Sfengbojiang             freeClientAsync(c); /* Close the client in the parent side. */
1685*572c4311Sfengbojiang             return 0;
1686*572c4311Sfengbojiang         }
1687*572c4311Sfengbojiang     } else {
1688*572c4311Sfengbojiang         serverLog(LL_WARNING,
1689*572c4311Sfengbojiang             "Redis synchronous debugging eval session started");
1690*572c4311Sfengbojiang     }
1691*572c4311Sfengbojiang 
1692*572c4311Sfengbojiang     /* Setup our debugging session. */
1693*572c4311Sfengbojiang     anetBlock(NULL,ldb.fd);
1694*572c4311Sfengbojiang     anetSendTimeout(NULL,ldb.fd,5000);
1695*572c4311Sfengbojiang     ldb.active = 1;
1696*572c4311Sfengbojiang 
1697*572c4311Sfengbojiang     /* First argument of EVAL is the script itself. We split it into different
1698*572c4311Sfengbojiang      * lines since this is the way the debugger accesses the source code. */
1699*572c4311Sfengbojiang     sds srcstring = sdsdup(c->argv[1]->ptr);
1700*572c4311Sfengbojiang     size_t srclen = sdslen(srcstring);
1701*572c4311Sfengbojiang     while(srclen && (srcstring[srclen-1] == '\n' ||
1702*572c4311Sfengbojiang                      srcstring[srclen-1] == '\r'))
1703*572c4311Sfengbojiang     {
1704*572c4311Sfengbojiang         srcstring[--srclen] = '\0';
1705*572c4311Sfengbojiang     }
1706*572c4311Sfengbojiang     sdssetlen(srcstring,srclen);
1707*572c4311Sfengbojiang     ldb.src = sdssplitlen(srcstring,sdslen(srcstring),"\n",1,&ldb.lines);
1708*572c4311Sfengbojiang     sdsfree(srcstring);
1709*572c4311Sfengbojiang     return 1;
1710*572c4311Sfengbojiang }
1711*572c4311Sfengbojiang 
1712*572c4311Sfengbojiang /* End a debugging session after the EVAL call with debugging enabled
1713*572c4311Sfengbojiang  * returned. */
ldbEndSession(client * c)1714*572c4311Sfengbojiang void ldbEndSession(client *c) {
1715*572c4311Sfengbojiang     /* Emit the remaining logs and an <endsession> mark. */
1716*572c4311Sfengbojiang     ldbLog(sdsnew("<endsession>"));
1717*572c4311Sfengbojiang     ldbSendLogs();
1718*572c4311Sfengbojiang 
1719*572c4311Sfengbojiang     /* If it's a fork()ed session, we just exit. */
1720*572c4311Sfengbojiang     if (ldb.forked) {
1721*572c4311Sfengbojiang         writeToClient(c->fd, c, 0);
1722*572c4311Sfengbojiang         serverLog(LL_WARNING,"Lua debugging session child exiting");
1723*572c4311Sfengbojiang         exitFromChild(0);
1724*572c4311Sfengbojiang     } else {
1725*572c4311Sfengbojiang         serverLog(LL_WARNING,
1726*572c4311Sfengbojiang             "Redis synchronous debugging eval session ended");
1727*572c4311Sfengbojiang     }
1728*572c4311Sfengbojiang 
1729*572c4311Sfengbojiang     /* Otherwise let's restore client's state. */
1730*572c4311Sfengbojiang     anetNonBlock(NULL,ldb.fd);
1731*572c4311Sfengbojiang     anetSendTimeout(NULL,ldb.fd,0);
1732*572c4311Sfengbojiang 
1733*572c4311Sfengbojiang     /* Close the client connectin after sending the final EVAL reply
1734*572c4311Sfengbojiang      * in order to signal the end of the debugging session. */
1735*572c4311Sfengbojiang     c->flags |= CLIENT_CLOSE_AFTER_REPLY;
1736*572c4311Sfengbojiang 
1737*572c4311Sfengbojiang     /* Cleanup. */
1738*572c4311Sfengbojiang     sdsfreesplitres(ldb.src,ldb.lines);
1739*572c4311Sfengbojiang     ldb.lines = 0;
1740*572c4311Sfengbojiang     ldb.active = 0;
1741*572c4311Sfengbojiang }
1742*572c4311Sfengbojiang 
1743*572c4311Sfengbojiang /* If the specified pid is among the list of children spawned for
1744*572c4311Sfengbojiang  * forked debugging sessions, it is removed from the children list.
1745*572c4311Sfengbojiang  * If the pid was found non-zero is returned. */
ldbRemoveChild(pid_t pid)1746*572c4311Sfengbojiang int ldbRemoveChild(pid_t pid) {
1747*572c4311Sfengbojiang     listNode *ln = listSearchKey(ldb.children,(void*)(unsigned long)pid);
1748*572c4311Sfengbojiang     if (ln) {
1749*572c4311Sfengbojiang         listDelNode(ldb.children,ln);
1750*572c4311Sfengbojiang         return 1;
1751*572c4311Sfengbojiang     }
1752*572c4311Sfengbojiang     return 0;
1753*572c4311Sfengbojiang }
1754*572c4311Sfengbojiang 
1755*572c4311Sfengbojiang /* Return the number of children we still did not receive termination
1756*572c4311Sfengbojiang  * acknowledge via wait() in the parent process. */
ldbPendingChildren(void)1757*572c4311Sfengbojiang int ldbPendingChildren(void) {
1758*572c4311Sfengbojiang     return listLength(ldb.children);
1759*572c4311Sfengbojiang }
1760*572c4311Sfengbojiang 
1761*572c4311Sfengbojiang /* Kill all the forked sessions. */
ldbKillForkedSessions(void)1762*572c4311Sfengbojiang void ldbKillForkedSessions(void) {
1763*572c4311Sfengbojiang     listIter li;
1764*572c4311Sfengbojiang     listNode *ln;
1765*572c4311Sfengbojiang 
1766*572c4311Sfengbojiang     listRewind(ldb.children,&li);
1767*572c4311Sfengbojiang     while((ln = listNext(&li))) {
1768*572c4311Sfengbojiang         pid_t pid = (unsigned long) ln->value;
1769*572c4311Sfengbojiang         serverLog(LL_WARNING,"Killing debugging session %ld",(long)pid);
1770*572c4311Sfengbojiang         kill(pid,SIGKILL);
1771*572c4311Sfengbojiang     }
1772*572c4311Sfengbojiang     listRelease(ldb.children);
1773*572c4311Sfengbojiang     ldb.children = listCreate();
1774*572c4311Sfengbojiang }
1775*572c4311Sfengbojiang 
1776*572c4311Sfengbojiang /* Wrapper for EVAL / EVALSHA that enables debugging, and makes sure
1777*572c4311Sfengbojiang  * that when EVAL returns, whatever happened, the session is ended. */
evalGenericCommandWithDebugging(client * c,int evalsha)1778*572c4311Sfengbojiang void evalGenericCommandWithDebugging(client *c, int evalsha) {
1779*572c4311Sfengbojiang     if (ldbStartSession(c)) {
1780*572c4311Sfengbojiang         evalGenericCommand(c,evalsha);
1781*572c4311Sfengbojiang         ldbEndSession(c);
1782*572c4311Sfengbojiang     } else {
1783*572c4311Sfengbojiang         ldbDisable(c);
1784*572c4311Sfengbojiang     }
1785*572c4311Sfengbojiang }
1786*572c4311Sfengbojiang 
1787*572c4311Sfengbojiang /* Return a pointer to ldb.src source code line, considering line to be
1788*572c4311Sfengbojiang  * one-based, and returning a special string for out of range lines. */
ldbGetSourceLine(int line)1789*572c4311Sfengbojiang char *ldbGetSourceLine(int line) {
1790*572c4311Sfengbojiang     int idx = line-1;
1791*572c4311Sfengbojiang     if (idx < 0 || idx >= ldb.lines) return "<out of range source code line>";
1792*572c4311Sfengbojiang     return ldb.src[idx];
1793*572c4311Sfengbojiang }
1794*572c4311Sfengbojiang 
1795*572c4311Sfengbojiang /* Return true if there is a breakpoint in the specified line. */
ldbIsBreakpoint(int line)1796*572c4311Sfengbojiang int ldbIsBreakpoint(int line) {
1797*572c4311Sfengbojiang     int j;
1798*572c4311Sfengbojiang 
1799*572c4311Sfengbojiang     for (j = 0; j < ldb.bpcount; j++)
1800*572c4311Sfengbojiang         if (ldb.bp[j] == line) return 1;
1801*572c4311Sfengbojiang     return 0;
1802*572c4311Sfengbojiang }
1803*572c4311Sfengbojiang 
1804*572c4311Sfengbojiang /* Add the specified breakpoint. Ignore it if we already reached the max.
1805*572c4311Sfengbojiang  * Returns 1 if the breakpoint was added (or was already set). 0 if there is
1806*572c4311Sfengbojiang  * no space for the breakpoint or if the line is invalid. */
ldbAddBreakpoint(int line)1807*572c4311Sfengbojiang int ldbAddBreakpoint(int line) {
1808*572c4311Sfengbojiang     if (line <= 0 || line > ldb.lines) return 0;
1809*572c4311Sfengbojiang     if (!ldbIsBreakpoint(line) && ldb.bpcount != LDB_BREAKPOINTS_MAX) {
1810*572c4311Sfengbojiang         ldb.bp[ldb.bpcount++] = line;
1811*572c4311Sfengbojiang         return 1;
1812*572c4311Sfengbojiang     }
1813*572c4311Sfengbojiang     return 0;
1814*572c4311Sfengbojiang }
1815*572c4311Sfengbojiang 
1816*572c4311Sfengbojiang /* Remove the specified breakpoint, returning 1 if the operation was
1817*572c4311Sfengbojiang  * performed or 0 if there was no such breakpoint. */
ldbDelBreakpoint(int line)1818*572c4311Sfengbojiang int ldbDelBreakpoint(int line) {
1819*572c4311Sfengbojiang     int j;
1820*572c4311Sfengbojiang 
1821*572c4311Sfengbojiang     for (j = 0; j < ldb.bpcount; j++) {
1822*572c4311Sfengbojiang         if (ldb.bp[j] == line) {
1823*572c4311Sfengbojiang             ldb.bpcount--;
1824*572c4311Sfengbojiang             memmove(ldb.bp+j,ldb.bp+j+1,ldb.bpcount-j);
1825*572c4311Sfengbojiang             return 1;
1826*572c4311Sfengbojiang         }
1827*572c4311Sfengbojiang     }
1828*572c4311Sfengbojiang     return 0;
1829*572c4311Sfengbojiang }
1830*572c4311Sfengbojiang 
1831*572c4311Sfengbojiang /* Expect a valid multi-bulk command in the debugging client query buffer.
1832*572c4311Sfengbojiang  * On success the command is parsed and returned as an array of SDS strings,
1833*572c4311Sfengbojiang  * otherwise NULL is returned and there is to read more buffer. */
ldbReplParseCommand(int * argcp)1834*572c4311Sfengbojiang sds *ldbReplParseCommand(int *argcp) {
1835*572c4311Sfengbojiang     sds *argv = NULL;
1836*572c4311Sfengbojiang     int argc = 0;
1837*572c4311Sfengbojiang     if (sdslen(ldb.cbuf) == 0) return NULL;
1838*572c4311Sfengbojiang 
1839*572c4311Sfengbojiang     /* Working on a copy is simpler in this case. We can modify it freely
1840*572c4311Sfengbojiang      * for the sake of simpler parsing. */
1841*572c4311Sfengbojiang     sds copy = sdsdup(ldb.cbuf);
1842*572c4311Sfengbojiang     char *p = copy;
1843*572c4311Sfengbojiang 
1844*572c4311Sfengbojiang     /* This Redis protocol parser is a joke... just the simplest thing that
1845*572c4311Sfengbojiang      * works in this context. It is also very forgiving regarding broken
1846*572c4311Sfengbojiang      * protocol. */
1847*572c4311Sfengbojiang 
1848*572c4311Sfengbojiang     /* Seek and parse *<count>\r\n. */
1849*572c4311Sfengbojiang     p = strchr(p,'*'); if (!p) goto protoerr;
1850*572c4311Sfengbojiang     char *plen = p+1; /* Multi bulk len pointer. */
1851*572c4311Sfengbojiang     p = strstr(p,"\r\n"); if (!p) goto protoerr;
1852*572c4311Sfengbojiang     *p = '\0'; p += 2;
1853*572c4311Sfengbojiang     *argcp = atoi(plen);
1854*572c4311Sfengbojiang     if (*argcp <= 0 || *argcp > 1024) goto protoerr;
1855*572c4311Sfengbojiang 
1856*572c4311Sfengbojiang     /* Parse each argument. */
1857*572c4311Sfengbojiang     argv = zmalloc(sizeof(sds)*(*argcp));
1858*572c4311Sfengbojiang     argc = 0;
1859*572c4311Sfengbojiang     while(argc < *argcp) {
1860*572c4311Sfengbojiang         if (*p != '$') goto protoerr;
1861*572c4311Sfengbojiang         plen = p+1; /* Bulk string len pointer. */
1862*572c4311Sfengbojiang         p = strstr(p,"\r\n"); if (!p) goto protoerr;
1863*572c4311Sfengbojiang         *p = '\0'; p += 2;
1864*572c4311Sfengbojiang         int slen = atoi(plen); /* Length of this arg. */
1865*572c4311Sfengbojiang         if (slen <= 0 || slen > 1024) goto protoerr;
1866*572c4311Sfengbojiang         argv[argc++] = sdsnewlen(p,slen);
1867*572c4311Sfengbojiang         p += slen; /* Skip the already parsed argument. */
1868*572c4311Sfengbojiang         if (p[0] != '\r' || p[1] != '\n') goto protoerr;
1869*572c4311Sfengbojiang         p += 2; /* Skip \r\n. */
1870*572c4311Sfengbojiang     }
1871*572c4311Sfengbojiang     sdsfree(copy);
1872*572c4311Sfengbojiang     return argv;
1873*572c4311Sfengbojiang 
1874*572c4311Sfengbojiang protoerr:
1875*572c4311Sfengbojiang     sdsfreesplitres(argv,argc);
1876*572c4311Sfengbojiang     sdsfree(copy);
1877*572c4311Sfengbojiang     return NULL;
1878*572c4311Sfengbojiang }
1879*572c4311Sfengbojiang 
1880*572c4311Sfengbojiang /* Log the specified line in the Lua debugger output. */
ldbLogSourceLine(int lnum)1881*572c4311Sfengbojiang void ldbLogSourceLine(int lnum) {
1882*572c4311Sfengbojiang     char *line = ldbGetSourceLine(lnum);
1883*572c4311Sfengbojiang     char *prefix;
1884*572c4311Sfengbojiang     int bp = ldbIsBreakpoint(lnum);
1885*572c4311Sfengbojiang     int current = ldb.currentline == lnum;
1886*572c4311Sfengbojiang 
1887*572c4311Sfengbojiang     if (current && bp)
1888*572c4311Sfengbojiang         prefix = "->#";
1889*572c4311Sfengbojiang     else if (current)
1890*572c4311Sfengbojiang         prefix = "-> ";
1891*572c4311Sfengbojiang     else if (bp)
1892*572c4311Sfengbojiang         prefix = "  #";
1893*572c4311Sfengbojiang     else
1894*572c4311Sfengbojiang         prefix = "   ";
1895*572c4311Sfengbojiang     sds thisline = sdscatprintf(sdsempty(),"%s%-3d %s", prefix, lnum, line);
1896*572c4311Sfengbojiang     ldbLog(thisline);
1897*572c4311Sfengbojiang }
1898*572c4311Sfengbojiang 
1899*572c4311Sfengbojiang /* Implement the "list" command of the Lua debugger. If around is 0
1900*572c4311Sfengbojiang  * the whole file is listed, otherwise only a small portion of the file
1901*572c4311Sfengbojiang  * around the specified line is shown. When a line number is specified
1902*572c4311Sfengbojiang  * the amonut of context (lines before/after) is specified via the
1903*572c4311Sfengbojiang  * 'context' argument. */
ldbList(int around,int context)1904*572c4311Sfengbojiang void ldbList(int around, int context) {
1905*572c4311Sfengbojiang     int j;
1906*572c4311Sfengbojiang 
1907*572c4311Sfengbojiang     for (j = 1; j <= ldb.lines; j++) {
1908*572c4311Sfengbojiang         if (around != 0 && abs(around-j) > context) continue;
1909*572c4311Sfengbojiang         ldbLogSourceLine(j);
1910*572c4311Sfengbojiang     }
1911*572c4311Sfengbojiang }
1912*572c4311Sfengbojiang 
1913*572c4311Sfengbojiang /* Append an human readable representation of the Lua value at position 'idx'
1914*572c4311Sfengbojiang  * on the stack of the 'lua' state, to the SDS string passed as argument.
1915*572c4311Sfengbojiang  * The new SDS string with the represented value attached is returned.
1916*572c4311Sfengbojiang  * Used in order to implement ldbLogStackValue().
1917*572c4311Sfengbojiang  *
1918*572c4311Sfengbojiang  * The element is not automatically removed from the stack, nor it is
1919*572c4311Sfengbojiang  * converted to a different type. */
1920*572c4311Sfengbojiang #define LDB_MAX_VALUES_DEPTH (LUA_MINSTACK/2)
ldbCatStackValueRec(sds s,lua_State * lua,int idx,int level)1921*572c4311Sfengbojiang sds ldbCatStackValueRec(sds s, lua_State *lua, int idx, int level) {
1922*572c4311Sfengbojiang     int t = lua_type(lua,idx);
1923*572c4311Sfengbojiang 
1924*572c4311Sfengbojiang     if (level++ == LDB_MAX_VALUES_DEPTH)
1925*572c4311Sfengbojiang         return sdscat(s,"<max recursion level reached! Nested table?>");
1926*572c4311Sfengbojiang 
1927*572c4311Sfengbojiang     switch(t) {
1928*572c4311Sfengbojiang     case LUA_TSTRING:
1929*572c4311Sfengbojiang         {
1930*572c4311Sfengbojiang         size_t strl;
1931*572c4311Sfengbojiang         char *strp = (char*)lua_tolstring(lua,idx,&strl);
1932*572c4311Sfengbojiang         s = sdscatrepr(s,strp,strl);
1933*572c4311Sfengbojiang         }
1934*572c4311Sfengbojiang         break;
1935*572c4311Sfengbojiang     case LUA_TBOOLEAN:
1936*572c4311Sfengbojiang         s = sdscat(s,lua_toboolean(lua,idx) ? "true" : "false");
1937*572c4311Sfengbojiang         break;
1938*572c4311Sfengbojiang     case LUA_TNUMBER:
1939*572c4311Sfengbojiang         s = sdscatprintf(s,"%g",(double)lua_tonumber(lua,idx));
1940*572c4311Sfengbojiang         break;
1941*572c4311Sfengbojiang     case LUA_TNIL:
1942*572c4311Sfengbojiang         s = sdscatlen(s,"nil",3);
1943*572c4311Sfengbojiang         break;
1944*572c4311Sfengbojiang     case LUA_TTABLE:
1945*572c4311Sfengbojiang         {
1946*572c4311Sfengbojiang         int expected_index = 1; /* First index we expect in an array. */
1947*572c4311Sfengbojiang         int is_array = 1; /* Will be set to null if check fails. */
1948*572c4311Sfengbojiang         /* Note: we create two representations at the same time, one
1949*572c4311Sfengbojiang          * assuming the table is an array, one assuming it is not. At the
1950*572c4311Sfengbojiang          * end we know what is true and select the right one. */
1951*572c4311Sfengbojiang         sds repr1 = sdsempty();
1952*572c4311Sfengbojiang         sds repr2 = sdsempty();
1953*572c4311Sfengbojiang         lua_pushnil(lua); /* The first key to start the iteration is nil. */
1954*572c4311Sfengbojiang         while (lua_next(lua,idx-1)) {
1955*572c4311Sfengbojiang             /* Test if so far the table looks like an array. */
1956*572c4311Sfengbojiang             if (is_array &&
1957*572c4311Sfengbojiang                 (lua_type(lua,-2) != LUA_TNUMBER ||
1958*572c4311Sfengbojiang                  lua_tonumber(lua,-2) != expected_index)) is_array = 0;
1959*572c4311Sfengbojiang             /* Stack now: table, key, value */
1960*572c4311Sfengbojiang             /* Array repr. */
1961*572c4311Sfengbojiang             repr1 = ldbCatStackValueRec(repr1,lua,-1,level);
1962*572c4311Sfengbojiang             repr1 = sdscatlen(repr1,"; ",2);
1963*572c4311Sfengbojiang             /* Full repr. */
1964*572c4311Sfengbojiang             repr2 = sdscatlen(repr2,"[",1);
1965*572c4311Sfengbojiang             repr2 = ldbCatStackValueRec(repr2,lua,-2,level);
1966*572c4311Sfengbojiang             repr2 = sdscatlen(repr2,"]=",2);
1967*572c4311Sfengbojiang             repr2 = ldbCatStackValueRec(repr2,lua,-1,level);
1968*572c4311Sfengbojiang             repr2 = sdscatlen(repr2,"; ",2);
1969*572c4311Sfengbojiang             lua_pop(lua,1); /* Stack: table, key. Ready for next iteration. */
1970*572c4311Sfengbojiang             expected_index++;
1971*572c4311Sfengbojiang         }
1972*572c4311Sfengbojiang         /* Strip the last " ;" from both the representations. */
1973*572c4311Sfengbojiang         if (sdslen(repr1)) sdsrange(repr1,0,-3);
1974*572c4311Sfengbojiang         if (sdslen(repr2)) sdsrange(repr2,0,-3);
1975*572c4311Sfengbojiang         /* Select the right one and discard the other. */
1976*572c4311Sfengbojiang         s = sdscatlen(s,"{",1);
1977*572c4311Sfengbojiang         s = sdscatsds(s,is_array ? repr1 : repr2);
1978*572c4311Sfengbojiang         s = sdscatlen(s,"}",1);
1979*572c4311Sfengbojiang         sdsfree(repr1);
1980*572c4311Sfengbojiang         sdsfree(repr2);
1981*572c4311Sfengbojiang         }
1982*572c4311Sfengbojiang         break;
1983*572c4311Sfengbojiang     case LUA_TFUNCTION:
1984*572c4311Sfengbojiang     case LUA_TUSERDATA:
1985*572c4311Sfengbojiang     case LUA_TTHREAD:
1986*572c4311Sfengbojiang     case LUA_TLIGHTUSERDATA:
1987*572c4311Sfengbojiang         {
1988*572c4311Sfengbojiang         const void *p = lua_topointer(lua,idx);
1989*572c4311Sfengbojiang         char *typename = "unknown";
1990*572c4311Sfengbojiang         if (t == LUA_TFUNCTION) typename = "function";
1991*572c4311Sfengbojiang         else if (t == LUA_TUSERDATA) typename = "userdata";
1992*572c4311Sfengbojiang         else if (t == LUA_TTHREAD) typename = "thread";
1993*572c4311Sfengbojiang         else if (t == LUA_TLIGHTUSERDATA) typename = "light-userdata";
1994*572c4311Sfengbojiang         s = sdscatprintf(s,"\"%s@%p\"",typename,p);
1995*572c4311Sfengbojiang         }
1996*572c4311Sfengbojiang         break;
1997*572c4311Sfengbojiang     default:
1998*572c4311Sfengbojiang         s = sdscat(s,"\"<unknown-lua-type>\"");
1999*572c4311Sfengbojiang         break;
2000*572c4311Sfengbojiang     }
2001*572c4311Sfengbojiang     return s;
2002*572c4311Sfengbojiang }
2003*572c4311Sfengbojiang 
2004*572c4311Sfengbojiang /* Higher level wrapper for ldbCatStackValueRec() that just uses an initial
2005*572c4311Sfengbojiang  * recursion level of '0'. */
ldbCatStackValue(sds s,lua_State * lua,int idx)2006*572c4311Sfengbojiang sds ldbCatStackValue(sds s, lua_State *lua, int idx) {
2007*572c4311Sfengbojiang     return ldbCatStackValueRec(s,lua,idx,0);
2008*572c4311Sfengbojiang }
2009*572c4311Sfengbojiang 
2010*572c4311Sfengbojiang /* Produce a debugger log entry representing the value of the Lua object
2011*572c4311Sfengbojiang  * currently on the top of the stack. The element is ot popped nor modified.
2012*572c4311Sfengbojiang  * Check ldbCatStackValue() for the actual implementation. */
ldbLogStackValue(lua_State * lua,char * prefix)2013*572c4311Sfengbojiang void ldbLogStackValue(lua_State *lua, char *prefix) {
2014*572c4311Sfengbojiang     sds s = sdsnew(prefix);
2015*572c4311Sfengbojiang     s = ldbCatStackValue(s,lua,-1);
2016*572c4311Sfengbojiang     ldbLogWithMaxLen(s);
2017*572c4311Sfengbojiang }
2018*572c4311Sfengbojiang 
2019*572c4311Sfengbojiang char *ldbRedisProtocolToHuman_Int(sds *o, char *reply);
2020*572c4311Sfengbojiang char *ldbRedisProtocolToHuman_Bulk(sds *o, char *reply);
2021*572c4311Sfengbojiang char *ldbRedisProtocolToHuman_Status(sds *o, char *reply);
2022*572c4311Sfengbojiang char *ldbRedisProtocolToHuman_MultiBulk(sds *o, char *reply);
2023*572c4311Sfengbojiang 
2024*572c4311Sfengbojiang /* Get Redis protocol from 'reply' and appends it in human readable form to
2025*572c4311Sfengbojiang  * the passed SDS string 'o'.
2026*572c4311Sfengbojiang  *
2027*572c4311Sfengbojiang  * Note that the SDS string is passed by reference (pointer of pointer to
2028*572c4311Sfengbojiang  * char*) so that we can return a modified pointer, as for SDS semantics. */
ldbRedisProtocolToHuman(sds * o,char * reply)2029*572c4311Sfengbojiang char *ldbRedisProtocolToHuman(sds *o, char *reply) {
2030*572c4311Sfengbojiang     char *p = reply;
2031*572c4311Sfengbojiang     switch(*p) {
2032*572c4311Sfengbojiang     case ':': p = ldbRedisProtocolToHuman_Int(o,reply); break;
2033*572c4311Sfengbojiang     case '$': p = ldbRedisProtocolToHuman_Bulk(o,reply); break;
2034*572c4311Sfengbojiang     case '+': p = ldbRedisProtocolToHuman_Status(o,reply); break;
2035*572c4311Sfengbojiang     case '-': p = ldbRedisProtocolToHuman_Status(o,reply); break;
2036*572c4311Sfengbojiang     case '*': p = ldbRedisProtocolToHuman_MultiBulk(o,reply); break;
2037*572c4311Sfengbojiang     }
2038*572c4311Sfengbojiang     return p;
2039*572c4311Sfengbojiang }
2040*572c4311Sfengbojiang 
2041*572c4311Sfengbojiang /* The following functions are helpers for ldbRedisProtocolToHuman(), each
2042*572c4311Sfengbojiang  * take care of a given Redis return type. */
2043*572c4311Sfengbojiang 
ldbRedisProtocolToHuman_Int(sds * o,char * reply)2044*572c4311Sfengbojiang char *ldbRedisProtocolToHuman_Int(sds *o, char *reply) {
2045*572c4311Sfengbojiang     char *p = strchr(reply+1,'\r');
2046*572c4311Sfengbojiang     *o = sdscatlen(*o,reply+1,p-reply-1);
2047*572c4311Sfengbojiang     return p+2;
2048*572c4311Sfengbojiang }
2049*572c4311Sfengbojiang 
ldbRedisProtocolToHuman_Bulk(sds * o,char * reply)2050*572c4311Sfengbojiang char *ldbRedisProtocolToHuman_Bulk(sds *o, char *reply) {
2051*572c4311Sfengbojiang     char *p = strchr(reply+1,'\r');
2052*572c4311Sfengbojiang     long long bulklen;
2053*572c4311Sfengbojiang 
2054*572c4311Sfengbojiang     string2ll(reply+1,p-reply-1,&bulklen);
2055*572c4311Sfengbojiang     if (bulklen == -1) {
2056*572c4311Sfengbojiang         *o = sdscatlen(*o,"NULL",4);
2057*572c4311Sfengbojiang         return p+2;
2058*572c4311Sfengbojiang     } else {
2059*572c4311Sfengbojiang         *o = sdscatrepr(*o,p+2,bulklen);
2060*572c4311Sfengbojiang         return p+2+bulklen+2;
2061*572c4311Sfengbojiang     }
2062*572c4311Sfengbojiang }
2063*572c4311Sfengbojiang 
ldbRedisProtocolToHuman_Status(sds * o,char * reply)2064*572c4311Sfengbojiang char *ldbRedisProtocolToHuman_Status(sds *o, char *reply) {
2065*572c4311Sfengbojiang     char *p = strchr(reply+1,'\r');
2066*572c4311Sfengbojiang 
2067*572c4311Sfengbojiang     *o = sdscatrepr(*o,reply,p-reply);
2068*572c4311Sfengbojiang     return p+2;
2069*572c4311Sfengbojiang }
2070*572c4311Sfengbojiang 
ldbRedisProtocolToHuman_MultiBulk(sds * o,char * reply)2071*572c4311Sfengbojiang char *ldbRedisProtocolToHuman_MultiBulk(sds *o, char *reply) {
2072*572c4311Sfengbojiang     char *p = strchr(reply+1,'\r');
2073*572c4311Sfengbojiang     long long mbulklen;
2074*572c4311Sfengbojiang     int j = 0;
2075*572c4311Sfengbojiang 
2076*572c4311Sfengbojiang     string2ll(reply+1,p-reply-1,&mbulklen);
2077*572c4311Sfengbojiang     p += 2;
2078*572c4311Sfengbojiang     if (mbulklen == -1) {
2079*572c4311Sfengbojiang         *o = sdscatlen(*o,"NULL",4);
2080*572c4311Sfengbojiang         return p;
2081*572c4311Sfengbojiang     }
2082*572c4311Sfengbojiang     *o = sdscatlen(*o,"[",1);
2083*572c4311Sfengbojiang     for (j = 0; j < mbulklen; j++) {
2084*572c4311Sfengbojiang         p = ldbRedisProtocolToHuman(o,p);
2085*572c4311Sfengbojiang         if (j != mbulklen-1) *o = sdscatlen(*o,",",1);
2086*572c4311Sfengbojiang     }
2087*572c4311Sfengbojiang     *o = sdscatlen(*o,"]",1);
2088*572c4311Sfengbojiang     return p;
2089*572c4311Sfengbojiang }
2090*572c4311Sfengbojiang 
2091*572c4311Sfengbojiang /* Log a Redis reply as debugger output, in an human readable format.
2092*572c4311Sfengbojiang  * If the resulting string is longer than 'len' plus a few more chars
2093*572c4311Sfengbojiang  * used as prefix, it gets truncated. */
ldbLogRedisReply(char * reply)2094*572c4311Sfengbojiang void ldbLogRedisReply(char *reply) {
2095*572c4311Sfengbojiang     sds log = sdsnew("<reply> ");
2096*572c4311Sfengbojiang     ldbRedisProtocolToHuman(&log,reply);
2097*572c4311Sfengbojiang     ldbLogWithMaxLen(log);
2098*572c4311Sfengbojiang }
2099*572c4311Sfengbojiang 
2100*572c4311Sfengbojiang /* Implements the "print <var>" command of the Lua debugger. It scans for Lua
2101*572c4311Sfengbojiang  * var "varname" starting from the current stack frame up to the top stack
2102*572c4311Sfengbojiang  * frame. The first matching variable is printed. */
ldbPrint(lua_State * lua,char * varname)2103*572c4311Sfengbojiang void ldbPrint(lua_State *lua, char *varname) {
2104*572c4311Sfengbojiang     lua_Debug ar;
2105*572c4311Sfengbojiang 
2106*572c4311Sfengbojiang     int l = 0; /* Stack level. */
2107*572c4311Sfengbojiang     while (lua_getstack(lua,l,&ar) != 0) {
2108*572c4311Sfengbojiang         l++;
2109*572c4311Sfengbojiang         const char *name;
2110*572c4311Sfengbojiang         int i = 1; /* Variable index. */
2111*572c4311Sfengbojiang         while((name = lua_getlocal(lua,&ar,i)) != NULL) {
2112*572c4311Sfengbojiang             i++;
2113*572c4311Sfengbojiang             if (strcmp(varname,name) == 0) {
2114*572c4311Sfengbojiang                 ldbLogStackValue(lua,"<value> ");
2115*572c4311Sfengbojiang                 lua_pop(lua,1);
2116*572c4311Sfengbojiang                 return;
2117*572c4311Sfengbojiang             } else {
2118*572c4311Sfengbojiang                 lua_pop(lua,1); /* Discard the var name on the stack. */
2119*572c4311Sfengbojiang             }
2120*572c4311Sfengbojiang         }
2121*572c4311Sfengbojiang     }
2122*572c4311Sfengbojiang 
2123*572c4311Sfengbojiang     /* Let's try with global vars in two selected cases */
2124*572c4311Sfengbojiang     if (!strcmp(varname,"ARGV") || !strcmp(varname,"KEYS")) {
2125*572c4311Sfengbojiang         lua_getglobal(lua, varname);
2126*572c4311Sfengbojiang         ldbLogStackValue(lua,"<value> ");
2127*572c4311Sfengbojiang         lua_pop(lua,1);
2128*572c4311Sfengbojiang     } else {
2129*572c4311Sfengbojiang         ldbLog(sdsnew("No such variable."));
2130*572c4311Sfengbojiang     }
2131*572c4311Sfengbojiang }
2132*572c4311Sfengbojiang 
2133*572c4311Sfengbojiang /* Implements the "print" command (without arguments) of the Lua debugger.
2134*572c4311Sfengbojiang  * Prints all the variables in the current stack frame. */
ldbPrintAll(lua_State * lua)2135*572c4311Sfengbojiang void ldbPrintAll(lua_State *lua) {
2136*572c4311Sfengbojiang     lua_Debug ar;
2137*572c4311Sfengbojiang     int vars = 0;
2138*572c4311Sfengbojiang 
2139*572c4311Sfengbojiang     if (lua_getstack(lua,0,&ar) != 0) {
2140*572c4311Sfengbojiang         const char *name;
2141*572c4311Sfengbojiang         int i = 1; /* Variable index. */
2142*572c4311Sfengbojiang         while((name = lua_getlocal(lua,&ar,i)) != NULL) {
2143*572c4311Sfengbojiang             i++;
2144*572c4311Sfengbojiang             if (!strstr(name,"(*temporary)")) {
2145*572c4311Sfengbojiang                 sds prefix = sdscatprintf(sdsempty(),"<value> %s = ",name);
2146*572c4311Sfengbojiang                 ldbLogStackValue(lua,prefix);
2147*572c4311Sfengbojiang                 sdsfree(prefix);
2148*572c4311Sfengbojiang                 vars++;
2149*572c4311Sfengbojiang             }
2150*572c4311Sfengbojiang             lua_pop(lua,1);
2151*572c4311Sfengbojiang         }
2152*572c4311Sfengbojiang     }
2153*572c4311Sfengbojiang 
2154*572c4311Sfengbojiang     if (vars == 0) {
2155*572c4311Sfengbojiang         ldbLog(sdsnew("No local variables in the current context."));
2156*572c4311Sfengbojiang     }
2157*572c4311Sfengbojiang }
2158*572c4311Sfengbojiang 
2159*572c4311Sfengbojiang /* Implements the break command to list, add and remove breakpoints. */
ldbBreak(sds * argv,int argc)2160*572c4311Sfengbojiang void ldbBreak(sds *argv, int argc) {
2161*572c4311Sfengbojiang     if (argc == 1) {
2162*572c4311Sfengbojiang         if (ldb.bpcount == 0) {
2163*572c4311Sfengbojiang             ldbLog(sdsnew("No breakpoints set. Use 'b <line>' to add one."));
2164*572c4311Sfengbojiang             return;
2165*572c4311Sfengbojiang         } else {
2166*572c4311Sfengbojiang             ldbLog(sdscatfmt(sdsempty(),"%i breakpoints set:",ldb.bpcount));
2167*572c4311Sfengbojiang             int j;
2168*572c4311Sfengbojiang             for (j = 0; j < ldb.bpcount; j++)
2169*572c4311Sfengbojiang                 ldbLogSourceLine(ldb.bp[j]);
2170*572c4311Sfengbojiang         }
2171*572c4311Sfengbojiang     } else {
2172*572c4311Sfengbojiang         int j;
2173*572c4311Sfengbojiang         for (j = 1; j < argc; j++) {
2174*572c4311Sfengbojiang             char *arg = argv[j];
2175*572c4311Sfengbojiang             long line;
2176*572c4311Sfengbojiang             if (!string2l(arg,sdslen(arg),&line)) {
2177*572c4311Sfengbojiang                 ldbLog(sdscatfmt(sdsempty(),"Invalid argument:'%s'",arg));
2178*572c4311Sfengbojiang             } else {
2179*572c4311Sfengbojiang                 if (line == 0) {
2180*572c4311Sfengbojiang                     ldb.bpcount = 0;
2181*572c4311Sfengbojiang                     ldbLog(sdsnew("All breakpoints removed."));
2182*572c4311Sfengbojiang                 } else if (line > 0) {
2183*572c4311Sfengbojiang                     if (ldb.bpcount == LDB_BREAKPOINTS_MAX) {
2184*572c4311Sfengbojiang                         ldbLog(sdsnew("Too many breakpoints set."));
2185*572c4311Sfengbojiang                     } else if (ldbAddBreakpoint(line)) {
2186*572c4311Sfengbojiang                         ldbList(line,1);
2187*572c4311Sfengbojiang                     } else {
2188*572c4311Sfengbojiang                         ldbLog(sdsnew("Wrong line number."));
2189*572c4311Sfengbojiang                     }
2190*572c4311Sfengbojiang                 } else if (line < 0) {
2191*572c4311Sfengbojiang                     if (ldbDelBreakpoint(-line))
2192*572c4311Sfengbojiang                         ldbLog(sdsnew("Breakpoint removed."));
2193*572c4311Sfengbojiang                     else
2194*572c4311Sfengbojiang                         ldbLog(sdsnew("No breakpoint in the specified line."));
2195*572c4311Sfengbojiang                 }
2196*572c4311Sfengbojiang             }
2197*572c4311Sfengbojiang         }
2198*572c4311Sfengbojiang     }
2199*572c4311Sfengbojiang }
2200*572c4311Sfengbojiang 
2201*572c4311Sfengbojiang /* Implements the Lua debugger "eval" command. It just compiles the user
2202*572c4311Sfengbojiang  * passed fragment of code and executes it, showing the result left on
2203*572c4311Sfengbojiang  * the stack. */
ldbEval(lua_State * lua,sds * argv,int argc)2204*572c4311Sfengbojiang void ldbEval(lua_State *lua, sds *argv, int argc) {
2205*572c4311Sfengbojiang     /* Glue the script together if it is composed of multiple arguments. */
2206*572c4311Sfengbojiang     sds code = sdsjoinsds(argv+1,argc-1," ",1);
2207*572c4311Sfengbojiang     sds expr = sdscatsds(sdsnew("return "),code);
2208*572c4311Sfengbojiang 
2209*572c4311Sfengbojiang     /* Try to compile it as an expression, prepending "return ". */
2210*572c4311Sfengbojiang     if (luaL_loadbuffer(lua,expr,sdslen(expr),"@ldb_eval")) {
2211*572c4311Sfengbojiang         lua_pop(lua,1);
2212*572c4311Sfengbojiang         /* Failed? Try as a statement. */
2213*572c4311Sfengbojiang         if (luaL_loadbuffer(lua,code,sdslen(code),"@ldb_eval")) {
2214*572c4311Sfengbojiang             ldbLog(sdscatfmt(sdsempty(),"<error> %s",lua_tostring(lua,-1)));
2215*572c4311Sfengbojiang             lua_pop(lua,1);
2216*572c4311Sfengbojiang             sdsfree(code);
2217*572c4311Sfengbojiang             return;
2218*572c4311Sfengbojiang         }
2219*572c4311Sfengbojiang     }
2220*572c4311Sfengbojiang 
2221*572c4311Sfengbojiang     /* Call it. */
2222*572c4311Sfengbojiang     sdsfree(code);
2223*572c4311Sfengbojiang     sdsfree(expr);
2224*572c4311Sfengbojiang     if (lua_pcall(lua,0,1,0)) {
2225*572c4311Sfengbojiang         ldbLog(sdscatfmt(sdsempty(),"<error> %s",lua_tostring(lua,-1)));
2226*572c4311Sfengbojiang         lua_pop(lua,1);
2227*572c4311Sfengbojiang         return;
2228*572c4311Sfengbojiang     }
2229*572c4311Sfengbojiang     ldbLogStackValue(lua,"<retval> ");
2230*572c4311Sfengbojiang     lua_pop(lua,1);
2231*572c4311Sfengbojiang }
2232*572c4311Sfengbojiang 
2233*572c4311Sfengbojiang /* Implement the debugger "redis" command. We use a trick in order to make
2234*572c4311Sfengbojiang  * the implementation very simple: we just call the Lua redis.call() command
2235*572c4311Sfengbojiang  * implementation, with ldb.step enabled, so as a side effect the Redis command
2236*572c4311Sfengbojiang  * and its reply are logged. */
ldbRedis(lua_State * lua,sds * argv,int argc)2237*572c4311Sfengbojiang void ldbRedis(lua_State *lua, sds *argv, int argc) {
2238*572c4311Sfengbojiang     int j, saved_rc = server.lua_replicate_commands;
2239*572c4311Sfengbojiang 
2240*572c4311Sfengbojiang     lua_getglobal(lua,"redis");
2241*572c4311Sfengbojiang     lua_pushstring(lua,"call");
2242*572c4311Sfengbojiang     lua_gettable(lua,-2);       /* Stack: redis, redis.call */
2243*572c4311Sfengbojiang     for (j = 1; j < argc; j++)
2244*572c4311Sfengbojiang         lua_pushlstring(lua,argv[j],sdslen(argv[j]));
2245*572c4311Sfengbojiang     ldb.step = 1;               /* Force redis.call() to log. */
2246*572c4311Sfengbojiang     server.lua_replicate_commands = 1;
2247*572c4311Sfengbojiang     lua_pcall(lua,argc-1,1,0);  /* Stack: redis, result */
2248*572c4311Sfengbojiang     ldb.step = 0;               /* Disable logging. */
2249*572c4311Sfengbojiang     server.lua_replicate_commands = saved_rc;
2250*572c4311Sfengbojiang     lua_pop(lua,2);             /* Discard the result and clean the stack. */
2251*572c4311Sfengbojiang }
2252*572c4311Sfengbojiang 
2253*572c4311Sfengbojiang /* Implements "trace" command of the Lua debugger. It just prints a backtrace
2254*572c4311Sfengbojiang  * querying Lua starting from the current callframe back to the outer one. */
ldbTrace(lua_State * lua)2255*572c4311Sfengbojiang void ldbTrace(lua_State *lua) {
2256*572c4311Sfengbojiang     lua_Debug ar;
2257*572c4311Sfengbojiang     int level = 0;
2258*572c4311Sfengbojiang 
2259*572c4311Sfengbojiang     while(lua_getstack(lua,level,&ar)) {
2260*572c4311Sfengbojiang         lua_getinfo(lua,"Snl",&ar);
2261*572c4311Sfengbojiang         if(strstr(ar.short_src,"user_script") != NULL) {
2262*572c4311Sfengbojiang             ldbLog(sdscatprintf(sdsempty(),"%s %s:",
2263*572c4311Sfengbojiang                 (level == 0) ? "In" : "From",
2264*572c4311Sfengbojiang                 ar.name ? ar.name : "top level"));
2265*572c4311Sfengbojiang             ldbLogSourceLine(ar.currentline);
2266*572c4311Sfengbojiang         }
2267*572c4311Sfengbojiang         level++;
2268*572c4311Sfengbojiang     }
2269*572c4311Sfengbojiang     if (level == 0) {
2270*572c4311Sfengbojiang         ldbLog(sdsnew("<error> Can't retrieve Lua stack."));
2271*572c4311Sfengbojiang     }
2272*572c4311Sfengbojiang }
2273*572c4311Sfengbojiang 
2274*572c4311Sfengbojiang /* Impleemnts the debugger "maxlen" command. It just queries or sets the
2275*572c4311Sfengbojiang  * ldb.maxlen variable. */
ldbMaxlen(sds * argv,int argc)2276*572c4311Sfengbojiang void ldbMaxlen(sds *argv, int argc) {
2277*572c4311Sfengbojiang     if (argc == 2) {
2278*572c4311Sfengbojiang         int newval = atoi(argv[1]);
2279*572c4311Sfengbojiang         ldb.maxlen_hint_sent = 1; /* User knows about this command. */
2280*572c4311Sfengbojiang         if (newval != 0 && newval <= 60) newval = 60;
2281*572c4311Sfengbojiang         ldb.maxlen = newval;
2282*572c4311Sfengbojiang     }
2283*572c4311Sfengbojiang     if (ldb.maxlen) {
2284*572c4311Sfengbojiang         ldbLog(sdscatprintf(sdsempty(),"<value> replies are truncated at %d bytes.",(int)ldb.maxlen));
2285*572c4311Sfengbojiang     } else {
2286*572c4311Sfengbojiang         ldbLog(sdscatprintf(sdsempty(),"<value> replies are unlimited."));
2287*572c4311Sfengbojiang     }
2288*572c4311Sfengbojiang }
2289*572c4311Sfengbojiang 
2290*572c4311Sfengbojiang /* Read debugging commands from client.
2291*572c4311Sfengbojiang  * Return C_OK if the debugging session is continuing, otherwise
2292*572c4311Sfengbojiang  * C_ERR if the client closed the connection or is timing out. */
ldbRepl(lua_State * lua)2293*572c4311Sfengbojiang int ldbRepl(lua_State *lua) {
2294*572c4311Sfengbojiang     sds *argv;
2295*572c4311Sfengbojiang     int argc;
2296*572c4311Sfengbojiang 
2297*572c4311Sfengbojiang     /* We continue processing commands until a command that should return
2298*572c4311Sfengbojiang      * to the Lua interpreter is found. */
2299*572c4311Sfengbojiang     while(1) {
2300*572c4311Sfengbojiang         while((argv = ldbReplParseCommand(&argc)) == NULL) {
2301*572c4311Sfengbojiang             char buf[1024];
2302*572c4311Sfengbojiang             int nread = read(ldb.fd,buf,sizeof(buf));
2303*572c4311Sfengbojiang             if (nread <= 0) {
2304*572c4311Sfengbojiang                 /* Make sure the script runs without user input since the
2305*572c4311Sfengbojiang                  * client is no longer connected. */
2306*572c4311Sfengbojiang                 ldb.step = 0;
2307*572c4311Sfengbojiang                 ldb.bpcount = 0;
2308*572c4311Sfengbojiang                 return C_ERR;
2309*572c4311Sfengbojiang             }
2310*572c4311Sfengbojiang             ldb.cbuf = sdscatlen(ldb.cbuf,buf,nread);
2311*572c4311Sfengbojiang         }
2312*572c4311Sfengbojiang 
2313*572c4311Sfengbojiang         /* Flush the old buffer. */
2314*572c4311Sfengbojiang         sdsfree(ldb.cbuf);
2315*572c4311Sfengbojiang         ldb.cbuf = sdsempty();
2316*572c4311Sfengbojiang 
2317*572c4311Sfengbojiang         /* Execute the command. */
2318*572c4311Sfengbojiang         if (!strcasecmp(argv[0],"h") || !strcasecmp(argv[0],"help")) {
2319*572c4311Sfengbojiang ldbLog(sdsnew("Redis Lua debugger help:"));
2320*572c4311Sfengbojiang ldbLog(sdsnew("[h]elp               Show this help."));
2321*572c4311Sfengbojiang ldbLog(sdsnew("[s]tep               Run current line and stop again."));
2322*572c4311Sfengbojiang ldbLog(sdsnew("[n]ext               Alias for step."));
2323*572c4311Sfengbojiang ldbLog(sdsnew("[c]continue          Run till next breakpoint."));
2324*572c4311Sfengbojiang ldbLog(sdsnew("[l]list              List source code around current line."));
2325*572c4311Sfengbojiang ldbLog(sdsnew("[l]list [line]       List source code around [line]."));
2326*572c4311Sfengbojiang ldbLog(sdsnew("                     line = 0 means: current position."));
2327*572c4311Sfengbojiang ldbLog(sdsnew("[l]list [line] [ctx] In this form [ctx] specifies how many lines"));
2328*572c4311Sfengbojiang ldbLog(sdsnew("                     to show before/after [line]."));
2329*572c4311Sfengbojiang ldbLog(sdsnew("[w]hole              List all source code. Alias for 'list 1 1000000'."));
2330*572c4311Sfengbojiang ldbLog(sdsnew("[p]rint              Show all the local variables."));
2331*572c4311Sfengbojiang ldbLog(sdsnew("[p]rint <var>        Show the value of the specified variable."));
2332*572c4311Sfengbojiang ldbLog(sdsnew("                     Can also show global vars KEYS and ARGV."));
2333*572c4311Sfengbojiang ldbLog(sdsnew("[b]reak              Show all breakpoints."));
2334*572c4311Sfengbojiang ldbLog(sdsnew("[b]reak <line>       Add a breakpoint to the specified line."));
2335*572c4311Sfengbojiang ldbLog(sdsnew("[b]reak -<line>      Remove breakpoint from the specified line."));
2336*572c4311Sfengbojiang ldbLog(sdsnew("[b]reak 0            Remove all breakpoints."));
2337*572c4311Sfengbojiang ldbLog(sdsnew("[t]race              Show a backtrace."));
2338*572c4311Sfengbojiang ldbLog(sdsnew("[e]eval <code>       Execute some Lua code (in a different callframe)."));
2339*572c4311Sfengbojiang ldbLog(sdsnew("[r]edis <cmd>        Execute a Redis command."));
2340*572c4311Sfengbojiang ldbLog(sdsnew("[m]axlen [len]       Trim logged Redis replies and Lua var dumps to len."));
2341*572c4311Sfengbojiang ldbLog(sdsnew("                     Specifying zero as <len> means unlimited."));
2342*572c4311Sfengbojiang ldbLog(sdsnew("[a]bort              Stop the execution of the script. In sync"));
2343*572c4311Sfengbojiang ldbLog(sdsnew("                     mode dataset changes will be retained."));
2344*572c4311Sfengbojiang ldbLog(sdsnew(""));
2345*572c4311Sfengbojiang ldbLog(sdsnew("Debugger functions you can call from Lua scripts:"));
2346*572c4311Sfengbojiang ldbLog(sdsnew("redis.debug()        Produce logs in the debugger console."));
2347*572c4311Sfengbojiang ldbLog(sdsnew("redis.breakpoint()   Stop execution like if there was a breakpoing."));
2348*572c4311Sfengbojiang ldbLog(sdsnew("                     in the next line of code."));
2349*572c4311Sfengbojiang             ldbSendLogs();
2350*572c4311Sfengbojiang         } else if (!strcasecmp(argv[0],"s") || !strcasecmp(argv[0],"step") ||
2351*572c4311Sfengbojiang                    !strcasecmp(argv[0],"n") || !strcasecmp(argv[0],"next")) {
2352*572c4311Sfengbojiang             ldb.step = 1;
2353*572c4311Sfengbojiang             break;
2354*572c4311Sfengbojiang         } else if (!strcasecmp(argv[0],"c") || !strcasecmp(argv[0],"continue")){
2355*572c4311Sfengbojiang             break;
2356*572c4311Sfengbojiang         } else if (!strcasecmp(argv[0],"t") || !strcasecmp(argv[0],"trace")) {
2357*572c4311Sfengbojiang             ldbTrace(lua);
2358*572c4311Sfengbojiang             ldbSendLogs();
2359*572c4311Sfengbojiang         } else if (!strcasecmp(argv[0],"m") || !strcasecmp(argv[0],"maxlen")) {
2360*572c4311Sfengbojiang             ldbMaxlen(argv,argc);
2361*572c4311Sfengbojiang             ldbSendLogs();
2362*572c4311Sfengbojiang         } else if (!strcasecmp(argv[0],"b") || !strcasecmp(argv[0],"break")) {
2363*572c4311Sfengbojiang             ldbBreak(argv,argc);
2364*572c4311Sfengbojiang             ldbSendLogs();
2365*572c4311Sfengbojiang         } else if (!strcasecmp(argv[0],"e") || !strcasecmp(argv[0],"eval")) {
2366*572c4311Sfengbojiang             ldbEval(lua,argv,argc);
2367*572c4311Sfengbojiang             ldbSendLogs();
2368*572c4311Sfengbojiang         } else if (!strcasecmp(argv[0],"a") || !strcasecmp(argv[0],"abort")) {
2369*572c4311Sfengbojiang             lua_pushstring(lua, "script aborted for user request");
2370*572c4311Sfengbojiang             lua_error(lua);
2371*572c4311Sfengbojiang         } else if (argc > 1 &&
2372*572c4311Sfengbojiang                    (!strcasecmp(argv[0],"r") || !strcasecmp(argv[0],"redis"))) {
2373*572c4311Sfengbojiang             ldbRedis(lua,argv,argc);
2374*572c4311Sfengbojiang             ldbSendLogs();
2375*572c4311Sfengbojiang         } else if ((!strcasecmp(argv[0],"p") || !strcasecmp(argv[0],"print"))) {
2376*572c4311Sfengbojiang             if (argc == 2)
2377*572c4311Sfengbojiang                 ldbPrint(lua,argv[1]);
2378*572c4311Sfengbojiang             else
2379*572c4311Sfengbojiang                 ldbPrintAll(lua);
2380*572c4311Sfengbojiang             ldbSendLogs();
2381*572c4311Sfengbojiang         } else if (!strcasecmp(argv[0],"l") || !strcasecmp(argv[0],"list")){
2382*572c4311Sfengbojiang             int around = ldb.currentline, ctx = 5;
2383*572c4311Sfengbojiang             if (argc > 1) {
2384*572c4311Sfengbojiang                 int num = atoi(argv[1]);
2385*572c4311Sfengbojiang                 if (num > 0) around = num;
2386*572c4311Sfengbojiang             }
2387*572c4311Sfengbojiang             if (argc > 2) ctx = atoi(argv[2]);
2388*572c4311Sfengbojiang             ldbList(around,ctx);
2389*572c4311Sfengbojiang             ldbSendLogs();
2390*572c4311Sfengbojiang         } else if (!strcasecmp(argv[0],"w") || !strcasecmp(argv[0],"whole")){
2391*572c4311Sfengbojiang             ldbList(1,1000000);
2392*572c4311Sfengbojiang             ldbSendLogs();
2393*572c4311Sfengbojiang         } else {
2394*572c4311Sfengbojiang             ldbLog(sdsnew("<error> Unknown Redis Lua debugger command or "
2395*572c4311Sfengbojiang                           "wrong number of arguments."));
2396*572c4311Sfengbojiang             ldbSendLogs();
2397*572c4311Sfengbojiang         }
2398*572c4311Sfengbojiang 
2399*572c4311Sfengbojiang         /* Free the command vector. */
2400*572c4311Sfengbojiang         sdsfreesplitres(argv,argc);
2401*572c4311Sfengbojiang     }
2402*572c4311Sfengbojiang 
2403*572c4311Sfengbojiang     /* Free the current command argv if we break inside the while loop. */
2404*572c4311Sfengbojiang     sdsfreesplitres(argv,argc);
2405*572c4311Sfengbojiang     return C_OK;
2406*572c4311Sfengbojiang }
2407*572c4311Sfengbojiang 
2408*572c4311Sfengbojiang /* This is the core of our Lua debugger, called each time Lua is about
2409*572c4311Sfengbojiang  * to start executing a new line. */
luaLdbLineHook(lua_State * lua,lua_Debug * ar)2410*572c4311Sfengbojiang void luaLdbLineHook(lua_State *lua, lua_Debug *ar) {
2411*572c4311Sfengbojiang     lua_getstack(lua,0,ar);
2412*572c4311Sfengbojiang     lua_getinfo(lua,"Sl",ar);
2413*572c4311Sfengbojiang     ldb.currentline = ar->currentline;
2414*572c4311Sfengbojiang 
2415*572c4311Sfengbojiang     int bp = ldbIsBreakpoint(ldb.currentline) || ldb.luabp;
2416*572c4311Sfengbojiang     int timeout = 0;
2417*572c4311Sfengbojiang 
2418*572c4311Sfengbojiang     /* Events outside our script are not interesting. */
2419*572c4311Sfengbojiang     if(strstr(ar->short_src,"user_script") == NULL) return;
2420*572c4311Sfengbojiang 
2421*572c4311Sfengbojiang     /* Check if a timeout occurred. */
2422*572c4311Sfengbojiang     if (ar->event == LUA_HOOKCOUNT && ldb.step == 0 && bp == 0) {
2423*572c4311Sfengbojiang         mstime_t elapsed = mstime() - server.lua_time_start;
2424*572c4311Sfengbojiang         mstime_t timelimit = server.lua_time_limit ?
2425*572c4311Sfengbojiang                              server.lua_time_limit : 5000;
2426*572c4311Sfengbojiang         if (elapsed >= timelimit) {
2427*572c4311Sfengbojiang             timeout = 1;
2428*572c4311Sfengbojiang             ldb.step = 1;
2429*572c4311Sfengbojiang         } else {
2430*572c4311Sfengbojiang             return; /* No timeout, ignore the COUNT event. */
2431*572c4311Sfengbojiang         }
2432*572c4311Sfengbojiang     }
2433*572c4311Sfengbojiang 
2434*572c4311Sfengbojiang     if (ldb.step || bp) {
2435*572c4311Sfengbojiang         char *reason = "step over";
2436*572c4311Sfengbojiang         if (bp) reason = ldb.luabp ? "redis.breakpoint() called" :
2437*572c4311Sfengbojiang                                      "break point";
2438*572c4311Sfengbojiang         else if (timeout) reason = "timeout reached, infinite loop?";
2439*572c4311Sfengbojiang         ldb.step = 0;
2440*572c4311Sfengbojiang         ldb.luabp = 0;
2441*572c4311Sfengbojiang         ldbLog(sdscatprintf(sdsempty(),
2442*572c4311Sfengbojiang             "* Stopped at %d, stop reason = %s",
2443*572c4311Sfengbojiang             ldb.currentline, reason));
2444*572c4311Sfengbojiang         ldbLogSourceLine(ldb.currentline);
2445*572c4311Sfengbojiang         ldbSendLogs();
2446*572c4311Sfengbojiang         if (ldbRepl(lua) == C_ERR && timeout) {
2447*572c4311Sfengbojiang             /* If the client closed the connection and we have a timeout
2448*572c4311Sfengbojiang              * connection, let's kill the script otherwise the process
2449*572c4311Sfengbojiang              * will remain blocked indefinitely. */
2450*572c4311Sfengbojiang             lua_pushstring(lua, "timeout during Lua debugging with client closing connection");
2451*572c4311Sfengbojiang             lua_error(lua);
2452*572c4311Sfengbojiang         }
2453*572c4311Sfengbojiang         server.lua_time_start = mstime();
2454*572c4311Sfengbojiang     }
2455*572c4311Sfengbojiang }
2456*572c4311Sfengbojiang 
2457