ieee1275: split up grub_machine_get_bootlocation
[grub.git] / util / grub-editenv.c
1 /* grub-editenv.c - tool to edit environment block.  */
2 /*
3  *  GRUB  --  GRand Unified Bootloader
4  *  Copyright (C) 2008,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/emu/misc.h>
23 #include <grub/util/misc.h>
24 #include <grub/lib/envblk.h>
25 #include <grub/i18n.h>
26 #include <grub/emu/hostfile.h>
27 #include <grub/util/install.h>
28
29 #include <stdio.h>
30 #include <unistd.h>
31 #include <string.h>
32 #include <stdlib.h>
33 #pragma GCC diagnostic ignored "-Wmissing-prototypes"
34 #pragma GCC diagnostic ignored "-Wmissing-declarations"
35 #include <argp.h>
36 #pragma GCC diagnostic error "-Wmissing-prototypes"
37 #pragma GCC diagnostic error "-Wmissing-declarations"
38
39
40 #include "progname.h"
41
42 #define DEFAULT_ENVBLK_PATH DEFAULT_DIRECTORY "/" GRUB_ENVBLK_DEFCFG
43
44 static struct argp_option options[] = {
45   {0,        0, 0, OPTION_DOC, N_("Commands:"), 1},
46   {"create", 0, 0, OPTION_DOC|OPTION_NO_USAGE,
47    N_("Create a blank environment block file."), 0},
48   {"list",   0, 0, OPTION_DOC|OPTION_NO_USAGE,
49    N_("List the current variables."), 0},
50   /* TRANSLATORS: "set" is a keyword. It's a summary of "set" subcommand.  */
51   {N_("set [NAME=VALUE ...]"), 0, 0, OPTION_DOC|OPTION_NO_USAGE,
52    N_("Set variables."), 0},
53   /* TRANSLATORS: "unset" is a keyword. It's a summary of "unset" subcommand.  */
54   {N_("unset [NAME ...]"),    0, 0, OPTION_DOC|OPTION_NO_USAGE,
55    N_("Delete variables."), 0},
56
57   {0,         0, 0, OPTION_DOC, N_("Options:"), -1},
58   {"verbose", 'v', 0, 0, N_("print verbose messages."), 0},
59
60   { 0, 0, 0, 0, 0, 0 }
61 };
62
63 /* Print the version information.  */
64 static void
65 print_version (FILE *stream, struct argp_state *state)
66 {
67   fprintf (stream, "%s (%s) %s\n", program_name, PACKAGE_NAME, PACKAGE_VERSION);
68 }
69 void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
70
71 /* Set the bug report address */
72 const char *argp_program_bug_address = "<"PACKAGE_BUGREPORT">";
73
74 static error_t argp_parser (int key, char *arg, struct argp_state *state)
75 {
76   switch (key)
77     {
78       case 'v':
79         verbosity++;
80         break;
81
82       case ARGP_KEY_NO_ARGS:
83         fprintf (stderr, "%s",
84                  _("You need to specify at least one command.\n"));
85         argp_usage (state);
86         break;
87
88       default:
89         return ARGP_ERR_UNKNOWN;
90     }
91
92   return 0;
93 }
94
95 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
96
97 static char *
98 help_filter (int key, const char *text, void *input __attribute__ ((unused)))
99 {
100   switch (key)
101     {
102       case ARGP_KEY_HELP_POST_DOC:
103         return xasprintf (text, DEFAULT_ENVBLK_PATH, DEFAULT_ENVBLK_PATH);
104
105       default:
106         return (char *) text;
107     }
108 }
109
110 #pragma GCC diagnostic error "-Wformat-nonliteral"
111
112 struct argp argp = {
113   options, argp_parser, N_("FILENAME COMMAND"),
114   "\n"N_("\
115 Tool to edit environment block.")
116 "\v"N_("\
117 If FILENAME is `-', the default value %s is used.\n\n\
118 There is no `delete' command; if you want to delete the whole environment\n\
119 block, use `rm %s'."),
120   NULL, help_filter, NULL
121 };
122
123 static grub_envblk_t
124 open_envblk_file (const char *name)
125 {
126   FILE *fp;
127   char *buf;
128   size_t size;
129   grub_envblk_t envblk;
130
131   fp = grub_util_fopen (name, "rb");
132   if (! fp)
133     {
134       /* Create the file implicitly.  */
135       grub_util_create_envblk_file (name);
136       fp = grub_util_fopen (name, "rb");
137       if (! fp)
138         grub_util_error (_("cannot open `%s': %s"), name,
139                          strerror (errno));
140     }
141
142   if (fseek (fp, 0, SEEK_END) < 0)
143     grub_util_error (_("cannot seek `%s': %s"), name,
144                      strerror (errno));
145
146   size = (size_t) ftell (fp);
147
148   if (fseek (fp, 0, SEEK_SET) < 0)
149     grub_util_error (_("cannot seek `%s': %s"), name,
150                      strerror (errno));
151
152   buf = xmalloc (size);
153
154   if (fread (buf, 1, size, fp) != size)
155     grub_util_error (_("cannot read `%s': %s"), name,
156                      strerror (errno));
157
158   fclose (fp);
159
160   envblk = grub_envblk_open (buf, size);
161   if (! envblk)
162     grub_util_error ("%s", _("invalid environment block"));
163
164   return envblk;
165 }
166
167 static int
168 print_var (const char *varname, const char *value,
169            void *hook_data __attribute__ ((unused)))
170 {
171   printf ("%s=%s\n", varname, value);
172   return 0;
173 }
174
175 static void
176 list_variables (const char *name)
177 {
178   grub_envblk_t envblk;
179
180   envblk = open_envblk_file (name);
181   grub_envblk_iterate (envblk, NULL, print_var);
182   grub_envblk_close (envblk);
183 }
184
185 static void
186 write_envblk (const char *name, grub_envblk_t envblk)
187 {
188   FILE *fp;
189
190   fp = grub_util_fopen (name, "wb");
191   if (! fp)
192     grub_util_error (_("cannot open `%s': %s"), name,
193                      strerror (errno));
194
195   if (fwrite (grub_envblk_buffer (envblk), 1, grub_envblk_size (envblk), fp)
196       != grub_envblk_size (envblk))
197     grub_util_error (_("cannot write to `%s': %s"), name,
198                      strerror (errno));
199
200   grub_util_file_sync (fp);
201   fclose (fp);
202 }
203
204 static void
205 set_variables (const char *name, int argc, char *argv[])
206 {
207   grub_envblk_t envblk;
208
209   envblk = open_envblk_file (name);
210   while (argc)
211     {
212       char *p;
213
214       p = strchr (argv[0], '=');
215       if (! p)
216         grub_util_error (_("invalid parameter %s"), argv[0]);
217
218       *(p++) = 0;
219
220       if (! grub_envblk_set (envblk, argv[0], p))
221         grub_util_error ("%s", _("environment block too small"));
222
223       argc--;
224       argv++;
225     }
226
227   write_envblk (name, envblk);
228   grub_envblk_close (envblk);
229 }
230
231 static void
232 unset_variables (const char *name, int argc, char *argv[])
233 {
234   grub_envblk_t envblk;
235
236   envblk = open_envblk_file (name);
237   while (argc)
238     {
239       grub_envblk_delete (envblk, argv[0]);
240
241       argc--;
242       argv++;
243     }
244
245   write_envblk (name, envblk);
246   grub_envblk_close (envblk);
247 }
248
249 int
250 main (int argc, char *argv[])
251 {
252   const char *filename;
253   char *command;
254   int curindex, arg_count;
255
256   grub_util_host_init (&argc, &argv);
257
258   /* Parse our arguments */
259   if (argp_parse (&argp, argc, argv, 0, &curindex, 0) != 0)
260     {
261       fprintf (stderr, "%s", _("Error in parsing command line arguments\n"));
262       exit(1);
263     }
264
265   arg_count = argc - curindex;
266
267   if (arg_count == 1)
268     {
269       filename = DEFAULT_ENVBLK_PATH;
270       command  = argv[curindex++];
271     }
272   else
273     {
274       filename = argv[curindex++];
275       if (strcmp (filename, "-") == 0)
276         filename = DEFAULT_ENVBLK_PATH;
277       command  = argv[curindex++];
278     }
279
280   if (strcmp (command, "create") == 0)
281     grub_util_create_envblk_file (filename);
282   else if (strcmp (command, "list") == 0)
283     list_variables (filename);
284   else if (strcmp (command, "set") == 0)
285     set_variables (filename, argc - curindex, argv + curindex);
286   else if (strcmp (command, "unset") == 0)
287     unset_variables (filename, argc - curindex, argv + curindex);
288   else
289     {
290       char *program = xstrdup(program_name);
291       fprintf (stderr, _("Unknown command `%s'.\n"), command);
292       argp_help (&argp, stderr, ARGP_HELP_STD_USAGE, program);
293       free(program);
294       exit(1);
295     }
296
297   return 0;
298 }