[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
automagic module loading - normal commands
From: |
Tomas Ebenlendr |
Subject: |
automagic module loading - normal commands |
Date: |
Wed, 22 Sep 2004 23:04:50 +0200 |
User-agent: |
Mutt/1.5.6i |
I want to do better my autocmd patch. Now it reads file autocmd.lst in
root directory. (this can be changed via variable 'autocmd'). I have
following questions:
- Do we want to have special file like autocmd.lst? Or
to 'probe' all modules: read a module, and read from some special
elf section supported commands? Or both? (Or other way to decide
which module to load?)
- Do we want to have automatic module loading hardcoded? Or should
there be a generic interface, so some other module will drive
automatic module loading?
- If there will be autocmd.lst:
- is autocmd.lst good name?
- Shoud it be generated from *.rmk files?
Or from *.c (by preprocessing and greping, such as symbols
are from *.h)
Or else way?
I can implement any solution. Just feel free and say your opinion about
this. (And other things that you like/dislike on the patch.)
Here is current version: (warning patch may be not aplicable, see date of
files, to know version of grub).
diff -rupN -x CVS grub2_x/autocmd.lst grub2_debug/autocmd.lst
--- grub2_x/autocmd.lst 1970-01-01 01:00:00.000000000 +0100
+++ grub2_debug/autocmd.lst 2004-06-29 01:52:26.000000000 +0200
@@ -0,0 +1,2 @@
+boot boot
+chainloader chain
diff -rupN -x CVS grub2_x/include/grub/normal.h
grub2_debug/include/grub/normal.h
--- grub2_x/include/grub/normal.h 2004-06-05 00:20:17.000000000 +0200
+++ grub2_debug/include/grub/normal.h 2004-06-29 03:07:59.000000000 +0200
@@ -1,7 +1,7 @@
/* normal.h - prototypes for the normal mode */
/*
* GRUB -- GRand Unified Bootloader
- * Copyright (C) 2002,2003 Free Software Foundation, Inc.
+ * Copyright (C) 2002,2003,2004 Free Software Foundation, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -136,6 +136,7 @@ grub_err_t grub_set_history (int newsize
int grub_iterate_commands (int (*iterate) (grub_command_t));
int grub_command_execute (char *cmdline);
void grub_command_init (void);
+void grub_command_done (void);
void grub_normal_init_page (void);
int grub_arg_parse (grub_command_t parser, int argc, char **argv,
struct grub_arg_list *usr, char ***args, int *argnum);
diff -rupN -x CVS grub2_x/normal/command.c grub2_debug/normal/command.c
--- grub2_x/normal/command.c 2004-06-05 00:20:18.000000000 +0200
+++ grub2_debug/normal/command.c 2004-07-01 16:44:07.000000000 +0200
@@ -1,6 +1,6 @@
/*
* GRUB -- GRand Unified Bootloader
- * Copyright (C) 2003 Free Software Foundation, Inc.
+ * Copyright (C) 2003,2004 Free Software Foundation, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -24,9 +24,21 @@
#include <grub/term.h>
#include <grub/env.h>
#include <grub/dl.h>
+#include <grub/file.h>
static grub_command_t grub_command_list;
+typedef struct
+{
+ char * cmdname;
+ char * modulename;
+} grub_autocmd_list_t;
+
+static grub_autocmd_list_t * grub_autocmd_list = 0;
+/* Value less than zero disables warnings at start. */
+static int grub_autocmd_count = -1;
+static char * grub_autocmd_buffer = 0;
+
void
grub_register_command (const char *name,
grub_err_t (*func) (struct grub_arg_list *state,
@@ -82,6 +94,8 @@ grub_command_find (char *cmdline)
{
char *first_space;
grub_command_t cmd;
+ grub_dl_t mod;
+ int i;
first_space = grub_strchr (cmdline, ' ');
if (first_space)
@@ -91,8 +105,40 @@ grub_command_find (char *cmdline)
if (grub_strcmp (cmdline, cmd->name) == 0)
break;
+ /* Automatic module loading. */
if (! cmd)
- grub_error (GRUB_ERR_UNKNOWN_COMMAND, "unknown command `%s'", cmdline);
+ {
+ for (i = 0; i < grub_autocmd_count; i++)
+ {
+ if (grub_strcmp (cmdline, grub_autocmd_list[i].cmdname) == 0)
+ {
+ mod = grub_dl_load (grub_autocmd_list[i].modulename);
+
+ if (mod)
+ {
+ grub_dl_ref (mod);
+ for (cmd = grub_command_list; cmd; cmd = cmd->next)
+ if (grub_strcmp (cmdline, cmd->name) == 0)
+ break;
+
+ /* Unload module if command was not there. */
+ if (!cmd)
+ {
+ if (! grub_dl_unref (mod))
+ grub_dl_unload (mod);
+
+ grub_error(GRUB_ERR_UNKNOWN_COMMAND,
+ "command `%s' not found in module `%s'",
+ cmdline, grub_autocmd_list[i].modulename);
+ }
+ }
+
+ break;
+ }
+ }
+ if (i >= grub_autocmd_count)
+ grub_error (GRUB_ERR_UNKNOWN_COMMAND, "unknown command `%s'", cmdline);
+ }
if (first_space)
*first_space = ' ';
@@ -171,6 +217,185 @@ grub_command_execute (char *cmdline)
return ret;
}
+
+/* Reads autocmd.lst and sets up list of commands provided by modules. */
+static grub_err_t
+grub_autocmd_read (const char * name, int silent)
+{
+ grub_file_t file = 0;
+ grub_ssize_t size;
+ int state, i;
+ char *cmdname = 0, *modulename = 0, *pos, *end;
+
+ if ((name != 0) && (name[0] != 0))
+ {
+ file = grub_file_open (name);
+ if (! file)
+ {
+ if (! silent)
+ grub_error (grub_errno, "couldn't open file %s", name);
+
+ /* Not goto failed. Preserve old setting here. */
+ return grub_errno;
+ }
+ }
+
+ grub_free (grub_autocmd_buffer);
+ grub_autocmd_buffer = 0;
+ grub_free (grub_autocmd_list);
+ grub_autocmd_list = 0;
+ grub_autocmd_count = 0;
+
+ /* Disable autoloading. */
+ if ((name == 0) || (name[0] == 0))
+ return 0;
+
+ size = grub_file_size (file);
+ grub_autocmd_buffer = grub_malloc(size + 1);
+ if (! grub_autocmd_buffer)
+ goto failed;
+ if (grub_file_read (file, grub_autocmd_buffer, size) != (int) size)
+ goto failed;
+
+ /* Don't allow unfinished line. */
+ grub_autocmd_buffer[size] = '\n';
+ end = grub_autocmd_buffer + size + 1;
+
+ /* Count number of entries. */
+ /* Following state machine accepts lines with at least 2 words,
+ * the second word must not contain `/'. */
+ state = 0;
+ /* State machine for text parsing:
+ * state == 0 begining of line,
+ * state == 1 first word,
+ * state == 2 spaces after first word,
+ * state == 3 rest of the line.
+ * state == 5 error. \0 or / in module name. */
+ for (pos = grub_autocmd_buffer; pos < end; pos++)
+ switch (*pos)
+ {
+ case '\0':
+ /* Bad character in text file. */
+ state = 5;
+ break;
+
+ case '\n':
+
+ /* At least two words. */
+ if (state == 3)
+ grub_autocmd_count++;
+
+ state = 0;
+ break;
+
+ case ' ':
+ if (state == 1)
+ state = 2;
+ break;
+
+ case '/':
+ /* Bad module name. */
+ if (state == 3)
+ state = 5;
+
+ default:
+ /* Move to state 1 or 3. */
+ state |= 1;
+ }
+
+ grub_autocmd_list = grub_malloc(grub_autocmd_count
+ * sizeof(grub_autocmd_list_t));
+ if (! grub_autocmd_list) goto failed;
+
+ /* Fill in the list. */
+ /* The same state machine. It sets pointers to names of commands and
+ * modules. A name is a word separated by ` '. */
+ i=0; state = 0;
+ for (pos = grub_autocmd_buffer; pos < end; pos++)
+ switch (*pos)
+ {
+ case '\n':
+
+ /* At least two words. */
+ if (state == 3)
+ {
+ grub_autocmd_list[i].cmdname = cmdname;
+ grub_autocmd_list[i].modulename = modulename;
+ i++;
+ *pos = 0;
+ }
+
+ state = 0;
+ break;
+
+ case ' ':
+ /* Terminate the word. */
+ *pos = 0;
+ if (state == 1)
+ state = 2;
+ break;
+
+ case '/':
+ case '\0':
+ /* Bad module name. */
+ if (state == 3)
+ state = 5;
+
+ default:
+ switch (state)
+ {
+ case 0:
+ cmdname = pos;
+ state = 1;
+ break;
+ case 2:
+ modulename = pos;
+ state = 3;
+ break;
+ }
+ }
+
+ grub_file_close(file);
+ return 0;
+
+failed:
+ grub_file_close(file);
+ grub_free (grub_autocmd_buffer);
+ grub_autocmd_buffer = 0;
+ grub_free (grub_autocmd_list);
+ grub_autocmd_list = 0;
+ grub_autocmd_count = 0;
+
+ if (! silent) grub_error(grub_errno, "not enough memory");
+ return grub_errno;
+}
+
+/* `autocmd' variable write hook */
+static grub_err_t
+grub_autocmd_set (struct grub_env_var * env)
+{
+ char * p;
+ char * prefix = grub_env_get("prefix");
+
+ p = grub_strchr (env->value, '/');
+ if (! p)
+ {
+ p = grub_malloc (grub_strlen (prefix) + 1
+ + grub_strlen (env->value) + 1);
+ if (p)
+ {
+ grub_sprintf (p, "%s/%s", prefix, env->value);
+ grub_autocmd_read (p, grub_autocmd_count < 0);
+ grub_free (p);
+ }
+ return grub_errno;
+ }
+ else
+ return grub_autocmd_read(env->value, grub_autocmd_count < 0);
+}
+
+/* Basic normal mode commands. */
+
static grub_err_t
rescue_command (struct grub_arg_list *state __attribute__ ((unused)),
int argc __attribute__ ((unused)),
@@ -303,6 +528,8 @@ lsmod_command (struct grub_arg_list *sta
void
grub_command_init (void)
{
+ char * fname;
+
/* This is a special command, because this never be called actually. */
grub_register_command ("title", 0, GRUB_COMMAND_FLAG_TITLE, 0, 0, 0);
@@ -323,4 +550,24 @@ grub_command_init (void)
grub_register_command ("lsmod", lsmod_command, GRUB_COMMAND_FLAG_BOTH,
"lsmod", "Show loaded modules.", 0);
+
+ grub_register_variable_hook("autocmd", 0, grub_autocmd_set);
+
+ fname = grub_env_get("autocmd");
+ /* Provide default value for `autocmd'. */
+ if ((fname == 0) || (fname[0] == 0))
+ {
+ grub_env_set ("autocmd", "autocmd.lst");
+ if (grub_autocmd_count <= 0)
+ grub_env_set ("autocmd", "");
+ }
+ else
+ grub_env_set("autocmd",fname);
+}
+
+void
+grub_command_done (void)
+{
+ grub_register_variable_hook("autocmd", 0, 0);
+ grub_autocmd_read(0, 0);
}
diff -rupN -x CVS grub2_x/normal/main.c grub2_debug/normal/main.c
--- grub2_x/normal/main.c 2004-06-05 00:20:18.000000000 +0200
+++ grub2_debug/normal/main.c 2004-07-01 16:45:38.000000000 +0200
@@ -1,7 +1,7 @@
/* main.c - the normal mode main routine */
/*
* GRUB -- GRand Unified Bootloader
- * Copyright (C) 2000,2001,2002,2003 Free Software Foundation, Inc.
+ * Copyright (C) 2000,2001,2002,2003,2004 Free Software Foundation, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -368,12 +368,14 @@ GRUB_MOD_INIT
grub_rescue_register_command ("normal", grub_rescue_cmd_normal,
"enter normal mode");
- /* This registers some built-in commands. */
+ /* This registers some built-in commands and sets up autoloading
+ * of commands. */
grub_command_init ();
}
GRUB_MOD_FINI
{
+ grub_command_done ();
grub_set_history (0);
grub_rescue_unregister_command ("normal");
}
--
Tomas 'ebi' Ebenlendr
http://get.to/ebik
PF 2004.72663172308
- automagic module loading - normal commands,
Tomas Ebenlendr <=