ieee1275: split up grub_machine_get_bootlocation
[grub.git] / util / grub-script-check.c
1 /* grub-script-check.c - check grub script file for syntax errors */
2 /*
3  *  GRUB  --  GRand Unified Bootloader
4  *  Copyright (C) 2009,2010  Free Software Foundation, Inc.
5  *
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.
10  *
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.
15  *
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/>.
18  */
19
20 #include <config.h>
21 #include <grub/types.h>
22 #include <grub/mm.h>
23 #include <grub/misc.h>
24 #include <grub/emu/misc.h>
25 #include <grub/util/misc.h>
26 #include <grub/i18n.h>
27 #include <grub/parser.h>
28 #include <grub/script_sh.h>
29
30 #define _GNU_SOURCE     1
31
32 #include <ctype.h>
33 #include <errno.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #pragma GCC diagnostic ignored "-Wmissing-prototypes"
38 #pragma GCC diagnostic ignored "-Wmissing-declarations"
39 #include <argp.h>
40 #pragma GCC diagnostic error "-Wmissing-prototypes"
41 #pragma GCC diagnostic error "-Wmissing-declarations"
42
43 #include "progname.h"
44
45 struct arguments
46 {
47   int verbose;
48   char *filename;
49 };
50
51 static struct argp_option options[] = {
52   {"verbose",     'v', 0,      0, N_("print verbose messages."), 0},
53   { 0, 0, 0, 0, 0, 0 }
54 };
55
56 static error_t
57 argp_parser (int key, char *arg, struct argp_state *state)
58 {
59   /* Get the input argument from argp_parse, which we
60      know is a pointer to our arguments structure. */
61   struct arguments *arguments = state->input;
62
63   switch (key)
64     {
65     case 'v':
66       arguments->verbose = 1;
67       break;
68
69     case ARGP_KEY_ARG:
70       if (state->arg_num == 0)
71         arguments->filename = xstrdup (arg);
72       else
73         {
74           /* Too many arguments. */
75           fprintf (stderr, _("Unknown extra argument `%s'."), arg);
76           fprintf (stderr, "\n");
77           argp_usage (state);
78         }
79       break;
80     default:
81       return ARGP_ERR_UNKNOWN;
82     }
83   return 0;
84 }
85
86 static struct argp argp = {
87   options, argp_parser, N_("[PATH]"),
88   N_("Checks GRUB script configuration file for syntax errors."),
89   NULL, NULL, NULL
90 };
91
92 /* Context for main.  */
93 struct main_ctx
94 {
95   int lineno;
96   FILE *file;
97   struct arguments arguments;
98 };
99
100 /* Helper for main.  */
101 static grub_err_t
102 get_config_line (char **line, int cont __attribute__ ((unused)), void *data)
103 {
104   struct main_ctx *ctx = data;
105   int i;
106   char *cmdline = 0;
107   size_t len = 0;
108   ssize_t curread;
109
110   curread = getline (&cmdline, &len, (ctx->file ?: stdin));
111   if (curread == -1)
112     {
113       *line = 0;
114       grub_errno = GRUB_ERR_READ_ERROR;
115
116       if (cmdline)
117         free (cmdline);
118       return grub_errno;
119     }
120
121   if (ctx->arguments.verbose)
122     grub_printf ("%s", cmdline);
123
124   for (i = 0; cmdline[i] != '\0'; i++)
125     {
126       /* Replace tabs and carriage returns with spaces.  */
127       if (cmdline[i] == '\t' || cmdline[i] == '\r')
128         cmdline[i] = ' ';
129
130       /* Replace '\n' with '\0'.  */
131       if (cmdline[i] == '\n')
132         cmdline[i] = '\0';
133     }
134
135   ctx->lineno++;
136   *line = grub_strdup (cmdline);
137
138   free (cmdline);
139   return 0;
140 }
141
142 int
143 main (int argc, char *argv[])
144 {
145   struct main_ctx ctx = {
146     .lineno = 0,
147     .file = 0
148   };
149   char *input;
150   int found_input = 0, found_cmd = 0;
151   struct grub_script *script = NULL;
152
153   grub_util_host_init (&argc, &argv);
154
155   memset (&ctx.arguments, 0, sizeof (struct arguments));
156
157   /* Check for options.  */
158   if (argp_parse (&argp, argc, argv, 0, 0, &ctx.arguments) != 0)
159     {
160       fprintf (stderr, "%s", _("Error in parsing command line arguments\n"));
161       exit(1);
162     }
163
164   /* Obtain ARGUMENT.  */
165   if (!ctx.arguments.filename)
166     {
167       ctx.file = 0; /* read from stdin */
168     }
169   else
170     {
171       ctx.file = grub_util_fopen (ctx.arguments.filename, "r");
172       if (! ctx.file)
173         {
174           char *program = xstrdup(program_name);
175           fprintf (stderr, _("cannot open `%s': %s"),
176                    ctx.arguments.filename, strerror (errno));
177           argp_help (&argp, stderr, ARGP_HELP_STD_USAGE, program);
178           free(program);
179           exit(1);
180         }
181     }
182
183   do
184     {
185       input = 0;
186       get_config_line (&input, 0, &ctx);
187       if (! input) 
188         break;
189       found_input = 1;
190
191       script = grub_script_parse (input, get_config_line, &ctx);
192       if (script)
193         {
194           if (script->cmd)
195             found_cmd = 1;
196           grub_script_execute (script);
197           grub_script_free (script);
198         }
199
200       grub_free (input);
201     } while (script != 0);
202
203   if (ctx.file) fclose (ctx.file);
204
205   if (found_input && script == 0)
206     {
207       fprintf (stderr, _("Syntax error at line %u\n"), ctx.lineno);
208       return 1;
209     }
210   if (! found_cmd)
211     {
212       fprintf (stderr, _("Script `%s' contains no commands and will do nothing\n"),
213                ctx.arguments.filename);
214       return 1;
215     }
216
217   return 0;
218 }