mirror of
				https://git.proxmox.com/git/grub2
				synced 2025-10-31 15:35:13 +00:00 
			
		
		
		
	 09fd6d8293
			
		
	
	
		09fd6d8293
		
	
	
	
	
		
			
			* grub-core/kern/parser.c (grub_parser_split_cmdline): Add getline_data argument, passed to getline. * grub-core/kern/rescue_parser.c (grub_rescue_parse_line): Add getline_data argument, passed to grub_parser_split_cmdline. * grub-core/script/lexer.c (grub_script_lexer_yywrap): Pass lexerstate->getline_data to lexerstate->getline. (grub_script_lexer_init): Add getline_data argument, saved in lexerstate->getline_data. * grub-core/script/main.c (grub_normal_parse_line): Add getline_data argument, passed to grub_script_parse. * grub-core/script/script.c (grub_script_parse): Add getline_data argument, passed to grub_script_lexer_init. * include/grub/parser.h (grub_parser_split_cmdline): Update prototype. Update all callers to pass appropriate getline data. (struct grub_parser.parse_line): Likewise. (grub_rescue_parse_line): Likewise. * include/grub/reader.h (grub_reader_getline_t): Add void * argument. * include/grub/script_sh.h (struct grub_lexer_param): Add getline_data member. (grub_script_parse): Update prototype. Update all callers to pass appropriate getline data. (grub_script_lexer_init): Likewise. (grub_normal_parse_line): Likewise. * grub-core/commands/legacycfg.c (legacy_file_getline): Add unused data argument. * grub-core/kern/parser.c (grub_parser_execute: getline): Make static instead of nested. Rename to ... (grub_parser_execute_getline): ... this. * grub-core/kern/rescue_reader.c (grub_rescue_read_line): Add unused data argument. * grub-core/normal/main.c (read_config_file: getline): Make static instead of nested. Rename to ... (read_config_file_getline): ... this. (grub_normal_read_line): Add unused data argument. * grub-core/script/execute.c (grub_script_execute_sourcecode: getline): Make static instead of nested. Rename to ... (grub_script_execute_sourcecode_getline): ... this. * util/grub-script-check.c (main: get_config_line): Make static instead of nested.
		
			
				
	
	
		
			397 lines
		
	
	
		
			9.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			397 lines
		
	
	
		
			9.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* script.c -- Functions to create an in memory description of the script. */
 | ||
| /*
 | ||
|  *  GRUB  --  GRand Unified Bootloader
 | ||
|  *  Copyright (C) 2005,2006,2007,2009,2010  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.
 | ||
| 
 | ||
|    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));
 | ||
|   if (!mem)
 | ||
|     return 0;
 | ||
| 
 | ||
|   grub_dprintf ("scripting", "malloc %p\n", mem);
 | ||
|   mem->next = state->memused;
 | ||
|   state->memused = mem;
 | ||
|   return (void *) &mem->mem;
 | ||
| }
 | ||
| 
 | ||
| /* Free all memory described by MEM.  */
 | ||
| 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)
 | ||
| {
 | ||
|   struct grub_script *s;
 | ||
|   struct grub_script *t;
 | ||
| 
 | ||
|   if (! script)
 | ||
|     return;
 | ||
| 
 | ||
|   if (script->mem)
 | ||
|     grub_script_mem_free (script->mem);
 | ||
| 
 | ||
|   s = script->children;
 | ||
|   while (s) {
 | ||
|     t = s->next_siblings;
 | ||
|     grub_script_unref (s);
 | ||
|     s = t;
 | ||
|   }
 | ||
|   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));
 | ||
|   if (!argpart)
 | ||
|     return arg;
 | ||
| 
 | ||
|   argpart->type = type;
 | ||
|   argpart->script = 0;
 | ||
| 
 | ||
|   len = grub_strlen (str) + 1;
 | ||
|   argpart->str = grub_script_malloc (state, len);
 | ||
|   if (!argpart->str)
 | ||
|     return arg; /* argpart is freed later, during grub_script_free.  */
 | ||
| 
 | ||
|   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));
 | ||
|   if (!link)
 | ||
|     return list;
 | ||
| 
 | ||
|   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));
 | ||
|   if (!cmd)
 | ||
|     return 0;
 | ||
| 
 | ||
|   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));
 | ||
|   if (!cmd)
 | ||
|     return 0;
 | ||
| 
 | ||
|   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 functions as a for statement.  */
 | ||
| struct grub_script_cmd *
 | ||
| grub_script_create_cmdfor (struct grub_parser_param *state,
 | ||
| 			   struct grub_script_arg *name,
 | ||
| 			   struct grub_script_arglist *words,
 | ||
| 			   struct grub_script_cmd *list)
 | ||
| {
 | ||
|   struct grub_script_cmdfor *cmd;
 | ||
| 
 | ||
|   grub_dprintf ("scripting", "cmdfor\n");
 | ||
| 
 | ||
|   cmd = grub_script_malloc (state, sizeof (*cmd));
 | ||
|   if (! cmd)
 | ||
|     return 0;
 | ||
| 
 | ||
|   cmd->cmd.exec = grub_script_execute_cmdfor;
 | ||
|   cmd->cmd.next = 0;
 | ||
|   cmd->name = name;
 | ||
|   cmd->words = words;
 | ||
|   cmd->list = list;
 | ||
| 
 | ||
|   return (struct grub_script_cmd *) cmd;
 | ||
| }
 | ||
| 
 | ||
| /* Create a "while" or "until" command.  */
 | ||
| struct grub_script_cmd *
 | ||
| grub_script_create_cmdwhile (struct grub_parser_param *state,
 | ||
| 			     struct grub_script_cmd *cond,
 | ||
| 			     struct grub_script_cmd *list,
 | ||
| 			     int is_an_until_loop)
 | ||
| {
 | ||
|   struct grub_script_cmdwhile *cmd;
 | ||
| 
 | ||
|   cmd = grub_script_malloc (state, sizeof (*cmd));
 | ||
|   if (! cmd)
 | ||
|     return 0;
 | ||
| 
 | ||
|   cmd->cmd.exec = grub_script_execute_cmdwhile;
 | ||
|   cmd->cmd.next = 0;
 | ||
|   cmd->cond = cond;
 | ||
|   cmd->list = list;
 | ||
|   cmd->until = is_an_until_loop;
 | ||
| 
 | ||
|   return (struct grub_script_cmd *) cmd;
 | ||
| }
 | ||
| 
 | ||
| /* Create a chain of commands.  LAST contains the command that should
 | ||
|    be added at the end of LIST's list.  If LIST is zero, a new list
 | ||
|    will be created.  */
 | ||
| struct grub_script_cmd *
 | ||
| grub_script_append_cmd (struct grub_parser_param *state,
 | ||
| 			struct grub_script_cmd *list,
 | ||
| 			struct grub_script_cmd *last)
 | ||
| {
 | ||
|   struct grub_script_cmd *ptr;
 | ||
| 
 | ||
|   grub_dprintf ("scripting", "append command\n");
 | ||
| 
 | ||
|   if (! last)
 | ||
|     return list;
 | ||
| 
 | ||
|   if (! list)
 | ||
|     {
 | ||
|       list = grub_script_malloc (state, sizeof (*list));
 | ||
|       if (! list)
 | ||
| 	return 0;
 | ||
| 
 | ||
|       list->exec = grub_script_execute_cmdlist;
 | ||
|       list->next = last;
 | ||
|     }
 | ||
|   else
 | ||
|     {
 | ||
|       ptr = list;
 | ||
|       while (ptr->next)
 | ||
| 	ptr = ptr->next;
 | ||
| 
 | ||
|       ptr->next = last;
 | ||
|     }
 | ||
| 
 | ||
|   return list;
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| 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)
 | ||
|     return 0;
 | ||
| 
 | ||
|   parsed->mem = mem;
 | ||
|   parsed->cmd = cmd;
 | ||
|   parsed->refcnt = 0;
 | ||
|   parsed->children = 0;
 | ||
|   parsed->next_siblings = 0;
 | ||
| 
 | ||
|   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, void *getline_data)
 | ||
| {
 | ||
|   struct grub_script *parsed;
 | ||
|   struct grub_script_mem *membackup;
 | ||
|   struct grub_lexer_param *lexstate;
 | ||
|   struct grub_parser_param *parsestate;
 | ||
| 
 | ||
|   parsed = grub_script_create (0, 0);
 | ||
|   if (!parsed)
 | ||
|     return 0;
 | ||
| 
 | ||
|   parsestate = grub_zalloc (sizeof (*parsestate));
 | ||
|   if (!parsestate)
 | ||
|     {
 | ||
|       grub_free (parsed);
 | ||
|       return 0;
 | ||
|     }
 | ||
| 
 | ||
|   /* Initialize the lexer.  */
 | ||
|   lexstate = grub_script_lexer_init (parsestate, script,
 | ||
| 				     getline, getline_data);
 | ||
|   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_script_lexer_fini (lexstate);
 | ||
|       grub_free (parsestate);
 | ||
|       grub_free (parsed);
 | ||
|       return 0;
 | ||
|     }
 | ||
| 
 | ||
|   parsed->mem = grub_script_mem_record_stop (parsestate, membackup);
 | ||
|   parsed->cmd = parsestate->parsed;
 | ||
|   parsed->children = parsestate->scripts;
 | ||
| 
 | ||
|   grub_script_lexer_fini (lexstate);
 | ||
|   grub_free (parsestate);
 | ||
| 
 | ||
|   return parsed;
 | ||
| }
 |