]>
Commit | Line | Data |
---|---|---|
a1447506 | 1 | /* grub-setup.c - make GRUB usable */ |
2 | /* | |
3 | * GRUB -- GRand Unified Bootloader | |
2f1a3acf | 4 | * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010 Free Software Foundation, Inc. |
a1447506 | 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/util/misc.h> | |
23 | #include <grub/device.h> | |
4b2e6ca2 | 24 | #include <grub/i18n.h> |
a1447506 | 25 | #include <grub/disk.h> |
26 | #include <grub/file.h> | |
27 | #include <grub/fs.h> | |
28 | #include <grub/partition.h> | |
71acf5e5 | 29 | #include <grub/msdos_partition.h> |
a1447506 | 30 | #include <grub/gpt_partition.h> |
31 | #include <grub/env.h> | |
ab4da2cd | 32 | #include <grub/emu/hostdisk.h> |
a1447506 | 33 | #include <grub/machine/boot.h> |
34 | #include <grub/machine/kernel.h> | |
35 | #include <grub/term.h> | |
36 | #include <grub/util/raid.h> | |
37 | #include <grub/util/lvm.h> | |
6e86896e | 38 | #include <grub/util/ofpath.h> |
a1447506 | 39 | |
40 | #include <grub_setup_init.h> | |
41 | ||
42 | #include <stdio.h> | |
43 | #include <unistd.h> | |
44 | #include <string.h> | |
45 | #include <stdlib.h> | |
46 | #include <sys/types.h> | |
47 | #include <sys/stat.h> | |
48 | #include <dirent.h> | |
ab4da2cd | 49 | #include <grub/emu/getroot.h> |
a1447506 | 50 | |
51 | #define _GNU_SOURCE 1 | |
52 | #include <getopt.h> | |
53 | ||
4b2e6ca2 DM |
54 | #include "progname.h" |
55 | ||
a1447506 | 56 | /* This program fills in various fields inside of the 'boot' and 'core' |
57 | * image files. | |
58 | * | |
59 | * The 'boot' image needs to know the OBP path name of the root | |
60 | * device. It also needs to know the initial block number of | |
61 | * 'core' (which is 'diskboot' concatenated with 'kernel' and | |
62 | * all the modules, this is created by grub-mkimage). This resulting | |
67e23c90 | 63 | * 'boot' image is 512 bytes in size and is placed in the second block |
a1447506 | 64 | * of a partition. |
65 | * | |
66 | * The initial 'diskboot' block acts as a loader for the actual GRUB | |
67 | * kernel. It contains the loading code and then a block list. | |
68 | * | |
69 | * The block list of 'core' starts at the end of the 'diskboot' image | |
70 | * and works it's way backwards towards the end of the code of 'diskboot'. | |
71 | * | |
72 | * We patch up the images with the necessary values and write out the | |
73 | * result. | |
74 | */ | |
75 | ||
76 | #define DEFAULT_BOOT_FILE "boot.img" | |
77 | #define DEFAULT_CORE_FILE "core.img" | |
78 | ||
8ea6ecb3 VS |
79 | #define grub_target_to_host16(x) grub_be_to_cpu16(x) |
80 | #define grub_target_to_host32(x) grub_be_to_cpu32(x) | |
81 | #define grub_target_to_host64(x) grub_be_to_cpu64(x) | |
82 | #define grub_host_to_target16(x) grub_cpu_to_be16(x) | |
83 | #define grub_host_to_target32(x) grub_cpu_to_be32(x) | |
84 | #define grub_host_to_target64(x) grub_cpu_to_be64(x) | |
85 | ||
a1447506 | 86 | /* This is the blocklist used in the diskboot image. */ |
87 | struct boot_blocklist | |
88 | { | |
89 | grub_uint64_t start; | |
90 | grub_uint32_t len; | |
91 | } __attribute__ ((packed)); | |
92 | ||
93 | void | |
94 | grub_putchar (int c) | |
95 | { | |
96 | putchar (c); | |
97 | } | |
98 | ||
99 | int | |
100 | grub_getkey (void) | |
101 | { | |
102 | return -1; | |
103 | } | |
104 | ||
a1447506 | 105 | void |
106 | grub_refresh (void) | |
107 | { | |
108 | fflush (stdout); | |
109 | } | |
110 | ||
111 | static void | |
112 | setup (const char *prefix, const char *dir, | |
113 | const char *boot_file, const char *core_file, | |
114 | const char *root, const char *dest) | |
115 | { | |
116 | char *boot_path, *core_path; | |
117 | char *boot_img, *core_img; | |
118 | size_t boot_size, core_size; | |
119 | grub_uint16_t core_sectors; | |
120 | grub_device_t root_dev, dest_dev; | |
ee9056d0 | 121 | char *boot_devpath; |
b076cdc7 | 122 | grub_disk_addr_t *kernel_byte; |
a1447506 | 123 | struct boot_blocklist *first_block, *block; |
124 | char *tmp_img; | |
125 | int i; | |
126 | grub_disk_addr_t first_sector; | |
127 | grub_uint16_t last_length = GRUB_DISK_SECTOR_SIZE; | |
128 | grub_file_t file; | |
129 | FILE *fp; | |
130 | struct { grub_uint64_t start; grub_uint64_t end; } embed_region; | |
131 | embed_region.start = embed_region.end = ~0UL; | |
132 | ||
133 | auto void NESTED_FUNC_ATTR save_first_sector (grub_disk_addr_t sector, | |
134 | unsigned int offset, | |
135 | unsigned int length); | |
136 | auto void NESTED_FUNC_ATTR save_blocklists (grub_disk_addr_t sector, | |
137 | unsigned int offset, | |
138 | unsigned int length); | |
139 | ||
140 | void NESTED_FUNC_ATTR save_first_sector (grub_disk_addr_t sector, | |
141 | unsigned int offset, | |
142 | unsigned int length) | |
143 | { | |
144 | grub_util_info ("first sector is <%llu,%u,%u>", sector, offset, length); | |
145 | ||
146 | if (offset != 0 || length != GRUB_DISK_SECTOR_SIZE) | |
70a14d3d | 147 | grub_util_error ("the first sector of the core file " |
a1447506 | 148 | "is not sector-aligned"); |
149 | ||
150 | first_sector = sector; | |
151 | } | |
152 | ||
153 | void NESTED_FUNC_ATTR save_blocklists (grub_disk_addr_t sector, | |
154 | unsigned int offset, | |
155 | unsigned int length) | |
156 | { | |
157 | struct boot_blocklist *prev = block + 1; | |
158 | ||
159 | grub_util_info ("saving <%llu,%u,%u>", sector, offset, length); | |
160 | ||
161 | if (offset != 0 || last_length != GRUB_DISK_SECTOR_SIZE) | |
70a14d3d | 162 | grub_util_error ("non-sector-aligned data is found in the core file"); |
a1447506 | 163 | |
164 | if (block != first_block | |
165 | && (grub_be_to_cpu64 (prev->start) | |
166 | + grub_be_to_cpu16 (prev->len)) == sector) | |
167 | prev->len = grub_cpu_to_be16 (grub_be_to_cpu16 (prev->len) + 1); | |
168 | else | |
169 | { | |
170 | block->start = grub_cpu_to_be64 (sector); | |
171 | block->len = grub_cpu_to_be16 (1); | |
172 | ||
173 | block--; | |
174 | if (block->len) | |
70a14d3d | 175 | grub_util_error ("the sectors of the core file are too fragmented"); |
a1447506 | 176 | } |
177 | ||
178 | last_length = length; | |
179 | } | |
180 | ||
181 | /* Read the boot image by the OS service. */ | |
182 | boot_path = grub_util_get_path (dir, boot_file); | |
183 | boot_size = grub_util_get_image_size (boot_path); | |
184 | if (boot_size != GRUB_DISK_SECTOR_SIZE) | |
70a14d3d | 185 | grub_util_error ("the size of `%s' is not %d", |
a1447506 | 186 | boot_path, GRUB_DISK_SECTOR_SIZE); |
187 | boot_img = grub_util_read_image (boot_path); | |
188 | free (boot_path); | |
189 | ||
190 | /* Set the addresses of variables in the boot image. */ | |
191 | boot_devpath = (char *) (boot_img | |
192 | + GRUB_BOOT_AOUT_HEADER_SIZE | |
193 | + GRUB_BOOT_MACHINE_BOOT_DEVPATH); | |
b076cdc7 VS |
194 | kernel_byte = (grub_disk_addr_t *) (boot_img |
195 | + GRUB_BOOT_AOUT_HEADER_SIZE | |
196 | + GRUB_BOOT_MACHINE_KERNEL_BYTE); | |
a1447506 | 197 | |
198 | core_path = grub_util_get_path (dir, core_file); | |
199 | core_size = grub_util_get_image_size (core_path); | |
200 | core_sectors = ((core_size + GRUB_DISK_SECTOR_SIZE - 1) | |
201 | >> GRUB_DISK_SECTOR_BITS); | |
202 | if (core_size < GRUB_DISK_SECTOR_SIZE) | |
70a14d3d | 203 | grub_util_error ("the size of `%s' is too small", core_path); |
a1447506 | 204 | |
205 | core_img = grub_util_read_image (core_path); | |
206 | free (core_path); | |
207 | ||
208 | /* Have FIRST_BLOCK to point to the first blocklist. */ | |
209 | first_block = (struct boot_blocklist *) (core_img | |
210 | + GRUB_DISK_SECTOR_SIZE | |
211 | - sizeof (*block)); | |
212 | ||
6e86896e | 213 | grub_util_info ("root is `%s', dest is `%s'", root, dest); |
a1447506 | 214 | |
215 | /* Open the root device and the destination device. */ | |
216 | grub_util_info ("Opening root"); | |
217 | root_dev = grub_device_open (root); | |
218 | if (! root_dev) | |
219 | grub_util_error ("%s", grub_errmsg); | |
220 | ||
221 | grub_util_info ("Opening dest"); | |
222 | dest_dev = grub_device_open (dest); | |
223 | if (! dest_dev) | |
224 | grub_util_error ("%s", grub_errmsg); | |
225 | ||
226 | grub_util_info ("setting the root device to `%s'", root); | |
227 | if (grub_env_set ("root", root) != GRUB_ERR_NONE) | |
228 | grub_util_error ("%s", grub_errmsg); | |
229 | ||
230 | /* The core image must be put on a filesystem unfortunately. */ | |
231 | grub_util_info ("will leave the core image on the filesystem"); | |
232 | ||
233 | /* Make sure that GRUB reads the identical image as the OS. */ | |
234 | tmp_img = xmalloc (core_size); | |
235 | core_path = grub_util_get_path (prefix, core_file); | |
236 | ||
237 | /* It is a Good Thing to sync two times. */ | |
238 | sync (); | |
239 | sync (); | |
240 | ||
241 | #define MAX_TRIES 5 | |
242 | ||
243 | for (i = 0; i < MAX_TRIES; i++) | |
244 | { | |
245 | grub_util_info ("attempting to read the core image `%s' from GRUB%s", | |
246 | core_path, (i == 0) ? "" : " again"); | |
247 | ||
248 | grub_disk_cache_invalidate_all (); | |
249 | ||
250 | file = grub_file_open (core_path); | |
251 | if (file) | |
252 | { | |
253 | if (grub_file_size (file) != core_size) | |
254 | grub_util_info ("succeeded in opening the core image but the size is different (%d != %d)", | |
255 | (int) grub_file_size (file), (int) core_size); | |
256 | else if (grub_file_read (file, tmp_img, core_size) | |
257 | != (grub_ssize_t) core_size) | |
258 | grub_util_info ("succeeded in opening the core image but cannot read %d bytes", | |
259 | (int) core_size); | |
260 | else if (memcmp (core_img, tmp_img, core_size) != 0) | |
261 | { | |
262 | #if 0 | |
263 | FILE *dump; | |
264 | FILE *dump2; | |
265 | ||
266 | dump = fopen ("dump.img", "wb"); | |
267 | if (dump) | |
268 | { | |
269 | fwrite (tmp_img, 1, core_size, dump); | |
270 | fclose (dump); | |
271 | } | |
272 | ||
273 | dump2 = fopen ("dump2.img", "wb"); | |
274 | if (dump2) | |
275 | { | |
276 | fwrite (core_img, 1, core_size, dump2); | |
277 | fclose (dump2); | |
278 | } | |
279 | ||
280 | #endif | |
281 | grub_util_info ("succeeded in opening the core image but the data is different"); | |
282 | } | |
283 | else | |
284 | { | |
285 | grub_file_close (file); | |
286 | break; | |
287 | } | |
288 | ||
289 | grub_file_close (file); | |
290 | } | |
291 | else | |
292 | grub_util_info ("couldn't open the core image"); | |
293 | ||
294 | if (grub_errno) | |
295 | grub_util_info ("error message = %s", grub_errmsg); | |
296 | ||
297 | grub_errno = GRUB_ERR_NONE; | |
298 | sync (); | |
299 | sleep (1); | |
300 | } | |
301 | ||
302 | if (i == MAX_TRIES) | |
70a14d3d | 303 | grub_util_error ("cannot read `%s' correctly", core_path); |
a1447506 | 304 | |
305 | /* Clean out the blocklists. */ | |
306 | block = first_block; | |
307 | while (block->len) | |
308 | { | |
309 | block->start = 0; | |
310 | block->len = 0; | |
311 | ||
312 | block--; | |
313 | ||
314 | if ((char *) block <= core_img) | |
70a14d3d | 315 | grub_util_error ("no terminator in the core image"); |
a1447506 | 316 | } |
317 | ||
318 | /* Now read the core image to determine where the sectors are. */ | |
319 | file = grub_file_open (core_path); | |
320 | if (! file) | |
321 | grub_util_error ("%s", grub_errmsg); | |
322 | ||
323 | file->read_hook = save_first_sector; | |
324 | if (grub_file_read (file, tmp_img, GRUB_DISK_SECTOR_SIZE) | |
325 | != GRUB_DISK_SECTOR_SIZE) | |
70a14d3d | 326 | grub_util_error ("failed to read the first sector of the core image"); |
a1447506 | 327 | |
328 | block = first_block; | |
329 | file->read_hook = save_blocklists; | |
330 | if (grub_file_read (file, tmp_img, core_size - GRUB_DISK_SECTOR_SIZE) | |
331 | != (grub_ssize_t) core_size - GRUB_DISK_SECTOR_SIZE) | |
70a14d3d | 332 | grub_util_error ("failed to read the rest sectors of the core image"); |
a1447506 | 333 | |
ee9056d0 VS |
334 | if (file->device->disk->id != dest_dev->disk->id) |
335 | { | |
336 | const char *dest_ofpath; | |
337 | dest_ofpath | |
338 | = grub_util_devname_to_ofpath (grub_util_biosdisk_get_osdev (file->device->disk)); | |
339 | grub_util_info ("dest_ofpath is `%s'", dest_ofpath); | |
340 | strncpy (boot_devpath, dest_ofpath, GRUB_BOOT_MACHINE_BOOT_DEVPATH_END | |
341 | - GRUB_BOOT_MACHINE_BOOT_DEVPATH - 1); | |
342 | boot_devpath[GRUB_BOOT_MACHINE_BOOT_DEVPATH_END | |
343 | - GRUB_BOOT_MACHINE_BOOT_DEVPATH - 1] = 0; | |
344 | } | |
345 | else | |
346 | { | |
347 | grub_util_info ("non cross-disk install"); | |
348 | memset (boot_devpath, 0, GRUB_BOOT_MACHINE_BOOT_DEVPATH_END | |
349 | - GRUB_BOOT_MACHINE_BOOT_DEVPATH); | |
350 | } | |
351 | ||
a1447506 | 352 | grub_file_close (file); |
353 | ||
354 | free (core_path); | |
355 | free (tmp_img); | |
356 | ||
b076cdc7 | 357 | *kernel_byte = grub_cpu_to_be64 (first_sector << GRUB_DISK_SECTOR_BITS); |
a1447506 | 358 | |
a1447506 | 359 | grub_util_info ("boot device path %s, prefix is %s, dest is %s", |
360 | boot_devpath, prefix, dest); | |
361 | ||
362 | /* Write the first two sectors of the core image onto the disk. */ | |
363 | core_path = grub_util_get_path (dir, core_file); | |
364 | grub_util_info ("opening the core image `%s'", core_path); | |
365 | fp = fopen (core_path, "r+b"); | |
366 | if (! fp) | |
70a14d3d | 367 | grub_util_error ("cannot open `%s'", core_path); |
a1447506 | 368 | |
369 | grub_util_write_image (core_img, GRUB_DISK_SECTOR_SIZE, fp); | |
370 | fclose (fp); | |
371 | free (core_path); | |
372 | ||
373 | /* Write the boot image onto the disk. */ | |
374 | if (grub_disk_write (dest_dev->disk, 1, 0, GRUB_DISK_SECTOR_SIZE, boot_img)) | |
375 | grub_util_error ("%s", grub_errmsg); | |
376 | ||
377 | /* Sync is a Good Thing. */ | |
378 | sync (); | |
379 | ||
380 | free (core_img); | |
381 | free (boot_img); | |
382 | grub_device_close (dest_dev); | |
383 | grub_device_close (root_dev); | |
384 | } | |
385 | ||
386 | static struct option options[] = | |
387 | { | |
388 | {"boot-image", required_argument, 0, 'b'}, | |
389 | {"core-image", required_argument, 0, 'c'}, | |
390 | {"directory", required_argument, 0, 'd'}, | |
391 | {"device-map", required_argument, 0, 'm'}, | |
392 | {"root-device", required_argument, 0, 'r'}, | |
393 | {"help", no_argument, 0, 'h'}, | |
394 | {"version", no_argument, 0, 'V'}, | |
395 | {"verbose", no_argument, 0, 'v'}, | |
396 | {0, 0, 0, 0} | |
397 | }; | |
398 | ||
399 | static void | |
400 | usage (int status) | |
401 | { | |
402 | if (status) | |
70a14d3d | 403 | fprintf (stderr, "Try `%s --help' for more information.\n", program_name); |
a1447506 | 404 | else |
405 | printf ("\ | |
8a4c07fd | 406 | Usage: %s [OPTION]... DEVICE\n\ |
a1447506 | 407 | \n\ |
408 | Set up images to boot from DEVICE.\n\ | |
70a14d3d | 409 | DEVICE must be a GRUB device (e.g. `(hd0,1)').\n\ |
094dfb69 | 410 | \n\ |
c88a83f6 | 411 | You should not normally run %s directly. Use grub-install instead.\n\ |
a1447506 | 412 | \n\ |
413 | -b, --boot-image=FILE use FILE as the boot image [default=%s]\n\ | |
414 | -c, --core-image=FILE use FILE as the core image [default=%s]\n\ | |
415 | -d, --directory=DIR use GRUB files in the directory DIR [default=%s]\n\ | |
416 | -m, --device-map=FILE use FILE as the device map [default=%s]\n\ | |
417 | -r, --root-device=DEV use DEV as the root device [default=guessed]\n\ | |
418 | -h, --help display this message and exit\n\ | |
419 | -V, --version print version information and exit\n\ | |
420 | -v, --verbose print verbose messages\n\ | |
421 | \n\ | |
422 | Report bugs to <%s>.\n\ | |
7d24e434 | 423 | ", program_name, program_name, |
a1447506 | 424 | DEFAULT_BOOT_FILE, DEFAULT_CORE_FILE, DEFAULT_DIRECTORY, |
425 | DEFAULT_DEVICE_MAP, PACKAGE_BUGREPORT); | |
426 | ||
427 | exit (status); | |
428 | } | |
429 | ||
430 | struct grub_setup_info | |
431 | { | |
432 | char *boot_file; | |
433 | char *core_file; | |
434 | char *dir; | |
435 | char *dev_map; | |
436 | char *root_dev; | |
437 | char *prefix; | |
438 | char *dest_dev; | |
439 | }; | |
440 | ||
441 | static void | |
442 | init_info (struct grub_setup_info *gp) | |
443 | { | |
444 | gp->boot_file = NULL; | |
445 | gp->core_file = NULL; | |
446 | gp->dir = NULL; | |
447 | gp->dev_map = NULL; | |
448 | gp->root_dev = NULL; | |
449 | gp->prefix = NULL; | |
7428eb2c | 450 | gp->dest_dev = NULL; |
a1447506 | 451 | } |
452 | ||
453 | static int | |
454 | parse_options (struct grub_setup_info *gp, int argc, char *argv[]) | |
455 | { | |
456 | while (1) | |
457 | { | |
458 | int c = getopt_long (argc, argv, "b:c:d:m:r:hVv", options, 0); | |
459 | ||
460 | if (c == -1) | |
461 | break; | |
462 | else | |
463 | switch (c) | |
464 | { | |
465 | case 'b': | |
466 | if (gp->boot_file) | |
467 | free (gp->boot_file); | |
468 | ||
469 | gp->boot_file = xstrdup (optarg); | |
470 | break; | |
471 | ||
472 | case 'c': | |
473 | if (gp->core_file) | |
474 | free (gp->core_file); | |
475 | ||
476 | gp->core_file = xstrdup (optarg); | |
477 | break; | |
478 | ||
479 | case 'd': | |
480 | if (gp->dir) | |
481 | free (gp->dir); | |
482 | ||
483 | gp->dir = xstrdup (optarg); | |
484 | break; | |
485 | ||
486 | case 'm': | |
487 | if (gp->dev_map) | |
488 | free (gp->dev_map); | |
489 | ||
490 | gp->dev_map = xstrdup (optarg); | |
491 | break; | |
492 | ||
493 | case 'r': | |
494 | if (gp->root_dev) | |
495 | free (gp->root_dev); | |
496 | ||
497 | gp->root_dev = xstrdup (optarg); | |
498 | break; | |
499 | ||
500 | case 'h': | |
501 | usage (0); | |
502 | break; | |
503 | ||
504 | case 'V': | |
0ea7c4f9 | 505 | printf ("%s (%s) %s\n", program_name, PACKAGE_NAME, PACKAGE_VERSION); |
a1447506 | 506 | return 0; |
507 | ||
508 | case 'v': | |
509 | verbosity++; | |
510 | break; | |
511 | ||
512 | default: | |
513 | usage (1); | |
514 | break; | |
515 | } | |
516 | } | |
517 | ||
518 | if (verbosity > 1) | |
519 | grub_env_set ("debug", "all"); | |
520 | ||
521 | if (optind >= argc) | |
522 | { | |
523 | fprintf (stderr, "No device is specified.\n"); | |
524 | usage (1); | |
525 | } | |
526 | ||
527 | if (optind + 1 != argc) | |
528 | { | |
529 | fprintf (stderr, "Unknown extra argument `%s'.\n", argv[optind + 1]); | |
530 | usage (1); | |
531 | } | |
532 | return 1; | |
533 | } | |
534 | ||
535 | static char * | |
536 | get_device_name (char *dev) | |
537 | { | |
538 | size_t len = strlen (dev); | |
539 | ||
540 | if (dev[0] != '(' || dev[len - 1] != ')') | |
541 | return 0; | |
542 | ||
543 | dev[len - 1] = '\0'; | |
544 | return dev + 1; | |
545 | } | |
546 | ||
547 | static void | |
548 | find_dest_dev (struct grub_setup_info *gp, char *argv[]) | |
549 | { | |
550 | gp->dest_dev = get_device_name (argv[optind]); | |
551 | if (! gp->dest_dev) | |
552 | { | |
553 | /* Possibly, the user specified an OS device file. */ | |
554 | gp->dest_dev = grub_util_get_grub_dev (argv[optind]); | |
555 | if (! gp->dest_dev) | |
556 | { | |
557 | fprintf (stderr, "Invalid device `%s'.\n", argv[optind]); | |
558 | usage (1); | |
559 | } | |
70a14d3d | 560 | grub_util_info ("transformed OS device `%s' into GRUB device `%s'", |
a1447506 | 561 | argv[optind], gp->dest_dev); |
562 | } | |
563 | else | |
564 | { | |
565 | /* For simplicity. */ | |
566 | gp->dest_dev = xstrdup (gp->dest_dev); | |
70a14d3d | 567 | grub_util_info ("Using `%s' as GRUB device", gp->dest_dev); |
a1447506 | 568 | } |
569 | } | |
570 | ||
571 | static void | |
572 | check_root_dev (struct grub_setup_info *gp) | |
573 | { | |
574 | if (gp->root_dev) | |
575 | { | |
576 | char *tmp = get_device_name (gp->root_dev); | |
577 | ||
578 | if (! tmp) | |
70a14d3d | 579 | grub_util_error ("invalid root device `%s'", gp->root_dev); |
a1447506 | 580 | |
581 | tmp = xstrdup (tmp); | |
582 | free (gp->root_dev); | |
583 | gp->root_dev = tmp; | |
584 | } | |
585 | else | |
586 | { | |
587 | char *dir = gp->dir ? gp->dir : DEFAULT_DIRECTORY; | |
588 | char *root_device = grub_guess_root_device (dir); | |
589 | ||
590 | gp->root_dev = grub_util_get_grub_dev (root_device); | |
591 | if (! gp->root_dev) | |
592 | { | |
593 | grub_util_info ("guessing the root device failed, because of `%s'", | |
594 | grub_errmsg); | |
70a14d3d | 595 | grub_util_error ("cannot guess the root device. " |
596 | "Specify the option `--root-device'"); | |
a1447506 | 597 | } |
70a14d3d | 598 | grub_util_info ("guessed root device `%s' and root_dev `%s' from " |
599 | "dir `%s'", root_device, gp->root_dev, dir); | |
a1447506 | 600 | } |
601 | } | |
602 | ||
603 | static void | |
604 | free_memory (struct grub_setup_info *gp) | |
605 | { | |
606 | free (gp->boot_file); | |
607 | free (gp->core_file); | |
608 | free (gp->dir); | |
609 | free (gp->dev_map); | |
610 | free (gp->root_dev); | |
611 | free (gp->prefix); | |
612 | free (gp->dest_dev); | |
613 | } | |
614 | ||
615 | int | |
616 | main (int argc, char *argv[]) | |
617 | { | |
618 | struct grub_setup_info ginfo; | |
619 | ||
8a4c07fd | 620 | set_program_name (argv[0]); |
2f1a3acf YB |
621 | |
622 | grub_util_init_nls (); | |
a1447506 | 623 | |
624 | init_info (&ginfo); | |
625 | if (!parse_options (&ginfo, argc, argv)) | |
626 | return 0; | |
627 | ||
628 | /* Initialize the emulated biosdisk driver. */ | |
629 | grub_util_biosdisk_init (ginfo.dev_map ? ginfo.dev_map : DEFAULT_DEVICE_MAP); | |
630 | ||
631 | /* Initialize all modules. */ | |
632 | grub_init_all (); | |
633 | ||
634 | find_dest_dev (&ginfo, argv); | |
635 | ||
60b4a7c4 BC |
636 | ginfo.prefix = grub_make_system_path_relative_to_its_root (ginfo.dir ? |
637 | : DEFAULT_DIRECTORY); | |
a1447506 | 638 | |
639 | check_root_dev (&ginfo); | |
640 | ||
641 | /* Do the real work. */ | |
642 | setup (ginfo.prefix, | |
643 | ginfo.dir ? ginfo.dir : DEFAULT_DIRECTORY, | |
644 | ginfo.boot_file ? ginfo.boot_file : DEFAULT_BOOT_FILE, | |
645 | ginfo.core_file ? ginfo.core_file : DEFAULT_CORE_FILE, | |
646 | ginfo.root_dev, ginfo.dest_dev); | |
647 | ||
648 | /* Free resources. */ | |
649 | grub_fini_all (); | |
650 | ||
651 | free_memory (&ginfo); | |
652 | ||
653 | return 0; | |
654 | } |