1 /* script.c -- Functions to create an in memory description of the script. */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2005,2006,2007,2009 Free Software Foundation, Inc.
6 * GRUB 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 3 of the License, or
9 * (at your option) any later version.
11 * GRUB 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 GRUB. If not, see <http://www.gnu.org/licenses/>.
20 #include <grub/misc.h>
21 #include <grub/script_sh.h>
22 #include <grub/parser.h>
25 /* It is not possible to deallocate the memory when a syntax error was
26 found. Because of that it is required to keep track of all memory
27 allocations. The memory is freed in case of an error, or
28 assigned to the parsed script when parsing was successful. */
32 /* In case of the normal malloc, some additional bytes are allocated
33 for this datastructure. All reserved memory is stored in a linked
34 list so it can be easily freed. The original memory can be found
36 struct grub_script_mem
38 struct grub_script_mem
*next
;
42 /* Return malloc'ed memory and keep track of the allocation. */
44 grub_script_malloc (struct grub_parser_param
*state
, grub_size_t size
)
46 struct grub_script_mem
*mem
;
47 mem
= (struct grub_script_mem
*) grub_malloc (size
+ sizeof (*mem
)
50 grub_dprintf ("scripting", "malloc %p\n", mem
);
51 mem
->next
= state
->memused
;
53 return (void *) &mem
->mem
;
56 /* Free all memory described by MEM. */
58 grub_script_mem_free (struct grub_script_mem
*mem
)
60 struct grub_script_mem
*memfree
;
65 grub_dprintf ("scripting", "free %p\n", mem
);
71 /* Start recording memory usage. Returns the memory that should be
72 restored when calling stop. */
73 struct grub_script_mem
*
74 grub_script_mem_record (struct grub_parser_param
*state
)
76 struct grub_script_mem
*mem
= state
->memused
;
82 /* Stop recording memory usage. Restore previous recordings using
83 RESTORE. Return the recorded memory. */
84 struct grub_script_mem
*
85 grub_script_mem_record_stop (struct grub_parser_param
*state
,
86 struct grub_script_mem
*restore
)
88 struct grub_script_mem
*mem
= state
->memused
;
89 state
->memused
= restore
;
93 /* Free the memory reserved for CMD and all of it's children. */
95 grub_script_free (struct grub_script
*script
)
99 grub_script_mem_free (script
->mem
);
105 /* Extend the argument arg with a variable or string of text. If ARG
106 is zero a new list is created. */
107 struct grub_script_arg
*
108 grub_script_arg_add (struct grub_parser_param
*state
, struct grub_script_arg
*arg
,
109 grub_script_arg_type_t type
, char *str
)
111 struct grub_script_arg
*argpart
;
112 struct grub_script_arg
*ll
;
115 argpart
= (struct grub_script_arg
*) grub_script_malloc (state
, sizeof (*arg
));
116 argpart
->type
= type
;
117 len
= grub_strlen (str
) + 1;
118 argpart
->str
= grub_script_malloc (state
, len
);
119 grub_memcpy (argpart
->str
, str
, len
);
125 for (ll
= arg
; ll
->next
; ll
= ll
->next
);
131 /* Add the argument ARG to the end of the argument list LIST. If LIST
132 is zero, a new list will be created. */
133 struct grub_script_arglist
*
134 grub_script_add_arglist (struct grub_parser_param
*state
,
135 struct grub_script_arglist
*list
, struct grub_script_arg
*arg
)
137 struct grub_script_arglist
*link
;
138 struct grub_script_arglist
*ll
;
140 grub_dprintf ("scripting", "arglist\n");
142 link
= (struct grub_script_arglist
*) grub_script_malloc (state
, sizeof (*link
));
155 /* Look up the last link in the chain. */
156 for (ll
= list
; ll
->next
; ll
= ll
->next
);
162 /* Create a command that describes a single command line. CMDLINE
163 contains the name of the command that should be executed. ARGLIST
164 holds all arguments for this command. */
165 struct grub_script_cmd
*
166 grub_script_create_cmdline (struct grub_parser_param
*state
,
167 struct grub_script_arglist
*arglist
)
169 struct grub_script_cmdline
*cmd
;
171 grub_dprintf ("scripting", "cmdline\n");
173 cmd
= grub_script_malloc (state
, sizeof (*cmd
));
174 cmd
->cmd
.exec
= grub_script_execute_cmdline
;
176 cmd
->arglist
= arglist
;
178 return (struct grub_script_cmd
*) cmd
;
181 /* Create a command that functions as an if statement. If BOOL is
182 evaluated to true (the value is returned in envvar '?'), the
183 interpreter will run the command TRUE, otherwise the interpreter
184 runs the command FALSE. */
185 struct grub_script_cmd
*
186 grub_script_create_cmdif (struct grub_parser_param
*state
,
187 struct grub_script_cmd
*exec_to_evaluate
,
188 struct grub_script_cmd
*exec_on_true
,
189 struct grub_script_cmd
*exec_on_false
)
191 struct grub_script_cmdif
*cmd
;
193 grub_dprintf ("scripting", "cmdif\n");
195 cmd
= grub_script_malloc (state
, sizeof (*cmd
));
196 cmd
->cmd
.exec
= grub_script_execute_cmdif
;
198 cmd
->exec_to_evaluate
= exec_to_evaluate
;
199 cmd
->exec_on_true
= exec_on_true
;
200 cmd
->exec_on_false
= exec_on_false
;
202 return (struct grub_script_cmd
*) cmd
;
205 /* Create a command that adds a menu entry to the menu. Title is an
206 argument that is parsed to generate a string that can be used as
207 the title. The sourcecode for this entry is passed in SOURCECODE.
208 The options for this entry are passed in OPTIONS. */
209 struct grub_script_cmd
*
210 grub_script_create_cmdmenu (struct grub_parser_param
*state
,
211 struct grub_script_arglist
*arglist
,
215 struct grub_script_cmd_menuentry
*cmd
;
218 /* Skip leading newlines to make the sourcecode better readable when
220 while (*sourcecode
== '\n')
223 /* Having trailing returns can some some annoying conflicts, remove
224 them. XXX: Can the parser be improved to handle this? */
225 for (i
= grub_strlen (sourcecode
) - 1; i
> 0; i
--)
227 if (sourcecode
[i
] != '\n')
229 sourcecode
[i
] = '\0';
232 cmd
= grub_script_malloc (state
, sizeof (*cmd
));
233 cmd
->cmd
.exec
= grub_script_execute_menuentry
;
235 /* XXX: Check if this memory is properly freed. */
236 cmd
->sourcecode
= sourcecode
;
237 cmd
->arglist
= arglist
;
238 cmd
->options
= options
;
240 return (struct grub_script_cmd
*) cmd
;
243 /* Create a block of commands. CMD contains the command that should
244 be added at the end of CMDBLOCK's list. If CMDBLOCK is zero, a new
245 cmdblock will be created. */
246 struct grub_script_cmd
*
247 grub_script_add_cmd (struct grub_parser_param
*state
,
248 struct grub_script_cmdblock
*cmdblock
,
249 struct grub_script_cmd
*cmd
)
251 grub_dprintf ("scripting", "cmdblock\n");
254 return (struct grub_script_cmd
*) cmdblock
;
258 cmdblock
= (struct grub_script_cmdblock
*) grub_script_malloc (state
,
260 cmdblock
->cmd
.exec
= grub_script_execute_cmdblock
;
261 cmdblock
->cmd
.next
= 0;
262 cmdblock
->cmdlist
= cmd
;
267 cmd
->next
= cmdblock
->cmdlist
;
268 cmdblock
->cmdlist
= cmd
;
271 return (struct grub_script_cmd
*) cmdblock
;
277 grub_script_create (struct grub_script_cmd
*cmd
, struct grub_script_mem
*mem
)
279 struct grub_script
*parsed
;
281 parsed
= grub_malloc (sizeof (*parsed
));
284 grub_script_mem_free (mem
);
296 /* Parse the script passed in SCRIPT and return the parsed
297 datastructure that is ready to be interpreted. */
299 grub_script_parse (char *script
, grub_reader_getline_t getline
)
301 struct grub_script
*parsed
;
302 struct grub_script_mem
*membackup
;
303 struct grub_lexer_param
*lexstate
;
304 struct grub_parser_param
*parsestate
;
306 parsed
= grub_malloc (sizeof (*parsed
));
310 parsestate
= grub_zalloc (sizeof (*parsestate
));
314 /* Initialize the lexer. */
315 lexstate
= grub_script_lexer_init (script
, getline
);
319 grub_free (parsestate
);
323 parsestate
->lexerstate
= lexstate
;
325 membackup
= grub_script_mem_record (parsestate
);
327 /* Parse the script. */
328 if (grub_script_yyparse (parsestate
) || parsestate
->err
)
330 struct grub_script_mem
*memfree
;
331 memfree
= grub_script_mem_record_stop (parsestate
, membackup
);
332 grub_script_mem_free (memfree
);
333 grub_free (lexstate
);
334 grub_free (parsestate
);
338 parsed
->mem
= grub_script_mem_record_stop (parsestate
, membackup
);
339 parsed
->cmd
= parsestate
->parsed
;
341 grub_free (lexstate
);
342 grub_free (parsestate
);