]> git.proxmox.com Git - grub2.git/blob - util/grub-setup.c
Clarify and unify messages.
[grub2.git] / util / grub-setup.c
1 /* grub-setup.c - make GRUB usable */
2 /*
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2011 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/device.h>
25 #include <grub/disk.h>
26 #include <grub/file.h>
27 #include <grub/fs.h>
28 #include <grub/partition.h>
29 #include <grub/env.h>
30 #include <grub/emu/hostdisk.h>
31 #include <grub/machine/boot.h>
32 #include <grub/machine/kernel.h>
33 #include <grub/term.h>
34 #include <grub/i18n.h>
35 #include <grub/util/lvm.h>
36 #ifdef GRUB_MACHINE_IEEE1275
37 #include <grub/util/ofpath.h>
38 #endif
39
40 #include <stdio.h>
41 #include <unistd.h>
42 #include <string.h>
43 #include <stdlib.h>
44 #include <sys/types.h>
45 #include <sys/stat.h>
46 #include <dirent.h>
47 #include <assert.h>
48 #include <grub/emu/getroot.h>
49 #include "progname.h"
50 #include <grub/reed_solomon.h>
51 #include <grub/msdos_partition.h>
52 #include <include/grub/crypto.h>
53
54 #define _GNU_SOURCE 1
55 #include <argp.h>
56
57 /* On SPARC this program fills in various fields inside of the 'boot' and 'core'
58 * image files.
59 *
60 * The 'boot' image needs to know the OBP path name of the root
61 * device. It also needs to know the initial block number of
62 * 'core' (which is 'diskboot' concatenated with 'kernel' and
63 * all the modules, this is created by grub-mkimage). This resulting
64 * 'boot' image is 512 bytes in size and is placed in the second block
65 * of a partition.
66 *
67 * The initial 'diskboot' block acts as a loader for the actual GRUB
68 * kernel. It contains the loading code and then a block list.
69 *
70 * The block list of 'core' starts at the end of the 'diskboot' image
71 * and works it's way backwards towards the end of the code of 'diskboot'.
72 *
73 * We patch up the images with the necessary values and write out the
74 * result.
75 */
76
77 #define DEFAULT_BOOT_FILE "boot.img"
78 #define DEFAULT_CORE_FILE "core.img"
79
80 #ifdef GRUB_MACHINE_SPARC64
81 #define grub_target_to_host16(x) grub_be_to_cpu16(x)
82 #define grub_target_to_host32(x) grub_be_to_cpu32(x)
83 #define grub_target_to_host64(x) grub_be_to_cpu64(x)
84 #define grub_host_to_target16(x) grub_cpu_to_be16(x)
85 #define grub_host_to_target32(x) grub_cpu_to_be32(x)
86 #define grub_host_to_target64(x) grub_cpu_to_be64(x)
87 #elif defined (GRUB_MACHINE_PCBIOS)
88 #define grub_target_to_host16(x) grub_le_to_cpu16(x)
89 #define grub_target_to_host32(x) grub_le_to_cpu32(x)
90 #define grub_target_to_host64(x) grub_le_to_cpu64(x)
91 #define grub_host_to_target16(x) grub_cpu_to_le16(x)
92 #define grub_host_to_target32(x) grub_cpu_to_le32(x)
93 #define grub_host_to_target64(x) grub_cpu_to_le64(x)
94 #else
95 #error Complete this
96 #endif
97
98 static void
99 write_rootdev (char *core_img, grub_device_t root_dev,
100 char *boot_img, grub_uint64_t first_sector)
101 {
102 #ifdef GRUB_MACHINE_PCBIOS
103 {
104 grub_uint8_t *boot_drive;
105 grub_disk_addr_t *kernel_sector;
106 boot_drive = (grub_uint8_t *) (boot_img + GRUB_BOOT_MACHINE_BOOT_DRIVE);
107 kernel_sector = (grub_disk_addr_t *) (boot_img
108 + GRUB_BOOT_MACHINE_KERNEL_SECTOR);
109
110 /* FIXME: can this be skipped? */
111 *boot_drive = 0xFF;
112
113 *kernel_sector = grub_cpu_to_le64 (first_sector);
114 }
115 #endif
116 #ifdef GRUB_MACHINE_IEEE1275
117 {
118 grub_disk_addr_t *kernel_byte;
119 kernel_byte = (grub_disk_addr_t *) (boot_img
120 + GRUB_BOOT_AOUT_HEADER_SIZE
121 + GRUB_BOOT_MACHINE_KERNEL_BYTE);
122 *kernel_byte = grub_cpu_to_be64 (first_sector << GRUB_DISK_SECTOR_BITS);
123 }
124 #endif
125 }
126
127 #ifdef GRUB_MACHINE_IEEE1275
128 #define BOOT_SECTOR 1
129 #else
130 #define BOOT_SECTOR 0
131 #endif
132
133 static void
134 setup (const char *dir,
135 const char *boot_file, const char *core_file,
136 const char *dest, int force,
137 int fs_probe, int allow_floppy)
138 {
139 char *boot_path, *core_path, *core_path_dev, *core_path_dev_full;
140 char *boot_img, *core_img;
141 char *root = 0;
142 size_t boot_size, core_size;
143 grub_uint16_t core_sectors;
144 grub_device_t root_dev = 0, dest_dev;
145 struct grub_boot_blocklist *first_block, *block, *last_block;
146 char *tmp_img;
147 int i;
148 grub_disk_addr_t first_sector;
149 #ifdef GRUB_MACHINE_PCBIOS
150 grub_uint16_t current_segment
151 = GRUB_BOOT_MACHINE_KERNEL_SEG + (GRUB_DISK_SECTOR_SIZE >> 4);
152 #endif
153 grub_uint16_t last_length = GRUB_DISK_SECTOR_SIZE;
154 grub_file_t file;
155 FILE *fp;
156
157 auto void NESTED_FUNC_ATTR save_first_sector (grub_disk_addr_t sector,
158 unsigned offset,
159 unsigned length);
160 auto void NESTED_FUNC_ATTR save_blocklists (grub_disk_addr_t sector,
161 unsigned offset,
162 unsigned length);
163
164 void NESTED_FUNC_ATTR save_first_sector (grub_disk_addr_t sector,
165 unsigned offset,
166 unsigned length)
167 {
168 grub_util_info ("the first sector is <%llu,%u,%u>",
169 sector, offset, length);
170
171 if (offset != 0 || length != GRUB_DISK_SECTOR_SIZE)
172 grub_util_error (_("the first sector of the core file is not sector-aligned"));
173
174 first_sector = sector;
175 }
176
177 void NESTED_FUNC_ATTR save_blocklists (grub_disk_addr_t sector,
178 unsigned offset,
179 unsigned length)
180 {
181 struct grub_boot_blocklist *prev = block + 1;
182
183 grub_util_info ("saving <%llu,%u,%u>", sector, offset, length);
184
185 if (offset != 0 || last_length != GRUB_DISK_SECTOR_SIZE)
186 grub_util_error (_("non-sector-aligned data is found in the core file"));
187
188 if (block != first_block
189 && (grub_target_to_host64 (prev->start)
190 + grub_target_to_host16 (prev->len)) == sector)
191 prev->len = grub_host_to_target16 (grub_target_to_host16 (prev->len) + 1);
192 else
193 {
194 block->start = grub_host_to_target64 (sector);
195 block->len = grub_host_to_target16 (1);
196 #ifdef GRUB_MACHINE_PCBIOS
197 block->segment = grub_host_to_target16 (current_segment);
198 #endif
199
200 block--;
201 if (block->len)
202 grub_util_error (_("the sectors of the core file are too fragmented"));
203 }
204
205 last_length = length;
206 #ifdef GRUB_MACHINE_PCBIOS
207 current_segment += GRUB_DISK_SECTOR_SIZE >> 4;
208 #endif
209 }
210
211 /* Read the boot image by the OS service. */
212 boot_path = grub_util_get_path (dir, boot_file);
213 boot_size = grub_util_get_image_size (boot_path);
214 if (boot_size != GRUB_DISK_SECTOR_SIZE)
215 grub_util_error (_("the size of `%s' is not %u"),
216 boot_path, GRUB_DISK_SECTOR_SIZE);
217 boot_img = grub_util_read_image (boot_path);
218 free (boot_path);
219
220 core_path = grub_util_get_path (dir, core_file);
221 core_size = grub_util_get_image_size (core_path);
222 core_sectors = ((core_size + GRUB_DISK_SECTOR_SIZE - 1)
223 >> GRUB_DISK_SECTOR_BITS);
224 if (core_size < GRUB_DISK_SECTOR_SIZE)
225 grub_util_error (_("the size of `%s' is too small"), core_path);
226 #ifdef GRUB_MACHINE_PCBIOS
227 if (core_size > 0xFFFF * GRUB_DISK_SECTOR_SIZE)
228 grub_util_error (_("the size of `%s' is too large"), core_path);
229 #endif
230
231 core_img = grub_util_read_image (core_path);
232
233 /* Have FIRST_BLOCK to point to the first blocklist. */
234 first_block = (struct grub_boot_blocklist *) (core_img
235 + GRUB_DISK_SECTOR_SIZE
236 - sizeof (*block));
237 grub_util_info ("root is `%s', dest is `%s'", root, dest);
238
239 grub_util_info ("Opening dest");
240 dest_dev = grub_device_open (dest);
241 if (! dest_dev)
242 grub_util_error ("%s", _(grub_errmsg));
243
244 {
245 char **root_devices = grub_guess_root_devices (dir);
246 char **cur;
247 int found = 0;
248
249 for (cur = root_devices; *cur; cur++)
250 {
251 char *drive;
252 grub_device_t try_dev;
253
254 drive = grub_util_get_grub_dev (*cur);
255 if (!drive)
256 continue;
257 try_dev = grub_device_open (drive);
258 if (! try_dev)
259 continue;
260 if (!found && try_dev->disk->id == dest_dev->disk->id
261 && try_dev->disk->dev->id == dest_dev->disk->dev->id)
262 {
263 if (root_dev)
264 grub_device_close (root_dev);
265 free (root);
266 root_dev = try_dev;
267 root = drive;
268 found = 1;
269 continue;
270 }
271 if (!root_dev)
272 {
273 root_dev = try_dev;
274 root = drive;
275 continue;
276 }
277 grub_device_close (try_dev);
278 free (drive);
279 }
280 if (!root_dev)
281 {
282 grub_util_error ("guessing the root device failed, because of `%s'",
283 grub_errmsg);
284 }
285 grub_util_info ("guessed root_dev `%s' from "
286 "dir `%s'", root_dev->disk->name, dir);
287 }
288
289 grub_util_info ("setting the root device to `%s'", root);
290 if (grub_env_set ("root", root) != GRUB_ERR_NONE)
291 grub_util_error ("%s", _(grub_errmsg));
292
293 #ifdef GRUB_MACHINE_PCBIOS
294 /* Read the original sector from the disk. */
295 tmp_img = xmalloc (GRUB_DISK_SECTOR_SIZE);
296 if (grub_disk_read (dest_dev->disk, 0, 0, GRUB_DISK_SECTOR_SIZE, tmp_img))
297 grub_util_error ("%s", _(grub_errmsg));
298 #endif
299
300 #ifdef GRUB_MACHINE_PCBIOS
301 {
302 grub_uint16_t *boot_drive_check;
303 boot_drive_check = (grub_uint16_t *) (boot_img
304 + GRUB_BOOT_MACHINE_DRIVE_CHECK);
305 /* Copy the possible DOS BPB. */
306 memcpy (boot_img + GRUB_BOOT_MACHINE_BPB_START,
307 tmp_img + GRUB_BOOT_MACHINE_BPB_START,
308 GRUB_BOOT_MACHINE_BPB_END - GRUB_BOOT_MACHINE_BPB_START);
309
310 /* If DEST_DRIVE is a hard disk, enable the workaround, which is
311 for buggy BIOSes which don't pass boot drive correctly. Instead,
312 they pass 0x00 or 0x01 even when booted from 0x80. */
313 if (!allow_floppy && !grub_util_biosdisk_is_floppy (dest_dev->disk))
314 /* Replace the jmp (2 bytes) with double nop's. */
315 *boot_drive_check = 0x9090;
316 }
317 #endif
318
319 #ifdef GRUB_MACHINE_PCBIOS
320 {
321 grub_partition_map_t dest_partmap = NULL;
322 grub_partition_t container = dest_dev->disk->partition;
323 int multiple_partmaps = 0;
324 int is_ldm;
325 grub_err_t err;
326 grub_disk_addr_t *sectors;
327 int i;
328 grub_fs_t fs;
329 unsigned int nsec;
330
331 /* Unlike root_dev, with dest_dev we're interested in the partition map even
332 if dest_dev itself is a whole disk. */
333 auto int NESTED_FUNC_ATTR identify_partmap (grub_disk_t disk,
334 const grub_partition_t p);
335 int NESTED_FUNC_ATTR identify_partmap (grub_disk_t disk __attribute__ ((unused)),
336 const grub_partition_t p)
337 {
338 if (p->parent != container)
339 return 0;
340 /* NetBSD and OpenBSD subpartitions have metadata inside a partition,
341 so they are safe to ignore.
342 */
343 if (grub_strcmp (p->partmap->name, "netbsd") == 0
344 || grub_strcmp (p->partmap->name, "openbsd") == 0)
345 return 0;
346 if (dest_partmap == NULL)
347 {
348 dest_partmap = p->partmap;
349 return 0;
350 }
351 if (dest_partmap == p->partmap)
352 return 0;
353 multiple_partmaps = 1;
354 return 1;
355 }
356
357 grub_partition_iterate (dest_dev->disk, identify_partmap);
358
359 if (container && grub_strcmp (container->partmap->name, "msdos") == 0
360 && dest_partmap
361 && (container->msdostype == GRUB_PC_PARTITION_TYPE_NETBSD
362 || container->msdostype == GRUB_PC_PARTITION_TYPE_OPENBSD))
363 {
364 grub_util_warn (_("Attempting to install GRUB to a disk with multiple partition labels or both partition label and filesystem. This is not supported yet."));
365 goto unable_to_embed;
366 }
367
368 fs = grub_fs_probe (dest_dev);
369 if (!fs)
370 grub_errno = GRUB_ERR_NONE;
371
372 is_ldm = grub_util_is_ldm (dest_dev->disk);
373
374 #ifdef GRUB_MACHINE_PCBIOS
375 if (fs_probe)
376 {
377 if (!fs && !dest_partmap)
378 grub_util_error (_("unable to identify a filesystem in %s; safety check can't be performed"),
379 dest_dev->disk->name);
380 if (fs && !fs->reserved_first_sector)
381 grub_util_error (_("%s appears to contain a %s filesystem which isn't known to "
382 "reserve space for DOS-style boot. Installing GRUB there could "
383 "result in FILESYSTEM DESTRUCTION if valuable data is overwritten "
384 "by grub-setup (--skip-fs-probe disables this "
385 "check, use at your own risk)"), dest_dev->disk->name, fs->name);
386
387 if (dest_partmap && strcmp (dest_partmap->name, "msdos") != 0
388 && strcmp (dest_partmap->name, "gpt") != 0
389 && strcmp (dest_partmap->name, "bsd") != 0
390 && strcmp (dest_partmap->name, "netbsd") != 0
391 && strcmp (dest_partmap->name, "openbsd") != 0
392 && strcmp (dest_partmap->name, "sunpc") != 0)
393 grub_util_error (_("%s appears to contain a %s partition map which isn't known to "
394 "reserve space for DOS-style boot. Installing GRUB there could "
395 "result in FILESYSTEM DESTRUCTION if valuable data is overwritten "
396 "by grub-setup (--skip-fs-probe disables this "
397 "check, use at your own risk)"), dest_dev->disk->name, dest_partmap->name);
398 if (is_ldm && dest_partmap && strcmp (dest_partmap->name, "msdos") != 0
399 && strcmp (dest_partmap->name, "gpt") != 0)
400 grub_util_error (_("%s appears to contain a %s partition map and "
401 "LDM which isn't known to be a safe combination."
402 " Installing GRUB there could "
403 "result in FILESYSTEM DESTRUCTION if valuable data"
404 " is overwritten "
405 "by grub-setup (--skip-fs-probe disables this "
406 "check, use at your own risk)"),
407 dest_dev->disk->name, dest_partmap->name);
408
409 }
410 #endif
411
412 /* Copy the partition table. */
413 if (dest_partmap ||
414 (!allow_floppy && !grub_util_biosdisk_is_floppy (dest_dev->disk)))
415 memcpy (boot_img + GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC,
416 tmp_img + GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC,
417 GRUB_BOOT_MACHINE_PART_END - GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC);
418
419 free (tmp_img);
420
421 if (! dest_partmap && ! fs && !is_ldm)
422 {
423 grub_util_warn (_("Attempting to install GRUB to a partitionless disk or to a partition. This is a BAD idea."));
424 goto unable_to_embed;
425 }
426 if (multiple_partmaps || (dest_partmap && fs) || (is_ldm && fs))
427 {
428 grub_util_warn (_("Attempting to install GRUB to a disk with multiple partition labels. This is not supported yet."));
429 goto unable_to_embed;
430 }
431
432 if (dest_partmap && !dest_partmap->embed)
433 {
434 grub_util_warn (_("Partition style '%s' doesn't support embeding"),
435 dest_partmap->name);
436 goto unable_to_embed;
437 }
438
439 if (fs && !fs->embed)
440 {
441 grub_util_warn (_("File system '%s' doesn't support embeding"),
442 fs->name);
443 goto unable_to_embed;
444 }
445
446 nsec = core_sectors;
447 if (is_ldm)
448 err = grub_util_ldm_embed (dest_dev->disk, &nsec,
449 GRUB_EMBED_PCBIOS, &sectors);
450 else if (dest_partmap)
451 err = dest_partmap->embed (dest_dev->disk, &nsec,
452 GRUB_EMBED_PCBIOS, &sectors);
453 else
454 err = fs->embed (dest_dev, &nsec,
455 GRUB_EMBED_PCBIOS, &sectors);
456 if (!err && nsec < core_sectors)
457 {
458 err = grub_error (GRUB_ERR_OUT_OF_RANGE,
459 N_("Your embedding area is unusually small. "
460 "core.img won't fit in it."));
461 }
462
463 if (err)
464 {
465 grub_util_warn ("%s", _(grub_errmsg));
466 grub_errno = GRUB_ERR_NONE;
467 goto unable_to_embed;
468 }
469
470 if (nsec > 2 * core_sectors)
471 nsec = 2 * core_sectors;
472 if (nsec > ((0x78000 - GRUB_KERNEL_I386_PC_LINK_ADDR)
473 >> GRUB_DISK_SECTOR_BITS))
474 nsec = ((0x78000 - GRUB_KERNEL_I386_PC_LINK_ADDR)
475 >> GRUB_DISK_SECTOR_BITS);
476
477 /* Clean out the blocklists. */
478 block = first_block;
479 while (block->len)
480 {
481 grub_memset (block, 0, sizeof (block));
482
483 block--;
484
485 if ((char *) block <= core_img)
486 grub_util_error (_("no terminator in the core image"));
487 }
488
489 save_first_sector (sectors[0] + grub_partition_get_start (container),
490 0, GRUB_DISK_SECTOR_SIZE);
491
492 block = first_block;
493 for (i = 1; i < nsec; i++)
494 save_blocklists (sectors[i] + grub_partition_get_start (container),
495 0, GRUB_DISK_SECTOR_SIZE);
496
497 write_rootdev (core_img, root_dev, boot_img, first_sector);
498
499 core_img = realloc (core_img, nsec * GRUB_DISK_SECTOR_SIZE);
500 first_block = (struct grub_boot_blocklist *) (core_img
501 + GRUB_DISK_SECTOR_SIZE
502 - sizeof (*block));
503
504 grub_size_t no_rs_length;
505 *(grub_uint32_t *) (core_img + GRUB_DISK_SECTOR_SIZE
506 + GRUB_KERNEL_I386_PC_REED_SOLOMON_REDUNDANCY)
507 = grub_host_to_target32 (nsec * GRUB_DISK_SECTOR_SIZE - core_size);
508 no_rs_length = grub_target_to_host16
509 (*(grub_uint16_t *) (core_img
510 + GRUB_DISK_SECTOR_SIZE
511 + GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_LENGTH));
512
513 if (no_rs_length == 0xffff)
514 grub_util_error (_("core.img version mismatch"));
515
516 void *tmp = xmalloc (core_size);
517 grub_memcpy (tmp, core_img, core_size);
518 grub_reed_solomon_add_redundancy (core_img + no_rs_length + GRUB_DISK_SECTOR_SIZE,
519 core_size - no_rs_length - GRUB_DISK_SECTOR_SIZE,
520 nsec * GRUB_DISK_SECTOR_SIZE
521 - core_size);
522 assert (grub_memcmp (tmp, core_img, core_size) == 0);
523 free (tmp);
524
525 /* Make sure that the second blocklist is a terminator. */
526 block = first_block - 1;
527 block->start = 0;
528 block->len = 0;
529 block->segment = 0;
530
531 /* Write the core image onto the disk. */
532 for (i = 0; i < nsec; i++)
533 grub_disk_write (dest_dev->disk, sectors[i], 0,
534 GRUB_DISK_SECTOR_SIZE,
535 core_img + i * GRUB_DISK_SECTOR_SIZE);
536
537 grub_free (sectors);
538
539 goto finish;
540 }
541 #endif
542
543 unable_to_embed:
544
545 #ifdef GRUB_MACHINE_PCBIOS
546 if (dest_dev->disk->id != root_dev->disk->id
547 || dest_dev->disk->dev->id != root_dev->disk->dev->id)
548 grub_util_error (_("embedding is not possible, but this is required for "
549 "cross-disk, RAID and LVM install"));
550 #else
551 if (dest_dev->disk->dev->id != root_dev->disk->dev->id)
552 grub_util_error (_("embedding is not possible, but this is required for "
553 "RAID and LVM install"));
554
555 #endif
556
557 grub_util_warn (_("Embedding is not possible. GRUB can only be installed in this "
558 "setup by using blocklists. However, blocklists are UNRELIABLE and "
559 "their use is discouraged."));
560 if (! force)
561 grub_util_error (_("will not proceed with blocklists"));
562
563 /* The core image must be put on a filesystem unfortunately. */
564 grub_util_info ("will leave the core image on the filesystem");
565
566 /* Make sure that GRUB reads the identical image as the OS. */
567 tmp_img = xmalloc (core_size);
568 core_path_dev_full = grub_util_get_path (dir, core_file);
569 core_path_dev = grub_make_system_path_relative_to_its_root (core_path_dev_full);
570 free (core_path_dev_full);
571
572 grub_util_biosdisk_flush (root_dev->disk);
573
574 #define MAX_TRIES 5
575
576 for (i = 0; i < MAX_TRIES; i++)
577 {
578 grub_util_info ((i == 0) ? _("attempting to read the core image `%s' from GRUB")
579 : _("attempting to read the core image `%s' from GRUB again"),
580 core_path_dev);
581
582 grub_disk_cache_invalidate_all ();
583
584 grub_file_filter_disable_compression ();
585 file = grub_file_open (core_path_dev);
586 if (file)
587 {
588 if (grub_file_size (file) != core_size)
589 grub_util_info ("succeeded in opening the core image but the size is different (%d != %d)",
590 (int) grub_file_size (file), (int) core_size);
591 else if (grub_file_read (file, tmp_img, core_size)
592 != (grub_ssize_t) core_size)
593 grub_util_info ("succeeded in opening the core image but cannot read %d bytes",
594 (int) core_size);
595 else if (memcmp (core_img, tmp_img, core_size) != 0)
596 {
597 #if 0
598 FILE *dump;
599 FILE *dump2;
600
601 dump = fopen ("dump.img", "wb");
602 if (dump)
603 {
604 fwrite (tmp_img, 1, core_size, dump);
605 fclose (dump);
606 }
607
608 dump2 = fopen ("dump2.img", "wb");
609 if (dump2)
610 {
611 fwrite (core_img, 1, core_size, dump2);
612 fclose (dump2);
613 }
614
615 #endif
616 grub_util_info ("succeeded in opening the core image but the data is different");
617 }
618 else
619 {
620 grub_file_close (file);
621 break;
622 }
623
624 grub_file_close (file);
625 }
626 else
627 grub_util_info ("couldn't open the core image");
628
629 if (grub_errno)
630 grub_util_info ("error message = %s", grub_errmsg);
631
632 grub_errno = GRUB_ERR_NONE;
633 grub_util_biosdisk_flush (root_dev->disk);
634 sleep (1);
635 }
636
637 if (i == MAX_TRIES)
638 grub_util_error (_("cannot read `%s' correctly"), core_path_dev);
639
640 /* Clean out the blocklists. */
641 block = first_block;
642 while (block->len)
643 {
644 block->start = 0;
645 block->len = 0;
646 #ifdef GRUB_MACHINE_PCBIOS
647 block->segment = 0;
648 #endif
649
650 block--;
651
652 if ((char *) block <= core_img)
653 grub_util_error (_("no terminator in the core image"));
654 }
655
656 /* Now read the core image to determine where the sectors are. */
657 grub_file_filter_disable_compression ();
658 file = grub_file_open (core_path_dev);
659 if (! file)
660 grub_util_error ("%s", _(grub_errmsg));
661
662 file->read_hook = save_first_sector;
663 if (grub_file_read (file, tmp_img, GRUB_DISK_SECTOR_SIZE)
664 != GRUB_DISK_SECTOR_SIZE)
665 grub_util_error (_("failed to read the first sector of the core image"));
666
667 block = first_block;
668 file->read_hook = save_blocklists;
669 if (grub_file_read (file, tmp_img, core_size - GRUB_DISK_SECTOR_SIZE)
670 != (grub_ssize_t) core_size - GRUB_DISK_SECTOR_SIZE)
671 grub_util_error (_("failed to read the rest sectors of the core image"));
672
673 #ifdef GRUB_MACHINE_IEEE1275
674 {
675 char *boot_devpath;
676 boot_devpath = (char *) (boot_img
677 + GRUB_BOOT_AOUT_HEADER_SIZE
678 + GRUB_BOOT_MACHINE_BOOT_DEVPATH);
679 if (dest_dev->disk->id != root_dev->disk->id
680 || dest_dev->disk->dev->id != root_dev->disk->dev->id)
681 {
682 const char *dest_ofpath;
683 dest_ofpath
684 = grub_util_devname_to_ofpath (grub_util_biosdisk_get_osdev (root_dev->disk));
685 grub_util_info ("dest_ofpath is `%s'", dest_ofpath);
686 strncpy (boot_devpath, dest_ofpath, GRUB_BOOT_MACHINE_BOOT_DEVPATH_END
687 - GRUB_BOOT_MACHINE_BOOT_DEVPATH - 1);
688 boot_devpath[GRUB_BOOT_MACHINE_BOOT_DEVPATH_END
689 - GRUB_BOOT_MACHINE_BOOT_DEVPATH - 1] = 0;
690 }
691 else
692 {
693 grub_util_info ("non cross-disk install");
694 memset (boot_devpath, 0, GRUB_BOOT_MACHINE_BOOT_DEVPATH_END
695 - GRUB_BOOT_MACHINE_BOOT_DEVPATH);
696 }
697 grub_util_info ("boot device path %s", boot_devpath);
698 }
699 #endif
700
701 grub_file_close (file);
702
703 free (core_path_dev);
704 free (tmp_img);
705
706 write_rootdev (core_img, root_dev, boot_img, first_sector);
707
708 /* Write the first two sectors of the core image onto the disk. */
709 grub_util_info ("opening the core image `%s'", core_path);
710 fp = fopen (core_path, "r+b");
711 if (! fp)
712 grub_util_error (_("cannot open `%s': %s"), core_path,
713 strerror (errno));
714
715 grub_util_write_image (core_img, GRUB_DISK_SECTOR_SIZE * 2, fp, core_path);
716 fclose (fp);
717
718 finish:
719
720 /* Write the boot image onto the disk. */
721 if (grub_disk_write (dest_dev->disk, BOOT_SECTOR,
722 0, GRUB_DISK_SECTOR_SIZE, boot_img))
723 grub_util_error ("%s", _(grub_errmsg));
724
725 grub_util_biosdisk_flush (root_dev->disk);
726 grub_util_biosdisk_flush (dest_dev->disk);
727
728 free (core_path);
729 free (core_img);
730 free (boot_img);
731 grub_device_close (dest_dev);
732 grub_device_close (root_dev);
733 }
734
735 static struct argp_option options[] = {
736 {"boot-image", 'b', N_("FILE"), 0,
737 N_("Use FILE as the boot image [default=%s]"), 0},
738 {"core-image", 'c', N_("FILE"), 0,
739 N_("Use FILE as the core image [default=%s]"), 0},
740 {"directory", 'd', N_("DIR"), 0,
741 N_("Use GRUB files in the directory DIR [default=%s]"), 0},
742 {"device-map", 'm', N_("FILE"), 0,
743 N_("Use FILE as the device map [default=%s]"), 0},
744 {"root-device", 'r', N_("DEVICE"), 0,
745 N_("Use DEV as the root device [default=guessed]"), 0},
746 {"force", 'f', 0, 0,
747 N_("Install even if problems are detected"), 0},
748 {"skip-fs-probe",'s',0, 0,
749 N_("Do not probe for filesystems in DEVICE"), 0},
750 {"verbose", 'v', 0, 0, N_("print verbose messages."), 0},
751 {"allow-floppy", 'a', 0, 0,
752 N_("Make the drive also bootable as floppy (default for fdX devices). May break on some BIOSes."), 0},
753
754 { 0, 0, 0, 0, 0, 0 }
755 };
756
757 static char *
758 help_filter (int key, const char *text, void *input __attribute__ ((unused)))
759 {
760 switch (key)
761 {
762 case 'b':
763 return xasprintf (text, DEFAULT_BOOT_FILE);
764
765 case 'c':
766 return xasprintf (text, DEFAULT_CORE_FILE);
767
768 case 'd':
769 return xasprintf (text, DEFAULT_DIRECTORY);
770
771 case 'm':
772 return xasprintf (text, DEFAULT_DEVICE_MAP);
773
774 default:
775 return (char *) text;
776 }
777 }
778
779 struct arguments
780 {
781 char *boot_file;
782 char *core_file;
783 char *dir;
784 char *dev_map;
785 int force;
786 int fs_probe;
787 int allow_floppy;
788 char *device;
789 };
790
791 static error_t
792 argp_parser (int key, char *arg, struct argp_state *state)
793 {
794 /* Get the input argument from argp_parse, which we
795 know is a pointer to our arguments structure. */
796 struct arguments *arguments = state->input;
797
798 char *p;
799
800 switch (key)
801 {
802 case 'a':
803 arguments->allow_floppy = 1;
804 break;
805
806 case 'b':
807 if (arguments->boot_file)
808 free (arguments->boot_file);
809
810 arguments->boot_file = xstrdup (arg);
811 break;
812
813 case 'c':
814 if (arguments->core_file)
815 free (arguments->core_file);
816
817 arguments->core_file = xstrdup (arg);
818 break;
819
820 case 'd':
821 if (arguments->dir)
822 free (arguments->dir);
823
824 arguments->dir = xstrdup (arg);
825 break;
826
827 case 'm':
828 if (arguments->dev_map)
829 free (arguments->dev_map);
830
831 arguments->dev_map = xstrdup (arg);
832 break;
833
834 case 'f':
835 arguments->force = 1;
836 break;
837
838 case 's':
839 arguments->fs_probe = 0;
840 break;
841
842 case 'v':
843 verbosity++;
844 break;
845
846 case ARGP_KEY_ARG:
847 if (state->arg_num == 0)
848 arguments->device = xstrdup(arg);
849 else
850 {
851 /* Too many arguments. */
852 fprintf (stderr, _("Unknown extra argument `%s'.\n"), arg);
853 argp_usage (state);
854 }
855 break;
856
857 case ARGP_KEY_NO_ARGS:
858 fprintf (stderr, "%s", _("No device is specified.\n"));
859 argp_usage (state);
860 exit (1);
861 break;
862
863 default:
864 return ARGP_ERR_UNKNOWN;
865 }
866
867 return 0;
868 }
869
870 static struct argp argp = {
871 options, argp_parser, N_("DEVICE"),
872 "\n"N_("\
873 Set up images to boot from DEVICE.\n\
874 \n\
875 You should not normally run this program directly. Use grub-install instead.")
876 "\v"N_("\
877 DEVICE must be an OS device (e.g. /dev/sda)."),
878 NULL, help_filter, NULL
879 };
880
881 static char *
882 get_device_name (char *dev)
883 {
884 size_t len = strlen (dev);
885
886 if (dev[0] != '(' || dev[len - 1] != ')')
887 return 0;
888
889 dev[len - 1] = '\0';
890 return dev + 1;
891 }
892
893 int
894 main (int argc, char *argv[])
895 {
896 char *root_dev = NULL;
897 char *dest_dev = NULL;
898 struct arguments arguments;
899
900 set_program_name (argv[0]);
901
902 grub_util_init_nls ();
903
904 /* Default option values. */
905 memset (&arguments, 0, sizeof (struct arguments));
906 arguments.fs_probe = 1;
907
908 /* Parse our arguments */
909 if (argp_parse (&argp, argc, argv, 0, 0, &arguments) != 0)
910 {
911 fprintf (stderr, "%s", _("Error in parsing command line arguments\n"));
912 exit(1);
913 }
914
915 #ifdef GRUB_MACHINE_IEEE1275
916 arguments.force = 1;
917 #endif
918
919 if (verbosity > 1)
920 grub_env_set ("debug", "all");
921
922 /* Initialize the emulated biosdisk driver. */
923 grub_util_biosdisk_init (arguments.dev_map ? : DEFAULT_DEVICE_MAP);
924
925 /* Initialize all modules. */
926 grub_init_all ();
927 grub_gcry_init_all ();
928
929 grub_lvm_fini ();
930 grub_mdraid09_fini ();
931 grub_mdraid1x_fini ();
932 grub_diskfilter_fini ();
933 grub_diskfilter_init ();
934 grub_mdraid09_init ();
935 grub_mdraid1x_init ();
936 grub_lvm_init ();
937
938 dest_dev = get_device_name (arguments.device);
939 if (! dest_dev)
940 {
941 /* Possibly, the user specified an OS device file. */
942 dest_dev = grub_util_get_grub_dev (arguments.device);
943 if (! dest_dev)
944 {
945 char *program = xstrdup(program_name);
946 fprintf (stderr, _("Invalid device `%s'.\n"), arguments.device);
947 argp_help (&argp, stderr, ARGP_HELP_STD_USAGE, program);
948 free(program);
949 exit(1);
950 }
951 grub_util_info ("transformed OS device `%s' into GRUB device `%s'",
952 arguments.device, dest_dev);
953 }
954 else
955 {
956 /* For simplicity. */
957 dest_dev = xstrdup (dest_dev);
958 grub_util_info ("Using `%s' as GRUB device", dest_dev);
959 }
960
961 /* Do the real work. */
962 setup (arguments.dir ? : DEFAULT_DIRECTORY,
963 arguments.boot_file ? : DEFAULT_BOOT_FILE,
964 arguments.core_file ? : DEFAULT_CORE_FILE,
965 dest_dev, arguments.force,
966 arguments.fs_probe, arguments.allow_floppy);
967
968 /* Free resources. */
969 grub_fini_all ();
970 grub_util_biosdisk_fini ();
971
972 free (arguments.boot_file);
973 free (arguments.core_file);
974 free (arguments.dir);
975 free (arguments.dev_map);
976 free (arguments.device);
977 free (root_dev);
978 free (dest_dev);
979
980 return 0;
981 }