/* execute.c -- Execute a GRUB script. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2005,2007,2008,2009,2010 Free Software Foundation, Inc.
*
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/script_sh.h>
/* Max digits for a char is 3 (0xFF is 255), similarly for an int it
is sizeof (int) * 3, and one extra for a possible -ve sign. */
static unsigned long is_continue;
static unsigned long active_loops;
static unsigned long active_breaks;
static unsigned long function_return;
/* Scope for grub script functions. */
struct grub_script_scope
{
unsigned flags;
unsigned shifts;
};
/* Wildcard translator for GRUB script. */
static void
{
if (scope)
{
}
}
{
char *p = 0;
unsigned long count;
if (argc == 0)
count = 1;
(*p != '\0'))
if (active_breaks > active_loops)
return GRUB_ERR_NONE;
}
{
char *p = 0;
unsigned long n = 0;
if (! scope)
return GRUB_ERR_NONE;
if (argc == 0)
n = 1;
else if (argc > 1)
return GRUB_ERR_BAD_ARGUMENT;
else
{
if (*p != '\0')
return GRUB_ERR_BAD_ARGUMENT;
}
return GRUB_ERR_BAD_ARGUMENT;
return GRUB_ERR_NONE;
}
{
if (! scope)
return GRUB_ERR_INVALID_COMMAND;
if (! new_scope)
return grub_errno;
{
return grub_errno;
}
return GRUB_ERR_NONE;
}
{
char *p;
unsigned long n;
if (argc == 0)
{
function_return = 1;
}
if (*p != '\0')
function_return = 1;
}
static int
{
if (grub_isdigit (name[0]) ||
return 1;
return 0;
}
static char **
{
unsigned i;
if (grub_script_argv_next (&result))
goto fail;
if (! grub_env_special (name))
{
const char *v = grub_env_get (name);
if (v && v[0])
{
if (type == GRUB_SCRIPT_ARG_TYPE_VAR)
{
if (grub_script_argv_split_append (&result, v))
goto fail;
}
else
goto fail;
}
}
else if (! scope)
{
if (grub_script_argv_append (&result, 0, 0))
goto fail;
}
{
goto fail;
}
{
if (type == GRUB_SCRIPT_ARG_TYPE_VAR)
{
if (i != 0 && grub_script_argv_next (&result))
goto fail;
goto fail;
}
else
{
goto fail;
goto fail;
}
}
{
{
if (i != 0 && grub_script_argv_next (&result))
goto fail;
if (type == GRUB_SCRIPT_ARG_TYPE_VAR)
{
goto fail;
}
else
goto fail;
}
}
else
{
if (num == 0)
; /* XXX no file name, for now. */
{
if (type == GRUB_SCRIPT_ARG_TYPE_VAR)
{
goto fail;
}
else
))
goto fail;
}
}
fail:
return 0;
}
static grub_err_t
{
if (grub_env_special (name))
}
/* Convert arguments in ARGLIST into ARGV form. */
static int
struct grub_script_argv *argv)
{
int i;
char **values = 0;
{
int r;
char *p = 0;
if (! grub_wildcard_translator || escape_type == 0)
if (escape_type > 0)
p = grub_wildcard_translator->escape (s);
else if (escape_type < 0)
p = grub_wildcard_translator->unescape (s);
if (! p)
return 1;
grub_free (p);
return r;
}
{
if (grub_script_argv_next (&result))
goto fail;
while (arg)
{
{
case GRUB_SCRIPT_ARG_TYPE_VAR:
{
if (i != 0 && grub_script_argv_next (&result))
goto fail;
{
grub_strlen (values[i])))
goto fail;
}
else
{
goto fail;
}
}
break;
goto fail;
break;
goto fail;
break;
goto fail;
break;
}
}
}
/* Perform wildcard expansion. */
{
int j;
int failed = 0;
char **expansions = 0;
for (i = 0; unexpanded.args[i]; i++)
{
&expansions))
{
goto fail;
}
if (! expansions)
{
}
else
{
for (j = 0; expansions[j]; j++)
{
grub_free (expansions[j]);
}
if (failed)
{
goto fail;
}
}
}
}
return 0;
fail:
return 1;
}
static grub_err_t
{
int ret;
extern int grub_more, real_grub_more;
if (cmd == 0)
return 0;
return ret;
}
/* Execute a function call. */
{
active_loops = 0;
function_return = 0;
return ret;
}
/* Execute a source script. */
{
{
const char *p;
if (! source)
{
*line = 0;
return 0;
}
if (p)
else
source = p ? p + 1 : 0;
return 0;
}
while (source)
{
char *line;
if (! parsed_script)
{
ret = grub_errno;
break;
}
}
return ret;
}
/* Execute a single command line. */
{
char *cmdname;
int argc;
char **args;
int invert;
/* Lookup the command. */
return grub_errno;
invert = 0;
{
{
}
invert = 1;
}
if (! grubcmd)
{
/* It's not a GRUB command, try all functions. */
if (! func)
{
/* As a last resort, try if it is an assignment. */
if (eq)
{
/* This was set because the command was not found. */
/* Create two strings and set the variable. */
*eq = '\0';
eq++;
}
grub_print_error ();
return 0;
}
}
/* Execute the GRUB command or function. */
if (grubcmd)
{
"%s isn't allowed to execute in an extractor",
cmdname);
else
}
else
if (invert)
{
if (ret == GRUB_ERR_TEST_FAILURE)
else if (ret == GRUB_ERR_NONE)
else
{
grub_print_error ();
ret = GRUB_ERR_NONE;
}
}
/* Free arguments. */
if (grub_errno == GRUB_ERR_TEST_FAILURE)
grub_print_error ();
return ret;
}
/* Execute a block of one or more commands. */
{
int ret = 0;
/* Loop over every command and execute it. */
{
if (active_breaks)
break;
if (function_return)
break;
}
return ret;
}
/* Execute an if statement. */
{
int ret;
const char *result;
/* Check if the commands results in a true or a false. The value is
read from the env variable `?'. */
if (function_return)
return ret;
/* Execute the `if' or the `else' part depending on the value of
`?'. */
else
}
/* Execute a for statement. */
{
unsigned i;
return grub_errno;
active_loops++;
result = 0;
{
active_breaks = 0;
if (! active_breaks)
{
if (function_return)
break;
}
}
if (active_breaks)
active_loops--;
return result;
}
/* Execute a "while" or "until" command. */
{
int result;
active_loops++;
do {
if (function_return)
break;
break;
if (function_return)
break;
active_breaks = 0;
if (active_breaks)
break;
} while (1); /* XXX Put a check for ^C here */
if (active_breaks)
active_loops--;
return result;
}
/* Execute any GRUB pre-parsed command or script. */
{
if (script == 0)
return 0;
}