1N/A/* cmdline.c - the device-independent GRUB text command line */
1N/A/*
1N/A * GRUB -- GRand Unified Bootloader
1N/A * Copyright (C) 1999,2000,2001,2002,2004 Free Software Foundation, Inc.
1N/A *
1N/A * This program is free software; you can redistribute it and/or modify
1N/A * it under the terms of the GNU General Public License as published by
1N/A * the Free Software Foundation; either version 2 of the License, or
1N/A * (at your option) any later version.
1N/A *
1N/A * This program is distributed in the hope that it will be useful,
1N/A * but WITHOUT ANY WARRANTY; without even the implied warranty of
1N/A * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1N/A * GNU General Public License for more details.
1N/A *
1N/A * You should have received a copy of the GNU General Public License
1N/A * along with this program; if not, write to the Free Software
1N/A * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
1N/A */
1N/A
1N/A#include <shared.h>
1N/A#include <term.h>
1N/A
1N/Aextern struct term_entry *current_term;
1N/A
1N/A#ifdef SUPPORT_DISKLESS
1N/A# include <grub.h>
1N/A#endif
1N/A
1N/Agrub_jmp_buf restart_cmdline_env;
1N/A
1N/A/* Find the next word from CMDLINE and return the pointer. If
1N/A AFTER_EQUAL is non-zero, assume that the character `=' is treated as
1N/A a space. Caution: this assumption is for backward compatibility. */
1N/Achar *
1N/Askip_to (int after_equal, char *cmdline)
1N/A{
1N/A /* Skip until we hit whitespace, or maybe an equal sign. */
1N/A while (*cmdline && *cmdline != ' ' && *cmdline != '\t' &&
1N/A ! (after_equal && *cmdline == '='))
1N/A cmdline ++;
1N/A
1N/A /* Skip whitespace, and maybe equal signs. */
1N/A while (*cmdline == ' ' || *cmdline == '\t' ||
1N/A (after_equal && *cmdline == '='))
1N/A cmdline ++;
1N/A
1N/A return cmdline;
1N/A}
1N/A
1N/A/* Print a helpful message for the command-line interface. */
1N/Avoid
1N/Aprint_cmdline_message (int forever)
1N/A{
1N/A printf (" [ Minimal BASH-like line editing is supported. For the first word, TAB\n"
1N/A " lists possible command completions. Anywhere else TAB lists the possible\n"
1N/A " completions of a device/filename.%s ]\n",
1N/A (forever ? "" : " ESC at any time exits."));
1N/A}
1N/A
1N/A/* Find the builtin whose command name is COMMAND and return the
1N/A pointer. If not found, return 0. */
1N/Astruct builtin *
1N/Afind_command (char *command)
1N/A{
1N/A char *ptr;
1N/A char c;
1N/A struct builtin **builtin;
1N/A
1N/A /* Find the first space and terminate the command name. */
1N/A ptr = command;
1N/A while (*ptr && *ptr != ' ' && *ptr != '\t' && *ptr != '=')
1N/A ptr ++;
1N/A
1N/A c = *ptr;
1N/A *ptr = 0;
1N/A
1N/A /* Seek out the builtin whose command name is COMMAND. */
1N/A for (builtin = builtin_table; *builtin != 0; builtin++)
1N/A {
1N/A int ret = grub_strcmp (command, (*builtin)->name);
1N/A
1N/A if (ret == 0)
1N/A {
1N/A /* Find the builtin for COMMAND. */
1N/A *ptr = c;
1N/A return *builtin;
1N/A }
1N/A else if (ret < 0)
1N/A break;
1N/A }
1N/A
1N/A /* Cannot find COMMAND. */
1N/A errnum = ERR_UNRECOGNIZED;
1N/A *ptr = c;
1N/A return 0;
1N/A}
1N/A
1N/A/* Initialize the data for the command-line. */
1N/Astatic void
1N/Ainit_cmdline (void)
1N/A{
1N/A /* Initialization. */
1N/A saved_drive = boot_drive;
1N/A saved_partition = install_partition;
1N/A current_drive = GRUB_INVALID_DRIVE;
1N/A errnum = 0;
1N/A count_lines = -1;
1N/A
1N/A /* Restore memory probe state. */
1N/A mbi.mem_upper = saved_mem_upper;
1N/A if (mbi.mmap_length)
1N/A mbi.flags |= MB_INFO_MEM_MAP;
1N/A
1N/A /* Initialize the data for the builtin commands. */
1N/A init_builtins ();
1N/A}
1N/A
1N/A/* Enter the command-line interface. HEAP is used for the command-line
1N/A buffer. Return only if FOREVER is nonzero and get_cmdline returns
1N/A nonzero (ESC is pushed). */
1N/Avoid
1N/Aenter_cmdline (char *heap, int forever)
1N/A{
1N/A /* Initialize the data and print a message. */
1N/A init_cmdline ();
1N/A grub_setjmp (restart_cmdline_env);
1N/A init_page ();
1N/A#ifdef SUPPORT_DISKLESS
1N/A print_network_configuration ();
1N/A grub_putchar ('\n');
1N/A#endif
1N/A print_cmdline_message (forever);
1N/A
1N/A while (1)
1N/A {
1N/A struct builtin *builtin;
1N/A char *arg;
1N/A
1N/A *heap = 0;
1N/A print_error ();
1N/A errnum = ERR_NONE;
1N/A
1N/A /* Get the command-line with the minimal BASH-like interface. */
1N/A if (get_cmdline (PACKAGE "> ", heap, 2048, 0, 1))
1N/A return;
1N/A
1N/A /* If there was no command, grab a new one. */
1N/A if (! heap[0])
1N/A continue;
1N/A
1N/A /* Find a builtin. */
1N/A builtin = find_command (heap);
1N/A if (! builtin)
1N/A continue;
1N/A
1N/A /* If BUILTIN cannot be run in the command-line, skip it. */
1N/A if (! (builtin->flags & BUILTIN_CMDLINE))
1N/A {
1N/A errnum = ERR_UNRECOGNIZED;
1N/A continue;
1N/A }
1N/A
1N/A /* Invalidate the cache, because the user may exchange removable
1N/A disks. */
1N/A buf_drive = -1;
1N/A
1N/A /* Start to count lines, only if the internal pager is in use. */
1N/A if (use_pager)
1N/A count_lines = 0;
1N/A
1N/A /* Run BUILTIN->FUNC. */
1N/A arg = skip_to (1, heap);
1N/A (builtin->func) (arg, BUILTIN_CMDLINE);
1N/A
1N/A /* Finish the line count. */
1N/A count_lines = -1;
1N/A }
1N/A}
1N/A
1N/A/* Run an entry from the script SCRIPT. HEAP is used for the
1N/A command-line buffer. If an error occurs, return non-zero, otherwise
1N/A return zero. */
1N/Aint
1N/Arun_script (char *script, char *heap)
1N/A{
1N/A char *old_entry;
1N/A char *cur_entry = script;
1N/A
1N/A /* Initialize the data. */
1N/A init_cmdline ();
1N/A
1N/A while (1)
1N/A {
1N/A struct builtin *builtin;
1N/A char *arg;
1N/A
1N/A print_error ();
1N/A
1N/A if (errnum)
1N/A {
1N/A errnum = ERR_NONE;
1N/A
1N/A /*
1N/A * At this point something must have gone wrong, so dump the
1N/A * buffer and flip output back on.
1N/A */
1N/A builtin = find_command("verbose");
1N/A (builtin->func) ("on", BUILTIN_SCRIPT);
1N/A
1N/A /* If a fallback entry is defined, don't prompt a user's
1N/A intervention. */
1N/A if (fallback_entryno < 0)
1N/A {
1N/A grub_printf ("\nPress any key to continue...");
1N/A (void) getkey ();
1N/A }
1N/A
1N/A return 1;
1N/A }
1N/A
1N/A /* Copy the first string in CUR_ENTRY to HEAP. */
1N/A old_entry = cur_entry;
1N/A while (*cur_entry++)
1N/A ;
1N/A
1N/A grub_memmove (heap, old_entry, (int) cur_entry - (int) old_entry);
1N/A if (! *heap)
1N/A {
1N/A /* If there is no more command in SCRIPT... */
1N/A
1N/A /* If any kernel is not loaded, just exit successfully. */
1N/A if (kernel_type == KERNEL_TYPE_NONE)
1N/A return 0;
1N/A
1N/A if (reset_term)
1N/A if (current_term->shutdown) {
1N/A (*current_term->shutdown)();
1N/A current_term = term_table; /* assumption: console is first */
1N/A }
1N/A
1N/A
1N/A /* Otherwise, the command boot is run implicitly. */
1N/A grub_memmove (heap, "boot", 5);
1N/A }
1N/A
1N/A /* Find a builtin. */
1N/A builtin = find_command (heap);
1N/A if (! builtin)
1N/A {
1N/A grub_printf ("%s\n", old_entry);
1N/A continue;
1N/A }
1N/A
1N/A if (! (builtin->flags & BUILTIN_NO_ECHO))
1N/A grub_printf ("%s\n", old_entry);
1N/A
1N/A /* If BUILTIN cannot be run in the command-line, skip it. */
1N/A if (! (builtin->flags & BUILTIN_CMDLINE))
1N/A {
1N/A errnum = ERR_UNRECOGNIZED;
1N/A continue;
1N/A }
1N/A
1N/A /* Invalidate the cache, because the user may exchange removable
1N/A disks. */
1N/A buf_drive = -1;
1N/A
1N/A /* Run BUILTIN->FUNC. */
1N/A arg = skip_to (1, heap);
1N/A (builtin->func) (arg, BUILTIN_SCRIPT);
1N/A }
1N/A}