Hi,

Update for this patch:

1, enum_device now pass fs and uuid as well
2, enum_file change parameter order, now the callback function is the
first, path is the second
3, add parameter checking for library function
4, add three function

file_eof - test if eof is encounter for a file
file_exist - test if a file exists
add_menu - add menu item

I also add a script osdetect.lua which can detect Windows
2K/NT/XP/Vista and linux at runtime, to use it, add this in grub.cfg:

source osdetect.lua

-- 
Bean
diff --git a/conf/common.rmk b/conf/common.rmk
index fbca2e4..dc78df9 100644
--- a/conf/common.rmk
+++ b/conf/common.rmk
@@ -519,15 +519,14 @@ lua_mod_SOURCES = script/lua/lapi.c script/lua/lcode.c script/lua/ldebug.c \
 	script/lua/lstate.c script/lua/lstring.c script/lua/ltable.c \
 	script/lua/ltm.c script/lua/lundump.c script/lua/lvm.c \
 	script/lua/lzio.c script/lua/lauxlib.c script/lua/lbaselib.c \
-	script/lua/linit.c script/lua/ltablib.c \
+	script/lua/linit.c script/lua/ltablib.c script/lua/lstrlib.c \
 	script/lua/grub_main.c script/lua/grub_lib.c
 lua_mod_CFLAGS = $(COMMON_CFLAGS)
 lua_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
 # Extra libraries for lua
 # script/lua/lmathlib.c script/lua/loslib.c script/lua/liolib.c
-# script/lua/lstrlib.c script/lua/ldblib.c script/lua/ltablib.c
-# script/lua/loadlib.c
+# script/lua/ldblib.c script/lua/loadlib.c
 
 # Common Video Subsystem specific modules.
 pkglib_MODULES += video.mod videotest.mod bitmap.mod tga.mod jpeg.mod	\
diff --git a/script/lua/grub_lib.c b/script/lua/grub_lib.c
index 0295f0d..8561dd0 100644
--- a/script/lua/grub_lib.c
+++ b/script/lua/grub_lib.c
@@ -24,18 +24,47 @@
 #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;
@@ -50,15 +79,7 @@ grub_lua_run (lua_State *state)
       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
@@ -66,12 +87,12 @@ grub_lua_getenv (lua_State *state)
 {
   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);
@@ -87,11 +108,8 @@ grub_lua_setenv (lua_State *state)
 {
   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);
@@ -99,10 +117,322 @@ grub_lua_setenv (lua_State *state)
   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);
+	  }
+	grub_device_close (dev);
+      }
+    else
+      save_errno (state);
+
+    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;
+
+  name = luaL_checkstring (state, 1);
+  file = grub_file_open (name);
+  if (file)
+    {
+      result = 1;
+      grub_file_close (file);
+    }
+  else
+    {
+      result = 0;
+      grub_errno = 0;
+    }
+
+  lua_pushboolean (state, result);
+  return 1;
+}
+
+static int
+grub_lua_add_menu (lua_State *state)
+{   
+  int len, n;
+  const char *source;
+
+  source = luaL_checklstring (state, 1, &len);
+  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}
   };
diff --git a/script/lua/grub_lua.h b/script/lua/grub_lua.h
index a181b52..d5181f1 100644
--- a/script/lua/grub_lua.h
+++ b/script/lua/grub_lua.h
@@ -77,26 +77,28 @@ iscntrl (int c)
 }
 
 static inline int
-strcspn(const char *s1, const char *s2)
+isupper (int c)
 {
-  int size = 0;
-
-  while (*s1)
-    {
-      const char *p = s2;
+  return ((c >= 'A') && (c <= 'Z'));
+}
 
-      while (*p)
-	{
-	  if (*s1 == *p)
-	    return size;
-	  p++;
-	}
+static inline int
+islower (int c)
+{
+  return ((c >= 'a') && (c <= 'z'));
+}
 
-      s1++;
-      size++;
-    }
+static inline int
+ispunct (int c)
+{
+  return ((! isspace (c)) && (! isalnum (c)));
+}
 
-  return size;
+static inline int
+isxdigit (int c)
+{
+  return (isdigit (c) || ((c >= 'a') && (c <= 'f')) ||
+	  ((c >= 'A') && (c <= 'F')));
 }
 
 static inline int
@@ -105,4 +107,8 @@ abs (int c)
   return (c >= 0) ? : -c;
 }
 
+int strcspn (const char *s1, const char *s2);
+char *strpbrk (const char *s1, const char *s2);
+void *memchr (const void *s, int c, size_t n);
+
 #endif
diff --git a/script/lua/grub_main.c b/script/lua/grub_main.c
index 03f890a..b39141f 100644
--- a/script/lua/grub_main.c
+++ b/script/lua/grub_main.c
@@ -24,6 +24,61 @@
 #include <grub/dl.h>
 #include <grub/parser.h>
 
+static const char *
+scan_str (const char *s1, const char *s2)
+{
+  while (*s1)
+    {
+      const char *p = s2;
+
+      while (*p)
+	{
+	  if (*s1 == *p)
+	    return s1;
+	  p++;
+	}
+
+      s1++;
+    }
+
+  return s1;
+}
+
+int
+strcspn (const char *s1, const char *s2)
+{
+  const char *r;
+
+  r = scan_str (s1, s2);
+  return r - s1;
+}
+
+char *
+strpbrk (const char *s1, const char *s2)
+{
+  const char *r;
+
+  r = scan_str (s1, s2);
+  return (*r) ? (char *) r : 0;
+}
+
+void *
+memchr (const void *s, int c, size_t n)
+{
+  const unsigned char *p = s;
+
+  while (n)
+    {
+      if (*p == c)
+	return (void *) p;
+
+      n--;
+      p++;
+    }
+
+  return 0;
+}
+
 static lua_State *state;
 
 /* Call `grub_error' to report a Lua error.  The error message string must be
diff --git a/script/lua/linit.c b/script/lua/linit.c
index d034a2f..f920a0b 100644
--- a/script/lua/linit.c
+++ b/script/lua/linit.c
@@ -20,7 +20,7 @@ static const luaL_Reg lualibs[] = {
   {LUA_TABLIBNAME, luaopen_table},
 //  {LUA_IOLIBNAME, luaopen_io},
 //  {LUA_OSLIBNAME, luaopen_os},
-//  {LUA_STRLIBNAME, luaopen_string},
+  {LUA_STRLIBNAME, luaopen_string},
 //  {LUA_MATHLIBNAME, luaopen_math},
 //  {LUA_DBLIBNAME, luaopen_debug},
   {NULL, NULL}
diff --git a/util/osdetect.lua b/util/osdetect.lua
new file mode 100644
index 0000000..ff6b613
--- /dev/null
+++ b/util/osdetect.lua
@@ -0,0 +1,84 @@
+#!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 = "Other OS"
+  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"
+  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.img-" .. kernels[i]) then
+	  initrd = "\ninird /boot/initrd.img-" .. 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
+
+  grub.add_menu (source, title)
+  return 0
+end
+
+grub.enum_device (enum_device)
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to