]>
Commit | Line | Data |
---|---|---|
4b13b216 | 1 | /* grub-mkimage.c - make a bootable image */ |
6a161fa9 | 2 | /* |
4b13b216 | 3 | * GRUB -- GRand Unified Bootloader |
2f1a3acf | 4 | * Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 Free Software Foundation, Inc. |
6a161fa9 | 5 | * |
5a79f472 | 6 | * GRUB is free software: you can redistribute it and/or modify |
6a161fa9 | 7 | * it under the terms of the GNU General Public License as published by |
5a79f472 | 8 | * the Free Software Foundation, either version 3 of the License, or |
6a161fa9 | 9 | * (at your option) any later version. |
10 | * | |
5a79f472 | 11 | * GRUB is distributed in the hope that it will be useful, |
6a161fa9 | 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 | |
5a79f472 | 17 | * along with GRUB. If not, see <http://www.gnu.org/licenses/>. |
6a161fa9 | 18 | */ |
19 | ||
20 | #include <config.h> | |
4b13b216 | 21 | #include <grub/types.h> |
5855d253 | 22 | #include <grub/elf.h> |
a49217cf | 23 | #include <grub/aout.h> |
9a90f817 | 24 | #include <grub/i18n.h> |
4b13b216 | 25 | #include <grub/kernel.h> |
26 | #include <grub/disk.h> | |
692d7c28 | 27 | #include <grub/emu/misc.h> |
4b13b216 | 28 | #include <grub/util/misc.h> |
29 | #include <grub/util/resolve.h> | |
55a581dc | 30 | #include <grub/misc.h> |
614be3f1 | 31 | #include <grub/offsets.h> |
04360337 | 32 | #include <grub/crypto.h> |
5452733f | 33 | #include <grub/dl.h> |
e310b81f | 34 | #include <time.h> |
70ffcc93 | 35 | #include <multiboot.h> |
6a161fa9 | 36 | |
37 | #include <stdio.h> | |
38 | #include <unistd.h> | |
39 | #include <string.h> | |
40 | #include <stdlib.h> | |
3a73dcb6 | 41 | #include <assert.h> |
d31bc996 | 42 | #include <grub/efi/pe32.h> |
bc1cf01c VS |
43 | #include <grub/uboot/image.h> |
44 | #include <grub/arm/reloc.h> | |
d5e2a158 | 45 | #include <grub/ia64/reloc.h> |
71c1d67a | 46 | #include <grub/osdep/hostfile.h> |
ec16e026 | 47 | #include <grub/util/install.h> |
cd46aa6c | 48 | #include <grub/emu/config.h> |
6a161fa9 | 49 | |
50 | #define _GNU_SOURCE 1 | |
ca3e2088 VS |
51 | |
52 | #pragma GCC diagnostic ignored "-Wmissing-prototypes" | |
53 | #pragma GCC diagnostic ignored "-Wmissing-declarations" | |
c76899a0 | 54 | #include <argp.h> |
ca3e2088 VS |
55 | #pragma GCC diagnostic error "-Wmissing-prototypes" |
56 | #pragma GCC diagnostic error "-Wmissing-declarations" | |
57 | ||
6a161fa9 | 58 | |
548643e5 RM |
59 | #include "progname.h" |
60 | ||
6a161fa9 | 61 | \f |
62 | ||
c76899a0 | 63 | static struct argp_option options[] = { |
67093bc0 VS |
64 | {"directory", 'd', N_("DIR"), 0, |
65 | /* TRANSLATORS: platform here isn't identifier. It can be translated. */ | |
66 | N_("use images and modules under DIR [default=%s/<platform>]"), 0}, | |
1440b7eb | 67 | {"prefix", 'p', N_("DIR"), 0, N_("set prefix directory"), 0}, |
67093bc0 | 68 | {"memdisk", 'm', N_("FILE"), 0, |
ef292a87 VS |
69 | /* TRANSLATORS: "memdisk" here isn't an identifier, it can be translated. |
70 | "embed" is a verb (command description). "*/ | |
8573d302 | 71 | N_("embed FILE as a memdisk image\n" |
bfdfeb25 VS |
72 | "Implies `-p (memdisk)/boot/grub' and overrides any prefix supplied previously," |
73 | " but the prefix itself can be overridden by later options"), 0}, | |
fcbb723d | 74 | {"dtb", 'D', N_("FILE"), 0, N_("embed FILE as a device tree (DTB)\n"), 0}, |
ef292a87 | 75 | /* TRANSLATORS: "embed" is a verb (command description). "*/ |
9c4b5c13 | 76 | {"config", 'c', N_("FILE"), 0, N_("embed FILE as an early config"), 0}, |
5e3b8dcb VS |
77 | /* TRANSLATORS: "embed" is a verb (command description). "*/ |
78 | {"pubkey", 'k', N_("FILE"), 0, N_("embed FILE as public key for signature checking"), 0}, | |
9c4b5c13 VS |
79 | /* TRANSLATORS: NOTE is a name of segment. */ |
80 | {"note", 'n', 0, 0, N_("add NOTE segment for CHRP IEEE1275"), 0}, | |
c76899a0 | 81 | {"output", 'o', N_("FILE"), 0, N_("output a generated image to FILE [default=stdout]"), 0}, |
0ae70393 | 82 | {"format", 'O', N_("FORMAT"), 0, 0, 0}, |
79451522 | 83 | {"compression", 'C', "(xz|none|auto)", 0, N_("choose the compression to use for core image"), 0}, |
b1154713 | 84 | {"sbat", 's', N_("FILE"), 0, N_("SBAT metadata"), 0}, |
968de8c2 | 85 | {"disable-shim-lock", GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK, 0, 0, N_("disable shim_lock verifier"), 0}, |
0ae70393 | 86 | {"verbose", 'v', 0, 0, N_("print verbose messages."), 0}, |
c76899a0 VS |
87 | { 0, 0, 0, 0, 0, 0 } |
88 | }; | |
6a161fa9 | 89 | |
ae558c2c VS |
90 | #pragma GCC diagnostic ignored "-Wformat-nonliteral" |
91 | ||
c76899a0 VS |
92 | static char * |
93 | help_filter (int key, const char *text, void *input __attribute__ ((unused))) | |
6a161fa9 | 94 | { |
c76899a0 | 95 | switch (key) |
614be3f1 | 96 | { |
c76899a0 | 97 | case 'd': |
cd46aa6c | 98 | return xasprintf (text, grub_util_get_pkglibdir ()); |
c76899a0 VS |
99 | case 'O': |
100 | { | |
ec16e026 | 101 | char *formats = grub_install_get_image_targets_string (), *ret; |
b2b149cb | 102 | ret = xasprintf ("%s\n%s %s", _("generate an image in FORMAT"), |
0ae70393 | 103 | _("available formats:"), formats); |
c76899a0 VS |
104 | free (formats); |
105 | return ret; | |
106 | } | |
107 | default: | |
108 | return (char *) text; | |
614be3f1 | 109 | } |
6a161fa9 | 110 | } |
111 | ||
ae558c2c VS |
112 | #pragma GCC diagnostic error "-Wformat-nonliteral" |
113 | ||
c76899a0 | 114 | struct arguments |
6a161fa9 | 115 | { |
c76899a0 VS |
116 | size_t nmodules; |
117 | size_t modules_max; | |
118 | char **modules; | |
119 | char *output; | |
120 | char *dir; | |
121 | char *prefix; | |
122 | char *memdisk; | |
fcbb723d | 123 | char *dtb; |
5e3b8dcb VS |
124 | char **pubkeys; |
125 | size_t npubkeys; | |
c76899a0 VS |
126 | char *font; |
127 | char *config; | |
b1154713 | 128 | char *sbat; |
c76899a0 | 129 | int note; |
968de8c2 | 130 | int disable_shim_lock; |
ec16e026 | 131 | const struct grub_install_image_target_desc *image_target; |
c76899a0 VS |
132 | grub_compression_t comp; |
133 | }; | |
6a161fa9 | 134 | |
c76899a0 VS |
135 | static error_t |
136 | argp_parser (int key, char *arg, struct argp_state *state) | |
137 | { | |
138 | /* Get the input argument from argp_parse, which we | |
139 | know is a pointer to our arguments structure. */ | |
140 | struct arguments *arguments = state->input; | |
bdca2607 | 141 | |
c76899a0 | 142 | switch (key) |
6a161fa9 | 143 | { |
c76899a0 VS |
144 | case 'o': |
145 | if (arguments->output) | |
146 | free (arguments->output); | |
6a161fa9 | 147 | |
c76899a0 VS |
148 | arguments->output = xstrdup (arg); |
149 | break; | |
150 | ||
151 | case 'O': | |
152 | { | |
ec16e026 | 153 | arguments->image_target = grub_install_get_image_target (arg); |
c76899a0 | 154 | if (!arguments->image_target) |
6a161fa9 | 155 | { |
c76899a0 VS |
156 | printf (_("unknown target format %s\n"), arg); |
157 | argp_usage (state); | |
158 | exit (1); | |
159 | } | |
160 | break; | |
161 | } | |
162 | case 'd': | |
163 | if (arguments->dir) | |
164 | free (arguments->dir); | |
6a161fa9 | 165 | |
c76899a0 VS |
166 | arguments->dir = xstrdup (arg); |
167 | break; | |
6a161fa9 | 168 | |
c76899a0 VS |
169 | case 'n': |
170 | arguments->note = 1; | |
171 | break; | |
2296410f | 172 | |
c76899a0 VS |
173 | case 'm': |
174 | if (arguments->memdisk) | |
175 | free (arguments->memdisk); | |
55a581dc | 176 | |
c76899a0 | 177 | arguments->memdisk = xstrdup (arg); |
b39f9d20 | 178 | |
c76899a0 VS |
179 | if (arguments->prefix) |
180 | free (arguments->prefix); | |
a9207284 | 181 | |
c76899a0 VS |
182 | arguments->prefix = xstrdup ("(memdisk)/boot/grub"); |
183 | break; | |
55a581dc | 184 | |
fcbb723d VS |
185 | case 'D': |
186 | if (arguments->dtb) | |
187 | free (arguments->dtb); | |
188 | ||
189 | arguments->dtb = xstrdup (arg); | |
190 | break; | |
191 | ||
5e3b8dcb VS |
192 | case 'k': |
193 | arguments->pubkeys = xrealloc (arguments->pubkeys, | |
194 | sizeof (arguments->pubkeys[0]) | |
195 | * (arguments->npubkeys + 1)); | |
196 | arguments->pubkeys[arguments->npubkeys++] = xstrdup (arg); | |
197 | break; | |
198 | ||
c76899a0 VS |
199 | case 'c': |
200 | if (arguments->config) | |
201 | free (arguments->config); | |
5e898c9d | 202 | |
c76899a0 VS |
203 | arguments->config = xstrdup (arg); |
204 | break; | |
5e898c9d | 205 | |
c76899a0 VS |
206 | case 'C': |
207 | if (grub_strcmp (arg, "xz") == 0) | |
208 | { | |
2c44e493 | 209 | #ifdef HAVE_LIBLZMA |
ec16e026 | 210 | arguments->comp = GRUB_COMPRESSION_XZ; |
2c44e493 | 211 | #else |
495fc8c1 VS |
212 | grub_util_error ("%s", |
213 | _("grub-mkimage is compiled without XZ support")); | |
2c44e493 | 214 | #endif |
c76899a0 VS |
215 | } |
216 | else if (grub_strcmp (arg, "none") == 0) | |
ec16e026 | 217 | arguments->comp = GRUB_COMPRESSION_NONE; |
a9d96eeb | 218 | else if (grub_strcmp (arg, "auto") == 0) |
ec16e026 | 219 | arguments->comp = GRUB_COMPRESSION_AUTO; |
c76899a0 VS |
220 | else |
221 | grub_util_error (_("Unknown compression format %s"), arg); | |
222 | break; | |
223 | ||
224 | case 'p': | |
225 | if (arguments->prefix) | |
226 | free (arguments->prefix); | |
227 | ||
228 | arguments->prefix = xstrdup (arg); | |
229 | break; | |
230 | ||
b1154713 PJ |
231 | case 's': |
232 | if (arguments->sbat) | |
233 | free (arguments->sbat); | |
234 | ||
235 | arguments->sbat = xstrdup (arg); | |
236 | break; | |
237 | ||
968de8c2 DJL |
238 | case GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK: |
239 | arguments->disable_shim_lock = 1; | |
240 | break; | |
241 | ||
c76899a0 VS |
242 | case 'v': |
243 | verbosity++; | |
244 | break; | |
245 | case ARGP_KEY_ARG: | |
246 | assert (arguments->nmodules < arguments->modules_max); | |
247 | arguments->modules[arguments->nmodules++] = xstrdup(arg); | |
248 | break; | |
758194b0 | 249 | |
c76899a0 VS |
250 | default: |
251 | return ARGP_ERR_UNKNOWN; | |
252 | } | |
253 | return 0; | |
254 | } | |
6a161fa9 | 255 | |
c76899a0 VS |
256 | static struct argp argp = { |
257 | options, argp_parser, N_("[OPTION]... [MODULES]"), | |
258 | N_("Make a bootable image of GRUB."), | |
259 | NULL, help_filter, NULL | |
260 | }; | |
261 | ||
262 | int | |
263 | main (int argc, char *argv[]) | |
264 | { | |
265 | FILE *fp = stdout; | |
266 | struct arguments arguments; | |
377c1211 | 267 | unsigned i; |
bf697e28 | 268 | |
ae5540d3 | 269 | grub_util_host_init (&argc, &argv); |
6a161fa9 | 270 | |
c76899a0 | 271 | memset (&arguments, 0, sizeof (struct arguments)); |
ec16e026 | 272 | arguments.comp = GRUB_COMPRESSION_AUTO; |
c76899a0 VS |
273 | arguments.modules_max = argc + 1; |
274 | arguments.modules = xmalloc ((arguments.modules_max + 1) | |
275 | * sizeof (arguments.modules[0])); | |
276 | memset (arguments.modules, 0, (arguments.modules_max + 1) | |
277 | * sizeof (arguments.modules[0])); | |
6a161fa9 | 278 | |
c76899a0 VS |
279 | if (argp_parse (&argp, argc, argv, 0, 0, &arguments) != 0) |
280 | { | |
281 | fprintf (stderr, "%s", _("Error in parsing command line arguments\n")); | |
282 | exit(1); | |
6a161fa9 | 283 | } |
284 | ||
c76899a0 | 285 | if (!arguments.image_target) |
614be3f1 | 286 | { |
c76899a0 | 287 | char *program = xstrdup(program_name); |
0ae70393 | 288 | printf ("%s\n", _("Target format not specified (use the -O option).")); |
c76899a0 VS |
289 | argp_help (&argp, stderr, ARGP_HELP_STD_USAGE, program); |
290 | free (program); | |
291 | exit(1); | |
614be3f1 VS |
292 | } |
293 | ||
1440b7eb AB |
294 | if (!arguments.prefix) |
295 | { | |
296 | char *program = xstrdup(program_name); | |
297 | printf ("%s\n", _("Prefix not specified (use the -p option).")); | |
298 | argp_help (&argp, stderr, ARGP_HELP_STD_USAGE, program); | |
299 | free (program); | |
300 | exit(1); | |
301 | } | |
302 | ||
c76899a0 | 303 | if (arguments.output) |
6a161fa9 | 304 | { |
bb338aaf | 305 | fp = grub_util_fopen (arguments.output, "wb"); |
6a161fa9 | 306 | if (! fp) |
0ae70393 VS |
307 | grub_util_error (_("cannot open `%s': %s"), arguments.output, |
308 | strerror (errno)); | |
6a161fa9 | 309 | } |
310 | ||
c76899a0 | 311 | if (!arguments.dir) |
94ac7906 | 312 | { |
ec16e026 | 313 | const char *dn = grub_util_get_target_dirname (arguments.image_target); |
cd46aa6c VS |
314 | const char *pkglibdir = grub_util_get_pkglibdir (); |
315 | char *ptr; | |
316 | arguments.dir = xmalloc (grub_strlen (pkglibdir) + grub_strlen (dn) + 2); | |
317 | ptr = grub_stpcpy (arguments.dir, pkglibdir); | |
318 | *ptr++ = '/'; | |
319 | strcpy (ptr, dn); | |
94ac7906 VS |
320 | } |
321 | ||
1440b7eb | 322 | grub_install_generate_image (arguments.dir, arguments.prefix, fp, |
ec16e026 VS |
323 | arguments.output, arguments.modules, |
324 | arguments.memdisk, arguments.pubkeys, | |
325 | arguments.npubkeys, arguments.config, | |
326 | arguments.image_target, arguments.note, | |
b1154713 | 327 | arguments.comp, arguments.dtb, |
968de8c2 | 328 | arguments.sbat, arguments.disable_shim_lock); |
6a161fa9 | 329 | |
62daa270 CW |
330 | if (grub_util_file_sync (fp) < 0) |
331 | grub_util_error (_("cannot sync `%s': %s"), arguments.output ? : "stdout", | |
332 | strerror (errno)); | |
333 | if (fclose (fp) == EOF) | |
334 | grub_util_error (_("cannot close `%s': %s"), arguments.output ? : "stdout", | |
335 | strerror (errno)); | |
6a161fa9 | 336 | |
377c1211 VS |
337 | for (i = 0; i < arguments.nmodules; i++) |
338 | free (arguments.modules[i]); | |
339 | ||
962b69d9 | 340 | free (arguments.dir); |
377c1211 VS |
341 | free (arguments.prefix); |
342 | free (arguments.modules); | |
6a161fa9 | 343 | |
c821711f LL |
344 | if (arguments.output) |
345 | free (arguments.output); | |
346 | ||
b1154713 PJ |
347 | if (arguments.sbat) |
348 | free (arguments.sbat); | |
349 | ||
6a161fa9 | 350 | return 0; |
351 | } |