mirror of
				https://git.proxmox.com/git/grub2
				synced 2025-10-31 10:26:53 +00:00 
			
		
		
		
	 342d6edb97
			
		
	
	
		342d6edb97
		
	
	
	
	
		
			
			lexer calls yylex_fatal on fatal internal errors. yylex_fatal itself is declared as noreturn and calls exit. Returning from noreturn function has unpredictable consequences.
		
			
				
	
	
		
			394 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			394 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| %{
 | |
| /* yylex.l  The scripting lexer.  */
 | |
| /*
 | |
|  *  GRUB  --  GRand Unified Bootloader
 | |
|  *  Copyright (C) 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/parser.h>
 | |
| #include <grub/misc.h>
 | |
| #include <grub/mm.h>
 | |
| #include <grub/script_sh.h>
 | |
| #include <grub/i18n.h>
 | |
| #include "grub_script.tab.h"
 | |
| 
 | |
| #pragma GCC diagnostic ignored "-Wunused-parameter"
 | |
| #pragma GCC diagnostic ignored "-Wmissing-prototypes"
 | |
| #pragma GCC diagnostic ignored "-Wmissing-declarations"
 | |
| #pragma GCC diagnostic ignored "-Wunused-function"
 | |
| #pragma GCC diagnostic ignored "-Wsign-compare"
 | |
| 
 | |
| #define yyalloc(size, scanner)   (grub_malloc((size)))
 | |
| #define yyfree(ptr, scanner)   (grub_free((ptr)))
 | |
| #define yyrealloc(ptr, size, scanner) (grub_realloc((ptr), (size)))
 | |
| 
 | |
| /* 
 | |
|  * As we don't have access to yyscanner, we cannot do much except to
 | |
|  * print the fatal error.
 | |
|  */
 | |
| #define YY_FATAL_ERROR(msg)                     \
 | |
|   do {                                          \
 | |
|     grub_printf (_("fatal error: %s\n"), _(msg));     \
 | |
|   } while (0)
 | |
| 
 | |
| #define COPY(str, hint)                         \
 | |
|   do {                                          \
 | |
|     copy_string (yyextra, str, hint);           \
 | |
|   } while (0)
 | |
| 
 | |
| 
 | |
| #define RECORD                                  \
 | |
|   do {                                          \
 | |
|     grub_script_lexer_record (yyextra, yytext); \
 | |
|   } while (0)
 | |
| 
 | |
| #define ARG(t)                        \
 | |
|   do {                                \
 | |
|     yyextra->lexerstate->type = t;    \
 | |
|     return GRUB_PARSER_TOKEN_WORD;    \
 | |
|   } while (0)
 | |
| 
 | |
| /* We don't need YY_INPUT, as we rely on yy_scan_strings */
 | |
| #define YY_INPUT(buf,res,max) do { res = 0; } while (0)
 | |
| 
 | |
| /* forward declarations */
 | |
| static int grub_lexer_unput (const char *input, yyscan_t yyscanner);
 | |
| static int grub_lexer_resplit (const char *input, yyscan_t yyscanner);
 | |
| 
 | |
| static void  copy_string (struct grub_parser_param *, const char *,
 | |
|                           unsigned hint);
 | |
| 
 | |
| %}
 | |
| 
 | |
| %top{
 | |
| 
 | |
| #include <config.h>
 | |
| 
 | |
| #include <sys/types.h>
 | |
| 
 | |
| typedef size_t yy_size_t;
 | |
| #define YY_TYPEDEF_YY_SIZE_T 1
 | |
| 
 | |
| /* 
 | |
|  * Some flex hacks for -nostdinc; XXX We need to fix these when libc
 | |
|  * support becomes availble in GRUB.
 | |
|  */
 | |
| 
 | |
| #ifndef GRUB_UTIL
 | |
| #define stdin  0
 | |
| #define stdout 0
 | |
| 
 | |
| #define fprintf(...) 0
 | |
| #define exit(...) grub_fatal("fatal error in lexer")
 | |
| #endif
 | |
| 
 | |
| }
 | |
| 
 | |
| %option ecs
 | |
| %option meta-ecs
 | |
| 
 | |
| %option warn
 | |
| %option array
 | |
| %option stack
 | |
| %option reentrant
 | |
| %option bison-bridge
 | |
| %option never-interactive
 | |
| 
 | |
| %option noyyfree noyyalloc noyyrealloc
 | |
| %option nounistd nostdinit nodefault noyylineno
 | |
| 
 | |
| /* Reduce lexer size, by not defining these.  */
 | |
| %option noyy_top_state
 | |
| %option noinput nounput
 | |
| %option noyyget_in noyyset_in
 | |
| %option noyyget_out noyyset_out
 | |
| %option noyyget_debug noyyset_debug
 | |
| %option noyyget_lineno noyyset_lineno
 | |
| 
 | |
| %option extra-type="struct grub_parser_param*"
 | |
| 
 | |
| BLANK           [ \t]
 | |
| COMMENT         #.*$
 | |
| 
 | |
| CHAR            [^{}|&$;<> \t\n\'\"\\]
 | |
| DIGITS          [[:digit:]]+
 | |
| NAME            [[:alpha:]_][[:alnum:]_]*
 | |
| 
 | |
| ESC             \\(.|\n)
 | |
| SQCHR           [^\']
 | |
| DQCHR           {ESC}|[^\\\"]
 | |
| DQSTR           \"{DQCHR}*\"
 | |
| I18NSTR         \$\"{DQCHR}*\"
 | |
| SQSTR           \'{SQCHR}*\'
 | |
| SPECIAL         \?|\#|\*|\@
 | |
| VARIABLE        ${NAME}|$\{{NAME}\}|${DIGITS}|$\{{DIGITS}\}|${SPECIAL}|$\{{SPECIAL}\}
 | |
| WORD            ({CHAR}|{DQSTR}|{SQSTR}|{ESC}|{VARIABLE}|{I18NSTR})+
 | |
| 
 | |
| MULTILINE       {WORD}?((\"{DQCHR}*)|(\$\"{DQCHR}*)|(\'{SQCHR}*))
 | |
| POS_MULTILINE   {WORD}?\\\n
 | |
| 
 | |
| %x              SPLIT
 | |
| %x              DQUOTE
 | |
| %x              I18NQUOTE
 | |
| %x              SQUOTE
 | |
| %x              VAR
 | |
| 
 | |
| %%
 | |
| 
 | |
|  /* White spaces */
 | |
| {BLANK}+        { RECORD; }
 | |
| {COMMENT}       { RECORD; }
 | |
| 
 | |
|  /* Special symbols */
 | |
| "\n"            { RECORD; return GRUB_PARSER_TOKEN_NEWLINE; }
 | |
| "||"            { RECORD; return GRUB_PARSER_TOKEN_OR;      }
 | |
| "&&"            { RECORD; return GRUB_PARSER_TOKEN_AND;     }
 | |
| ";;"            { RECORD; return GRUB_PARSER_TOKEN_SEMI2;   }
 | |
| "|"             { RECORD; return GRUB_PARSER_TOKEN_PIPE;    }
 | |
| "&"             { RECORD; return GRUB_PARSER_TOKEN_AMP;     }
 | |
| ";"             { RECORD; return GRUB_PARSER_TOKEN_SEMI;    }
 | |
| "<"             { RECORD; return GRUB_PARSER_TOKEN_LT;      }
 | |
| ">"             { RECORD; return GRUB_PARSER_TOKEN_GT;      }
 | |
| 
 | |
|  /* Reserved words */
 | |
| "{"             { RECORD; return GRUB_PARSER_TOKEN_LBR;       }
 | |
| "}"             { RECORD; return GRUB_PARSER_TOKEN_RBR;       }
 | |
| "[["            { RECORD; return GRUB_PARSER_TOKEN_LSQBR2;    }
 | |
| "]]"            { RECORD; return GRUB_PARSER_TOKEN_RSQBR2;    }
 | |
| "case"          { RECORD; return GRUB_PARSER_TOKEN_CASE;      }
 | |
| "do"            { RECORD; return GRUB_PARSER_TOKEN_DO;        }
 | |
| "done"          { RECORD; return GRUB_PARSER_TOKEN_DONE;      }
 | |
| "elif"          { RECORD; return GRUB_PARSER_TOKEN_ELIF;      }
 | |
| "else"          { RECORD; return GRUB_PARSER_TOKEN_ELSE;      }
 | |
| "esac"          { RECORD; return GRUB_PARSER_TOKEN_ESAC;      }
 | |
| "fi"            { RECORD; return GRUB_PARSER_TOKEN_FI;        }
 | |
| "for"           { RECORD; return GRUB_PARSER_TOKEN_FOR;       }
 | |
| "if"            { RECORD; return GRUB_PARSER_TOKEN_IF;        }
 | |
| "in"            { RECORD; return GRUB_PARSER_TOKEN_IN;        }
 | |
| "select"        { RECORD; return GRUB_PARSER_TOKEN_SELECT;    }
 | |
| "then"          { RECORD; return GRUB_PARSER_TOKEN_THEN;      }
 | |
| "until"         { RECORD; return GRUB_PARSER_TOKEN_UNTIL;     }
 | |
| "while"         { RECORD; return GRUB_PARSER_TOKEN_WHILE;     }
 | |
| "function"      { RECORD; return GRUB_PARSER_TOKEN_FUNCTION;  }
 | |
| 
 | |
| {MULTILINE}     {
 | |
|                   if (grub_lexer_unput (yytext, yyscanner))
 | |
| 		    return GRUB_PARSER_TOKEN_BAD;
 | |
| 		}
 | |
| 
 | |
| {POS_MULTILINE} {
 | |
|                   if (yyg->yy_c_buf_p + 1 == &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] )
 | |
| 		    {
 | |
| 		      if (grub_lexer_unput (yytext, yyscanner))
 | |
| 			return GRUB_PARSER_TOKEN_BAD;
 | |
| 		    }
 | |
| 		  else
 | |
| 		    {
 | |
| 		      RECORD;
 | |
| 		      yypush_buffer_state (YY_CURRENT_BUFFER, yyscanner);
 | |
| 		      if (grub_lexer_resplit (yytext, yyscanner))
 | |
| 			{
 | |
| 			  yypop_buffer_state (yyscanner);
 | |
| 			  return GRUB_PARSER_TOKEN_WORD;
 | |
| 			}
 | |
| 		      yyextra->lexerstate->resplit = 1;
 | |
| 		    }
 | |
| 		}
 | |
| 
 | |
| 
 | |
| {NAME}          { RECORD; return GRUB_PARSER_TOKEN_NAME; }
 | |
| {WORD}          {
 | |
|                   RECORD;
 | |
| 		  yypush_buffer_state (YY_CURRENT_BUFFER, yyscanner);
 | |
| 		  if (grub_lexer_resplit (yytext, yyscanner))
 | |
| 		    {
 | |
| 		      yypop_buffer_state (yyscanner);
 | |
| 		      return GRUB_PARSER_TOKEN_WORD;
 | |
| 		    }
 | |
| 		  yyextra->lexerstate->resplit = 1;
 | |
|                 }
 | |
| .               {
 | |
|                   grub_script_yyerror (yyextra, yytext);
 | |
| 		  return GRUB_PARSER_TOKEN_BAD;
 | |
|                 }
 | |
| 
 | |
|  /* Split word into multiple args */
 | |
| 
 | |
| <SPLIT>{
 | |
|   \\.           { COPY (yytext, yyleng); }
 | |
|   \\\n          { /* ignore */ }
 | |
|   \"            {
 | |
|                   yy_push_state (DQUOTE, yyscanner);
 | |
|                   ARG (GRUB_SCRIPT_ARG_TYPE_TEXT);
 | |
|                 }
 | |
|   \'            {
 | |
|                   yy_push_state (SQUOTE, yyscanner);
 | |
|                   ARG (GRUB_SCRIPT_ARG_TYPE_TEXT);
 | |
|                 }
 | |
|   "\$\""        {
 | |
|                   yy_push_state (I18NQUOTE, yyscanner);
 | |
|                   ARG (GRUB_SCRIPT_ARG_TYPE_GETTEXT);
 | |
|                 }
 | |
|   \$            {
 | |
|                   yy_push_state (VAR, yyscanner);
 | |
|                   ARG (GRUB_SCRIPT_ARG_TYPE_TEXT);
 | |
|                 }
 | |
|   \\            |
 | |
|   [^\"\'\$\\]+  { COPY (yytext, yyleng); }
 | |
|   <<EOF>>       {
 | |
|                   yy_pop_state (yyscanner);
 | |
|                   yypop_buffer_state (yyscanner);
 | |
| 		  yyextra->lexerstate->resplit = 0;
 | |
|                   yyextra->lexerstate->merge_end = 1;
 | |
|                   ARG (GRUB_SCRIPT_ARG_TYPE_TEXT);
 | |
|                 }
 | |
| }
 | |
| 
 | |
| <VAR>{
 | |
|   {SPECIAL}     |
 | |
|   {DIGITS}      |
 | |
|   {NAME}        {
 | |
|                   COPY (yytext, yyleng);
 | |
|                   yy_pop_state (yyscanner);
 | |
|                   if (YY_START == SPLIT)
 | |
|                     ARG (GRUB_SCRIPT_ARG_TYPE_VAR);
 | |
|                   else
 | |
|                     ARG (GRUB_SCRIPT_ARG_TYPE_DQVAR);
 | |
|                 }
 | |
|   \{{SPECIAL}\} |
 | |
|   \{{DIGITS}\}  |
 | |
|   \{{NAME}\}    {
 | |
|                   yytext[yyleng - 1] = '\0';
 | |
|                   COPY (yytext + 1, yyleng - 2);
 | |
|                   yy_pop_state (yyscanner);
 | |
|                   if (YY_START == SPLIT)
 | |
|                     ARG (GRUB_SCRIPT_ARG_TYPE_VAR);
 | |
|                   else
 | |
|                     ARG (GRUB_SCRIPT_ARG_TYPE_DQVAR);
 | |
|                 }
 | |
|   .|\n          { return GRUB_PARSER_TOKEN_BAD; }
 | |
| }
 | |
| 
 | |
| <SQUOTE>{
 | |
|   \'            {
 | |
|                   yy_pop_state (yyscanner);
 | |
|                   ARG (GRUB_SCRIPT_ARG_TYPE_SQSTR);
 | |
|                 }
 | |
|   [^\']+        { COPY (yytext, yyleng); }
 | |
| }
 | |
| 
 | |
| <DQUOTE>{
 | |
|   \\\$          { COPY ("$", 1); }
 | |
|   \\\\          { COPY ("\\", 1); }
 | |
|   \\\"          { COPY ("\"", 1); }
 | |
|   \\\n          { /* ignore */ }
 | |
|   [^\"\$\\\n]+  { COPY (yytext, yyleng); }
 | |
|   \"            {
 | |
|                   yy_pop_state (yyscanner);
 | |
|                   ARG (GRUB_SCRIPT_ARG_TYPE_DQSTR);
 | |
|                 }
 | |
|   \$            {
 | |
|                   yy_push_state (VAR, yyscanner);
 | |
|                   ARG (GRUB_SCRIPT_ARG_TYPE_DQSTR);
 | |
|                 }
 | |
|   (.|\n)        { COPY (yytext, yyleng); }
 | |
| }
 | |
| 
 | |
| <I18NQUOTE>{
 | |
|   \\\\          { COPY ("\\\\", 2); }
 | |
|   \\\"          { COPY ("\"", 1); }
 | |
|   \\\n          { /* ignore */ }
 | |
|   [^\"\\\n]+    { COPY (yytext, yyleng); }
 | |
|   \"            {
 | |
|                   yy_pop_state (yyscanner);
 | |
|                   ARG (GRUB_SCRIPT_ARG_TYPE_GETTEXT);
 | |
|                 }
 | |
|   \\            { COPY ("\\", 1); }
 | |
|   (.|\n)        { COPY (yytext, yyleng); }
 | |
| }
 | |
| 
 | |
| <<EOF>>         {
 | |
|                   yypop_buffer_state (yyscanner);
 | |
| 		  yyextra->lexerstate->eof = 1;
 | |
| 		  return GRUB_PARSER_TOKEN_EOF;
 | |
|                 }
 | |
| %%
 | |
| 
 | |
| int
 | |
| yywrap (yyscan_t yyscanner)
 | |
| {
 | |
|   if (yyget_extra (yyscanner)->lexerstate->resplit)
 | |
|     return 1;
 | |
| 
 | |
|   return grub_script_lexer_yywrap (yyget_extra (yyscanner), 0);
 | |
| }
 | |
| 
 | |
| static void copy_string (struct grub_parser_param *parser, const char *str, unsigned hint)
 | |
| {
 | |
|   grub_size_t size;
 | |
|   char *ptr;
 | |
|   unsigned len;
 | |
| 
 | |
|   len = hint ? hint : grub_strlen (str);
 | |
|   if (parser->lexerstate->used + len >= parser->lexerstate->size)
 | |
|     {
 | |
|       size = len * 2;
 | |
|       if (size < parser->lexerstate->size * 2)
 | |
|         size = parser->lexerstate->size * 2;
 | |
|       ptr = grub_realloc (parser->lexerstate->text, size);
 | |
|       if (!ptr)
 | |
|         {
 | |
|           grub_script_yyerror (parser, 0);
 | |
|           return;
 | |
|         }
 | |
| 
 | |
|       parser->lexerstate->text = ptr;
 | |
|       parser->lexerstate->size = size;
 | |
|     }
 | |
|   grub_strcpy (parser->lexerstate->text + parser->lexerstate->used - 1, str);
 | |
|   parser->lexerstate->used += len;
 | |
| }
 | |
| 
 | |
| static int
 | |
| grub_lexer_resplit (const char *text, yyscan_t yyscanner)
 | |
| {
 | |
|   /* resplit text */
 | |
|   if (yy_scan_string (text, yyscanner))
 | |
|     {
 | |
|       yyget_extra (yyscanner)->lexerstate->merge_start = 1;
 | |
|       yy_push_state (SPLIT, yyscanner);
 | |
|       return 0;
 | |
|     }
 | |
|   grub_script_yyerror (yyget_extra (yyscanner), 0);
 | |
|   return 1;
 | |
| }
 | |
| 
 | |
| static int
 | |
| grub_lexer_unput (const char *text, yyscan_t yyscanner)
 | |
| {
 | |
|   struct grub_lexer_param *lexerstate = yyget_extra (yyscanner)->lexerstate;
 | |
| 
 | |
|   grub_free (lexerstate->prefix);
 | |
| 
 | |
|   lexerstate->prefix = grub_strdup (text);
 | |
|   if (! lexerstate->prefix)
 | |
|     {
 | |
|       grub_script_yyerror (yyget_extra (yyscanner), N_("out of memory"));
 | |
|       return 1;
 | |
|     }
 | |
|   return 0;
 | |
| }
 |