3 Copyright (C) 2013 PilzAdam <pilzadam@minetest.net>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "lua_api/l_settings.h"
21 #include "lua_api/l_internal.h"
22 #include "cpp_api/s_security.h"
23 #include "threading/mutex_auto_lock.h"
24 #include "util/string.h" // FlagDesc
31 * 'secure.*' settings from being set
32 * some mapgen settings from being set
33 * (not security-criticial, just to avoid messing up user configs)
35 #define CHECK_SETTING_SECURITY(L, name) \
36 if (o->m_settings == g_settings) { \
37 if (checkSettingSecurity(L, name) == -1) \
41 static inline int checkSettingSecurity(lua_State* L, const std::string &name)
43 if (ScriptApiSecurity::isSecure(L) && name.compare(0, 7, "secure.") == 0)
44 throw LuaError("Attempt to set secure setting.");
46 bool is_mainmenu = false;
48 is_mainmenu = ModApiBase::getGuiEngine(L) != nullptr;
50 if (!is_mainmenu && (name == "mg_name" || name == "mg_flags")) {
51 errorstream << "Tried to set global setting " << name << ", ignoring. "
52 "minetest.set_mapgen_setting() should be used instead." << std::endl;
53 infostream << script_get_backtrace(L) << std::endl;
60 LuaSettings::LuaSettings(Settings *settings, const std::string &filename) :
66 LuaSettings::LuaSettings(const std::string &filename, bool write_allowed) :
68 m_is_own_settings(true),
69 m_write_allowed(write_allowed)
71 m_settings = new Settings();
72 m_settings->readConfigFile(filename.c_str());
75 LuaSettings::~LuaSettings()
77 if (m_is_own_settings)
82 void LuaSettings::create(lua_State *L, Settings *settings,
83 const std::string &filename)
85 LuaSettings *o = new LuaSettings(settings, filename);
86 *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
87 luaL_getmetatable(L, className);
88 lua_setmetatable(L, -2);
93 int LuaSettings::gc_object(lua_State* L)
95 LuaSettings* o = *(LuaSettings **)(lua_touserdata(L, 1));
101 // get(self, key) -> value
102 int LuaSettings::l_get(lua_State* L)
104 NO_MAP_LOCK_REQUIRED;
105 LuaSettings* o = checkobject(L, 1);
107 std::string key = std::string(luaL_checkstring(L, 2));
108 if (o->m_settings->exists(key)) {
109 std::string value = o->m_settings->get(key);
110 lua_pushstring(L, value.c_str());
118 // get_bool(self, key) -> boolean
119 int LuaSettings::l_get_bool(lua_State* L)
121 NO_MAP_LOCK_REQUIRED;
122 LuaSettings* o = checkobject(L, 1);
124 std::string key = std::string(luaL_checkstring(L, 2));
125 if (o->m_settings->exists(key)) {
126 bool value = o->m_settings->getBool(key);
127 lua_pushboolean(L, value);
129 // Push default value
130 if (lua_isboolean(L, 3))
131 lua_pushboolean(L, readParam<bool>(L, 3));
139 // get_np_group(self, key) -> value
140 int LuaSettings::l_get_np_group(lua_State *L)
142 NO_MAP_LOCK_REQUIRED;
143 LuaSettings *o = checkobject(L, 1);
145 std::string key = std::string(luaL_checkstring(L, 2));
146 if (o->m_settings->exists(key)) {
148 o->m_settings->getNoiseParams(key, np);
149 push_noiseparams(L, &np);
157 // get_flags(self, key) -> table or nil
158 int LuaSettings::l_get_flags(lua_State *L)
160 NO_MAP_LOCK_REQUIRED;
161 LuaSettings *o = checkobject(L, 1);
162 std::string key = std::string(luaL_checkstring(L, 2));
165 auto flagdesc = o->m_settings->getFlagDescFallback(key);
166 if (o->m_settings->getFlagStrNoEx(key, flags, flagdesc)) {
168 int table = lua_gettop(L);
169 for (size_t i = 0; flagdesc[i].name; ++i) {
170 lua_pushboolean(L, flags & flagdesc[i].flag);
171 lua_setfield(L, table, flagdesc[i].name);
173 lua_pushvalue(L, table);
181 // set(self, key, value)
182 int LuaSettings::l_set(lua_State* L)
184 NO_MAP_LOCK_REQUIRED;
185 LuaSettings* o = checkobject(L, 1);
187 std::string key = std::string(luaL_checkstring(L, 2));
188 const char* value = luaL_checkstring(L, 3);
190 CHECK_SETTING_SECURITY(L, key);
192 if (!o->m_settings->set(key, value))
193 throw LuaError("Invalid sequence found in setting parameters");
198 // set_bool(self, key, value)
199 int LuaSettings::l_set_bool(lua_State* L)
201 NO_MAP_LOCK_REQUIRED;
202 LuaSettings* o = checkobject(L, 1);
204 std::string key = std::string(luaL_checkstring(L, 2));
205 bool value = readParam<bool>(L, 3);
207 CHECK_SETTING_SECURITY(L, key);
209 o->m_settings->setBool(key, value);
214 // set_np_group(self, key, value)
215 int LuaSettings::l_set_np_group(lua_State *L)
217 NO_MAP_LOCK_REQUIRED;
218 LuaSettings *o = checkobject(L, 1);
220 std::string key = std::string(luaL_checkstring(L, 2));
222 read_noiseparams(L, 3, &value);
224 CHECK_SETTING_SECURITY(L, key);
226 o->m_settings->setNoiseParams(key, value);
231 // remove(self, key) -> success
232 int LuaSettings::l_remove(lua_State* L)
234 NO_MAP_LOCK_REQUIRED;
235 LuaSettings* o = checkobject(L, 1);
237 std::string key = std::string(luaL_checkstring(L, 2));
239 CHECK_SETTING_SECURITY(L, key);
241 bool success = o->m_settings->remove(key);
242 lua_pushboolean(L, success);
247 // get_names(self) -> {key1, ...}
248 int LuaSettings::l_get_names(lua_State* L)
250 NO_MAP_LOCK_REQUIRED;
251 LuaSettings* o = checkobject(L, 1);
253 std::vector<std::string> keys = o->m_settings->getNames();
256 for (unsigned int i=0; i < keys.size(); i++)
258 lua_pushstring(L, keys[i].c_str());
259 lua_rawseti(L, -2, i + 1);
265 // write(self) -> success
266 int LuaSettings::l_write(lua_State* L)
268 NO_MAP_LOCK_REQUIRED;
269 LuaSettings* o = checkobject(L, 1);
271 if (!o->m_write_allowed) {
272 throw LuaError("Settings: writing " + o->m_filename +
273 " not allowed with mod security on.");
276 bool success = o->m_settings->updateConfigFile(o->m_filename.c_str());
277 lua_pushboolean(L, success);
282 static void push_settings_table(lua_State *L, const Settings *settings)
284 std::vector<std::string> keys = settings->getNames();
286 for (const std::string &key : keys) {
288 Settings *group = nullptr;
290 if (settings->getNoEx(key, value)) {
291 lua_pushstring(L, value.c_str());
292 } else if (settings->getGroupNoEx(key, group)) {
293 // Recursively push tables
294 push_settings_table(L, group);
296 // Impossible case (multithreading) due to MutexAutoLock
300 lua_setfield(L, -2, key.c_str());
304 // to_table(self) -> {[key1]=value1,...}
305 int LuaSettings::l_to_table(lua_State* L)
307 NO_MAP_LOCK_REQUIRED;
308 LuaSettings* o = checkobject(L, 1);
310 MutexAutoLock(o->m_settings->m_mutex);
311 push_settings_table(L, o->m_settings);
316 void LuaSettings::Register(lua_State* L)
319 int methodtable = lua_gettop(L);
320 luaL_newmetatable(L, className);
321 int metatable = lua_gettop(L);
323 lua_pushliteral(L, "__metatable");
324 lua_pushvalue(L, methodtable);
325 lua_settable(L, metatable); // hide metatable from Lua getmetatable()
327 lua_pushliteral(L, "__index");
328 lua_pushvalue(L, methodtable);
329 lua_settable(L, metatable);
331 lua_pushliteral(L, "__gc");
332 lua_pushcfunction(L, gc_object);
333 lua_settable(L, metatable);
335 lua_pop(L, 1); // drop metatable
337 luaL_register(L, nullptr, methods); // fill methodtable
338 lua_pop(L, 1); // drop methodtable
340 // Can be created from Lua (Settings(filename))
341 lua_register(L, className, create_object);
344 // LuaSettings(filename)
345 // Creates a LuaSettings and leaves it on top of the stack
346 int LuaSettings::create_object(lua_State* L)
348 NO_MAP_LOCK_REQUIRED;
349 bool write_allowed = true;
350 const char* filename = luaL_checkstring(L, 1);
351 CHECK_SECURE_PATH_POSSIBLE_WRITE(L, filename, &write_allowed);
352 LuaSettings* o = new LuaSettings(filename, write_allowed);
353 *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
354 luaL_getmetatable(L, className);
355 lua_setmetatable(L, -2);
359 LuaSettings* LuaSettings::checkobject(lua_State* L, int narg)
361 NO_MAP_LOCK_REQUIRED;
362 luaL_checktype(L, narg, LUA_TUSERDATA);
363 void *ud = luaL_checkudata(L, narg, className);
365 luaL_typerror(L, narg, className);
366 return *(LuaSettings**) ud; // unbox pointer
369 const char LuaSettings::className[] = "Settings";
370 const luaL_Reg LuaSettings::methods[] = {
371 luamethod(LuaSettings, get),
372 luamethod(LuaSettings, get_bool),
373 luamethod(LuaSettings, get_np_group),
374 luamethod(LuaSettings, get_flags),
375 luamethod(LuaSettings, set),
376 luamethod(LuaSettings, set_bool),
377 luamethod(LuaSettings, set_np_group),
378 luamethod(LuaSettings, remove),
379 luamethod(LuaSettings, get_names),
380 luamethod(LuaSettings, write),
381 luamethod(LuaSettings, to_table),