mirror of
				https://git.proxmox.com/git/grub2
				synced 2025-11-04 09:14:22 +00:00 
			
		
		
		
	* script/sh/execute.c: Move from here ...
        * script/execute.c: ... to here.  Update all users.
        * script/sh/function.c: Move from here ...
        * script/function.c: ... to here.  Update all users.
        * script/sh/lexer.c: Move from here ...
        * script/lexer.c: ... to here.  Update all users.
        * script/sh/main.c: Move from here ...
        * script/main.c: ... to here.  Update all users.
        * script/sh/parser.y: Move from here ...
        * script/parser.y: ... to here.  Update all users.
        * script/sh/script.c: Move from here ...
        * script/script.c: ... to here.  Update all users.
		
	
			
		
			
				
	
	
		
			346 lines
		
	
	
		
			9.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			346 lines
		
	
	
		
			9.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* script.c -- Functions to create an in memory description of the script. */
 | 
						||
/*
 | 
						||
 *  GRUB  --  GRand Unified Bootloader
 | 
						||
 *  Copyright (C) 2005,2006,2007,2009  Free Software Foundation, Inc.
 | 
						||
 *
 | 
						||
 *  GRUB is free software: you can redistribute it and/or modify
 | 
						||
 *  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/misc.h>
 | 
						||
#include <grub/script_sh.h>
 | 
						||
#include <grub/parser.h>
 | 
						||
#include <grub/mm.h>
 | 
						||
 | 
						||
/* It is not possible to deallocate the memory when a syntax error was
 | 
						||
   found.  Because of that it is required to keep track of all memory
 | 
						||
   allocations.  The memory is freed in case of an error, or
 | 
						||
   assigned to the parsed script when parsing was successful.  */
 | 
						||
 | 
						||
/* XXX */
 | 
						||
 | 
						||
/* In case of the normal malloc, some additional bytes are allocated
 | 
						||
   for this datastructure.  All reserved memory is stored in a linked
 | 
						||
   list so it can be easily freed.  The original memory can be found
 | 
						||
   from &mem.  */
 | 
						||
struct grub_script_mem
 | 
						||
{
 | 
						||
  struct grub_script_mem *next;
 | 
						||
  char mem;
 | 
						||
};
 | 
						||
 | 
						||
/* Return malloc'ed memory and keep track of the allocation.  */
 | 
						||
void *
 | 
						||
grub_script_malloc (struct grub_parser_param *state, grub_size_t size)
 | 
						||
{
 | 
						||
  struct grub_script_mem *mem;
 | 
						||
  mem = (struct grub_script_mem *) grub_malloc (size + sizeof (*mem)
 | 
						||
						- sizeof (char));
 | 
						||
 | 
						||
  grub_dprintf ("scripting", "malloc %p\n", mem);
 | 
						||
  mem->next = state->memused;
 | 
						||
  state->memused = mem;
 | 
						||
  return (void *) &mem->mem;
 | 
						||
}
 | 
						||
 | 
						||
/* Free all memory described by MEM.  */
 | 
						||
static void
 | 
						||
grub_script_mem_free (struct grub_script_mem *mem)
 | 
						||
{
 | 
						||
  struct grub_script_mem *memfree;
 | 
						||
 | 
						||
  while (mem)
 | 
						||
    {
 | 
						||
      memfree = mem->next;
 | 
						||
      grub_dprintf ("scripting", "free %p\n", mem);
 | 
						||
      grub_free (mem);
 | 
						||
      mem = memfree;
 | 
						||
    }
 | 
						||
}
 | 
						||
 | 
						||
/* Start recording memory usage.  Returns the memory that should be
 | 
						||
   restored when calling stop.  */
 | 
						||
struct grub_script_mem *
 | 
						||
grub_script_mem_record (struct grub_parser_param *state)
 | 
						||
{
 | 
						||
  struct grub_script_mem *mem = state->memused;
 | 
						||
  state->memused = 0;
 | 
						||
 | 
						||
  return mem;
 | 
						||
}
 | 
						||
 | 
						||
/* Stop recording memory usage.  Restore previous recordings using
 | 
						||
   RESTORE.  Return the recorded memory.  */
 | 
						||
struct grub_script_mem *
 | 
						||
grub_script_mem_record_stop (struct grub_parser_param *state,
 | 
						||
			     struct grub_script_mem *restore)
 | 
						||
{
 | 
						||
  struct grub_script_mem *mem = state->memused;
 | 
						||
  state->memused = restore;
 | 
						||
  return mem;
 | 
						||
}
 | 
						||
 | 
						||
/* Free the memory reserved for CMD and all of it's children.  */
 | 
						||
void
 | 
						||
grub_script_free (struct grub_script *script)
 | 
						||
{
 | 
						||
  if (! script)
 | 
						||
    return;
 | 
						||
  grub_script_mem_free (script->mem);
 | 
						||
  grub_free (script);
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
 | 
						||
/* Extend the argument arg with a variable or string of text.  If ARG
 | 
						||
   is zero a new list is created.  */
 | 
						||
struct grub_script_arg *
 | 
						||
grub_script_arg_add (struct grub_parser_param *state, struct grub_script_arg *arg,
 | 
						||
		     grub_script_arg_type_t type, char *str)
 | 
						||
{
 | 
						||
  struct grub_script_arg *argpart;
 | 
						||
  struct grub_script_arg *ll;
 | 
						||
  int len;
 | 
						||
 | 
						||
  argpart = (struct grub_script_arg *) grub_script_malloc (state, sizeof (*arg));
 | 
						||
  argpart->type = type;
 | 
						||
  len = grub_strlen (str) + 1;
 | 
						||
  argpart->str = grub_script_malloc (state, len);
 | 
						||
  grub_memcpy (argpart->str, str, len);
 | 
						||
  argpart->next = 0;
 | 
						||
 | 
						||
  if (! arg)
 | 
						||
    return argpart;
 | 
						||
 | 
						||
  for (ll = arg; ll->next; ll = ll->next);
 | 
						||
  ll->next = argpart;
 | 
						||
 | 
						||
  return arg;
 | 
						||
}
 | 
						||
 | 
						||
/* Add the argument ARG to the end of the argument list LIST.  If LIST
 | 
						||
   is zero, a new list will be created.  */
 | 
						||
struct grub_script_arglist *
 | 
						||
grub_script_add_arglist (struct grub_parser_param *state,
 | 
						||
			 struct grub_script_arglist *list, struct grub_script_arg *arg)
 | 
						||
{
 | 
						||
  struct grub_script_arglist *link;
 | 
						||
  struct grub_script_arglist *ll;
 | 
						||
 | 
						||
  grub_dprintf ("scripting", "arglist\n");
 | 
						||
 | 
						||
  link = (struct grub_script_arglist *) grub_script_malloc (state, sizeof (*link));
 | 
						||
  link->next = 0;
 | 
						||
  link->arg = arg;
 | 
						||
  link->argcount = 0;
 | 
						||
 | 
						||
  if (! list)
 | 
						||
    {
 | 
						||
      link->argcount++;
 | 
						||
      return link;
 | 
						||
    }
 | 
						||
 | 
						||
  list->argcount++;
 | 
						||
 | 
						||
  /* Look up the last link in the chain.  */
 | 
						||
  for (ll = list; ll->next; ll = ll->next);
 | 
						||
  ll->next = link;
 | 
						||
 | 
						||
  return list;
 | 
						||
}
 | 
						||
 | 
						||
/* Create a command that describes a single command line.  CMDLINE
 | 
						||
   contains the name of the command that should be executed.  ARGLIST
 | 
						||
   holds all arguments for this command.  */
 | 
						||
struct grub_script_cmd *
 | 
						||
grub_script_create_cmdline (struct grub_parser_param *state,
 | 
						||
			    struct grub_script_arglist *arglist)
 | 
						||
{
 | 
						||
  struct grub_script_cmdline *cmd;
 | 
						||
 | 
						||
  grub_dprintf ("scripting", "cmdline\n");
 | 
						||
 | 
						||
  cmd = grub_script_malloc (state, sizeof (*cmd));
 | 
						||
  cmd->cmd.exec = grub_script_execute_cmdline;
 | 
						||
  cmd->cmd.next = 0;
 | 
						||
  cmd->arglist = arglist;
 | 
						||
 | 
						||
  return (struct grub_script_cmd *) cmd;
 | 
						||
}
 | 
						||
 | 
						||
/* Create a command that functions as an if statement.  If BOOL is
 | 
						||
   evaluated to true (the value is returned in envvar '?'), the
 | 
						||
   interpreter will run the command TRUE, otherwise the interpreter
 | 
						||
   runs the command FALSE.  */
 | 
						||
struct grub_script_cmd *
 | 
						||
grub_script_create_cmdif (struct grub_parser_param *state,
 | 
						||
			  struct grub_script_cmd *exec_to_evaluate,
 | 
						||
			  struct grub_script_cmd *exec_on_true,
 | 
						||
			  struct grub_script_cmd *exec_on_false)
 | 
						||
{
 | 
						||
  struct grub_script_cmdif *cmd;
 | 
						||
 | 
						||
  grub_dprintf ("scripting", "cmdif\n");
 | 
						||
 | 
						||
  cmd = grub_script_malloc (state, sizeof (*cmd));
 | 
						||
  cmd->cmd.exec = grub_script_execute_cmdif;
 | 
						||
  cmd->cmd.next = 0;
 | 
						||
  cmd->exec_to_evaluate = exec_to_evaluate;
 | 
						||
  cmd->exec_on_true = exec_on_true;
 | 
						||
  cmd->exec_on_false = exec_on_false;
 | 
						||
 | 
						||
  return (struct grub_script_cmd *) cmd;
 | 
						||
}
 | 
						||
 | 
						||
/* Create a command that adds a menu entry to the menu.  Title is an
 | 
						||
   argument that is parsed to generate a string that can be used as
 | 
						||
   the title.  The sourcecode for this entry is passed in SOURCECODE.
 | 
						||
   The options for this entry are passed in OPTIONS.  */
 | 
						||
struct grub_script_cmd *
 | 
						||
grub_script_create_cmdmenu (struct grub_parser_param *state,
 | 
						||
			    struct grub_script_arglist *arglist,
 | 
						||
			    char *sourcecode,
 | 
						||
			    int options)
 | 
						||
{
 | 
						||
  struct grub_script_cmd_menuentry *cmd;
 | 
						||
  int i;
 | 
						||
 | 
						||
  /* Skip leading newlines to make the sourcecode better readable when
 | 
						||
     using the editor.  */
 | 
						||
  while (*sourcecode == '\n')
 | 
						||
    sourcecode++;
 | 
						||
 | 
						||
  /* Having trailing returns can some some annoying conflicts, remove
 | 
						||
     them.  XXX: Can the parser be improved to handle this?  */
 | 
						||
  for (i = grub_strlen (sourcecode) - 1; i > 0; i--)
 | 
						||
    {
 | 
						||
      if (sourcecode[i] != '\n')
 | 
						||
	break;
 | 
						||
      sourcecode[i] = '\0';
 | 
						||
    }
 | 
						||
 | 
						||
  cmd = grub_script_malloc (state, sizeof (*cmd));
 | 
						||
  cmd->cmd.exec = grub_script_execute_menuentry;
 | 
						||
  cmd->cmd.next = 0;
 | 
						||
  /* XXX: Check if this memory is properly freed.  */
 | 
						||
  cmd->sourcecode = sourcecode;
 | 
						||
  cmd->arglist = arglist;
 | 
						||
  cmd->options = options;
 | 
						||
 | 
						||
  return (struct grub_script_cmd *) cmd;
 | 
						||
}
 | 
						||
 | 
						||
/* Create a block of commands.  CMD contains the command that should
 | 
						||
   be added at the end of CMDBLOCK's list.  If CMDBLOCK is zero, a new
 | 
						||
   cmdblock will be created.  */
 | 
						||
struct grub_script_cmd *
 | 
						||
grub_script_add_cmd (struct grub_parser_param *state,
 | 
						||
		     struct grub_script_cmdblock *cmdblock,
 | 
						||
		     struct grub_script_cmd *cmd)
 | 
						||
{
 | 
						||
  grub_dprintf ("scripting", "cmdblock\n");
 | 
						||
 | 
						||
  if (! cmd)
 | 
						||
    return (struct grub_script_cmd *) cmdblock;
 | 
						||
 | 
						||
  if (! cmdblock)
 | 
						||
    {
 | 
						||
      cmdblock = (struct grub_script_cmdblock *) grub_script_malloc (state,
 | 
						||
								     sizeof (*cmdblock));
 | 
						||
      cmdblock->cmd.exec = grub_script_execute_cmdblock;
 | 
						||
      cmdblock->cmd.next = 0;
 | 
						||
      cmdblock->cmdlist = cmd;
 | 
						||
      cmd->next = 0;
 | 
						||
    }
 | 
						||
  else
 | 
						||
    {
 | 
						||
      cmd->next = cmdblock->cmdlist;
 | 
						||
      cmdblock->cmdlist = cmd;
 | 
						||
    }
 | 
						||
 | 
						||
  return (struct grub_script_cmd *) cmdblock;
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
 | 
						||
struct grub_script *
 | 
						||
grub_script_create (struct grub_script_cmd *cmd, struct grub_script_mem *mem)
 | 
						||
{
 | 
						||
  struct grub_script *parsed;
 | 
						||
 | 
						||
  parsed = grub_malloc (sizeof (*parsed));
 | 
						||
  if (! parsed)
 | 
						||
    {
 | 
						||
      grub_script_mem_free (mem);
 | 
						||
      grub_free (cmd);
 | 
						||
 | 
						||
      return 0;
 | 
						||
    }
 | 
						||
 | 
						||
  parsed->mem = mem;
 | 
						||
  parsed->cmd = cmd;
 | 
						||
 | 
						||
  return parsed;
 | 
						||
}
 | 
						||
 | 
						||
/* Parse the script passed in SCRIPT and return the parsed
 | 
						||
   datastructure that is ready to be interpreted.  */
 | 
						||
struct grub_script *
 | 
						||
grub_script_parse (char *script, grub_reader_getline_t getline)
 | 
						||
{
 | 
						||
  struct grub_script *parsed;
 | 
						||
  struct grub_script_mem *membackup;
 | 
						||
  struct grub_lexer_param *lexstate;
 | 
						||
  struct grub_parser_param *parsestate;
 | 
						||
 | 
						||
  parsed = grub_malloc (sizeof (*parsed));
 | 
						||
  if (! parsed)
 | 
						||
    return 0;
 | 
						||
 | 
						||
  parsestate = grub_zalloc (sizeof (*parsestate));
 | 
						||
  if (! parsestate)
 | 
						||
    return 0;
 | 
						||
 | 
						||
  /* Initialize the lexer.  */
 | 
						||
  lexstate = grub_script_lexer_init (script, getline);
 | 
						||
  if (! lexstate)
 | 
						||
    {
 | 
						||
      grub_free (parsed);
 | 
						||
      grub_free (parsestate);
 | 
						||
      return 0;
 | 
						||
    }
 | 
						||
 | 
						||
  parsestate->lexerstate = lexstate;
 | 
						||
 | 
						||
  membackup = grub_script_mem_record (parsestate);
 | 
						||
 | 
						||
  /* Parse the script.  */
 | 
						||
  if (grub_script_yyparse (parsestate) || parsestate->err)
 | 
						||
    {
 | 
						||
      struct grub_script_mem *memfree;
 | 
						||
      memfree = grub_script_mem_record_stop (parsestate, membackup);
 | 
						||
      grub_script_mem_free (memfree);
 | 
						||
      grub_free (lexstate);
 | 
						||
      grub_free (parsestate);
 | 
						||
      return 0;
 | 
						||
    }
 | 
						||
 | 
						||
  parsed->mem = grub_script_mem_record_stop (parsestate, membackup);
 | 
						||
  parsed->cmd = parsestate->parsed;
 | 
						||
 | 
						||
  grub_free (lexstate);
 | 
						||
  grub_free (parsestate);
 | 
						||
 | 
						||
  return parsed;
 | 
						||
}
 |