• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 *
skip_to(int after_equal,char * cmdline)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
print_cmdline_message(int forever)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 *
find_command(char * command)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
init_cmdline(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
enter_cmdline(char * heap,int forever)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
run_script(char * script,char * heap)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