lua from C: unify the way we throw lua_error()

It's often a bit shorter, and it provides us with location.
parent 83539eb7
......@@ -27,10 +27,8 @@ struct kr_cache * cache_assert_open(lua_State *L)
struct engine *engine = engine_luaget(L);
struct kr_cache *cache = &engine->resolver.cache;
assert(cache);
if (!cache || !kr_cache_is_open(cache)) {
format_error(L, "no cache is open yet, use cache.open() or cache.size, etc.");
lua_error(L);
}
if (!cache || !kr_cache_is_open(cache))
lua_error_p(L, "no cache is open yet, use cache.open() or cache.size, etc.");
return cache;
}
......@@ -80,10 +78,9 @@ static int cache_checkpoint(lua_State *L)
return 1;
}
if (lua_gettop(L) != 1 || !lua_isboolean(L, 1) || !lua_toboolean(L, 1)) {
format_error(L, "cache.checkpoint() takes no parameters or a true value");
lua_error(L);
}
if (lua_gettop(L) != 1 || !lua_isboolean(L, 1) || !lua_toboolean(L, 1))
lua_error_p(L, "cache.checkpoint() takes no parameters or a true value");
kr_cache_make_checkpoint(cache);
return 1;
}
......@@ -129,15 +126,14 @@ static int cache_max_ttl(lua_State *L)
int n = lua_gettop(L);
if (n > 0) {
if (!lua_isnumber(L, 1)) {
format_error(L, "expected 'max_ttl(number ttl)'");
lua_error(L);
}
if (!lua_isnumber(L, 1))
lua_error_p(L, "expected 'max_ttl(number ttl)'");
uint32_t min = cache->ttl_min;
int64_t ttl = lua_tonumber(L, 1);
if (ttl < 0 || ttl < min || ttl > UINT32_MAX) {
format_error(L, "max_ttl must be larger than minimum TTL, and in range <1, " STR(UINT32_MAX) ">'");
lua_error(L);
lua_error_p(L,
"max_ttl must be larger than minimum TTL, and in range <1, "
STR(UINT32_MAX) ">'");
}
cache->ttl_max = ttl;
}
......@@ -152,15 +148,14 @@ static int cache_min_ttl(lua_State *L)
int n = lua_gettop(L);
if (n > 0) {
if (!lua_isnumber(L, 1)) {
format_error(L, "expected 'min_ttl(number ttl)'");
lua_error(L);
}
if (!lua_isnumber(L, 1))
lua_error_p(L, "expected 'min_ttl(number ttl)'");
uint32_t max = cache->ttl_max;
int64_t ttl = lua_tonumber(L, 1);
if (ttl < 0 || ttl > max || ttl > UINT32_MAX) {
format_error(L, "min_ttl must be smaller than maximum TTL, and in range <0, " STR(UINT32_MAX) ">'");
lua_error(L);
lua_error_p(L,
"min_ttl must be smaller than maximum TTL, and in range <0, "
STR(UINT32_MAX) ">'");
}
cache->ttl_min = ttl;
}
......@@ -173,28 +168,24 @@ static int cache_open(lua_State *L)
{
/* Check parameters */
int n = lua_gettop(L);
if (n < 1 || !lua_isnumber(L, 1)) {
format_error(L, "expected 'open(number max_size, string config = \"\")'");
lua_error(L);
}
if (n < 1 || !lua_isnumber(L, 1))
lua_error_p(L, "expected 'open(number max_size, string config = \"\")'");
/* Select cache storage backend */
struct engine *engine = engine_luaget(L);
lua_Number csize_lua = lua_tonumber(L, 1);
if (!(csize_lua >= 8192 && csize_lua < SIZE_MAX)) { /* min. is basically arbitrary */
format_error(L, "invalid cache size specified, it must be in range <8192, " STR(SIZE_MAX) ">");
lua_error(L);
lua_error_p(L, "invalid cache size specified, it must be in range <8192, "
STR(SIZE_MAX) ">");
}
size_t cache_size = csize_lua;
const char *conf = n > 1 ? lua_tostring(L, 2) : NULL;
const char *uri = conf;
const struct kr_cdb_api *api = cache_select(engine, &conf);
if (!api) {
format_error(L, "unsupported cache backend");
lua_error(L);
}
if (!api)
lua_error_p(L, "unsupported cache backend");
/* Close if already open */
kr_cache_close(&engine->resolver.cache);
......@@ -268,20 +259,15 @@ static int cache_prune(lua_State *L)
/* Check parameters */
int prune_max = UINT16_MAX;
int n = lua_gettop(L);
if (n >= 1 && lua_isnumber(L, 1)) {
if (n >= 1 && lua_isnumber(L, 1))
prune_max = lua_tointeger(L, 1);
}
/* Check if API supports pruning. */
int ret = kr_error(ENOSYS);
if (cache->api->prune) {
if (cache->api->prune)
ret = cache->api->prune(cache->db, prune_max);
}
/* Commit and format result. */
if (ret < 0) {
format_error(L, kr_strerror(ret));
lua_error(L);
}
lua_error_maybe(L, ret);
lua_pushinteger(L, ret);
return 1;
}
......@@ -293,10 +279,7 @@ static int cache_clear_everything(lua_State *L)
/* Clear records and packets. */
int ret = kr_cache_clear(cache);
if (ret < 0) {
format_error(L, kr_strerror(ret));
lua_error(L);
}
lua_error_maybe(L, ret);
/* Clear reputation tables */
struct engine *engine = engine_luaget(L);
......@@ -346,19 +329,14 @@ static int cache_get(lua_State *L)
/* Check parameters */
int n = lua_gettop(L);
if (n < 1 || !lua_isstring(L, 1)) {
format_error(L, "expected 'cache.get(string key)'");
lua_error(L);
}
if (n < 1 || !lua_isstring(L, 1))
lua_error_p(L, "expected 'cache.get(string key)'");
/* Retrieve set of keys */
const char *prefix = lua_tostring(L, 1);
knot_db_val_t keyval[100][2];
int ret = cache_prefixed(cache, prefix, false/*FIXME*/, keyval, 100);
if (ret < 0) {
format_error(L, kr_strerror(ret));
lua_error(L);
}
lua_error_maybe(L, ret);
/* Format output */
lua_newtable(L);
for (int i = 0; i < ret; ++i) {
......@@ -369,10 +347,8 @@ static int cache_get(lua_State *L)
#endif
static int cache_get(lua_State *L)
{
int ret = kr_error(ENOSYS);
format_error(L, kr_strerror(ret));
lua_error(L);
return ret;
lua_error_maybe(L, ENOSYS);
return kr_error(ENOSYS); /* doesn't happen */
}
/** Set time interval for cleaning rtt cache.
......@@ -391,15 +367,13 @@ static int cache_ns_tout(lua_State *L)
return 1;
}
if (!lua_isnumber(L, 1)) {
format_error(L, "expected 'cache.ns_tout(interval in ms)'");
lua_error(L);
}
if (!lua_isnumber(L, 1))
lua_error_p(L, "expected 'cache.ns_tout(interval in ms)'");
lua_Integer interval_lua = lua_tointeger(L, 1);
if (!(interval_lua > 0 && interval_lua < UINT_MAX)) {
format_error(L, "invalid interval specified, it must be in range > 0, < " STR(UINT_MAX));
lua_error(L);
lua_error_p(L, "invalid interval specified, it must be in range > 0, < "
STR(UINT_MAX));
}
ctx->cache_rtt_tout_retry_interval = interval_lua;
......
......@@ -71,10 +71,8 @@ static void event_fdcallback(uv_poll_t* handle, int status, int events)
static int event_sched(lua_State *L, unsigned timeout, unsigned repeat)
{
uv_timer_t *timer = malloc(sizeof(*timer));
if (!timer) {
format_error(L, "out of memory");
lua_error(L);
}
if (!timer)
lua_error_p(L, "out of memory");
/* Start timer with the reference */
uv_loop_t *loop = uv_default_loop();
......@@ -82,8 +80,7 @@ static int event_sched(lua_State *L, unsigned timeout, unsigned repeat)
int ret = uv_timer_start(timer, event_callback, timeout, repeat);
if (ret != 0) {
free(timer);
format_error(L, "couldn't start the event");
lua_error(L);
lua_error_p(L, "couldn't start the event");
}
/* Save callback and timer in registry */
......@@ -104,10 +101,8 @@ static int event_after(lua_State *L)
{
/* Check parameters */
int n = lua_gettop(L);
if (n < 2 || !lua_isnumber(L, 1) || !lua_isfunction(L, 2)) {
format_error(L, "expected 'after(number timeout, function)'");
lua_error(L);
}
if (n < 2 || !lua_isnumber(L, 1) || !lua_isfunction(L, 2))
lua_error_p(L, "expected 'after(number timeout, function)'");
return event_sched(L, lua_tonumber(L, 1), 0);
}
......@@ -116,20 +111,17 @@ static int event_recurrent(lua_State *L)
{
/* Check parameters */
int n = lua_gettop(L);
if (n < 2 || !lua_isnumber(L, 1) || !lua_isfunction(L, 2)) {
format_error(L, "expected 'recurrent(number interval, function)'");
lua_error(L);
}
if (n < 2 || !lua_isnumber(L, 1) || !lua_isfunction(L, 2))
lua_error_p(L, "expected 'recurrent(number interval, function)'");
return event_sched(L, 0, lua_tonumber(L, 1));
}
static int event_cancel(lua_State *L)
{
int n = lua_gettop(L);
if (n < 1 || !lua_isnumber(L, 1)) {
format_error(L, "expected 'cancel(number event)'");
lua_error(L);
}
if (n < 1 || !lua_isnumber(L, 1))
lua_error_p(L, "expected 'cancel(number event)'");
/* Fetch event if it exists */
lua_rawgeti(L, LUA_REGISTRYINDEX, lua_tointeger(L, 1));
......@@ -151,10 +143,8 @@ static int event_cancel(lua_State *L)
static int event_reschedule(lua_State *L)
{
int n = lua_gettop(L);
if (n < 2 || !lua_isnumber(L, 1) || !lua_isnumber(L, 2)) {
format_error(L, "expected 'reschedule(number event, number timeout)'");
lua_error(L);
}
if (n < 2 || !lua_isnumber(L, 1) || !lua_isnumber(L, 2))
lua_error_p(L, "expected 'reschedule(number event, number timeout)'");
/* Fetch event if it exists */
lua_rawgeti(L, LUA_REGISTRYINDEX, lua_tointeger(L, 1));
......@@ -185,16 +175,12 @@ static int event_fdwatch(lua_State *L)
{
/* Check parameters */
int n = lua_gettop(L);
if (n < 2 || !lua_isnumber(L, 1) || !lua_isfunction(L, 2)) {
format_error(L, "expected 'socket(number fd, function)'");
lua_error(L);
}
if (n < 2 || !lua_isnumber(L, 1) || !lua_isfunction(L, 2))
lua_error_p(L, "expected 'socket(number fd, function)'");
uv_poll_t *handle = malloc(sizeof(*handle));
if (!handle) {
format_error(L, "out of memory");
lua_error(L);
}
if (!handle)
lua_error_p(L, "out of memory");
/* Start timer with the reference */
int sock = lua_tonumber(L, 1);
......@@ -219,8 +205,7 @@ static int event_fdwatch(lua_State *L)
}
if (ret != 0) {
free(handle);
format_error(L, "couldn't start event poller");
lua_error(L);
lua_error_p(L, "couldn't start event poller");
}
/* Save callback and timer in registry */
......
......@@ -44,11 +44,11 @@ void kr_bindings_register(lua_State *L)
lualib(L, "worker", kr_bindings_worker);
}
int format_error(lua_State* L, const char *err)
void lua_error_p(lua_State *L, const char *fmt, ...)
{
/* Push a string describing location in the "parent" lua function. */
lua_Debug d;
lua_getstack(L, 1, &d);
/* error message prefix */
lua_getinfo(L, "Sln", &d);
if (strncmp(d.short_src, "[", 1) != 0) {
lua_pushstring(L, d.short_src);
......@@ -59,9 +59,13 @@ int format_error(lua_State* L, const char *err)
} else {
lua_pushstring(L, "error: ");
}
/* error message */
lua_pushstring(L, err);
/* Push formatted custom message. */
va_list args;
va_start(args, fmt);
lua_pushvfstring(L, fmt, args);
va_end(args);
/* Concatenate the two and throw a lua error. */
lua_concat(L, 2);
return 1;
lua_error(L);
}
......@@ -39,12 +39,19 @@
#define STR(s) STRINGIFY_TOKEN(s)
#define STRINGIFY_TOKEN(s) #s
/** @internal Prefix error with file:line
* Implementation in ./impl.c */
int KR_COLD format_error(lua_State* L, const char *err);
/** @internal Annotate for static checkers. */
KR_NORETURN int lua_error(lua_State *L);
/** Throw a formatted lua error. It doesn't return. */
KR_PRINTF(2) KR_NORETURN KR_COLD
void lua_error_p(lua_State *L, const char *fmt, ...);
/** Shortcut for common case. */
static inline void lua_error_maybe(lua_State *L, int err)
{
if (err) lua_error_p(L, "%s", kr_strerror(err));
}
static inline struct worker_ctx *wrk_luaget(lua_State *L) {
lua_getglobal(L, "__worker");
struct worker_ctx *worker = lua_touserdata(L, -1);
......
......@@ -35,15 +35,12 @@ static int mod_load(lua_State *L)
{
/* Check parameters */
int n = lua_gettop(L);
if (n != 1 || !lua_isstring(L, 1)) {
format_error(L, "expected 'load(string name)'");
lua_error(L);
}
if (n != 1 || !lua_isstring(L, 1))
lua_error_p(L, "expected 'load(string name)'");
/* Parse precedence declaration */
char *declaration = strdup(lua_tostring(L, 1));
if (!declaration) {
if (!declaration)
return kr_error(ENOMEM);
}
const char *name = strtok(declaration, " ");
const char *precedence = strtok(NULL, " ");
const char *ref = strtok(NULL, " ");
......@@ -53,11 +50,10 @@ static int mod_load(lua_State *L)
free(declaration);
if (ret != 0) {
if (ret == kr_error(EIDRM)) {
format_error(L, "referenced module not found");
lua_error_p(L, "referenced module not found");
} else {
format_error(L, kr_strerror(ret));
lua_error_maybe(L, ret);
}
lua_error(L);
}
lua_pushboolean(L, 1);
......@@ -69,17 +65,12 @@ static int mod_unload(lua_State *L)
{
/* Check parameters */
int n = lua_gettop(L);
if (n != 1 || !lua_isstring(L, 1)) {
format_error(L, "expected 'unload(string name)'");
lua_error(L);
}
if (n != 1 || !lua_isstring(L, 1))
lua_error_p(L, "expected 'unload(string name)'");
/* Unload engine module */
struct engine *engine = engine_luaget(L);
int ret = engine_unregister(engine, lua_tostring(L, 1));
if (ret != 0) {
format_error(L, kr_strerror(ret));
lua_error(L);
}
lua_error_maybe(L, ret);
lua_pushboolean(L, 1);
return 1;
......
This diff is collapsed.
......@@ -27,17 +27,13 @@ static int wrk_resolve(lua_State *L)
}
uint8_t dname[KNOT_DNAME_MAXLEN];
if (!knot_dname_from_str(dname, lua_tostring(L, 1), sizeof(dname))) {
lua_pushstring(L, "invalid qname");
lua_error(L);
};
if (!knot_dname_from_str(dname, lua_tostring(L, 1), sizeof(dname)))
lua_error_p(L, "invalid qname");
/* Check class and type */
uint16_t rrtype = lua_tointeger(L, 2);
if (!lua_isnumber(L, 2)) {
lua_pushstring(L, "invalid RR type");
lua_error(L);
}
if (!lua_isnumber(L, 2))
lua_error_p(L, "invalid RR type");
uint16_t rrclass = lua_tointeger(L, 3);
if (!lua_isnumber(L, 3)) { /* Default class is IN */
......@@ -46,17 +42,13 @@ static int wrk_resolve(lua_State *L)
/* Add query options */
const struct kr_qflags *options = lua_topointer(L, 4);
if (!options) { /* but we rely on the lua wrapper when dereferencing non-NULL */
lua_pushstring(L, "invalid options");
lua_error(L);
}
if (!options) /* but we rely on the lua wrapper when dereferencing non-NULL */
lua_error_p(L, "invalid options");
/* Create query packet */
knot_pkt_t *pkt = knot_pkt_new(NULL, KNOT_EDNS_MAX_UDP_PAYLOAD, NULL);
if (!pkt) {
lua_pushstring(L, kr_strerror(ENOMEM));
lua_error(L);
}
if (!pkt)
lua_error_maybe(L, ENOMEM);
knot_pkt_put_question(pkt, dname, rrclass, rrtype);
knot_wire_set_rd(pkt->wire);
knot_wire_set_ad(pkt->wire);
......@@ -65,7 +57,7 @@ static int wrk_resolve(lua_State *L)
pkt->opt_rr = knot_rrset_copy(worker->engine->resolver.opt_rr, NULL);
if (!pkt->opt_rr) {
knot_pkt_free(pkt);
return kr_error(ENOMEM);
lua_error_maybe(L, ENOMEM);
}
if (options->DNSSEC_WANT) {
knot_edns_set_do(pkt->opt_rr);
......@@ -80,8 +72,7 @@ static int wrk_resolve(lua_State *L)
if (!task) {
knot_rrset_free(pkt->opt_rr, NULL);
knot_pkt_free(pkt);
lua_pushstring(L, "couldn't create a resolution request");
lua_error(L);
lua_error_p(L, "couldn't create a resolution request");
}
/* Add initialisation callback */
......
......@@ -27,6 +27,7 @@
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
#include "daemon/bindings/impl.h"
#include "daemon/engine.h"
#include "daemon/ffimodule.h"
......@@ -62,9 +63,6 @@
#define TCP_BACKLOG_DEFAULT 511
#endif
/** @internal Annotate for static checkers. */
KR_NORETURN int lua_error (lua_State *L);
/* Cleanup engine state every 5 minutes */
const size_t CLEANUP_TIMER = 5*60*1000;
......@@ -133,31 +131,25 @@ static bool update_privileges(int uid, int gid)
static int l_setuser(lua_State *L)
{
int n = lua_gettop(L);
if (n < 1 || !lua_isstring(L, 1)) {
lua_pushliteral(L, "user(user[, group)");
lua_error(L);
}
if (n < 1 || !lua_isstring(L, 1))
lua_error_p(L, "user(user[, group])");
/* Fetch UID/GID based on string identifiers. */
struct passwd *user_pw = getpwnam(lua_tostring(L, 1));
if (!user_pw) {
lua_pushliteral(L, "invalid user name");
lua_error(L);
}
if (!user_pw)
lua_error_p(L, "invalid user name");
int uid = user_pw->pw_uid;
int gid = getgid();
if (n > 1 && lua_isstring(L, 2)) {
struct group *group_pw = getgrnam(lua_tostring(L, 2));
if (!group_pw) {
lua_pushliteral(L, "invalid group name");
lua_error(L);
}
if (!group_pw)
lua_error_p(L, "invalid group name");
gid = group_pw->gr_gid;
}
/* Drop privileges */
bool ret = update_privileges(uid, gid);
if (!ret) {
lua_pushstring(L, strerror(errno));
lua_error(L);
lua_error_maybe(L, errno);
}
lua_pushboolean(L, ret);
return 1;
......@@ -220,17 +212,13 @@ static int l_hostname(lua_State *L)
lua_pushstring(L, engine_get_hostname(engine));
return 1;
}
if ((lua_gettop(L) != 1) || !lua_isstring(L, 1)) {
lua_pushstring(L, "hostname takes at most one parameter: (\"fqdn\")");
lua_error(L);
}
if ((lua_gettop(L) != 1) || !lua_isstring(L, 1))
lua_error_p(L, "hostname takes at most one parameter: (\"fqdn\")");
if (engine_set_hostname(engine, lua_tostring(L, 1)) != 0) {
lua_pushstring(L, "setting hostname failed");
lua_error(L);
}
if (engine_set_hostname(engine, lua_tostring(L, 1)) != 0)
lua_error_p(L, "setting hostname failed");
lua_pushstring(L, engine_get_hostname(engine));
lua_pushstring(L, engine_get_hostname(engine));
return 1;
}
......@@ -288,15 +276,11 @@ static int l_moduledir(lua_State *L)
lua_pushstring(L, engine_get_moduledir(engine));
return 1;
}
if ((lua_gettop(L) != 1) || !lua_isstring(L, 1)) {
lua_pushstring(L, "moduledir takes at most one parameter: (\"directory\")");
lua_error(L);
}
if ((lua_gettop(L) != 1) || !lua_isstring(L, 1))
lua_error_p(L, "moduledir takes at most one parameter: (\"directory\")");
if (engine_set_moduledir(engine, lua_tostring(L, 1)) != 0) {
lua_pushstring(L, "setting moduledir failed");
lua_error(L);
}
if (engine_set_moduledir(engine, lua_tostring(L, 1)) != 0)
lua_error_p(L, "setting moduledir failed");
lua_pushstring(L, engine_get_moduledir(engine));
return 1;
......@@ -314,8 +298,7 @@ static int l_hint_root_file(lua_State *L)
if (!file) {
file = ROOTHINTS;
}
lua_push_printf(L, "error when opening '%s': %s", file, err);
lua_error(L);
lua_error_p(L, "error when opening '%s': %s", file, err);
} else {
lua_pushboolean(L, true);
return 1;
......@@ -454,18 +437,14 @@ static int l_tojson(lua_State *L)
static int l_fromjson(lua_State *L)
{
if (lua_gettop(L) != 1 || !lua_isstring(L, 1)) {
lua_pushliteral(L, "a JSON string is required");
lua_error(L);
}
if (lua_gettop(L) != 1 || !lua_isstring(L, 1))
lua_error_p(L, "a JSON string is required");
const char *json_str = lua_tostring(L, 1);
JsonNode *root_node = json_decode(json_str);
if (!root_node) {
lua_pushliteral(L, "invalid JSON string");
lua_error(L);
}
if (!root_node)
lua_error_p(L, "invalid JSON string");
l_unpack_json(L, root_node);
json_delete(root_node);
......@@ -478,10 +457,8 @@ static int l_fromjson(lua_State *L)
static int l_map(lua_State *L)
{
if (lua_gettop(L) != 1 || !lua_isstring(L, 1)) {
lua_pushliteral(L, "map('string with a lua expression')");
lua_error(L);
}
if (lua_gettop(L) != 1 || !lua_isstring(L, 1))
lua_error_p(L, "map('string with a lua expression')");
struct engine *engine = engine_luaget(L);
const char *cmd = lua_tostring(L, 1);
......@@ -534,10 +511,8 @@ static int l_trampoline(lua_State *L)
struct kr_module *module = lua_touserdata(L, lua_upvalueindex(1));
void* callback = lua_touserdata(L, lua_upvalueindex(2));
struct engine *engine = engine_luaget(L);
if (!module) {
lua_pushstring(L, "module closure missing upvalue");
lua_error(L);
}
if (!module)
lua_error_p(L, "module closure missing upvalue");
/* Now we only have property callback or config,
* if we expand the callables, we might need a callback_type.
......
......@@ -23,6 +23,7 @@
#include <string.h>
#include <unistd.h>
#include <lua.h>
#include <uv.h>
#ifdef HAS_SYSTEMD
#include <systemd/sd-daemon.h>
......
......@@ -25,7 +25,6 @@
#include <gnutls/gnutls.h>
#include <gnutls/crypto.h>
#include <lua.h>
#include <libknot/libknot.h>
#include <libknot/packet/pkt.h>
......@@ -412,17 +411,6 @@ static inline uint16_t kr_rrset_type_maysig(const knot_rrset_t *rr)
return type;
}
/** Printf onto the lua stack, avoiding additional copy (thin wrapper). */
KR_PRINTF(2)
static inline const char *lua_push_printf(lua_State *L, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
const char *ret = lua_pushvfstring(L, fmt, args);
va_end(args);
return ret;
}
/** @internal Return string representation of addr.
* @note return pointer to static string
*/
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment