summaryrefslogtreecommitdiffstats
path: root/debian/grub-extras/lua/grub_lib.c
diff options
context:
space:
mode:
Diffstat (limited to 'debian/grub-extras/lua/grub_lib.c')
-rw-r--r--debian/grub-extras/lua/grub_lib.c537
1 files changed, 537 insertions, 0 deletions
diff --git a/debian/grub-extras/lua/grub_lib.c b/debian/grub-extras/lua/grub_lib.c
new file mode 100644
index 0000000..3d25d02
--- /dev/null
+++ b/debian/grub-extras/lua/grub_lib.c
@@ -0,0 +1,537 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2009 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "lua.h"
+#include "lauxlib.h"
+#include "lualib.h"
+#include "grub_lib.h"
+
+#include <grub/env.h>
+#include <grub/parser.h>
+#include <grub/command.h>
+#include <grub/normal.h>
+#include <grub/file.h>
+#include <grub/device.h>
+
+#ifdef ENABLE_LUA_PCI
+#include <grub/pci.h>
+#endif
+
+/* Updates the globals grub_errno and grub_msg, leaving their values on the
+ top of the stack, and clears grub_errno. When grub_errno is zero, grub_msg
+ is not left on the stack. The value returned is the number of values left on
+ the stack. */
+static int
+push_result (lua_State *state)
+{
+ int saved_errno;
+ int num_results;
+
+ saved_errno = grub_errno;
+ grub_errno = 0;
+
+ /* Push once for setfield, and again to leave on the stack */
+ lua_pushinteger (state, saved_errno);
+ lua_pushinteger (state, saved_errno);
+ lua_setfield (state, LUA_GLOBALSINDEX, "grub_errno");
+
+ if (saved_errno)
+ {
+ /* Push once for setfield, and again to leave on the stack */
+ lua_pushstring (state, grub_errmsg);
+ lua_pushstring (state, grub_errmsg);
+ num_results = 2;
+ }
+ else
+ {
+ lua_pushnil (state);
+ num_results = 1;
+ }
+
+ lua_setfield (state, LUA_GLOBALSINDEX, "grub_errmsg");
+
+ return num_results;
+}
+
+/* Updates the globals grub_errno and grub_msg ( without leaving them on the
+ stack ), clears grub_errno, and returns the value of grub_errno before it
+ was cleared. */
+static int
+save_errno (lua_State *state)
+{
+ int saved_errno;
+
+ saved_errno = grub_errno;
+ lua_pop(state, push_result(state));
+
+ return saved_errno;
+}
+
+static int
+grub_lua_run (lua_State *state)
+{
+ int n;
+ char **args;
+ const char *s;
+
+ s = luaL_checkstring (state, 1);
+ if ((! grub_parser_split_cmdline (s, 0, 0, &n, &args))
+ && (n >= 0))
+ {
+ grub_command_t cmd;
+
+ cmd = grub_command_find (args[0]);
+ if (cmd)
+ (cmd->func) (cmd, n-1, &args[1]);
+ else
+ grub_error (GRUB_ERR_FILE_NOT_FOUND, "command not found");
+
+ grub_free (args[0]);
+ grub_free (args);
+ }
+
+ return push_result (state);
+}
+
+static int
+grub_lua_getenv (lua_State *state)
+{
+ int n, i;
+
+ n = lua_gettop (state);
+ for (i = 1; i <= n; i++)
+ {
+ const char *name, *value;
+
+ name = luaL_checkstring (state, i);
+ value = grub_env_get (name);
+ if (value)
+ lua_pushstring (state, value);
+ else
+ lua_pushnil (state);
+ }
+
+ return n;
+}
+
+static int
+grub_lua_setenv (lua_State *state)
+{
+ const char *name, *value;
+
+ name = luaL_checkstring (state, 1);
+ value = luaL_checkstring (state, 2);
+
+ if (name[0])
+ grub_env_set (name, value);
+
+ return 0;
+}
+
+/* Helper for grub_lua_enum_device. */
+static int
+grub_lua_enum_device_iter (const char *name, void *data)
+{
+ lua_State *state = data;
+ int result;
+ grub_device_t dev;
+
+ result = 0;
+ dev = grub_device_open (name);
+ if (dev)
+ {
+ grub_fs_t fs;
+
+ fs = grub_fs_probe (dev);
+ if (fs)
+ {
+ lua_pushvalue (state, 1);
+ lua_pushstring (state, name);
+ lua_pushstring (state, fs->name);
+ if (! fs->uuid)
+ lua_pushnil (state);
+ else
+ {
+ int err;
+ char *uuid;
+
+ err = fs->uuid (dev, &uuid);
+ if (err)
+ {
+ grub_errno = 0;
+ lua_pushnil (state);
+ }
+ else
+ {
+ lua_pushstring (state, uuid);
+ grub_free (uuid);
+ }
+ }
+
+ if (! fs->label)
+ lua_pushnil (state);
+ else
+ {
+ int err;
+ char *label = NULL;
+
+ err = fs->label (dev, &label);
+ if (err)
+ {
+ grub_errno = 0;
+ lua_pushnil (state);
+ }
+ else
+ {
+ if (label == NULL)
+ {
+ lua_pushnil (state);
+ }
+ else
+ {
+ lua_pushstring (state, label);
+ }
+ grub_free (label);
+ }
+ }
+
+ lua_call (state, 4, 1);
+ result = lua_tointeger (state, -1);
+ lua_pop (state, 1);
+ }
+ else
+ grub_errno = 0;
+ grub_device_close (dev);
+ }
+ else
+ grub_errno = 0;
+
+ return result;
+}
+
+static int
+grub_lua_enum_device (lua_State *state)
+{
+ luaL_checktype (state, 1, LUA_TFUNCTION);
+ grub_device_iterate (grub_lua_enum_device_iter, state);
+ return push_result (state);
+}
+
+static int
+enum_file (const char *name, const struct grub_dirhook_info *info,
+ void *data)
+{
+ int result;
+ lua_State *state = data;
+
+ lua_pushvalue (state, 1);
+ lua_pushstring (state, name);
+ lua_pushinteger (state, info->dir != 0);
+ lua_call (state, 2, 1);
+ result = lua_tointeger (state, -1);
+ lua_pop (state, 1);
+
+ return result;
+}
+
+static int
+grub_lua_enum_file (lua_State *state)
+{
+ char *device_name;
+ const char *arg;
+ grub_device_t dev;
+
+ luaL_checktype (state, 1, LUA_TFUNCTION);
+ arg = luaL_checkstring (state, 2);
+ device_name = grub_file_get_device_name (arg);
+ dev = grub_device_open (device_name);
+ if (dev)
+ {
+ grub_fs_t fs;
+ const char *path;
+
+ fs = grub_fs_probe (dev);
+ path = grub_strchr (arg, ')');
+ if (! path)
+ path = arg;
+ else
+ path++;
+
+ if (fs)
+ {
+ (fs->dir) (dev, path, enum_file, state);
+ }
+
+ grub_device_close (dev);
+ }
+
+ grub_free (device_name);
+
+ return push_result (state);
+}
+
+#ifdef ENABLE_LUA_PCI
+/* Helper for grub_lua_enum_pci. */
+static int
+grub_lua_enum_pci_iter (grub_pci_device_t dev, grub_pci_id_t pciid, void *data)
+{
+ lua_State *state = data;
+ int result;
+ grub_pci_address_t addr;
+ grub_uint32_t class;
+
+ lua_pushvalue (state, 1);
+ lua_pushinteger (state, grub_pci_get_bus (dev));
+ lua_pushinteger (state, grub_pci_get_device (dev));
+ lua_pushinteger (state, grub_pci_get_function (dev));
+ lua_pushinteger (state, pciid);
+
+ addr = grub_pci_make_address (dev, GRUB_PCI_REG_CLASS);
+ class = grub_pci_read (addr);
+ lua_pushinteger (state, class);
+
+ lua_call (state, 5, 1);
+ result = lua_tointeger (state, -1);
+ lua_pop (state, 1);
+
+ return result;
+}
+
+static int
+grub_lua_enum_pci (lua_State *state)
+{
+ luaL_checktype (state, 1, LUA_TFUNCTION);
+ grub_pci_iterate (grub_lua_enum_pci_iter, state);
+ return push_result (state);
+}
+#endif
+
+static int
+grub_lua_file_open (lua_State *state)
+{
+ grub_file_t file;
+ const char *name;
+
+ name = luaL_checkstring (state, 1);
+ file = grub_file_open (name);
+ save_errno (state);
+
+ if (! file)
+ return 0;
+
+ lua_pushlightuserdata (state, file);
+ return 1;
+}
+
+static int
+grub_lua_file_close (lua_State *state)
+{
+ grub_file_t file;
+
+ luaL_checktype (state, 1, LUA_TLIGHTUSERDATA);
+ file = lua_touserdata (state, 1);
+ grub_file_close (file);
+
+ return push_result (state);
+}
+
+static int
+grub_lua_file_seek (lua_State *state)
+{
+ grub_file_t file;
+ grub_off_t offset;
+
+ luaL_checktype (state, 1, LUA_TLIGHTUSERDATA);
+ file = lua_touserdata (state, 1);
+ offset = luaL_checkinteger (state, 2);
+
+ offset = grub_file_seek (file, offset);
+ save_errno (state);
+
+ lua_pushinteger (state, offset);
+ return 1;
+}
+
+static int
+grub_lua_file_read (lua_State *state)
+{
+ grub_file_t file;
+ luaL_Buffer b;
+ int n;
+
+ luaL_checktype (state, 1, LUA_TLIGHTUSERDATA);
+ file = lua_touserdata (state, 1);
+ n = luaL_checkinteger (state, 2);
+
+ luaL_buffinit (state, &b);
+ while (n)
+ {
+ char *p;
+ int nr;
+
+ nr = (n > LUAL_BUFFERSIZE) ? LUAL_BUFFERSIZE : n;
+ p = luaL_prepbuffer (&b);
+
+ nr = grub_file_read (file, p, nr);
+ if (nr <= 0)
+ break;
+
+ luaL_addsize (&b, nr);
+ n -= nr;
+ }
+
+ save_errno (state);
+ luaL_pushresult (&b);
+ return 1;
+}
+
+static int
+grub_lua_file_getline (lua_State *state)
+{
+ grub_file_t file;
+ char *line;
+
+ luaL_checktype (state, 1, LUA_TLIGHTUSERDATA);
+ file = lua_touserdata (state, 1);
+
+ line = grub_file_getline (file);
+ save_errno (state);
+
+ if (! line)
+ return 0;
+
+ lua_pushstring (state, line);
+ grub_free (line);
+ return 1;
+}
+
+static int
+grub_lua_file_getsize (lua_State *state)
+{
+ grub_file_t file;
+
+ luaL_checktype (state, 1, LUA_TLIGHTUSERDATA);
+ file = lua_touserdata (state, 1);
+
+ lua_pushinteger (state, file->size);
+ return 1;
+}
+
+static int
+grub_lua_file_getpos (lua_State *state)
+{
+ grub_file_t file;
+
+ luaL_checktype (state, 1, LUA_TLIGHTUSERDATA);
+ file = lua_touserdata (state, 1);
+
+ lua_pushinteger (state, file->offset);
+ return 1;
+}
+
+static int
+grub_lua_file_eof (lua_State *state)
+{
+ grub_file_t file;
+
+ luaL_checktype (state, 1, LUA_TLIGHTUSERDATA);
+ file = lua_touserdata (state, 1);
+
+ lua_pushboolean (state, file->offset >= file->size);
+ return 1;
+}
+
+static int
+grub_lua_file_exist (lua_State *state)
+{
+ grub_file_t file;
+ const char *name;
+ int result;
+
+ result = 0;
+ name = luaL_checkstring (state, 1);
+ file = grub_file_open (name);
+ if (file)
+ {
+ result++;
+ grub_file_close (file);
+ }
+ else
+ grub_errno = 0;
+
+ lua_pushboolean (state, result);
+ return 1;
+}
+
+static int
+grub_lua_add_menu (lua_State *state)
+{
+ int n;
+ const char *source;
+
+ source = luaL_checklstring (state, 1, 0);
+ n = lua_gettop (state) - 1;
+ if (n > 0)
+ {
+ const char **args;
+ char *p;
+ int i;
+
+ args = grub_malloc (n * sizeof (args[0]));
+ if (!args)
+ return push_result (state);
+ for (i = 0; i < n; i++)
+ args[i] = luaL_checkstring (state, 2 + i);
+
+ p = grub_strdup (source);
+ if (! p)
+ return push_result (state);
+
+ grub_normal_add_menu_entry (n, args, NULL, NULL, NULL, NULL, NULL, p, 0);
+ }
+ else
+ {
+ lua_pushstring (state, "not enough parameter");
+ lua_error (state);
+ }
+
+ return push_result (state);
+}
+
+luaL_Reg grub_lua_lib[] =
+ {
+ {"run", grub_lua_run},
+ {"getenv", grub_lua_getenv},
+ {"setenv", grub_lua_setenv},
+ {"enum_device", grub_lua_enum_device},
+ {"enum_file", grub_lua_enum_file},
+#ifdef ENABLE_LUA_PCI
+ {"enum_pci", grub_lua_enum_pci},
+#endif
+ {"file_open", grub_lua_file_open},
+ {"file_close", grub_lua_file_close},
+ {"file_seek", grub_lua_file_seek},
+ {"file_read", grub_lua_file_read},
+ {"file_getline", grub_lua_file_getline},
+ {"file_getsize", grub_lua_file_getsize},
+ {"file_getpos", grub_lua_file_getpos},
+ {"file_eof", grub_lua_file_eof},
+ {"file_exist", grub_lua_file_exist},
+ {"add_menu", grub_lua_add_menu},
+ {0, 0}
+ };