~darkmuggle-deactivatedaccount/ubuntu/quantal/grub2/fix-872244

« back to all changes in this revision

Viewing changes to grub-core/normal/main.c

  • Committer: Bazaar Package Importer
  • Author(s): Colin Watson, Colin Watson, Evan Broder, Mario Limonciello
  • Date: 2010-11-24 13:59:55 UTC
  • mfrom: (1.17.6 upstream) (17.6.15 experimental)
  • Revision ID: james.westby@ubuntu.com-20101124135955-r6ii5sepayr7jt53
Tags: 1.99~20101124-1ubuntu1
[ Colin Watson ]
* Resynchronise with Debian experimental.  Remaining changes:
  - Adjust for default Ubuntu boot options ("quiet splash").
  - Default to hiding the menu; holding down Shift at boot will show it.
  - Set a monochromatic theme for Ubuntu.
  - Apply Ubuntu GRUB Legacy changes to legacy update-grub script: title,
    recovery mode, quiet option, tweak how memtest86+ is displayed, and
    use UUIDs where appropriate.
  - Fix backslash-escaping in merge_debconf_into_conf.
  - Remove "GNU/Linux" from default distributor string.
  - Add crashkernel= options if kdump and makedumpfile are available.
  - If other operating systems are installed, then automatically unhide
    the menu.  Otherwise, if GRUB_HIDDEN_TIMEOUT is 0, then use keystatus
    if available to check whether Shift is pressed.  If it is, show the
    menu, otherwise boot immediately.  If keystatus is not available, then
    fall back to a short delay interruptible with Escape.
  - Allow Shift to interrupt 'sleep --interruptible'.
  - Don't display introductory message about line editing unless we're
    actually offering a shell prompt.  Don't clear the screen just before
    booting if we never drew the menu in the first place.
  - Remove some verbose messages printed before reading the configuration
    file.
  - Suppress progress messages as the kernel and initrd load for
    non-recovery kernel menu entries.
  - Change prepare_grub_to_access_device to handle filesystems
    loop-mounted on file images.
  - Ignore devices loop-mounted from files in 10_linux.
  - Show the boot menu if the previous boot failed, that is if it failed
    to get to the end of one of the normal runlevels.
  - Don't generate /boot/grub/device.map during grub-install or
    grub-mkconfig by default.
  - Adjust upgrade version checks for Ubuntu.
  - Don't display "GRUB loading" unless Shift is held down.
  - Adjust versions of grub-doc and grub-legacy-doc conflicts to tolerate
    our backport of the grub-doc split.
  - Fix LVM/RAID probing in the absence of /boot/grub/device.map.
  - Look for .mo files in /usr/share/locale-langpack as well, in
    preference.
  - Make sure GRUB_TIMEOUT isn't quoted unnecessarily.
  - Probe all devices in 'grub-probe --target=drive' if
    /boot/grub/device.map is missing.
  - Build-depend on qemu-kvm rather than qemu-system for grub-pc tests.
  - Use qemu rather than qemu-system-i386.
  - Program vesafb on BIOS systems rather than efifb.
  - Add a grub-rescue-efi-amd64 package containing a rescue CD-ROM image
    for EFI-AMD64.
  - On Wubi, don't ask for an install device, but just update wubildr
    using the diverted grub-install.
  - When embedding the core image in a post-MBR gap, check for and avoid
    sectors matching any of a list of known signatures.
  - Disable video_bochs and video_cirrus on PC BIOS systems, as probing
    PCI space seems to break on some systems.
* Downgrade "ACPI shutdown failed" error to a debug message, since it can
  cause spurious test failures.

[ Evan Broder ]
* Enable lua from grub-extras.
* Incorporate the bitop library into lua.
* Add enum_pci function to grub module in lua.
* Switch back to gfxpayload=keep by default, unless the video hardware
  is known to not support it.

[ Mario Limonciello ]
* Built part_msdos and vfat into bootx64.efi (LP: #677758)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* main.c - the normal mode main routine */
 
2
/*
 
3
 *  GRUB  --  GRand Unified Bootloader
 
4
 *  Copyright (C) 2000,2001,2002,2003,2005,2006,2007,2008,2009  Free Software Foundation, Inc.
 
5
 *
 
6
 *  GRUB 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 3 of the License, or
 
9
 *  (at your option) any later version.
 
10
 *
 
11
 *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
 
18
 */
 
19
 
 
20
#include <grub/kernel.h>
 
21
#include <grub/normal.h>
 
22
#include <grub/dl.h>
 
23
#include <grub/misc.h>
 
24
#include <grub/file.h>
 
25
#include <grub/mm.h>
 
26
#include <grub/term.h>
 
27
#include <grub/env.h>
 
28
#include <grub/parser.h>
 
29
#include <grub/reader.h>
 
30
#include <grub/menu_viewer.h>
 
31
#include <grub/auth.h>
 
32
#include <grub/i18n.h>
 
33
#include <grub/charset.h>
 
34
#include <grub/script_sh.h>
 
35
 
 
36
#define GRUB_DEFAULT_HISTORY_SIZE       50
 
37
 
 
38
static int nested_level = 0;
 
39
int grub_normal_exit_level = 0;
 
40
 
 
41
/* Read a line from the file FILE.  */
 
42
char *
 
43
grub_file_getline (grub_file_t file)
 
44
{
 
45
  char c;
 
46
  int pos = 0;
 
47
  int literal = 0;
 
48
  char *cmdline;
 
49
  int max_len = 64;
 
50
 
 
51
  /* Initially locate some space.  */
 
52
  cmdline = grub_malloc (max_len);
 
53
  if (! cmdline)
 
54
    return 0;
 
55
 
 
56
  while (1)
 
57
    {
 
58
      if (grub_file_read (file, &c, 1) != 1)
 
59
        break;
 
60
 
 
61
      /* Skip all carriage returns.  */
 
62
      if (c == '\r')
 
63
        continue;
 
64
 
 
65
      /* Replace tabs with spaces.  */
 
66
      if (c == '\t')
 
67
        c = ' ';
 
68
 
 
69
      /* The previous is a backslash, then...  */
 
70
      if (literal)
 
71
        {
 
72
          /* If it is a newline, replace it with a space and continue.  */
 
73
          if (c == '\n')
 
74
            {
 
75
              c = ' ';
 
76
 
 
77
              /* Go back to overwrite the backslash.  */
 
78
              if (pos > 0)
 
79
                pos--;
 
80
            }
 
81
 
 
82
          literal = 0;
 
83
        }
 
84
 
 
85
      if (c == '\\')
 
86
        literal = 1;
 
87
 
 
88
      if (pos == 0)
 
89
        {
 
90
          if (! grub_isspace (c))
 
91
            cmdline[pos++] = c;
 
92
        }
 
93
      else
 
94
        {
 
95
          if (pos >= max_len)
 
96
            {
 
97
              char *old_cmdline = cmdline;
 
98
              max_len = max_len * 2;
 
99
              cmdline = grub_realloc (cmdline, max_len);
 
100
              if (! cmdline)
 
101
                {
 
102
                  grub_free (old_cmdline);
 
103
                  return 0;
 
104
                }
 
105
            }
 
106
 
 
107
          if (c == '\n')
 
108
            break;
 
109
 
 
110
          cmdline[pos++] = c;
 
111
        }
 
112
    }
 
113
 
 
114
  cmdline[pos] = '\0';
 
115
 
 
116
  /* If the buffer is empty, don't return anything at all.  */
 
117
  if (pos == 0)
 
118
    {
 
119
      grub_free (cmdline);
 
120
      cmdline = 0;
 
121
    }
 
122
 
 
123
  return cmdline;
 
124
}
 
125
 
 
126
void
 
127
grub_normal_free_menu (grub_menu_t menu)
 
128
{
 
129
  grub_menu_entry_t entry = menu->entry_list;
 
130
 
 
131
  while (entry)
 
132
    {
 
133
      grub_menu_entry_t next_entry = entry->next;
 
134
 
 
135
      grub_free ((void *) entry->title);
 
136
      grub_free ((void *) entry->sourcecode);
 
137
      entry = next_entry;
 
138
    }
 
139
 
 
140
  grub_free (menu);
 
141
  grub_env_unset_menu ();
 
142
}
 
143
 
 
144
static grub_menu_t
 
145
read_config_file (const char *config)
 
146
{
 
147
  grub_file_t file;
 
148
 
 
149
  auto grub_err_t getline (char **line, int cont);
 
150
  grub_err_t getline (char **line, int cont __attribute__ ((unused)))
 
151
    {
 
152
      while (1)
 
153
        {
 
154
          char *buf;
 
155
 
 
156
          *line = buf = grub_file_getline (file);
 
157
          if (! buf)
 
158
            return grub_errno;
 
159
 
 
160
          if (buf[0] == '#')
 
161
            grub_free (*line);
 
162
          else
 
163
            break;
 
164
        }
 
165
 
 
166
      return GRUB_ERR_NONE;
 
167
    }
 
168
 
 
169
  grub_menu_t newmenu;
 
170
 
 
171
  newmenu = grub_env_get_menu ();
 
172
  if (! newmenu)
 
173
    {
 
174
      newmenu = grub_zalloc (sizeof (*newmenu));
 
175
      if (! newmenu)
 
176
        return 0;
 
177
 
 
178
      grub_env_set_menu (newmenu);
 
179
    }
 
180
 
 
181
  /* Try to open the config file.  */
 
182
  file = grub_file_open (config);
 
183
  if (! file)
 
184
    return 0;
 
185
 
 
186
  while (1)
 
187
    {
 
188
      char *line;
 
189
 
 
190
      /* Print an error, if any.  */
 
191
      grub_print_error ();
 
192
      grub_errno = GRUB_ERR_NONE;
 
193
 
 
194
      if ((getline (&line, 0)) || (! line))
 
195
        break;
 
196
 
 
197
      grub_normal_parse_line (line, getline);
 
198
      grub_free (line);
 
199
    }
 
200
 
 
201
  grub_file_close (file);
 
202
 
 
203
  return newmenu;
 
204
}
 
205
 
 
206
/* Initialize the screen.  */
 
207
void
 
208
grub_normal_init_page (struct grub_term_output *term)
 
209
{
 
210
  int msg_len;
 
211
  int posx;
 
212
  const char *msg = _("GNU GRUB  version %s");
 
213
  char *msg_formatted;
 
214
  grub_uint32_t *unicode_msg;
 
215
  grub_uint32_t *last_position;
 
216
 
 
217
  grub_term_cls (term);
 
218
 
 
219
  msg_formatted = grub_xasprintf (msg, PACKAGE_VERSION);
 
220
  if (!msg_formatted)
 
221
    return;
 
222
 
 
223
  msg_len = grub_utf8_to_ucs4_alloc (msg_formatted,
 
224
                                     &unicode_msg, &last_position);
 
225
  grub_free (msg_formatted);
 
226
 
 
227
  if (msg_len < 0)
 
228
    {
 
229
      return;
 
230
    }
 
231
 
 
232
  posx = grub_getstringwidth (unicode_msg, last_position, term);
 
233
  posx = (grub_term_width (term) - posx) / 2;
 
234
  grub_term_gotoxy (term, posx, 1);
 
235
 
 
236
  grub_print_ucs4 (unicode_msg, last_position, 0, 0, term);
 
237
  grub_putcode ('\n', term);
 
238
  grub_putcode ('\n', term);
 
239
  grub_free (unicode_msg);
 
240
}
 
241
 
 
242
static void
 
243
read_lists (const char *val)
 
244
{
 
245
  if (! grub_no_autoload)
 
246
    {
 
247
      read_command_list (val);
 
248
      read_fs_list (val);
 
249
      read_crypto_list (val);
 
250
      read_terminal_list (val);
 
251
    }
 
252
}
 
253
 
 
254
static char *
 
255
read_lists_hook (struct grub_env_var *var __attribute__ ((unused)),
 
256
                 const char *val)
 
257
{
 
258
  read_lists (val);
 
259
  return val ? grub_strdup (val) : NULL;
 
260
}
 
261
 
 
262
/* Read the config file CONFIG and execute the menu interface or
 
263
   the command line interface if BATCH is false.  */
 
264
void
 
265
grub_normal_execute (const char *config, int nested, int batch)
 
266
{
 
267
  grub_menu_t menu = 0;
 
268
  const char *prefix;
 
269
 
 
270
  if (! nested)
 
271
    {
 
272
      prefix = grub_env_get ("prefix");
 
273
      read_lists (prefix);
 
274
      grub_register_variable_hook ("prefix", NULL, read_lists_hook);
 
275
      grub_command_execute ("parser.grub", 0, 0);
 
276
    }
 
277
 
 
278
  if (config)
 
279
    {
 
280
      menu = read_config_file (config);
 
281
 
 
282
      /* Ignore any error.  */
 
283
      grub_errno = GRUB_ERR_NONE;
 
284
    }
 
285
 
 
286
  if (! batch)
 
287
    {
 
288
      if (menu && menu->size)
 
289
        {
 
290
          grub_show_menu (menu, nested);
 
291
          if (nested)
 
292
            grub_normal_free_menu (menu);
 
293
        }
 
294
    }
 
295
}
 
296
 
 
297
/* This starts the normal mode.  */
 
298
void
 
299
grub_enter_normal_mode (const char *config)
 
300
{
 
301
  nested_level++;
 
302
  grub_normal_execute (config, 0, 0);
 
303
  grub_cmdline_run (0);
 
304
  nested_level--;
 
305
  if (grub_normal_exit_level)
 
306
    grub_normal_exit_level--;
 
307
}
 
308
 
 
309
/* Enter normal mode from rescue mode.  */
 
310
static grub_err_t
 
311
grub_cmd_normal (struct grub_command *cmd __attribute__ ((unused)),
 
312
                 int argc, char *argv[])
 
313
{
 
314
  if (argc == 0)
 
315
    {
 
316
      /* Guess the config filename. It is necessary to make CONFIG static,
 
317
         so that it won't get broken by longjmp.  */
 
318
      char *config;
 
319
      const char *prefix;
 
320
 
 
321
      prefix = grub_env_get ("prefix");
 
322
      if (prefix)
 
323
        {
 
324
          config = grub_xasprintf ("%s/grub.cfg", prefix);
 
325
          if (! config)
 
326
            goto quit;
 
327
 
 
328
          grub_enter_normal_mode (config);
 
329
          grub_free (config);
 
330
        }
 
331
      else
 
332
        grub_enter_normal_mode (0);
 
333
    }
 
334
  else
 
335
    grub_enter_normal_mode (argv[0]);
 
336
 
 
337
quit:
 
338
  return 0;
 
339
}
 
340
 
 
341
/* Exit from normal mode to rescue mode.  */
 
342
static grub_err_t
 
343
grub_cmd_normal_exit (struct grub_command *cmd __attribute__ ((unused)),
 
344
                      int argc __attribute__ ((unused)),
 
345
                      char *argv[] __attribute__ ((unused)))
 
346
{
 
347
  if (nested_level <= grub_normal_exit_level)
 
348
    return grub_error (GRUB_ERR_BAD_ARGUMENT, "not in normal environment");
 
349
  grub_normal_exit_level++;
 
350
  return GRUB_ERR_NONE;
 
351
}
 
352
 
 
353
static grub_err_t
 
354
grub_normal_reader_init (int nested)
 
355
{
 
356
  struct grub_term_output *term;
 
357
  const char *msg = _("Minimal BASH-like line editing is supported. For "
 
358
                      "the first word, TAB lists possible command completions. Anywhere "
 
359
                      "else TAB lists possible device or file completions. %s");
 
360
  const char *msg_esc = _("ESC at any time exits.");
 
361
  char *msg_formatted;
 
362
 
 
363
  msg_formatted = grub_xasprintf (msg, nested ? msg_esc : "");
 
364
  if (!msg_formatted)
 
365
    return grub_errno;
 
366
 
 
367
  FOR_ACTIVE_TERM_OUTPUTS(term)
 
368
  {
 
369
    grub_normal_init_page (term);
 
370
    grub_term_setcursor (term, 1);
 
371
 
 
372
    grub_print_message_indented (msg_formatted, 3, STANDARD_MARGIN, term);
 
373
    grub_putcode ('\n', term);
 
374
    grub_putcode ('\n', term);
 
375
  }
 
376
  grub_free (msg_formatted);
 
377
 
 
378
  return 0;
 
379
}
 
380
 
 
381
static grub_err_t
 
382
grub_normal_read_line_real (char **line, int cont, int nested)
 
383
{
 
384
  const char *prompt;
 
385
 
 
386
  if (cont)
 
387
    prompt = ">";
 
388
  else
 
389
    prompt = "grub>";
 
390
 
 
391
  if (!prompt)
 
392
    return grub_errno;
 
393
 
 
394
  while (1)
 
395
    {
 
396
      *line = grub_cmdline_get (prompt);
 
397
      if (*line)
 
398
        break;
 
399
 
 
400
      if (cont || nested)
 
401
        {
 
402
          grub_free (*line);
 
403
          *line = 0;
 
404
          return grub_errno;
 
405
        }
 
406
    }
 
407
  
 
408
  return 0;
 
409
}
 
410
 
 
411
static grub_err_t
 
412
grub_normal_read_line (char **line, int cont)
 
413
{
 
414
  return grub_normal_read_line_real (line, cont, 0);
 
415
}
 
416
 
 
417
void
 
418
grub_cmdline_run (int nested)
 
419
{
 
420
  grub_err_t err = GRUB_ERR_NONE;
 
421
 
 
422
  err = grub_auth_check_authentication (NULL);
 
423
 
 
424
  if (err)
 
425
    {
 
426
      grub_print_error ();
 
427
      grub_errno = GRUB_ERR_NONE;
 
428
      return;
 
429
    }
 
430
 
 
431
  grub_normal_reader_init (nested);
 
432
 
 
433
  while (1)
 
434
    {
 
435
      char *line;
 
436
 
 
437
      if (grub_normal_exit_level)
 
438
        break;
 
439
 
 
440
      /* Print an error, if any.  */
 
441
      grub_print_error ();
 
442
      grub_errno = GRUB_ERR_NONE;
 
443
 
 
444
      grub_normal_read_line_real (&line, 0, nested);
 
445
      if (! line)
 
446
        break;
 
447
 
 
448
      grub_normal_parse_line (line, grub_normal_read_line);
 
449
      grub_free (line);
 
450
    }
 
451
}
 
452
 
 
453
static char *
 
454
grub_env_write_pager (struct grub_env_var *var __attribute__ ((unused)),
 
455
                      const char *val)
 
456
{
 
457
  grub_set_more ((*val == '1'));
 
458
  return grub_strdup (val);
 
459
}
 
460
 
 
461
/* clear */
 
462
static grub_err_t
 
463
grub_mini_cmd_clear (struct grub_command *cmd __attribute__ ((unused)),
 
464
                   int argc __attribute__ ((unused)),
 
465
                   char *argv[] __attribute__ ((unused)))
 
466
{
 
467
  grub_cls ();
 
468
  return 0;
 
469
}
 
470
 
 
471
static grub_command_t cmd_clear;
 
472
 
 
473
static void (*grub_xputs_saved) (const char *str);
 
474
 
 
475
GRUB_MOD_INIT(normal)
 
476
{
 
477
  /* Previously many modules depended on gzio. Be nice to user and load it.  */
 
478
  grub_dl_load ("gzio");
 
479
 
 
480
  grub_normal_auth_init ();
 
481
  grub_context_init ();
 
482
  grub_script_init ();
 
483
  grub_menu_init ();
 
484
 
 
485
  grub_xputs_saved = grub_xputs;
 
486
  grub_xputs = grub_xputs_normal;
 
487
 
 
488
  /* Normal mode shouldn't be unloaded.  */
 
489
  if (mod)
 
490
    grub_dl_ref (mod);
 
491
 
 
492
  cmd_clear =
 
493
    grub_register_command ("clear", grub_mini_cmd_clear,
 
494
                           0, N_("Clear the screen."));
 
495
 
 
496
  grub_set_history (GRUB_DEFAULT_HISTORY_SIZE);
 
497
 
 
498
  grub_register_variable_hook ("pager", 0, grub_env_write_pager);
 
499
 
 
500
  /* Register a command "normal" for the rescue mode.  */
 
501
  grub_register_command ("normal", grub_cmd_normal,
 
502
                         0, N_("Enter normal mode."));
 
503
  grub_register_command ("normal_exit", grub_cmd_normal_exit,
 
504
                         0, N_("Exit from normal mode."));
 
505
 
 
506
  /* Reload terminal colors when these variables are written to.  */
 
507
  grub_register_variable_hook ("color_normal", NULL, grub_env_write_color_normal);
 
508
  grub_register_variable_hook ("color_highlight", NULL, grub_env_write_color_highlight);
 
509
 
 
510
  /* Preserve hooks after context changes.  */
 
511
  grub_env_export ("color_normal");
 
512
  grub_env_export ("color_highlight");
 
513
 
 
514
  /* Set default color names.  */
 
515
  grub_env_set ("color_normal", "white/black");
 
516
  grub_env_set ("color_highlight", "black/white");
 
517
}
 
518
 
 
519
GRUB_MOD_FINI(normal)
 
520
{
 
521
  grub_context_fini ();
 
522
  grub_script_fini ();
 
523
  grub_menu_fini ();
 
524
  grub_normal_auth_fini ();
 
525
 
 
526
  grub_xputs = grub_xputs_saved;
 
527
 
 
528
  grub_set_history (0);
 
529
  grub_register_variable_hook ("pager", 0, 0);
 
530
  grub_fs_autoload_hook = 0;
 
531
  grub_unregister_command (cmd_clear);
 
532
}