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,2010 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 assigned
28 to the parsed script when parsing was successful.
30 In case of the normal malloc, some additional bytes are allocated
31 for this datastructure. All reserved memory is stored in a linked
32 list so it can be easily freed. The original memory can be found
34 struct grub_script_mem
36 struct grub_script_mem
*next
;
40 /* Return malloc'ed memory and keep track of the allocation. */
42 grub_script_malloc (struct grub_parser_param
*state
, grub_size_t size
)
44 struct grub_script_mem
*mem
;
45 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
)
97 struct grub_script
*s
;
98 struct grub_script
*t
;
104 grub_script_mem_free (script
->mem
);
106 s
= script
->children
;
108 t
= s
->next_siblings
;
109 grub_script_unref (s
);
117 /* Extend the argument arg with a variable or string of text. If ARG
118 is zero a new list is created. */
119 struct grub_script_arg
*
120 grub_script_arg_add (struct grub_parser_param
*state
,
121 struct grub_script_arg
*arg
, grub_script_arg_type_t type
,
124 struct grub_script_arg
*argpart
;
125 struct grub_script_arg
*ll
;
129 (struct grub_script_arg
*) grub_script_malloc (state
, sizeof (*arg
));
133 argpart
->type
= type
;
136 len
= grub_strlen (str
) + 1;
137 argpart
->str
= grub_script_malloc (state
, len
);
139 return arg
; /* argpart is freed later, during grub_script_free. */
141 grub_memcpy (argpart
->str
, str
, len
);
147 for (ll
= arg
; ll
->next
; ll
= ll
->next
);
153 /* Add the argument ARG to the end of the argument list LIST. If LIST
154 is zero, a new list will be created. */
155 struct grub_script_arglist
*
156 grub_script_add_arglist (struct grub_parser_param
*state
,
157 struct grub_script_arglist
*list
,
158 struct grub_script_arg
*arg
)
160 struct grub_script_arglist
*link
;
161 struct grub_script_arglist
*ll
;
163 grub_dprintf ("scripting", "arglist\n");
166 (struct grub_script_arglist
*) grub_script_malloc (state
, sizeof (*link
));
182 /* Look up the last link in the chain. */
183 for (ll
= list
; ll
->next
; ll
= ll
->next
);
189 /* Create a command that describes a single command line. CMDLINE
190 contains the name of the command that should be executed. ARGLIST
191 holds all arguments for this command. */
192 struct grub_script_cmd
*
193 grub_script_create_cmdline (struct grub_parser_param
*state
,
194 struct grub_script_arglist
*arglist
)
196 struct grub_script_cmdline
*cmd
;
198 grub_dprintf ("scripting", "cmdline\n");
200 cmd
= grub_script_malloc (state
, sizeof (*cmd
));
204 cmd
->cmd
.exec
= grub_script_execute_cmdline
;
206 cmd
->arglist
= arglist
;
208 return (struct grub_script_cmd
*) cmd
;
211 /* Create a command that functions as an if statement. If BOOL is
212 evaluated to true (the value is returned in envvar '?'), the
213 interpreter will run the command TRUE, otherwise the interpreter
214 runs the command FALSE. */
215 struct grub_script_cmd
*
216 grub_script_create_cmdif (struct grub_parser_param
*state
,
217 struct grub_script_cmd
*exec_to_evaluate
,
218 struct grub_script_cmd
*exec_on_true
,
219 struct grub_script_cmd
*exec_on_false
)
221 struct grub_script_cmdif
*cmd
;
223 grub_dprintf ("scripting", "cmdif\n");
225 cmd
= grub_script_malloc (state
, sizeof (*cmd
));
229 cmd
->cmd
.exec
= grub_script_execute_cmdif
;
231 cmd
->exec_to_evaluate
= exec_to_evaluate
;
232 cmd
->exec_on_true
= exec_on_true
;
233 cmd
->exec_on_false
= exec_on_false
;
235 return (struct grub_script_cmd
*) cmd
;
238 /* Create a command that functions as a for statement. */
239 struct grub_script_cmd
*
240 grub_script_create_cmdfor (struct grub_parser_param
*state
,
241 struct grub_script_arg
*name
,
242 struct grub_script_arglist
*words
,
243 struct grub_script_cmd
*list
)
245 struct grub_script_cmdfor
*cmd
;
247 grub_dprintf ("scripting", "cmdfor\n");
249 cmd
= grub_script_malloc (state
, sizeof (*cmd
));
253 cmd
->cmd
.exec
= grub_script_execute_cmdfor
;
259 return (struct grub_script_cmd
*) cmd
;
262 /* Create a "while" or "until" command. */
263 struct grub_script_cmd
*
264 grub_script_create_cmdwhile (struct grub_parser_param
*state
,
265 struct grub_script_cmd
*cond
,
266 struct grub_script_cmd
*list
,
267 int is_an_until_loop
)
269 struct grub_script_cmdwhile
*cmd
;
271 cmd
= grub_script_malloc (state
, sizeof (*cmd
));
275 cmd
->cmd
.exec
= grub_script_execute_cmdwhile
;
279 cmd
->until
= is_an_until_loop
;
281 return (struct grub_script_cmd
*) cmd
;
284 /* Create a chain of commands. LAST contains the command that should
285 be added at the end of LIST's list. If LIST is zero, a new list
287 struct grub_script_cmd
*
288 grub_script_append_cmd (struct grub_parser_param
*state
,
289 struct grub_script_cmd
*list
,
290 struct grub_script_cmd
*last
)
292 struct grub_script_cmd
*ptr
;
294 grub_dprintf ("scripting", "append command\n");
301 list
= grub_script_malloc (state
, sizeof (*list
));
305 list
->exec
= grub_script_execute_cmdlist
;
323 grub_script_create (struct grub_script_cmd
*cmd
, struct grub_script_mem
*mem
)
325 struct grub_script
*parsed
;
327 parsed
= grub_malloc (sizeof (*parsed
));
334 parsed
->children
= 0;
335 parsed
->next_siblings
= 0;
340 /* Parse the script passed in SCRIPT and return the parsed
341 datastructure that is ready to be interpreted. */
343 grub_script_parse (char *script
,
344 grub_reader_getline_t getline
, void *getline_data
)
346 struct grub_script
*parsed
;
347 struct grub_script_mem
*membackup
;
348 struct grub_lexer_param
*lexstate
;
349 struct grub_parser_param
*parsestate
;
351 parsed
= grub_script_create (0, 0);
355 parsestate
= grub_zalloc (sizeof (*parsestate
));
362 /* Initialize the lexer. */
363 lexstate
= grub_script_lexer_init (parsestate
, script
,
364 getline
, getline_data
);
368 grub_free (parsestate
);
372 parsestate
->lexerstate
= lexstate
;
374 membackup
= grub_script_mem_record (parsestate
);
376 /* Parse the script. */
377 if (grub_script_yyparse (parsestate
) || parsestate
->err
)
379 struct grub_script_mem
*memfree
;
380 memfree
= grub_script_mem_record_stop (parsestate
, membackup
);
381 grub_script_mem_free (memfree
);
382 grub_script_lexer_fini (lexstate
);
383 grub_free (parsestate
);
388 parsed
->mem
= grub_script_mem_record_stop (parsestate
, membackup
);
389 parsed
->cmd
= parsestate
->parsed
;
390 parsed
->children
= parsestate
->scripts
;
392 grub_script_lexer_fini (lexstate
);
393 grub_free (parsestate
);