#include <grub/env.h>
#include <grub/parser.h>
#include <grub/command.h>
+#include <grub/normal.h>
+#include <grub/file.h>
+#include <grub/device.h>
+
+static int
+save_errno (lua_State *state)
+{
+ int saved_errno;
+
+ saved_errno = grub_errno;
+ grub_errno = 0;
+
+ lua_pushinteger (state, saved_errno);
+ lua_setfield (state, LUA_GLOBALSINDEX, "grub_errno");
+
+ if (saved_errno)
+ lua_pushstring (state, grub_errmsg);
+ else
+ lua_pushnil (state);
+
+ lua_setfield (state, LUA_GLOBALSINDEX, "grub_errmsg");
+
+ return saved_errno;
+}
+
+static int
+push_result (lua_State *state)
+{
+ lua_pushinteger (state, save_errno (state));
+ return 1;
+}
static int
grub_lua_run (lua_State *state)
{
int n;
char **args;
- grub_err_t result;
-
- if (! lua_gettop(state))
- return 0;
+ const char *s;
- if ((! grub_parser_split_cmdline (lua_tostring (state, 1), 0, &n, &args))
+ s = luaL_checkstring (state, 1);
+ if ((! grub_parser_split_cmdline (s, 0, &n, &args))
&& (n >= 0))
{
grub_command_t cmd;
grub_free (args);
}
- result = grub_errno;
- grub_errno = 0;
-
- lua_pushinteger(state, result);
-
- if (result)
- lua_pushstring (state, grub_errmsg);
-
- return (result) ? 2 : 1;
+ return push_result (state);
}
static int
{
int n, i;
- n = lua_gettop(state);
+ n = lua_gettop (state);
for (i = 1; i <= n; i++)
{
const char *name, *value;
- name = lua_tostring (state, i);
+ name = luaL_checkstring (state, i);
value = grub_env_get (name);
if (value)
lua_pushstring (state, value);
{
const char *name, *value;
- if (lua_gettop(state) != 2)
- return 0;
-
- name = lua_tostring (state, 1);
- value = lua_tostring (state, 2);
+ name = luaL_checkstring (state, 1);
+ value = luaL_checkstring (state, 2);
if (name[0])
grub_env_set (name, value);
return 0;
}
+static int
+grub_lua_enum_device (lua_State *state)
+{
+ auto int enum_device (const char *name);
+ int enum_device (const char *name)
+ {
+ 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);
+ }
+ }
+
+ lua_call (state, 3, 1);
+ result = lua_tointeger (state, -1);
+ lua_pop (state, 1);
+ }
+ else
+ grub_errno = 0;
+ grub_device_close (dev);
+ }
+ else
+ grub_errno = 0;
+
+ return result;
+ }
+
+ luaL_checktype (state, 1, LUA_TFUNCTION);
+ grub_device_iterate (enum_device);
+ return push_result (state);
+}
+
+static int
+grub_lua_enum_file (lua_State *state)
+{
+ char *device_name;
+ const char *arg;
+ grub_device_t dev;
+
+ auto int enum_file (const char *name, const struct grub_dirhook_info *info);
+ int enum_file (const char *name, const struct grub_dirhook_info *info)
+ {
+ int result;
+
+ 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;
+ }
+
+ 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);
+ }
+
+ grub_device_close (dev);
+ }
+
+ grub_free (device_name);
+
+ return push_result (state);
+}
+
+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[sizeof (char *) * n];
+ char *p;
+ int i;
+
+ 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, p);
+ }
+ 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},
+ {"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}
};
--- /dev/null
+#!lua
+--
+-- 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/>.
+--
+
+function enum_device (device, fs, uuid)
+ local root
+ local title
+ local source
+ local kernels = {}
+ local kernel_num = 0
+
+ local function enum_file (name)
+ local version
+
+ version = string.match (name, "vmlinuz%-(.*)")
+ if (version ~= nil) then
+ table.insert (kernels, version)
+ kernel_num = kernel_num + 1
+ end
+ end
+
+ local function sort_kernel (first, second)
+ local a1, a2, a3, a4, b1, b2, b3, b4
+
+ a1, a2, a3, a4 = string.match (first, "(%d+)%.?(%d*).?(%d*)%-?(%d*)")
+ b1, b2, b3, b4 = string.match (second, "(%d+)%.?(%d*).?(%d*)%-?(%d*)")
+ return (a1 > b1) or (a2 > b2) or (a3 > b3) or (a4 < b4);
+ end
+
+ root = "(" .. device .. ")/"
+ source = "root (" .. device .. ")\nchainloader +1"
+ title = nil
+ if (grub.file_exist (root .. "bootmgr") and
+ grub.file_exist (root .. "boot/bcd")) then
+ title = "Windows Vista bootmgr"
+ elseif (grub.file_exist (root .. "ntldr") and
+ grub.file_exist (root .. "ntdetect.com") and
+ grub.file_exist (root .. "boot.ini")) then
+ title = "Windows NT/2000/XP loader"
+ elseif (grub.file_exist (root .. "windows/win.com")) then
+ title = "Windows 98/ME"
+ elseif (grub.file_exist (root .. "io.sys") and
+ grub.file_exist (root .. "command.com")) then
+ title = "MS-DOS"
+ elseif (grub.file_exist (root .. "kernel.sys")) then
+ title = "FreeDOS"
+ elseif (grub.file_exist (root .. "boot/loader") and
+ grub.file_exist (root .. "boot/devices.hints")) then
+ source = "root (" .. device .. ")\nfreebsd /boot/loader" ..
+ "\nfreebsd_loadenv /boot/device.hints"
+ title = "FreeBSD"
+ else
+ grub.enum_file (enum_file, root .. "boot")
+ if kernel_num ~= 0 then
+ table.sort (kernels, sort_kernel)
+ for i = 1, kernel_num do
+ local initrd
+
+ title = "Linux " .. kernels[i]
+ source = "root (" .. device ..
+ ")\nlinux /boot/vmlinuz-" .. kernels[i] ..
+ " root=UUID=" .. uuid .. " ro"
+
+ if grub.file_exist (root .. "boot/initrd-" ..
+ kernels[i] .. ".img") then
+ initrd = "\ninitrd /boot/initrd-" .. kernels[i] .. ".img"
+ elseif grub.file_exist (root .. "boot/initrd.img-" .. kernels[i]) then
+ initrd = "\ninitrd /boot/initrd.img-" .. kernels[i]
+ elseif grub.file_exist (root .. "boot/initrd-" .. kernels[i]) then
+ initrd = "\ninitrd /boot/initrd-" .. kernels[i]
+ else
+ initrd = ""
+ end
+
+ grub.add_menu (source .. initrd, title)
+ grub.add_menu (source .. " single" .. initrd,
+ title .. " (single-user mode)")
+ end
+ return 0
+ end
+ end
+
+ if title == nil then
+ local partition = string.match (device, ".*,(%d+)")
+
+ if (partition ~= nil) and (tonumber (partition) > 4) then
+ return 0
+ end
+
+ title = "Other OS"
+ end
+
+ grub.add_menu (source, title)
+ return 0
+end
+
+grub.enum_device (enum_device)