1 /* rescue.c - rescue mode */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2002,2003,2005,2007 Free Software Foundation, Inc.
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.
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.
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/>.
20 #include <grub/kernel.h>
21 #include <grub/rescue.h>
22 #include <grub/term.h>
23 #include <grub/misc.h>
24 #include <grub/disk.h>
25 #include <grub/file.h>
28 #include <grub/loader.h>
30 #include <grub/partition.h>
32 #include <grub/parser.h>
34 #define GRUB_RESCUE_BUF_SIZE 256
35 #define GRUB_RESCUE_MAX_ARGS 20
37 struct grub_rescue_command
40 void (*func
) (int argc
, char *argv
[]);
42 struct grub_rescue_command
*next
;
44 typedef struct grub_rescue_command
*grub_rescue_command_t
;
46 static char linebuf
[GRUB_RESCUE_BUF_SIZE
];
48 static grub_rescue_command_t grub_rescue_command_list
;
51 grub_rescue_register_command (const char *name
,
52 void (*func
) (int argc
, char *argv
[]),
55 grub_rescue_command_t cmd
;
57 cmd
= (grub_rescue_command_t
) grub_malloc (sizeof (*cmd
));
63 cmd
->message
= message
;
65 cmd
->next
= grub_rescue_command_list
;
66 grub_rescue_command_list
= cmd
;
70 grub_rescue_unregister_command (const char *name
)
72 grub_rescue_command_t
*p
, q
;
74 for (p
= &grub_rescue_command_list
, q
= *p
; q
; p
= &(q
->next
), q
= q
->next
)
75 if (grub_strcmp (name
, q
->name
) == 0)
83 /* Prompt to input a command and read the line. */
85 grub_rescue_get_command_line (const char *prompt
)
91 grub_memset (linebuf
, 0, GRUB_RESCUE_BUF_SIZE
);
93 while ((c
= GRUB_TERM_ASCII_CHAR (grub_getkey ())) != '\n' && c
!= '\r')
97 if (pos
< GRUB_RESCUE_BUF_SIZE
- 1)
122 grub_rescue_cmd_boot (int argc
__attribute__ ((unused
)),
123 char *argv
[] __attribute__ ((unused
)))
130 grub_rescue_cmd_cat (int argc
, char *argv
[])
133 char buf
[GRUB_DISK_SECTOR_SIZE
];
138 grub_error (GRUB_ERR_BAD_ARGUMENT
, "no file specified");
142 file
= grub_file_open (argv
[0]);
146 while ((size
= grub_file_read (file
, buf
, sizeof (buf
))) > 0)
150 for (i
= 0; i
< size
; i
++)
152 unsigned char c
= buf
[i
];
154 if ((grub_isprint (c
) || grub_isspace (c
)) && c
!= '\r')
158 grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT
);
159 grub_printf ("<%x>", (int) c
);
160 grub_setcolorstate (GRUB_TERM_COLOR_STANDARD
);
167 grub_file_close (file
);
171 grub_rescue_print_devices (const char *name
)
173 grub_printf ("(%s) ", name
);
179 grub_rescue_print_files (const char *filename
, int dir
)
181 grub_printf ("%s%s ", filename
, dir
? "/" : "");
188 grub_rescue_cmd_ls (int argc
, char *argv
[])
192 grub_device_iterate (grub_rescue_print_devices
);
203 device_name
= grub_file_get_device_name (argv
[0]);
204 dev
= grub_device_open (device_name
);
208 fs
= grub_fs_probe (dev
);
209 path
= grub_strchr (argv
[0], ')');
215 if (! path
&& ! device_name
)
217 grub_error (GRUB_ERR_BAD_ARGUMENT
, "invalid argument");
223 if (grub_errno
== GRUB_ERR_UNKNOWN_FS
)
224 grub_errno
= GRUB_ERR_NONE
;
226 grub_printf ("(%s): Filesystem is %s.\n",
227 device_name
, fs
? fs
->name
: "unknown");
231 (fs
->dir
) (dev
, path
, grub_rescue_print_files
);
238 grub_device_close (dev
);
240 grub_free (device_name
);
246 grub_rescue_cmd_help (int argc
__attribute__ ((unused
)),
247 char *argv
[] __attribute__ ((unused
)))
249 grub_rescue_command_t p
, q
;
251 /* Sort the commands. This is not a good algorithm, but this is enough,
252 because rescue mode has a small number of commands. */
253 for (p
= grub_rescue_command_list
; p
; p
= p
->next
)
254 for (q
= p
->next
; q
; q
= q
->next
)
255 if (grub_strcmp (p
->name
, q
->name
) > 0)
257 struct grub_rescue_command tmp
;
261 tmp
.message
= p
->message
;
265 p
->message
= q
->message
;
269 q
->message
= tmp
.message
;
273 for (p
= grub_rescue_command_list
; p
; p
= p
->next
)
274 grub_printf ("%s\t%s\n", p
->name
, p
->message
);
279 grub_rescue_cmd_info (void)
281 extern void grub_disk_cache_get_performance (unsigned long *,
283 unsigned long hits
, misses
;
285 grub_disk_cache_get_performance (&hits
, &misses
);
286 grub_printf ("Disk cache: hits = %u, misses = %u ", hits
, misses
);
289 unsigned long ratio
= hits
* 10000 / (hits
+ misses
);
290 grub_printf ("(%u.%u%%)\n", ratio
/ 100, ratio
% 100);
293 grub_printf ("(N/A)\n");
299 grub_rescue_cmd_root (int argc
, char *argv
[])
306 char *device_name
= grub_file_get_device_name (argv
[0]);
310 grub_env_set ("root", device_name
);
311 grub_free (device_name
);
314 dev
= grub_device_open (0);
318 fs
= grub_fs_probe (dev
);
319 if (grub_errno
== GRUB_ERR_UNKNOWN_FS
)
320 grub_errno
= GRUB_ERR_NONE
;
322 grub_printf ("(%s): Filesystem is %s.\n",
323 grub_env_get ("root"), fs
? fs
->name
: "unknown");
325 grub_device_close (dev
);
330 grub_rescue_cmd_testload (int argc
, char *argv
[])
336 auto void read_func (unsigned long sector
, unsigned offset
, unsigned len
);
338 void read_func (unsigned long sector
__attribute__ ((unused
)),
339 unsigned offset
__attribute__ ((unused
)),
340 unsigned len
__attribute__ ((unused
)))
348 grub_error (GRUB_ERR_BAD_ARGUMENT
, "no file specified");
352 file
= grub_file_open (argv
[0]);
356 size
= grub_file_size (file
) & ~(GRUB_DISK_SECTOR_SIZE
- 1);
359 grub_file_close (file
);
363 buf
= grub_malloc (size
);
367 grub_printf ("Reading %s sequentially", argv
[0]);
368 file
->read_hook
= read_func
;
369 if (grub_file_read (file
, buf
, size
) != size
)
371 grub_printf (" Done.\n");
373 /* Read sequentially again. */
374 grub_printf ("Reading %s sequentially again", argv
[0]);
375 if (grub_file_seek (file
, 0) < 0)
378 for (pos
= 0; pos
< size
; pos
+= GRUB_DISK_SECTOR_SIZE
)
380 char sector
[GRUB_DISK_SECTOR_SIZE
];
382 if (grub_file_read (file
, sector
, GRUB_DISK_SECTOR_SIZE
)
383 != GRUB_DISK_SECTOR_SIZE
)
386 if (grub_memcmp (sector
, buf
+ pos
, GRUB_DISK_SECTOR_SIZE
) != 0)
388 grub_printf ("\nDiffers in %d\n", pos
);
392 grub_printf (" Done.\n");
394 /* Read backwards and compare. */
395 grub_printf ("Reading %s backwards", argv
[0]);
399 char sector
[GRUB_DISK_SECTOR_SIZE
];
401 pos
-= GRUB_DISK_SECTOR_SIZE
;
403 if (grub_file_seek (file
, pos
) < 0)
406 if (grub_file_read (file
, sector
, GRUB_DISK_SECTOR_SIZE
)
407 != GRUB_DISK_SECTOR_SIZE
)
410 if (grub_memcmp (sector
, buf
+ pos
, GRUB_DISK_SECTOR_SIZE
) != 0)
414 grub_printf ("\nDiffers in %d\n", pos
);
416 for (i
= 0; i
< GRUB_DISK_SECTOR_SIZE
; i
++)
417 grub_putchar (buf
[pos
+ i
]);
425 grub_printf (" Done.\n");
429 grub_file_close (file
);
434 /* dump ADDRESS [SIZE] */
436 grub_rescue_cmd_dump (int argc
, char *argv
[])
439 grub_size_t size
= 4;
443 grub_error (GRUB_ERR_BAD_ARGUMENT
, "no address specified");
447 addr
= (grub_uint8_t
*) grub_strtoul (argv
[0], 0, 0);
452 size
= (grub_size_t
) grub_strtoul (argv
[1], 0, 0);
456 grub_printf ("%x%x ", *addr
>> 4, *addr
& 0xf);
463 grub_rescue_cmd_insmod (int argc
, char *argv
[])
470 grub_error (GRUB_ERR_BAD_ARGUMENT
, "no module specified");
474 p
= grub_strchr (argv
[0], '/');
476 mod
= grub_dl_load (argv
[0]);
478 mod
= grub_dl_load_file (argv
[0]);
486 grub_rescue_cmd_rmmod (int argc
, char *argv
[])
492 grub_error (GRUB_ERR_BAD_ARGUMENT
, "no module specified");
496 mod
= grub_dl_get (argv
[0]);
499 grub_error (GRUB_ERR_BAD_ARGUMENT
, "no such module");
503 if (grub_dl_unref (mod
) <= 0)
504 grub_dl_unload (mod
);
509 grub_rescue_cmd_lsmod (int argc
__attribute__ ((unused
)),
510 char *argv
[] __attribute__ ((unused
)))
512 auto int print_module (grub_dl_t mod
);
514 int print_module (grub_dl_t mod
)
518 grub_printf ("%s\t%d\t\t", mod
->name
, mod
->ref_count
);
519 for (dep
= mod
->dep
; dep
; dep
= dep
->next
)
524 grub_printf ("%s", dep
->mod
->name
);
532 grub_printf ("Name\tRef Count\tDependencies\n");
533 grub_dl_iterate (print_module
);
536 /* set ENVVAR=VALUE */
538 grub_rescue_cmd_set (int argc
, char *argv
[])
543 auto int print_env (struct grub_env_var
*env
);
545 int print_env (struct grub_env_var
*env
)
547 grub_printf ("%s=%s\n", env
->name
, env
->value
);
553 grub_env_iterate (print_env
);
558 val
= grub_strchr (var
, '=');
561 grub_error (GRUB_ERR_BAD_ARGUMENT
, "not an assignment");
566 grub_env_set (var
, val
+ 1);
571 grub_rescue_cmd_unset (int argc
, char *argv
[])
575 grub_error (GRUB_ERR_BAD_ARGUMENT
, "no environment variable specified");
579 grub_env_unset (argv
[0]);
584 grub_rescue_cmd_exit (int argc
__attribute__ ((unused
)),
585 char *argv
[] __attribute__ ((unused
)))
591 attempt_normal_mode (void)
593 grub_rescue_command_t cmd
;
595 for (cmd
= grub_rescue_command_list
; cmd
; cmd
= cmd
->next
)
597 if (grub_strcmp ("normal", cmd
->name
) == 0)
605 /* Enter the rescue mode. */
607 grub_enter_rescue_mode (void)
609 auto grub_err_t
getline (char **line
);
611 grub_err_t
getline (char **line
)
613 grub_rescue_get_command_line ("> ");
618 /* First of all, attempt to execute the normal mode. */
619 attempt_normal_mode ();
621 grub_printf ("Entering rescue mode...\n");
623 grub_rescue_register_command ("boot", grub_rescue_cmd_boot
,
624 "boot an operating system");
625 grub_rescue_register_command ("cat", grub_rescue_cmd_cat
,
626 "show the contents of a file");
627 grub_rescue_register_command ("help", grub_rescue_cmd_help
,
628 "show this message");
629 grub_rescue_register_command ("ls", grub_rescue_cmd_ls
,
630 "list devices or files");
631 grub_rescue_register_command ("root", grub_rescue_cmd_root
,
632 "set the root device");
633 grub_rescue_register_command ("dump", grub_rescue_cmd_dump
,
635 grub_rescue_register_command ("insmod", grub_rescue_cmd_insmod
,
637 grub_rescue_register_command ("rmmod", grub_rescue_cmd_rmmod
,
639 grub_rescue_register_command ("lsmod", grub_rescue_cmd_lsmod
,
640 "show loaded modules");
641 grub_rescue_register_command ("set", grub_rescue_cmd_set
,
642 "set an environment variable");
643 grub_rescue_register_command ("unset", grub_rescue_cmd_unset
,
644 "remove an environment variable");
645 grub_rescue_register_command ("exit", grub_rescue_cmd_exit
,
650 char *line
= linebuf
;
653 grub_rescue_command_t cmd
;
656 /* Print an error, if any. */
658 grub_errno
= GRUB_ERR_NONE
;
660 /* Get a command line. */
661 grub_rescue_get_command_line ("grub rescue> ");
665 if (grub_parser_split_cmdline (line
, getline
, &n
, &args
) || n
< 0)
668 /* In case of an assignment set the environment accordingly
669 instead of calling a function. */
670 if (n
== 0 && grub_strchr (line
, '='))
672 char *val
= grub_strchr (args
[0], '=');
674 grub_env_set (args
[0], val
+ 1);
680 /* Get the command name. */
683 /* If nothing is specified, restart. */
690 /* Find the command and execute it. */
691 for (cmd
= grub_rescue_command_list
; cmd
; cmd
= cmd
->next
)
693 if (grub_strcmp (name
, cmd
->name
) == 0)
695 (cmd
->func
) (n
, &args
[1]);
700 /* If not found, print an error message. */
703 grub_printf ("Unknown command `%s'\n", name
);
704 grub_printf ("Try `help' for usage\n");