Home | History | Annotate | Download | only in stage2
      1 /* cmdline.c - the device-independent GRUB text command line */
      2 /*
      3  *  GRUB  --  GRand Unified Bootloader
      4  *  Copyright (C) 1999,2000,2001,2002,2004  Free Software Foundation, Inc.
      5  *
      6  *  This program is free software; you can redistribute it and/or modify
      7  *  it under the terms of the GNU General Public License as published by
      8  *  the Free Software Foundation; either version 2 of the License, or
      9  *  (at your option) any later version.
     10  *
     11  *  This program is distributed in the hope that it will be useful,
     12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14  *  GNU General Public License for more details.
     15  *
     16  *  You should have received a copy of the GNU General Public License
     17  *  along with this program; if not, write to the Free Software
     18  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
     19  */
     20 
     21 #include <shared.h>
     22 
     23 #ifdef SUPPORT_DISKLESS
     24 # define GRUB	1
     25 # include <etherboot.h>
     26 #endif
     27 
     28 grub_jmp_buf restart_cmdline_env;
     29 
     30 /* Find the next word from CMDLINE and return the pointer. If
     31    AFTER_EQUAL is non-zero, assume that the character `=' is treated as
     32    a space. Caution: this assumption is for backward compatibility.  */
     33 char *
     34 skip_to (int after_equal, char *cmdline)
     35 {
     36   /* Skip until we hit whitespace, or maybe an equal sign. */
     37   while (*cmdline && *cmdline != ' ' && *cmdline != '\t' &&
     38 	 ! (after_equal && *cmdline == '='))
     39     cmdline ++;
     40 
     41   /* Skip whitespace, and maybe equal signs. */
     42   while (*cmdline == ' ' || *cmdline == '\t' ||
     43 	 (after_equal && *cmdline == '='))
     44     cmdline ++;
     45 
     46   return cmdline;
     47 }
     48 
     49 /* Print a helpful message for the command-line interface.  */
     50 void
     51 print_cmdline_message (int forever)
     52 {
     53   printf (" [ Minimal BASH-like line editing is supported.  For the first word, TAB\n"
     54 	  "   lists possible command completions.  Anywhere else TAB lists the possible\n"
     55 	  "   completions of a device/filename.%s ]\n",
     56 	  (forever ? "" : "  ESC at any time exits."));
     57 }
     58 
     59 /* Find the builtin whose command name is COMMAND and return the
     60    pointer. If not found, return 0.  */
     61 struct builtin *
     62 find_command (char *command)
     63 {
     64   char *ptr;
     65   char c;
     66   struct builtin **builtin;
     67 
     68   /* Find the first space and terminate the command name.  */
     69   ptr = command;
     70   while (*ptr && *ptr != ' ' && *ptr != '\t' && *ptr != '=')
     71     ptr ++;
     72 
     73   c = *ptr;
     74   *ptr = 0;
     75 
     76   /* Seek out the builtin whose command name is COMMAND.  */
     77   for (builtin = builtin_table; *builtin != 0; builtin++)
     78     {
     79       int ret = grub_strcmp (command, (*builtin)->name);
     80 
     81       if (ret == 0)
     82 	{
     83 	  /* Find the builtin for COMMAND.  */
     84 	  *ptr = c;
     85 	  return *builtin;
     86 	}
     87       else if (ret < 0)
     88 	break;
     89     }
     90 
     91   /* Cannot find COMMAND.  */
     92   errnum = ERR_UNRECOGNIZED;
     93   *ptr = c;
     94   return 0;
     95 }
     96 
     97 /* Initialize the data for the command-line.  */
     98 static void
     99 init_cmdline (void)
    100 {
    101   /* Initialization.  */
    102   saved_drive = boot_drive;
    103   saved_partition = install_partition;
    104   current_drive = GRUB_INVALID_DRIVE;
    105   errnum = 0;
    106   count_lines = -1;
    107 
    108   /* Restore memory probe state.  */
    109   mbi.mem_upper = saved_mem_upper;
    110   if (mbi.mmap_length)
    111     mbi.flags |= MB_INFO_MEM_MAP;
    112 
    113   /* Initialize the data for the builtin commands.  */
    114   init_builtins ();
    115 }
    116 
    117 /* Enter the command-line interface. HEAP is used for the command-line
    118    buffer. Return only if FOREVER is nonzero and get_cmdline returns
    119    nonzero (ESC is pushed).  */
    120 void
    121 enter_cmdline (char *heap, int forever)
    122 {
    123   /* Initialize the data and print a message.  */
    124   init_cmdline ();
    125   grub_setjmp (restart_cmdline_env);
    126   init_page ();
    127 #ifdef SUPPORT_DISKLESS
    128   print_network_configuration ();
    129   grub_putchar ('\n');
    130 #endif
    131   print_cmdline_message (forever);
    132 
    133   while (1)
    134     {
    135       struct builtin *builtin;
    136       char *arg;
    137 
    138       *heap = 0;
    139       print_error ();
    140       errnum = ERR_NONE;
    141 
    142       /* Get the command-line with the minimal BASH-like interface.  */
    143       if (get_cmdline (PACKAGE "> ", heap, 2048, 0, 1))
    144 	return;
    145 
    146       /* If there was no command, grab a new one. */
    147       if (! heap[0])
    148 	continue;
    149 
    150       /* Find a builtin.  */
    151       builtin = find_command (heap);
    152       if (! builtin)
    153 	continue;
    154 
    155       /* If BUILTIN cannot be run in the command-line, skip it.  */
    156       if (! (builtin->flags & BUILTIN_CMDLINE))
    157 	{
    158 	  errnum = ERR_UNRECOGNIZED;
    159 	  continue;
    160 	}
    161 
    162       /* Invalidate the cache, because the user may exchange removable
    163 	 disks.  */
    164       buf_drive = -1;
    165 
    166       /* Start to count lines, only if the internal pager is in use.  */
    167       if (use_pager)
    168 	count_lines = 0;
    169 
    170       /* Run BUILTIN->FUNC.  */
    171       arg = skip_to (1, heap);
    172       (builtin->func) (arg, BUILTIN_CMDLINE);
    173 
    174       /* Finish the line count.  */
    175       count_lines = -1;
    176     }
    177 }
    178 
    179 /* Run an entry from the script SCRIPT. HEAP is used for the
    180    command-line buffer. If an error occurs, return non-zero, otherwise
    181    return zero.  */
    182 int
    183 run_script (char *script, char *heap)
    184 {
    185   char *old_entry;
    186   char *cur_entry = script;
    187 
    188   /* Initialize the data.  */
    189   init_cmdline ();
    190 
    191   while (1)
    192     {
    193       struct builtin *builtin;
    194       char *arg;
    195 
    196       print_error ();
    197 
    198       if (errnum)
    199 	{
    200 	  errnum = ERR_NONE;
    201 
    202 	  /* If a fallback entry is defined, don't prompt a user's
    203 	     intervention.  */
    204 	  if (fallback_entryno < 0)
    205 	    {
    206 	      grub_printf ("\nPress any key to continue...");
    207 	      (void) getkey ();
    208 	    }
    209 
    210 	  return 1;
    211 	}
    212 
    213       /* Copy the first string in CUR_ENTRY to HEAP.  */
    214       old_entry = cur_entry;
    215       while (*cur_entry++)
    216 	;
    217 
    218       grub_memmove (heap, old_entry, (int) cur_entry - (int) old_entry);
    219       if (! *heap)
    220 	{
    221 	  /* If there is no more command in SCRIPT...  */
    222 
    223 	  /* If any kernel is not loaded, just exit successfully.  */
    224 	  if (kernel_type == KERNEL_TYPE_NONE)
    225 	    return 0;
    226 
    227 	  /* Otherwise, the command boot is run implicitly.  */
    228 	  grub_memmove (heap, "boot", 5);
    229 	}
    230 
    231       /* Find a builtin.  */
    232       builtin = find_command (heap);
    233       if (! builtin)
    234 	{
    235 	  grub_printf ("%s\n", old_entry);
    236 	  continue;
    237 	}
    238 
    239       if (! (builtin->flags & BUILTIN_NO_ECHO))
    240 	grub_printf ("%s\n", old_entry);
    241 
    242       /* If BUILTIN cannot be run in the command-line, skip it.  */
    243       if (! (builtin->flags & BUILTIN_CMDLINE))
    244 	{
    245 	  errnum = ERR_UNRECOGNIZED;
    246 	  continue;
    247 	}
    248 
    249       /* Invalidate the cache, because the user may exchange removable
    250 	 disks.  */
    251       buf_drive = -1;
    252 
    253       /* Run BUILTIN->FUNC.  */
    254       arg = skip_to (1, heap);
    255       (builtin->func) (arg, BUILTIN_SCRIPT);
    256     }
    257 }
    258