static int luv_new_signal(lua_State* L) { uv_signal_t* handle = lua_newuserdata(L, sizeof(*handle)); int ret = uv_signal_init(luv_loop(L), handle); if (ret < 0) { lua_pop(L, 1); return luv_error(L, ret); } handle->data = luv_setup_handle(L); return 1; }
static int luv_tcp_simultaneous_accepts(lua_State* L) { uv_tcp_t* handle = luv_check_tcp(L, 1); int ret, enable; luaL_checktype(L, 2, LUA_TBOOLEAN); enable = lua_toboolean(L, 2); ret = uv_tcp_simultaneous_accepts(handle, enable); if (ret < 0) return luv_error(L, ret); lua_pushinteger(L, ret); return 1; }
static int luv_getrusage(lua_State* L) { uv_rusage_t rusage; int ret = uv_getrusage(&rusage); if (ret < 0) return luv_error(L, ret); lua_createtable(L, 0, 16); // user CPU time used luv_push_timeval_table(L, &rusage.ru_utime); lua_setfield(L, -2, "utime"); // system CPU time used luv_push_timeval_table(L, &rusage.ru_stime); lua_setfield(L, -2, "stime"); // maximum resident set size lua_pushinteger(L, rusage.ru_maxrss); lua_setfield(L, -2, "maxrss"); // integral shared memory size lua_pushinteger(L, rusage.ru_ixrss); lua_setfield(L, -2, "ixrss"); // integral unshared data size lua_pushinteger(L, rusage.ru_idrss); lua_setfield(L, -2, "idrss"); // integral unshared stack size lua_pushinteger(L, rusage.ru_isrss); lua_setfield(L, -2, "isrss"); // page reclaims (soft page faults) lua_pushinteger(L, rusage.ru_minflt); lua_setfield(L, -2, "minflt"); // page faults (hard page faults) lua_pushinteger(L, rusage.ru_majflt); lua_setfield(L, -2, "majflt"); // swaps lua_pushinteger(L, rusage.ru_nswap); lua_setfield(L, -2, "nswap"); // block input operations lua_pushinteger(L, rusage.ru_inblock); lua_setfield(L, -2, "inblock"); // block output operations lua_pushinteger(L, rusage.ru_oublock); lua_setfield(L, -2, "oublock"); // IPC messages sent lua_pushinteger(L, rusage.ru_msgsnd); lua_setfield(L, -2, "msgsnd"); // IPC messages received lua_pushinteger(L, rusage.ru_msgrcv); lua_setfield(L, -2, "msgrcv"); // signals received lua_pushinteger(L, rusage.ru_nsignals); lua_setfield(L, -2, "nsignals"); // voluntary context switches lua_pushinteger(L, rusage.ru_nvcsw); lua_setfield(L, -2, "nvcsw"); // involuntary context switches lua_pushinteger(L, rusage.ru_nivcsw); lua_setfield(L, -2, "nivcsw"); return 1; }
static int luv_new_socket_poll(lua_State* L) { int fd = luaL_checkinteger(L, 1); uv_poll_t* handle = (uv_poll_t*)luv_newuserdata(L, sizeof(*handle)); int ret = uv_poll_init_socket(luv_loop(L), handle, fd); if (ret < 0) { lua_pop(L, 1); return luv_error(L, ret); } handle->data = luv_setup_handle(L); return 1; }
static int luv_fs_poll_start(lua_State* L) { uv_fs_poll_t* handle = luv_check_fs_poll(L, 1); const char* path = luaL_checkstring(L, 2); unsigned int interval = luaL_checkinteger(L, 3); int ret; luv_check_callback(L, handle->data, LUV_FS_POLL, 4); ret = uv_fs_poll_start(handle, luv_fs_poll_cb, path, interval); if (ret < 0) return luv_error(L, ret); lua_pushinteger(L, ret); return 1; }
static int luv_os_setpriority(lua_State* L) { uv_pid_t pid = luaL_checkinteger(L, 1); int priority= luaL_checkinteger(L, 2); int ret = uv_os_setpriority(pid, priority); if (ret == 0) { lua_pushboolean(L, 1); ret = 1; } else ret = luv_error(L, ret); return ret; }
static int luv_new_thread(lua_State* L) { int ret; size_t len; const char* buff; luv_thread_t* thread; int cbidx = 1; #if LUV_UV_VERSION_GEQ(1, 26, 0) uv_thread_options_t options; options.flags = UV_THREAD_NO_FLAGS; #endif thread = (luv_thread_t*)lua_newuserdata(L, sizeof(*thread)); memset(thread, 0, sizeof(*thread)); luaL_getmetatable(L, "uv_thread"); lua_setmetatable(L, -2); #if LUV_UV_VERSION_GEQ(1, 26, 0) if (lua_type(L, 1) == LUA_TTABLE) { cbidx++; lua_getfield(L, 1, "stack_size"); if (!lua_isnil(L, -1)) { options.flags |= UV_THREAD_HAS_STACK_SIZE; if (lua_isnumber(L, -1)) { options.stack_size = lua_tointeger(L, -1); } else { return luaL_argerror(L, 1, "stack_size option must be a number if set"); } } lua_pop(L, 1); } #endif buff = luv_thread_dumped(L, cbidx, &len); //clear in luv_thread_gc or in child threads thread->argc = luv_thread_arg_set(L, &thread->arg, cbidx+1, lua_gettop(L) - 1, LUVF_THREAD_UHANDLE); thread->len = len; thread->code = (char*)malloc(thread->len); memcpy(thread->code, buff, len); #if LUV_UV_VERSION_GEQ(1, 26, 0) ret = uv_thread_create_ex(&thread->handle, &options, luv_thread_cb, thread); #else ret = uv_thread_create(&thread->handle, luv_thread_cb, thread); #endif if (ret < 0) return luv_error(L, ret); return 1; }
static int luv_shutdown(lua_State* L) { uv_stream_t* handle = luv_check_stream(L, 1); int ref = luv_check_continuation(L, 2); uv_shutdown_t* req = lua_newuserdata(L, sizeof(*req)); int ret; req->data = luv_setup_req(L, ref); ret = uv_shutdown(req, handle, luv_shutdown_cb); if (ret < 0) { lua_pop(L, 1); return luv_error(L, ret); } return 1; }
static int luv_os_getpriority(lua_State* L) { int priority; uv_pid_t pid = luaL_checkinteger(L, 1); int ret = uv_os_getpriority(pid, &priority); if (ret == 0) { lua_pushnumber(L, priority); ret = 1; } else { ret = luv_error(L, ret); } return ret; }
static int luv_os_getenv(lua_State* L) { const char* name = luaL_checkstring(L, 1); size_t size = luaL_optinteger(L, 2, LUAL_BUFFERSIZE); char *buff = malloc(size); int ret = uv_os_getenv(name, buff, &size); if (ret == 0) { lua_pushlstring(L, buff, size); ret = 1; } else ret = luv_error(L, ret); free(buff); return ret; }
static int luv_tcp_keepalive(lua_State* L) { uv_tcp_t* handle = luv_check_tcp(L, 1); int ret, enable; unsigned int delay = 0; luaL_checktype(L, 2, LUA_TBOOLEAN); enable = lua_toboolean(L, 2); if (enable) { delay = luaL_checkinteger(L, 3); } ret = uv_tcp_keepalive(handle, enable, delay); if (ret < 0) return luv_error(L, ret); lua_pushinteger(L, ret); return 1; }
static int luv_if_indextoiid(lua_State* L) { char interface_id[UV_IF_NAMESIZE]; size_t interface_id_len = sizeof(interface_id); unsigned int ifindex = (unsigned int)luaL_checkinteger(L, 1); int ret = uv_if_indextoiid(ifindex - 1, interface_id, &interface_id_len); if (ret == 0) { lua_pushlstring(L, interface_id, interface_id_len); ret = 1; } else ret = luv_error(L, ret); return ret; }
static int luv_new_tty(lua_State* L) { int readable, ret; uv_tty_t* handle; uv_file fd = luaL_checkinteger(L, 1); luaL_checktype(L, 2, LUA_TBOOLEAN); readable = lua_toboolean(L, 2); handle = (uv_tty_t*)luv_newuserdata(L, sizeof(*handle)); ret = uv_tty_init(luv_loop(L), handle, fd, readable); if (ret < 0) { lua_pop(L, 1); return luv_error(L, ret); } handle->data = luv_setup_handle(L); return 1; }
static int luv_recv_buffer_size(lua_State* L) { uv_handle_t* handle = luv_check_handle(L, 1); int value; int ret; if (lua_isnoneornil(L, 2)) { value = 0; } else { value = luaL_checkinteger(L, 2); } ret = uv_recv_buffer_size(handle, &value); if (ret < 0) return luv_error(L, ret); lua_pushinteger(L, ret); return 1; }
static int luv_if_indextoname(lua_State* L) { /* 40 bytes address, 16 bytes device name, plus reserve. */ char scoped_addr[128]; size_t scoped_addr_len = sizeof(scoped_addr); unsigned int ifindex = (unsigned int)luaL_checkinteger(L, 1); int ret = uv_if_indextoname(ifindex - 1, scoped_addr, &scoped_addr_len); if (ret == 0) { lua_pushlstring(L, scoped_addr, scoped_addr_len); ret = 1; } else ret = luv_error(L, ret); return ret; }
static int luv_os_gethostname(lua_State* L) { #if LUV_UV_VERSION_GEQ(1, 26, 0) char hostname[UV_MAXHOSTNAMESIZE]; #else char hostname[PATH_MAX]; #endif size_t size = sizeof(hostname); int ret = uv_os_gethostname(hostname, &size); if (ret == 0) { lua_pushlstring(L, hostname, size); ret = 1; } else ret = luv_error(L, ret); return ret; }
static int luv_new_udp(lua_State* L) { uv_udp_t* handle = (uv_udp_t*)luv_newuserdata(L, sizeof(*handle)); int ret; if (lua_isnoneornil(L, 1)) { ret = uv_udp_init(luv_loop(L), handle); } else { ret = uv_udp_init_ex(luv_loop(L), handle, lua_tointeger(L, 1)); } if (ret < 0) { lua_pop(L, 1); return luv_error(L, ret); } handle->data = luv_setup_handle(L); return 1; }
static int luv_udp_try_send(lua_State* L) { uv_udp_t* handle = luv_check_udp(L, 1); uv_buf_t buf; int ret, port; const char* host; struct sockaddr_storage addr; luv_check_buf(L, 2, &buf); host = luaL_checkstring(L, 3); port = luaL_checkinteger(L, 4); if (uv_ip4_addr(host, port, (struct sockaddr_in*)&addr) && uv_ip6_addr(host, port, (struct sockaddr_in6*)&addr)) { return luaL_error(L, "Invalid IP address or port [%s:%d]", host, port); } ret = uv_udp_try_send(handle, &buf, 1, (struct sockaddr*)&addr); if (ret < 0) return luv_error(L, ret); lua_pushinteger(L, ret); return 1; }
static int luv_gettimeofday(lua_State* L) { uv_timeval64_t tv = { 0 }; int ret = uv_gettimeofday(&tv); if (ret == 0) { #if defined(__LP64__) lua_pushinteger(L, tv.tv_sec); #else lua_pushnumber(L, tv.tv_sec); #endif lua_pushinteger(L, tv.tv_usec); return 2; } else ret = luv_error(L, ret); return ret; }
static int luv_poll_start(lua_State* L) { uv_poll_t* handle = luv_check_poll(L, 1); int events, ret; switch (luaL_checkoption(L, 2, "rw", luv_pollevents)) { case 0: events = UV_READABLE; break; case 1: events = UV_WRITABLE; break; case 2: events = UV_READABLE | UV_WRITABLE; break; case 3: events = UV_DISCONNECT; break; case 4: events = UV_READABLE|UV_DISCONNECT; break; case 5: events = UV_WRITABLE|UV_DISCONNECT; break; case 6: events = UV_READABLE|UV_WRITABLE|UV_DISCONNECT; break; default: events = 0; /* unreachable */ } luv_check_callback(L, (luv_handle_t*)handle->data, LUV_POLL, 3); ret = uv_poll_start(handle, events, luv_poll_cb); if (ret < 0) return luv_error(L, ret); lua_pushinteger(L, ret); return 1; }
static int luv_os_uname(lua_State* L) { uv_utsname_t uname; int ret = uv_os_uname(&uname); if (ret == 0) { lua_newtable(L); lua_pushstring(L, uname.sysname); lua_setfield(L, -2, "sysname"); lua_pushstring(L, uname.release); lua_setfield(L, -2, "release"); lua_pushstring(L, uname.version); lua_setfield(L, -2, "version"); lua_pushstring(L, uname.machine); lua_setfield(L, -2, "machine"); ret = 1; } else ret = luv_error(L, ret); return ret; }
static int luv_fs_event_start(lua_State* L) { uv_fs_event_t* handle = luv_check_fs_event(L, 1); const char* path = luaL_checkstring(L, 2); int flags = 0, ret; luaL_checktype(L, 3, LUA_TTABLE); lua_getfield(L, 3, "watch_entry"); if (lua_toboolean(L, -1)) flags |= UV_FS_EVENT_WATCH_ENTRY; lua_pop(L, 1); lua_getfield(L, 3, "stat"); if (lua_toboolean(L, -1)) flags |= UV_FS_EVENT_STAT; lua_pop(L, 1); lua_getfield(L, 3, "recursive"); if (lua_toboolean(L, -1)) flags |= UV_FS_EVENT_RECURSIVE; lua_pop(L, 1); luv_check_callback(L, handle->data, LUV_FS_EVENT, 4); ret = uv_fs_event_start(handle, luv_fs_event_cb, path, flags); if (ret < 0) return luv_error(L, ret); lua_pushinteger(L, ret); return 1; }
static int luv_tcp_bind(lua_State* L) { uv_tcp_t* handle = luv_check_tcp(L, 1); const char* host = luaL_checkstring(L, 2); int port = luaL_checkinteger(L, 3); unsigned int flags = 0; struct sockaddr_storage addr; int ret; if (uv_ip4_addr(host, port, (struct sockaddr_in*)&addr) && uv_ip6_addr(host, port, (struct sockaddr_in6*)&addr)) { return luaL_error(L, "Invalid IP address or port [%s:%d]", host, port); } if (lua_type(L, 4) == LUA_TTABLE) { lua_getfield(L, 4, "ipv6only"); if (lua_toboolean(L, -1)) flags |= UV_TCP_IPV6ONLY; lua_pop(L, 1); } ret = uv_tcp_bind(handle, (struct sockaddr*)&addr, flags); if (ret < 0) return luv_error(L, ret); lua_pushinteger(L, ret); return 1; }
static int luv_try_write(lua_State* L) { uv_stream_t* handle = luv_check_stream(L, 1); int ret; if (lua_istable(L, 2)) { size_t count; uv_buf_t *bufs = luv_prep_bufs(L, 2, &count); ret = uv_try_write(handle, bufs, count); free(bufs); } else if (lua_isstring(L, 2)) { uv_buf_t buf; luv_check_buf(L, 2, &buf); ret = uv_try_write(handle, &buf, 1); } else { return luaL_argerror(L, 2, "data must be string or table of strings"); } if (ret < 0) return luv_error(L, ret); lua_pushinteger(L, ret); return 1; }
static int luv_signal_start(lua_State* L) { uv_signal_t* handle = luv_check_signal(L, 1); int signum, ret; if (lua_isnumber(L, 2)) { signum = lua_tointeger(L, 2); } else if (lua_isstring(L, 2)) { signum = luv_sig_string_to_num(luaL_checkstring(L, 2)); luaL_argcheck(L, signum, 2, "Invalid Signal name"); } else { return luaL_argerror(L, 2, "Missing Signal name"); } if (!lua_isnoneornil(L, 3)) { luv_check_callback(L, handle->data, LUV_SIGNAL, 3); } ret = uv_signal_start(handle, luv_signal_cb, signum); if (ret < 0) return luv_error(L, ret); lua_pushinteger(L, ret); return 1; }
static int luv_new_thread(lua_State* L) { int ret; size_t len; const char* buff; luv_thread_t* thread; thread = lua_newuserdata(L, sizeof(*thread)); memset(thread, 0, sizeof(*thread)); luaL_getmetatable(L, "uv_thread"); lua_setmetatable(L, -2); buff = luv_thread_dumped(L, 1, &len); thread->argc = luv_thread_arg_set(L, &thread->arg, 2, lua_gettop(L) - 1, 1); thread->len = len; thread->code = malloc(thread->len); memcpy(thread->code, buff, len); ret = uv_thread_create(&thread->handle, luv_thread_cb, thread); if (ret < 0) return luv_error(L, ret); return 1; }
static int luv_tcp_connect(lua_State* L) { uv_tcp_t* handle = luv_check_tcp(L, 1); const char* host = luaL_checkstring(L, 2); int port = luaL_checkinteger(L, 3); struct sockaddr_storage addr; uv_connect_t* req; int ret, ref; if (uv_ip4_addr(host, port, (struct sockaddr_in*)&addr) && uv_ip6_addr(host, port, (struct sockaddr_in6*)&addr)) { return luaL_error(L, "Invalid IP address or port [%s:%d]", host, port); } ref = luv_check_continuation(L, 4); req = lua_newuserdata(L, sizeof(*req)); req->data = luv_setup_req(L, ref); ret = uv_tcp_connect(req, handle, (struct sockaddr*)&addr, luv_connect_cb); if (ret < 0) { lua_pop(L, 1); return luv_error(L, ret); } return 1; }
static int luv_queue_work(lua_State* L) { int top = lua_gettop(L); luv_work_ctx_t* ctx = luv_check_work_ctx(L, 1); luv_work_t* work = malloc(sizeof(*work)); int ret; luv_thread_arg_set(L, &work->arg, 2, top); work->ctx = ctx; work->work.data = work; ret = uv_queue_work(luv_loop(L), &work->work, luv_work_cb, luv_after_work_cb); if (ret < 0) { free(work); return luv_error(L, ret); } //ref up to ctx lua_pushlightuserdata(L, work); lua_pushvalue(L, 1); lua_rawset(L, LUA_REGISTRYINDEX); lua_pushboolean(L, 1); return 1; }
static int luv_getaddrinfo(lua_State* L) { uv_getaddrinfo_t* req; const char* node; const char* service; struct addrinfo hints_s; struct addrinfo* hints = &hints_s; int ret, ref; if (lua_isnoneornil(L, 1)) node = NULL; else node = luaL_checkstring(L, 1); if (lua_isnoneornil(L, 2)) service = NULL; else service = luaL_checkstring(L, 2); if (!lua_isnoneornil(L, 3)) luaL_checktype(L, 3, LUA_TTABLE); else hints = NULL; if (hints) { // Initialize the hints memset(hints, 0, sizeof(*hints)); // Process the `family` hint. lua_getfield(L, 3, "family"); if (lua_isnumber(L, -1)) { hints->ai_family = lua_tointeger(L, -1); } else if (lua_isstring(L, -1)) { hints->ai_family = luv_af_string_to_num(lua_tostring(L, -1)); } else if (lua_isnil(L, -1)) { hints->ai_family = AF_UNSPEC; } else { luaL_argerror(L, 3, "family hint must be string if set"); } lua_pop(L, 1); // Process `socktype` hint lua_getfield(L, 3, "socktype"); if (lua_isnumber(L, -1)) { hints->ai_socktype = lua_tointeger(L, -1); } else if (lua_isstring(L, -1)) { hints->ai_socktype = luv_sock_string_to_num(lua_tostring(L, -1)); } else if (!lua_isnil(L, -1)) { return luaL_argerror(L, 3, "socktype hint must be string if set"); } lua_pop(L, 1); // Process the `protocol` hint lua_getfield(L, 3, "protocol"); if (lua_isnumber(L, -1)) { hints->ai_protocol = lua_tointeger(L, -1); } else if (lua_isstring(L, -1)) { int protocol = luv_af_string_to_num(lua_tostring(L, -1)); if (protocol) { hints->ai_protocol = protocol; } else { return luaL_argerror(L, 3, "Invalid protocol hint"); } } else if (!lua_isnil(L, -1)) { return luaL_argerror(L, 3, "protocol hint must be string if set"); } lua_pop(L, 1); lua_getfield(L, 3, "addrconfig"); if (lua_toboolean(L, -1)) hints->ai_flags |= AI_ADDRCONFIG; lua_pop(L, 1); #ifdef AI_V4MAPPED lua_getfield(L, 3, "v4mapped"); if (lua_toboolean(L, -1)) hints->ai_flags |= AI_V4MAPPED; lua_pop(L, 1); #endif #ifdef AI_ALL lua_getfield(L, 3, "all"); if (lua_toboolean(L, -1)) hints->ai_flags |= AI_ALL; lua_pop(L, 1); #endif lua_getfield(L, 3, "numerichost"); if (lua_toboolean(L, -1)) hints->ai_flags |= AI_NUMERICHOST; lua_pop(L, 1); lua_getfield(L, 3, "passive"); if (lua_toboolean(L, -1)) hints->ai_flags |= AI_PASSIVE; lua_pop(L, 1); lua_getfield(L, 3, "numericserv"); if (lua_toboolean(L, -1)) { hints->ai_flags |= AI_NUMERICSERV; /* On OS X upto at least OSX 10.9, getaddrinfo crashes * if AI_NUMERICSERV is set and the servname is NULL or "0". * This workaround avoids a segfault in libsystem. */ if (NULL == service) service = "00"; } lua_pop(L, 1); lua_getfield(L, 3, "canonname"); if (lua_toboolean(L, -1)) hints->ai_flags |= AI_CANONNAME; lua_pop(L, 1); } ref = luv_check_continuation(L, 4); req = (uv_getaddrinfo_t*)lua_newuserdata(L, sizeof(*req)); req->data = luv_setup_req(L, ref); ret = uv_getaddrinfo(luv_loop(L), req, ref == LUA_NOREF ? NULL : luv_getaddrinfo_cb, node, service, hints); if (ret < 0) { luv_cleanup_req(L, (luv_req_t*)req->data); lua_pop(L, 1); return luv_error(L, ret); } if (ref == LUA_NOREF) { lua_pop(L, 1); luv_pushaddrinfo(L, req->addrinfo); uv_freeaddrinfo(req->addrinfo); luv_cleanup_req(L, (luv_req_t*)req->data); } return 1; }
static int luv_spawn(lua_State* L) { uv_process_t* handle; uv_process_options_t options; size_t i, len = 0; int ret; memset(&options, 0, sizeof(options)); options.exit_cb = exit_cb; options.file = luaL_checkstring(L, 1); options.flags = 0; // Make sure the 2nd argument is a table luaL_checktype(L, 2, LUA_TTABLE); // get the args list lua_getfield(L, 2, "args"); // +1 for inserted command at front if (lua_type(L, -1) == LUA_TTABLE) { len = 1 + lua_rawlen(L, -1); } else if (lua_type(L, -1) != LUA_TNIL) { luv_clean_options(&options); return luaL_argerror(L, 3, "args option must be table"); } else { len = 1; } // +1 for null terminator at end options.args = malloc((len + 1) * sizeof(*options.args)); if (!options.args) { luv_clean_options(&options); return luaL_error(L, "Problem allocating args"); } options.args[0] = (char*)options.file; for (i = 1; i < len; ++i) { lua_rawgeti(L, -1, i); options.args[i] = (char*)lua_tostring(L, -1); lua_pop(L, 1); } options.args[len] = NULL; lua_pop(L, 1); // get the stdio list lua_getfield(L, 2, "stdio"); if (lua_type(L, -1) == LUA_TTABLE) { options.stdio_count = len = lua_rawlen(L, -1); options.stdio = malloc(len * sizeof(*options.stdio)); if (!options.stdio) { luv_clean_options(&options); return luaL_error(L, "Problem allocating stdio"); } for (i = 0; i < len; ++i) { lua_rawgeti(L, -1, i + 1); // integers are assumed to be file descripters if (lua_type(L, -1) == LUA_TNUMBER) { options.stdio[i].flags = UV_INHERIT_FD; options.stdio[i].data.fd = lua_tointeger(L, -1); } // userdata is assumed to be a uv_stream_t instance else if (lua_type(L, -1) == LUA_TUSERDATA) { uv_os_fd_t fd; uv_stream_t* stream = luv_check_stream(L, -1); int err = uv_fileno((uv_handle_t*)stream, &fd); if (err == UV_EINVAL || err == UV_EBADF) { options.stdio[i].flags = UV_CREATE_PIPE | UV_READABLE_PIPE | UV_WRITABLE_PIPE; } else { options.stdio[i].flags = UV_INHERIT_STREAM; } options.stdio[i].data.stream = stream; } else if (lua_type(L, -1) == LUA_TNIL) { options.stdio[i].flags = UV_IGNORE; } else { luv_clean_options(&options); return luaL_argerror(L, 2, "stdio table entries must be nil, uv_stream_t, or integer"); } lua_pop(L, 1); } } else if (lua_type(L, -1) != LUA_TNIL) { luv_clean_options(&options); return luaL_argerror(L, 2, "stdio option must be table"); } lua_pop(L, 1); // Get the env lua_getfield(L, 2, "env"); if (lua_type(L, -1) == LUA_TTABLE) { len = lua_rawlen(L, -1); options.env = malloc((len + 1) * sizeof(*options.env)); if (!options.env) { luv_clean_options(&options); return luaL_error(L, "Problem allocating env"); } for (i = 0; i < len; ++i) { lua_rawgeti(L, -1, i + 1); options.env[i] = (char*)lua_tostring(L, -1); lua_pop(L, 1); } options.env[len] = NULL; } else if (lua_type(L, -1) != LUA_TNIL) { luv_clean_options(&options); return luaL_argerror(L, 2, "env option must be table"); } lua_pop(L, 1); // Get the cwd lua_getfield(L, 2, "cwd"); if (lua_type(L, -1) == LUA_TSTRING) { options.cwd = (char*)lua_tostring(L, -1); } else if (lua_type(L, -1) != LUA_TNIL) { luv_clean_options(&options); return luaL_argerror(L, 2, "cwd option must be string"); } lua_pop(L, 1); // Check for uid lua_getfield(L, 2, "uid"); if (lua_type(L, -1) == LUA_TNUMBER) { options.uid = lua_tointeger(L, -1); options.flags |= UV_PROCESS_SETUID; } else if (lua_type(L, -1) != LUA_TNIL) { luv_clean_options(&options); return luaL_argerror(L, 2, "uid option must be number"); } lua_pop(L, 1); // Check for gid lua_getfield(L, 2, "gid"); if (lua_type(L, -1) == LUA_TNUMBER) { options.gid = lua_tointeger(L, -1); options.flags |= UV_PROCESS_SETGID; } else if (lua_type(L, -1) != LUA_TNIL) { luv_clean_options(&options); return luaL_argerror(L, 2, "gid option must be number"); } lua_pop(L, 1); // Check for the boolean flags lua_getfield(L, 2, "verbatim"); if (lua_toboolean(L, -1)) { options.flags |= UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS; } lua_pop(L, 1); lua_getfield(L, 2, "detached"); if (lua_toboolean(L, -1)) { options.flags |= UV_PROCESS_DETACHED; } lua_pop(L, 1); lua_getfield(L, 2, "hide"); if (lua_toboolean(L, -1)) { options.flags |= UV_PROCESS_WINDOWS_HIDE; } lua_pop(L, 1); handle = lua_newuserdata(L, sizeof(*handle)); handle->type = UV_PROCESS; handle->data = luv_setup_handle(L); if (!lua_isnoneornil(L, 3)) { luv_check_callback(L, handle->data, LUV_EXIT, 3); } ret = uv_spawn(luv_loop(L), handle, &options); luv_clean_options(&options); if (ret < 0) { /* The async callback is required here because luajit GC may reclaim the * luv handle before libuv is done closing it down. */ uv_close((uv_handle_t*)handle, luv_spawn_close_cb); return luv_error(L, ret); } lua_pushinteger(L, handle->pid); return 2; }