1 /* rescue.c - rescue mode */
3 * PUPA -- Preliminary Universal Programming Architecture for GRUB
4 * Copyright (C) 2002, 2003 Free Software Foundation, Inc.
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.
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.
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.
21 #include <pupa/kernel.h>
22 #include <pupa/rescue.h>
23 #include <pupa/term.h>
24 #include <pupa/misc.h>
25 #include <pupa/disk.h>
26 #include <pupa/file.h>
29 #include <pupa/loader.h>
31 #include <pupa/machine/partition.h>
34 #define PUPA_RESCUE_BUF_SIZE 256
35 #define PUPA_RESCUE_MAX_ARGS 20
37 struct pupa_rescue_command
40 void (*func
) (int argc
, char *argv
[]);
42 struct pupa_rescue_command
*next
;
44 typedef struct pupa_rescue_command
*pupa_rescue_command_t
;
46 static char linebuf
[PUPA_RESCUE_BUF_SIZE
];
48 static pupa_rescue_command_t pupa_rescue_command_list
;
51 pupa_rescue_register_command (const char *name
,
52 void (*func
) (int argc
, char *argv
[]),
55 pupa_rescue_command_t cmd
;
57 cmd
= (pupa_rescue_command_t
) pupa_malloc (sizeof (*cmd
));
63 cmd
->message
= message
;
65 cmd
->next
= pupa_rescue_command_list
;
66 pupa_rescue_command_list
= cmd
;
70 pupa_rescue_unregister_command (const char *name
)
72 pupa_rescue_command_t
*p
, q
;
74 for (p
= &pupa_rescue_command_list
, q
= *p
; q
; p
= &(q
->next
), q
= q
->next
)
75 if (pupa_strcmp (name
, q
->name
) == 0)
83 /* Prompt to input a command and read the line. */
85 pupa_rescue_get_command_line (const char *prompt
)
91 pupa_memset (linebuf
, 0, PUPA_RESCUE_BUF_SIZE
);
93 while ((c
= PUPA_TERM_ASCII_CHAR (pupa_getkey ())) != '\n' && c
!= '\r')
97 if (pos
< PUPA_RESCUE_BUF_SIZE
- 1)
122 pupa_rescue_cmd_boot (int argc
__attribute__ ((unused
)),
123 char *argv
[] __attribute__ ((unused
)))
130 pupa_rescue_cmd_cat (int argc
, char *argv
[])
133 char buf
[PUPA_DISK_SECTOR_SIZE
];
138 pupa_error (PUPA_ERR_BAD_ARGUMENT
, "no file specified");
142 file
= pupa_file_open (argv
[0]);
146 while ((size
= pupa_file_read (file
, buf
, sizeof (buf
))) > 0)
150 for (i
= 0; i
< size
; i
++)
152 unsigned char c
= buf
[i
];
154 if (pupa_isprint (c
) || pupa_isspace (c
))
158 pupa_setcolorstate (PUPA_TERM_COLOR_HIGHLIGHT
);
159 pupa_printf ("<%x>", (int) c
);
160 pupa_setcolorstate (PUPA_TERM_COLOR_STANDARD
);
167 pupa_file_close (file
);
171 pupa_rescue_print_disks (const char *name
)
174 auto int print_partition (const pupa_partition_t p
);
176 int print_partition (const pupa_partition_t p
)
178 char *pname
= pupa_partition_get_name (p
);
182 pupa_printf ("(%s,%s) ", name
, pname
);
189 dev
= pupa_device_open (name
);
190 pupa_errno
= PUPA_ERR_NONE
;
194 pupa_printf ("(%s) ", name
);
196 if (dev
->disk
&& dev
->disk
->has_partitions
)
198 pupa_partition_iterate (dev
->disk
, print_partition
);
199 pupa_errno
= PUPA_ERR_NONE
;
202 pupa_device_close (dev
);
209 pupa_rescue_print_files (const char *filename
, int dir
)
211 pupa_printf ("%s%s ", filename
, dir
? "/" : "");
218 pupa_rescue_cmd_ls (int argc
, char *argv
[])
222 pupa_disk_dev_iterate (pupa_rescue_print_disks
);
233 device_name
= pupa_file_get_device_name (argv
[0]);
234 dev
= pupa_device_open (device_name
);
238 fs
= pupa_fs_probe (dev
);
239 path
= pupa_strchr (argv
[0], '/');
241 if (! path
&& ! device_name
)
243 pupa_error (PUPA_ERR_BAD_ARGUMENT
, "invalid argument");
249 if (pupa_errno
== PUPA_ERR_UNKNOWN_FS
)
250 pupa_errno
= PUPA_ERR_NONE
;
252 pupa_printf ("(%s): Filesystem is %s.\n",
253 device_name
, fs
? fs
->name
: "unknown");
257 (fs
->dir
) (dev
, path
, pupa_rescue_print_files
);
264 pupa_device_close (dev
);
266 pupa_free (device_name
);
272 pupa_rescue_cmd_help (int argc
__attribute__ ((unused
)),
273 char *argv
[] __attribute__ ((unused
)))
275 pupa_rescue_command_t p
, q
;
277 /* Sort the commands. This is not a good algorithm, but this is enough,
278 because rescue mode has a small number of commands. */
279 for (p
= pupa_rescue_command_list
; p
; p
= p
->next
)
280 for (q
= p
->next
; q
; q
= q
->next
)
281 if (pupa_strcmp (p
->name
, q
->name
) > 0)
283 struct pupa_rescue_command tmp
;
287 tmp
.message
= p
->message
;
291 p
->message
= q
->message
;
295 q
->message
= tmp
.message
;
299 for (p
= pupa_rescue_command_list
; p
; p
= p
->next
)
300 pupa_printf ("%s\t%s\n", p
->name
, p
->message
);
305 pupa_rescue_cmd_info (void)
307 extern void pupa_disk_cache_get_performance (unsigned long *,
309 unsigned long hits
, misses
;
311 pupa_disk_cache_get_performance (&hits
, &misses
);
312 pupa_printf ("Disk cache: hits = %u, misses = %u ", hits
, misses
);
315 unsigned long ratio
= hits
* 10000 / (hits
+ misses
);
316 pupa_printf ("(%u.%u%%)\n", ratio
/ 100, ratio
% 100);
319 pupa_printf ("(N/A)\n");
325 pupa_rescue_cmd_root (int argc
, char *argv
[])
332 char *device_name
= pupa_file_get_device_name (argv
[0]);
336 pupa_device_set_root (device_name
);
337 pupa_free (device_name
);
340 dev
= pupa_device_open (0);
344 fs
= pupa_fs_probe (dev
);
345 if (pupa_errno
== PUPA_ERR_UNKNOWN_FS
)
346 pupa_errno
= PUPA_ERR_NONE
;
348 pupa_printf ("(%s): Filesystem is %s.\n",
349 pupa_device_get_root (), fs
? fs
->name
: "unknown");
351 pupa_device_close (dev
);
356 pupa_rescue_cmd_testload (int argc
, char *argv
[])
362 auto void read_func (unsigned long sector
, unsigned offset
, unsigned len
);
364 void read_func (unsigned long sector
__attribute__ ((unused
)),
365 unsigned offset
__attribute__ ((unused
)),
366 unsigned len
__attribute__ ((unused
)))
374 pupa_error (PUPA_ERR_BAD_ARGUMENT
, "no file specified");
378 file
= pupa_file_open (argv
[0]);
382 size
= pupa_file_size (file
) & ~(PUPA_DISK_SECTOR_SIZE
- 1);
385 pupa_file_close (file
);
389 buf
= pupa_malloc (size
);
393 pupa_printf ("Reading %s sequentially", argv
[0]);
394 file
->read_hook
= read_func
;
395 if (pupa_file_read (file
, buf
, size
) != size
)
397 pupa_printf (" Done.\n");
399 /* Read sequentially again. */
400 pupa_printf ("Reading %s sequentially again", argv
[0]);
401 if (pupa_file_seek (file
, 0) < 0)
404 for (pos
= 0; pos
< size
; pos
+= PUPA_DISK_SECTOR_SIZE
)
406 char sector
[PUPA_DISK_SECTOR_SIZE
];
408 if (pupa_file_read (file
, sector
, PUPA_DISK_SECTOR_SIZE
)
409 != PUPA_DISK_SECTOR_SIZE
)
412 if (pupa_memcmp (sector
, buf
+ pos
, PUPA_DISK_SECTOR_SIZE
) != 0)
414 pupa_printf ("\nDiffers in %d\n", pos
);
418 pupa_printf (" Done.\n");
420 /* Read backwards and compare. */
421 pupa_printf ("Reading %s backwards", argv
[0]);
425 char sector
[PUPA_DISK_SECTOR_SIZE
];
427 pos
-= PUPA_DISK_SECTOR_SIZE
;
429 if (pupa_file_seek (file
, pos
) < 0)
432 if (pupa_file_read (file
, sector
, PUPA_DISK_SECTOR_SIZE
)
433 != PUPA_DISK_SECTOR_SIZE
)
436 if (pupa_memcmp (sector
, buf
+ pos
, PUPA_DISK_SECTOR_SIZE
) != 0)
440 pupa_printf ("\nDiffers in %d\n", pos
);
442 for (i
= 0; i
< PUPA_DISK_SECTOR_SIZE
; i
++)
443 pupa_putchar (buf
[pos
+ i
]);
451 pupa_printf (" Done.\n");
455 pupa_file_close (file
);
460 /* dump ADDRESS [SIZE] */
462 pupa_rescue_cmd_dump (int argc
, char *argv
[])
465 pupa_size_t size
= 4;
469 pupa_error (PUPA_ERR_BAD_ARGUMENT
, "no address specified");
473 addr
= (pupa_uint8_t
*) pupa_strtoul (argv
[0], 0, 0);
478 size
= (pupa_size_t
) pupa_strtoul (argv
[1], 0, 0);
482 pupa_printf ("%x%x ", *addr
>> 4, *addr
& 0xf);
489 pupa_rescue_cmd_insmod (int argc
, char *argv
[])
496 pupa_error (PUPA_ERR_BAD_ARGUMENT
, "no module specified");
500 p
= pupa_strchr (argv
[0], '/');
502 mod
= pupa_dl_load (argv
[0]);
504 mod
= pupa_dl_load_file (argv
[0]);
512 pupa_rescue_cmd_rmmod (int argc
, char *argv
[])
518 pupa_error (PUPA_ERR_BAD_ARGUMENT
, "no module specified");
522 mod
= pupa_dl_get (argv
[0]);
525 pupa_error (PUPA_ERR_BAD_ARGUMENT
, "no such module");
529 if (! pupa_dl_unref (mod
))
530 pupa_dl_unload (mod
);
535 pupa_rescue_cmd_lsmod (int argc
__attribute__ ((unused
)),
536 char *argv
[] __attribute__ ((unused
)))
538 auto int print_module (pupa_dl_t mod
);
540 int print_module (pupa_dl_t mod
)
544 pupa_printf ("%s\t%d\t\t", mod
->name
, mod
->ref_count
);
545 for (dep
= mod
->dep
; dep
; dep
= dep
->next
)
550 pupa_printf ("%s", dep
->mod
->name
);
558 pupa_printf ("Name\tRef Count\tDependencies\n");
559 pupa_dl_iterate (print_module
);
562 /* set ENVVAR=VALUE */
564 pupa_rescue_cmd_set (int argc
, char *argv
[])
569 auto int print_env (struct pupa_env_var
*env
);
571 int print_env (struct pupa_env_var
*env
)
573 pupa_printf ("%s=%s\n", env
->name
, env
->value
);
579 pupa_env_iterate (print_env
);
584 val
= pupa_strchr (var
, '=');
587 pupa_error (PUPA_ERR_BAD_ARGUMENT
, "not an assignment");
592 pupa_env_set (var
, val
+ 1);
597 pupa_rescue_cmd_unset (int argc
, char *argv
[])
601 pupa_error (PUPA_ERR_BAD_ARGUMENT
, "no environment variable specified");
605 pupa_env_unset (argv
[0]);
609 attempt_normal_mode (void)
611 pupa_rescue_command_t cmd
;
613 for (cmd
= pupa_rescue_command_list
; cmd
; cmd
= cmd
->next
)
615 if (pupa_strcmp ("normal", cmd
->name
) == 0)
623 /* Enter the rescue mode. */
625 pupa_enter_rescue_mode (void)
627 auto pupa_err_t
getline (char **line
);
629 pupa_err_t
getline (char **line
)
631 pupa_rescue_get_command_line ("> ");
636 /* First of all, attempt to execute the normal mode. */
637 attempt_normal_mode ();
639 pupa_printf ("Entering into rescue mode...\n");
641 pupa_rescue_register_command ("boot", pupa_rescue_cmd_boot
,
642 "boot an operating system");
643 pupa_rescue_register_command ("cat", pupa_rescue_cmd_cat
,
644 "show the contents of a file");
645 pupa_rescue_register_command ("help", pupa_rescue_cmd_help
,
646 "show this message");
647 pupa_rescue_register_command ("ls", pupa_rescue_cmd_ls
,
648 "list devices or files");
649 pupa_rescue_register_command ("root", pupa_rescue_cmd_root
,
650 "set the root device");
651 pupa_rescue_register_command ("dump", pupa_rescue_cmd_dump
,
653 pupa_rescue_register_command ("insmod", pupa_rescue_cmd_insmod
,
655 pupa_rescue_register_command ("rmmod", pupa_rescue_cmd_rmmod
,
657 pupa_rescue_register_command ("lsmod", pupa_rescue_cmd_lsmod
,
658 "show loaded modules");
659 pupa_rescue_register_command ("set", pupa_rescue_cmd_set
,
660 "set an environment variable");
661 pupa_rescue_register_command ("unset", pupa_rescue_cmd_unset
,
662 "remove an environment variable");
666 char *line
= linebuf
;
669 pupa_rescue_command_t cmd
;
672 /* Print an error, if any. */
674 pupa_errno
= PUPA_ERR_NONE
;
676 /* Get a command line. */
677 pupa_rescue_get_command_line ("pupa rescue> ");
679 if (pupa_split_cmdline (line
, getline
, &n
, &args
))
682 /* In case of an assignment set the environment accordingly
683 instead of calling a function. */
684 if (n
== 0 && pupa_strchr (line
, '='))
686 char *val
= pupa_strchr (args
[0], '=');
688 pupa_env_set (args
[0], val
+ 1);
693 /* Get the command name. */
696 /* If nothing is specified, restart. */
700 /* Find the command and execute it. */
701 for (cmd
= pupa_rescue_command_list
; cmd
; cmd
= cmd
->next
)
703 if (pupa_strcmp (name
, cmd
->name
) == 0)
705 (cmd
->func
) (n
, &args
[1]);
710 /* If not found, print an error message. */
713 pupa_printf ("Unknown command `%s'\n", name
);
714 pupa_printf ("Try `help' for usage\n");