Hello,

I know that this is not the priority defined by Okuji, but as the work
is done, here are the patches...

The BOOTP/DHCP allow the dynamic allocation of parameters. The network
parameters were printed by GRUB, but not, for example, the filename to boot.
For an interactive use, this information has to be given. For a non
interactive use, this information must be kept and used.

It is not a good think to make an automatic download : it is the choice of
the user to use, or not, the information given. Secondly, the information
given doesn't imply that the kernel to load is a remote one : you can
imagine given the information to a machine so that it can load a different
_local_ kernel.

So the solution I have adopted is the following :

- The natural way (in the future) is something like : kernel $KERNEL
  [options], that is environment variables ; I have so implemented a "fake"
  environment table, the strict minimum ;
- I have made that for netboot, but in order that this could be reused for
  something else ;
- The user MUST specify the root fs to use : I don't make the assumption
  that, via netboot, the filename refers to a remote fs ;
- There is _no_ automatic downloading via bootp/dhcp : only the
  information about the filename is stored, and can be used via a new
  option of `kernel' : --env-kernel (the name can of course be changed,
  but I only wanted not to let think that this is an automatic
  downloading ; on the other hand, putting an option like `$KERNEL'
  would be definitively a bad idea since there is no real support for a
  symbol table;
- As highlightened by Okuji, the main problem is the use of dynamic memory;
  a real environment table has to use it ; I have so made static memory
  allocation, and the strict minimum, IMHO, the main problem has to be address
  after 1.0 is released.

  For the details, here are the ChangeLog entries :

        From Thierry Laronde <[EMAIL PROTECTED]> :
        Added the display and the backup of the filename given by
        BOOTP/DHCP, and the reuse of the information via the implementation of 
        a "fake" environment table :

        * stage2/shared.h:
         (KERNEL_BUF): new macro
         (KERNEL_BUFLEN): likewise
         (grub_error_t): new ERR_BAD_SYMBOL
         (symbol): new struct
         (grub_env): new variable - declaration
         (GRUB_ENV_SIZE): new macro
         (env_kernel): new variable - declaration
         (symb_search()): new function - declaration
         
        * stage2/common.c (err_list[]): new ERR_BAD_SYMBOL

        * stage2/builtins.c: definition of new variables `kernel',
         `grub_env' and `env_kernel' 
         (init_builtins): initialisation of `kernel'
         (symb_search): definition
         (bootp_func): displays filename given by bootp/dhcp
         (kernel_func): new option `--env-kernel'
        
        * netboot/main.c (await_reply): defining environment variable named
        "KERNEL"
        
        * stage2/boot.c (load_image): use of the flag `env_kernel'

        * docs/grub.texi (netboot): new option `--env-kernel'


Regards,
-- 
Thierry LARONDE <[EMAIL PROTECTED]>
10, rue du Bel Air, 74000 ANNECY - FRANCE/ Tel : 33.(0)4.50.67.46.61
/home du SDF (Site Debian Francophone) : http://sdf.polynum.org/
diff -pru grub/docs/grub.texi grub-alpha/docs/grub.texi
--- grub/docs/grub.texi Tue Feb 27 11:23:55 2001
+++ grub-alpha/docs/grub.texi   Fri Mar  2 15:44:30 2001
@@ -1169,7 +1169,8 @@ If you decided to use a server to assign
 server and run @command{bootp} (@pxref{bootp}), @command{dhcp}
 (@pxref{dhcp}) or @command{rarp} (@pxref{rarp}) for BOOTP, DHCP or RARP,
 respectively. Each command will show an assigned IP address, a netmask,
-an IP address for your TFTP server and a gateway. If any of the
+an IP address for your TFTP server and a gateway, and, if the option is
+set for BOOTP or DHCP, the filename to boot. If any of the
 addresses is wrong or it causes an error, probably the configuration of
 your servers isn't set up properly.
 
@@ -1185,7 +1186,10 @@ manually). @xref{ifconfig}, for more det
 
 Finally, download your OS images from your network. The network can be
 accessed using the network drive @samp{(nd)}. Everything else is very
-similar to the normal instructions (@pxref{Booting}).
+similar to the normal instructions (@pxref{Booting}), except that, if you
+use BOOTP or DHCP, and the filename to boot was given by the server, _after
+setting the correct root device via @command{root}_, you can give the option
+@kbd{--env-kernel} to @command{kernel} to tell GRUB to use the given value.
 
 Here is an example:
 
@@ -1196,6 +1200,7 @@ Probing... [NE*000]
 NE2000 base ...
 Address: 192.168.110.23    Netmask: 255.255.255.0
 Server: 192.168.110.14     Gateway: 192.168.110.1
+Boot file: none given
 
 grub> @kbd{root (nd)}
 grub> @kbd{kernel /tftproot/gnumach.gz root=sd0s1}
@@ -1204,6 +1209,22 @@ grub> @kbd{boot}
 @end group
 @end example
 
+Another example with the use of the "environment variable" :
+
+@example
+@group
+grub> @kbd{bootp}
+Probing... [NE*000]
+NE2000 base ...
+Address: 192.168.110.23    Netmask: 255.255.255.0
+Server: 192.168.110.14     Gateway: 192.168.110.1
+Boot file: /tftpboot/bzImage
+
+grub> @kbd{root (nd)}
+grub> @kbd{kernel --env-kernel root=/dev/hda5}
+grub> @kbd{boot}
+@end group
+@end example
 
 @node Diskless
 @section Booting from a network
diff -pru grub/netboot/main.c grub-alpha/netboot/main.c
--- grub/netboot/main.c Tue Feb 27 11:23:56 2001
+++ grub-alpha/netboot/main.c   Thu Mar  1 17:14:39 2001
@@ -851,6 +851,18 @@ await_reply (int type, int ival, void *p
                  kernel = kernel_buf;
                }
 #endif /* ! GRUB */
+#ifdef GRUB     
+             /* Setting the "environment" variable KERNEL for GRUB */
+             {
+               struct symbol *symb_ptr;
+                 
+               if ((symb_ptr = symb_search("KERNEL")))
+                 { 
+                   grub_memmove(symb_ptr->def, bootpreply->bp_file, 128);
+                   (symb_ptr->def)[128] = '\0';
+                 }
+             }
+#endif /* GRUB */            
              
              grub_memmove ((char *) BOOTP_DATA_ADDR, (char *) bootpreply,
                            sizeof (struct bootpd_t));
diff -pru grub/stage2/boot.c grub-alpha/stage2/boot.c
--- grub/stage2/boot.c  Mon Oct 16 06:27:56 2000
+++ grub-alpha/stage2/boot.c    Fri Mar  2 15:29:58 2001
@@ -317,7 +317,7 @@ load_image (char *kernel, char *arg, ker
             That is, copy "mem=XXX" to the end of the command-line, and
             avoid to copy spaces unnecessarily. Hell.  */
          {
-           char *src = skip_to (0, arg);
+           char *src = (env_kernel)? arg : skip_to (0, arg);
            char *dest = (char *) CL_MY_LOCATION;
 
            while (((int) dest) < CL_MY_END_ADDR && *src)
diff -pru grub/stage2/builtins.c grub-alpha/stage2/builtins.c
--- grub/stage2/builtins.c      Thu Mar  1 11:31:41 2001
+++ grub-alpha/stage2/builtins.c        Fri Mar  2 15:44:55 2001
@@ -80,6 +80,20 @@ int show_menu = 1;
 /* The BIOS drive map.  */
 static unsigned short bios_drive_map[DRIVE_MAP_SIZE + 1];
 
+/* We need to allow statically the memory for the KERNEL symbol */
+struct symbol kernel = {
+       NULL,
+       "KERNEL",
+       NULL    
+};
+
+/* GRUB environment table */
+struct symbol *grub_env [GRUB_ENV_SIZE] = {&kernel};
+
+/* Flag set if the kernel name is _not_ in the command line. See also boot.c
+ * for the explanation of this need */
+short env_kernel = 0;
+
 /* Initialize the data for builtins.  */
 void
 init_builtins (void)
@@ -88,6 +102,9 @@ init_builtins (void)
   /* BSD and chainloading evil hacks!  */
   bootdev = set_bootdev (0);
   mb_cmdline = (char *) MB_CMDLINE_BUF;
+  /* Kernel filename is not set */
+  kernel.def = (char *) KERNEL_BUF;
+  kernel.def[0] = '\0';
 }
 
 /* Initialize the data for the configuration file.  */
@@ -130,6 +147,19 @@ disk_read_print_func (int sector, int of
 }
 
 
+/* Functions to handle the environment table */
+struct symbol *
+symb_search(char *s)
+{
+       struct symbol *ps;
+
+       for (ps = grub_env[0]; ps != NULL; ps = ps->next)
+         if (grub_strcmp(s, ps->name) == 0)
+           return ps;
+       return NULL;
+}
+
+
 /* blocklist */
 static int
 blocklist_func (char *arg, int flags)
@@ -349,6 +379,8 @@ static struct builtin builtin_boot =
 static int
 bootp_func (char *arg, int flags)
 {
+  struct symbol *symb_ptr = NULL;
+  
   if (! bootp ())
     {
       if (errnum == ERR_NONE)
@@ -359,6 +391,9 @@ bootp_func (char *arg, int flags)
 
   /* Notify the configuration.  */
   print_network_configuration ();
+  grub_printf("Boot file: %s\n", 
+              ( (symb_ptr = symb_search("KERNEL")) && *symb_ptr->def)?
+              symb_ptr->def : "none given");
   return 0;
 }
 
@@ -2209,6 +2244,7 @@ static int
 kernel_func (char *arg, int flags)
 {
   int len;
+  struct symbol *symb_ptr = NULL;
   kernel_t suggested_type = KERNEL_TYPE_NONE;
   unsigned long load_flags = 0;
 
@@ -2250,6 +2286,17 @@ kernel_func (char *arg, int flags)
         has no effect.  */
       else if (grub_memcmp (arg, "--no-mem-option", 15) == 0)
        load_flags |= KERNEL_LOAD_NO_MEM_OPTION;
+      else if (grub_memcmp (arg, "--env-kernel", 12) == 0)
+        {
+          if (!(symb_ptr = symb_search("KERNEL")) || !(*symb_ptr->def)) 
+                 /* KERNEL is not set or definition is empty*/
+            {
+              errnum = ERR_BAD_SYMBOL;
+              return 1;
+            }
+         else
+           env_kernel = 1;
+        }
       else
        break;
 
@@ -2267,9 +2314,20 @@ kernel_func (char *arg, int flags)
       return 1;
     }
 
+  
   /* Copy the command-line to MB_CMDLINE.  */
   grub_memmove (mb_cmdline, arg, len + 1);
+  /* If we have to use the environment variable for the kernel */
+  /* We make the following assumptions :
+   *    - additionnal informations like "(nd)" MUST be set by the user
+   *      via the `root' command; the string is taken as is;
+   *    - if an environment variable is set, it is defined at least by the
+   *    empty string ; */
+  if (symb_ptr)
+      arg = symb_ptr->def;
+      
   kernel_type = load_image (arg, mb_cmdline, suggested_type, load_flags);
+  env_kernel = 0;
   if (kernel_type == KERNEL_TYPE_NONE)
     return 1;
 
@@ -2282,14 +2340,17 @@ static struct builtin builtin_kernel =
   "kernel",
   kernel_func,
   BUILTIN_CMDLINE,
-  "kernel [--no-mem-option] [--type=TYPE] FILE [ARG ...]",
+  "kernel [--no-mem-option] [--type=TYPE] [--env-kernel ] [FILE] [ARG ...]",
   "Attempt to load the primary boot image from FILE. The rest of the"
   "line is passed verbatim as the \"kernel command line\".  Any modules"
   " must be reloaded after using this command. The option --type is used"
   " to suggest what type of kernel to be loaded. TYPE must be either of"
   " \"netbsd\", \"freebsd\", \"openbsd\", \"linux\", \"biglinux\" and"
-  " \"multiboot\". The option --no-mem-option tells GRUB not to pass a"
-  " Linux's mem option automatically."
+  " \"multiboot\". The option \"--no-mem-option\" tells GRUB not to pass a"
+  " Linux's mem option automatically. The option \"--env-kernel\" is used to "
+  " tell GRUB to take the name of the kernel from a value already set in"
+  " the environment (only set when using `bootp' at the moment, and you "
+  " have to specify the correct root device first)."
 };
 
 
diff -pru grub/stage2/common.c grub-alpha/stage2/common.c
--- grub/stage2/common.c        Sun Nov 26 19:31:30 2000
+++ grub-alpha/stage2/common.c  Fri Mar  2 12:26:40 2001
@@ -84,6 +84,7 @@ char *err_list[] =
   [ERR_UNRECOGNIZED] = "Unrecognized command",
   [ERR_WONT_FIT] = "Selected item cannot fit into memory",
   [ERR_WRITE] = "Disk write error",
+  [ERR_BAD_SYMBOL] = "Environment variable not set or empty",
 };
 
 
diff -pru grub/stage2/shared.h grub-alpha/stage2/shared.h
--- grub/stage2/shared.h        Wed Feb 28 11:35:08 2001
+++ grub-alpha/stage2/shared.h  Fri Mar  2 15:16:02 2001
@@ -122,6 +122,14 @@ extern char *grub_scratch_mem;
 #define MENU_BUF               (UNIQUE_BUF + UNIQUE_BUFLEN)
 #define MENU_BUFLEN            (0x8000 + PASSWORD_BUF - UNIQUE_BUF)
 
+
+/* XXX These are all temporary work around. The right way is the
+ * implementation of a real symbol table, but this implies using dynamic 
+ * memory */
+/* The buffer for the kernel name. */
+#define KERNEL_BUF             (MENU_BUF + MENU_BUFLEN)
+#define KERNEL_BUFLEN          129 /* since via netboot we accept 128 +'\0'*/
+
 /* The size of the drive map.  */
 #define DRIVE_MAP_SIZE         8
 
@@ -538,6 +546,7 @@ typedef enum
   ERR_BAD_ARGUMENT,
   ERR_UNALIGNED,
   ERR_PRIVILEGED,
+  ERR_BAD_SYMBOL,
 
   MAX_ERR_NUM
 } grub_error_t;
@@ -846,6 +855,33 @@ struct builtin
 /* All the builtins are registered in this.  */
 extern struct builtin *builtin_table[];
 
+/* Structure symbol to handle environment variables */
+struct symbol 
+{
+  struct symbol *next;
+  char *name;
+  char *def;
+};
+
+/* grub_env table of symbols --- defined in builtins.c */
+/* We don't use dynamic memory at the moment, thus this environment is
+ * almost a fake one : the size of the table is hardcoded, and when a symbol
+ * is defined, it can be :
+ *   - invalid : symbol.def == NULL ;
+ *   - defined : !invalid, but can be the empty string if :
+ *               *symbol.definition == '\0';
+ * NOTE : at the moment a symbol can't be "unset" ! */               
+extern struct symbol *grub_env [];
+
+/* We define here the maximum size of the array */
+#define GRUB_ENV_SIZE 1
+
+/* XXX This flag is a work around because, at the moment, the way we handle
+ * the command line assumes that the kernel filename is the first token in
+ * it. This assumption is false when we take the kernel name from the
+ * environment variable */
+extern short env_kernel;
+
 /* The constants for kernel types.  */
 typedef enum
 {
@@ -1006,6 +1042,9 @@ int load_module (char *module, char *arg
 int load_initrd (char *initrd);
 
 int check_password(char *entered, char* expected, password_t type);
+
+/* Functions to handle environment table */
+struct symbol *symb_search(char *s);
 #endif
 
 void init_bios_info (void);

Reply via email to