8aa5a39a79465c33b0ff6a5a6b1bc82128df2e18
[grub.git] / util / 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/term.h>
32 #include <grub/i18n.h>
33
34 #ifdef GRUB_SETUP_SPARC64
35 #include <grub/util/ofpath.h>
36 #include <grub/sparc64/ieee1275/boot.h>
37 #include <grub/sparc64/ieee1275/kernel.h>
38 #else
39 #include <grub/i386/pc/boot.h>
40 #include <grub/i386/pc/kernel.h>
41 #endif
42
43 #include <stdio.h>
44 #include <unistd.h>
45 #include <string.h>
46 #include <stdlib.h>
47 #include <sys/types.h>
48 #include <sys/stat.h>
49 #include <dirent.h>
50 #include <assert.h>
51 #include <grub/emu/getroot.h>
52 #include "progname.h"
53 #include <grub/reed_solomon.h>
54 #include <grub/msdos_partition.h>
55 #include <grub/crypto.h>
56 #include <grub/util/install.h>
57 #include <grub/emu/hostfile.h>
58
59 #include <errno.h>
60
61 /* On SPARC this program fills in various fields inside of the 'boot' and 'core'
62  * image files.
63  *
64  * The 'boot' image needs to know the OBP path name of the root
65  * device.  It also needs to know the initial block number of
66  * 'core' (which is 'diskboot' concatenated with 'kernel' and
67  * all the modules, this is created by grub-mkimage).  This resulting
68  * 'boot' image is 512 bytes in size and is placed in the second block
69  * of a partition.
70  *
71  * The initial 'diskboot' block acts as a loader for the actual GRUB
72  * kernel.  It contains the loading code and then a block list.
73  *
74  * The block list of 'core' starts at the end of the 'diskboot' image
75  * and works it's way backwards towards the end of the code of 'diskboot'.
76  *
77  * We patch up the images with the necessary values and write out the
78  * result.
79  */
80
81 #ifdef GRUB_SETUP_SPARC64
82 #define grub_target_to_host16(x)        grub_be_to_cpu16(x)
83 #define grub_target_to_host32(x)        grub_be_to_cpu32(x)
84 #define grub_target_to_host64(x)        grub_be_to_cpu64(x)
85 #define grub_host_to_target16(x)        grub_cpu_to_be16(x)
86 #define grub_host_to_target32(x)        grub_cpu_to_be32(x)
87 #define grub_host_to_target64(x)        grub_cpu_to_be64(x)
88 #elif defined (GRUB_SETUP_BIOS)
89 #define grub_target_to_host16(x)        grub_le_to_cpu16(x)
90 #define grub_target_to_host32(x)        grub_le_to_cpu32(x)
91 #define grub_target_to_host64(x)        grub_le_to_cpu64(x)
92 #define grub_host_to_target16(x)        grub_cpu_to_le16(x)
93 #define grub_host_to_target32(x)        grub_cpu_to_le32(x)
94 #define grub_host_to_target64(x)        grub_cpu_to_le64(x)
95 #else
96 #error Complete this
97 #endif
98
99 static void
100 write_rootdev (grub_device_t root_dev,
101                char *boot_img, grub_uint64_t first_sector)
102 {
103 #ifdef GRUB_SETUP_BIOS
104   {
105     grub_uint8_t *boot_drive;
106     void *kernel_sector;
107     boot_drive = (grub_uint8_t *) (boot_img + GRUB_BOOT_MACHINE_BOOT_DRIVE);
108     kernel_sector = (boot_img + GRUB_BOOT_MACHINE_KERNEL_SECTOR);
109
110     /* FIXME: can this be skipped?  */
111     *boot_drive = 0xFF;
112
113     grub_set_unaligned64 (kernel_sector, grub_cpu_to_le64 (first_sector));
114   }
115 #endif
116 #ifdef GRUB_SETUP_SPARC64
117   {
118     void *kernel_byte;
119     kernel_byte = (boot_img + GRUB_BOOT_AOUT_HEADER_SIZE
120                    + GRUB_BOOT_MACHINE_KERNEL_BYTE);
121     grub_set_unaligned64 (kernel_byte,
122                           grub_cpu_to_be64 (first_sector << GRUB_DISK_SECTOR_BITS));
123   }
124 #endif
125 }
126
127 #ifdef GRUB_SETUP_SPARC64
128 #define BOOT_SECTOR 1
129 #else
130 #define BOOT_SECTOR 0
131 #endif
132
133 /* Helper for setup.  */
134
135 struct blocklists
136 {
137   struct grub_boot_blocklist *first_block, *block;
138 #ifdef GRUB_SETUP_BIOS
139   grub_uint16_t current_segment;
140 #endif
141   grub_uint16_t last_length;
142   grub_disk_addr_t first_sector;
143 };
144
145 /* Helper for setup.  */
146 static void
147 save_blocklists (grub_disk_addr_t sector, unsigned offset, unsigned length,
148                  void *data)
149 {
150   struct blocklists *bl = data;
151   struct grub_boot_blocklist *prev = bl->block + 1;
152   grub_uint64_t seclen;
153
154   grub_util_info ("saving <%"  GRUB_HOST_PRIuLONG_LONG ",%u,%u>",
155                   (unsigned long long) sector, offset, length);
156
157   if (bl->first_sector == (grub_disk_addr_t) -1)
158     {
159       if (offset != 0 || length < GRUB_DISK_SECTOR_SIZE)
160         grub_util_error ("%s", _("the first sector of the core file is not sector-aligned"));
161
162       bl->first_sector = sector;
163       sector++;
164       length -= GRUB_DISK_SECTOR_SIZE;
165       if (!length)
166         return;
167     }
168
169   if (offset != 0 || bl->last_length != 0)
170     grub_util_error ("%s", _("non-sector-aligned data is found in the core file"));
171
172   seclen = (length + GRUB_DISK_SECTOR_SIZE - 1) >> GRUB_DISK_SECTOR_BITS;
173
174   if (bl->block != bl->first_block
175       && (grub_target_to_host64 (prev->start)
176           + grub_target_to_host16 (prev->len)) == sector)
177     {
178       grub_uint16_t t = grub_target_to_host16 (prev->len);
179       t += seclen;
180       prev->len = grub_host_to_target16 (t);
181     }
182   else
183     {
184       bl->block->start = grub_host_to_target64 (sector);
185       bl->block->len = grub_host_to_target16 (seclen);
186 #ifdef GRUB_SETUP_BIOS
187       bl->block->segment = grub_host_to_target16 (bl->current_segment);
188 #endif
189
190       bl->block--;
191       if (bl->block->len)
192         grub_util_error ("%s", _("the sectors of the core file are too fragmented"));
193     }
194
195   bl->last_length = length & (GRUB_DISK_SECTOR_SIZE - 1);
196 #ifdef GRUB_SETUP_BIOS
197   bl->current_segment += seclen << (GRUB_DISK_SECTOR_BITS - 4);
198 #endif
199 }
200
201 #ifdef GRUB_SETUP_BIOS
202 /* Context for setup/identify_partmap.  */
203 struct identify_partmap_ctx
204 {
205   grub_partition_map_t dest_partmap;
206   grub_partition_t container;
207   int multiple_partmaps;
208 };
209
210 /* Helper for setup.
211    Unlike root_dev, with dest_dev we're interested in the partition map even
212    if dest_dev itself is a whole disk.  */
213 static int
214 identify_partmap (grub_disk_t disk __attribute__ ((unused)),
215                   const grub_partition_t p, void *data)
216 {
217   struct identify_partmap_ctx *ctx = data;
218
219   if (p->parent != ctx->container)
220     return 0;
221   /* NetBSD and OpenBSD subpartitions have metadata inside a partition,
222      so they are safe to ignore.
223    */
224   if (grub_strcmp (p->partmap->name, "netbsd") == 0
225       || grub_strcmp (p->partmap->name, "openbsd") == 0)
226     return 0;
227   if (ctx->dest_partmap == NULL)
228     {
229       ctx->dest_partmap = p->partmap;
230       return 0;
231     }
232   if (ctx->dest_partmap == p->partmap)
233     return 0;
234   ctx->multiple_partmaps = 1;
235   return 1;
236 }
237 #endif
238
239 #ifdef GRUB_SETUP_BIOS
240 #define SETUP grub_util_bios_setup
241 #elif GRUB_SETUP_SPARC64
242 #define SETUP grub_util_sparc_setup
243 #else
244 #error "Shouldn't happen"
245 #endif
246
247 void
248 SETUP (const char *dir,
249        const char *boot_file, const char *core_file,
250        const char *dest, int force,
251        int fs_probe, int allow_floppy,
252        int add_rs_codes __attribute__ ((unused))) /* unused on sparc64 */
253 {
254   char *core_path;
255   char *boot_img, *core_img, *boot_path;
256   char *root = 0;
257   size_t boot_size, core_size;
258 #ifdef GRUB_SETUP_BIOS
259   grub_uint16_t core_sectors;
260 #endif
261   grub_device_t root_dev = 0, dest_dev, core_dev;
262   grub_util_fd_t fp;
263   struct blocklists bl;
264
265   bl.first_sector = (grub_disk_addr_t) -1;
266
267 #ifdef GRUB_SETUP_BIOS
268   bl.current_segment =
269     GRUB_BOOT_I386_PC_KERNEL_SEG + (GRUB_DISK_SECTOR_SIZE >> 4);
270 #endif
271   bl.last_length = 0;
272
273   /* Read the boot image by the OS service.  */
274   boot_path = grub_util_get_path (dir, boot_file);
275   boot_size = grub_util_get_image_size (boot_path);
276   if (boot_size != GRUB_DISK_SECTOR_SIZE)
277     grub_util_error (_("the size of `%s' is not %u"),
278                      boot_path, GRUB_DISK_SECTOR_SIZE);
279   boot_img = grub_util_read_image (boot_path);
280   free (boot_path);
281
282   core_path = grub_util_get_path (dir, core_file);
283   core_size = grub_util_get_image_size (core_path);
284 #ifdef GRUB_SETUP_BIOS
285   core_sectors = ((core_size + GRUB_DISK_SECTOR_SIZE - 1)
286                   >> GRUB_DISK_SECTOR_BITS);
287 #endif
288   if (core_size < GRUB_DISK_SECTOR_SIZE)
289     grub_util_error (_("the size of `%s' is too small"), core_path);
290 #ifdef GRUB_SETUP_BIOS
291   if (core_size > 0xFFFF * GRUB_DISK_SECTOR_SIZE)
292     grub_util_error (_("the size of `%s' is too large"), core_path);
293 #endif
294
295   core_img = grub_util_read_image (core_path);
296
297   /* Have FIRST_BLOCK to point to the first blocklist.  */
298   bl.first_block = (struct grub_boot_blocklist *) (core_img
299                                                    + GRUB_DISK_SECTOR_SIZE
300                                                    - sizeof (*bl.block));
301   grub_util_info ("root is `%s', dest is `%s'", root, dest);
302
303   grub_util_info ("Opening dest");
304   dest_dev = grub_device_open (dest);
305   if (! dest_dev)
306     grub_util_error ("%s", grub_errmsg);
307
308   core_dev = dest_dev;
309
310   {
311     char **root_devices = grub_guess_root_devices (dir);
312     char **cur;
313     int found = 0;
314
315     if (!root_devices)
316       grub_util_error (_("cannot find a device for %s (is /dev mounted?)"), dir);
317
318     for (cur = root_devices; *cur; cur++)
319       {
320         char *drive;
321         grub_device_t try_dev;
322
323         drive = grub_util_get_grub_dev (*cur);
324         if (!drive)
325           continue;
326         try_dev = grub_device_open (drive);
327         if (! try_dev)
328           {
329             free (drive);
330             continue;
331           }
332         if (!found && try_dev->disk->id == dest_dev->disk->id
333             && try_dev->disk->dev->id == dest_dev->disk->dev->id)
334           {
335             if (root_dev)
336               grub_device_close (root_dev);
337             free (root);
338             root_dev = try_dev;
339             root = drive;
340             found = 1;
341             continue;
342           }
343         if (!root_dev)
344           {
345             root_dev = try_dev;
346             root = drive;
347             continue;
348           }
349         grub_device_close (try_dev);    
350         free (drive);
351       }
352     if (!root_dev)
353       {
354         grub_util_error ("guessing the root device failed, because of `%s'",
355                          grub_errmsg);
356       }
357     grub_util_info ("guessed root_dev `%s' from "
358                     "dir `%s'", root_dev->disk->name, dir);
359
360     for (cur = root_devices; *cur; cur++)
361       free (*cur);
362     free (root_devices);
363   }
364
365   grub_util_info ("setting the root device to `%s'", root);
366   if (grub_env_set ("root", root) != GRUB_ERR_NONE)
367     grub_util_error ("%s", grub_errmsg);
368
369 #ifdef GRUB_SETUP_BIOS
370   {
371     char *tmp_img;
372     grub_uint8_t *boot_drive_check;
373
374     /* Read the original sector from the disk.  */
375     tmp_img = xmalloc (GRUB_DISK_SECTOR_SIZE);
376     if (grub_disk_read (dest_dev->disk, 0, 0, GRUB_DISK_SECTOR_SIZE, tmp_img))
377       grub_util_error ("%s", grub_errmsg);
378     
379     boot_drive_check = (grub_uint8_t *) (boot_img
380                                           + GRUB_BOOT_MACHINE_DRIVE_CHECK);
381     /* Copy the possible DOS BPB.  */
382     memcpy (boot_img + GRUB_BOOT_MACHINE_BPB_START,
383             tmp_img + GRUB_BOOT_MACHINE_BPB_START,
384             GRUB_BOOT_MACHINE_BPB_END - GRUB_BOOT_MACHINE_BPB_START);
385
386     /* If DEST_DRIVE is a hard disk, enable the workaround, which is
387        for buggy BIOSes which don't pass boot drive correctly. Instead,
388        they pass 0x00 or 0x01 even when booted from 0x80.  */
389     if (!allow_floppy && !grub_util_biosdisk_is_floppy (dest_dev->disk))
390       {
391         /* Replace the jmp (2 bytes) with double nop's.  */
392         boot_drive_check[0] = 0x90;
393         boot_drive_check[1] = 0x90;
394       }
395
396     struct identify_partmap_ctx ctx = {
397       .dest_partmap = NULL,
398       .container = dest_dev->disk->partition,
399       .multiple_partmaps = 0
400     };
401     int is_ldm;
402     grub_err_t err;
403     grub_disk_addr_t *sectors;
404     int i;
405     grub_fs_t fs;
406     unsigned int nsec, maxsec;
407
408     grub_partition_iterate (dest_dev->disk, identify_partmap, &ctx);
409
410     /* Copy the partition table.  */
411     if (ctx.dest_partmap ||
412         (!allow_floppy && !grub_util_biosdisk_is_floppy (dest_dev->disk)))
413       memcpy (boot_img + GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC,
414               tmp_img + GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC,
415               GRUB_BOOT_MACHINE_PART_END - GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC);
416
417     free (tmp_img);
418
419     if (ctx.container
420         && grub_strcmp (ctx.container->partmap->name, "msdos") == 0
421         && ctx.dest_partmap
422         && (ctx.container->msdostype == GRUB_PC_PARTITION_TYPE_NETBSD
423             || ctx.container->msdostype == GRUB_PC_PARTITION_TYPE_OPENBSD))
424       {
425         grub_util_warn ("%s", _("Attempting to install GRUB to a disk with multiple partition labels or both partition label and filesystem.  This is not supported yet."));
426         goto unable_to_embed;
427       }
428
429     fs = grub_fs_probe (dest_dev);
430     if (!fs)
431       grub_errno = GRUB_ERR_NONE;
432
433     is_ldm = grub_util_is_ldm (dest_dev->disk);
434
435     if (fs_probe)
436       {
437         if (!fs && !ctx.dest_partmap)
438           grub_util_error (_("unable to identify a filesystem in %s; safety check can't be performed"),
439                            dest_dev->disk->name);
440         if (fs && !fs->reserved_first_sector)
441           /* TRANSLATORS: Filesystem may reserve the space just GRUB isn't sure about it.  */
442           grub_util_error (_("%s appears to contain a %s filesystem which isn't known to "
443                              "reserve space for DOS-style boot.  Installing GRUB there could "
444                              "result in FILESYSTEM DESTRUCTION if valuable data is overwritten "
445                              "by grub-setup (--skip-fs-probe disables this "
446                              "check, use at your own risk)"), dest_dev->disk->name, fs->name);
447
448         if (ctx.dest_partmap && strcmp (ctx.dest_partmap->name, "msdos") != 0
449             && strcmp (ctx.dest_partmap->name, "gpt") != 0
450             && strcmp (ctx.dest_partmap->name, "bsd") != 0
451             && strcmp (ctx.dest_partmap->name, "netbsd") != 0
452             && strcmp (ctx.dest_partmap->name, "openbsd") != 0
453             && strcmp (ctx.dest_partmap->name, "sunpc") != 0)
454           /* TRANSLATORS: Partition map may reserve the space just GRUB isn't sure about it.  */
455           grub_util_error (_("%s appears to contain a %s partition map which isn't known to "
456                              "reserve space for DOS-style boot.  Installing GRUB there could "
457                              "result in FILESYSTEM DESTRUCTION if valuable data is overwritten "
458                              "by grub-setup (--skip-fs-probe disables this "
459                              "check, use at your own risk)"), dest_dev->disk->name, ctx.dest_partmap->name);
460         if (is_ldm && ctx.dest_partmap && strcmp (ctx.dest_partmap->name, "msdos") != 0
461             && strcmp (ctx.dest_partmap->name, "gpt") != 0)
462           grub_util_error (_("%s appears to contain a %s partition map and "
463                              "LDM which isn't known to be a safe combination."
464                              "  Installing GRUB there could "
465                              "result in FILESYSTEM DESTRUCTION if valuable data"
466                              " is overwritten "
467                              "by grub-setup (--skip-fs-probe disables this "
468                              "check, use at your own risk)"),
469                            dest_dev->disk->name, ctx.dest_partmap->name);
470
471       }
472
473     if (! ctx.dest_partmap && ! fs && !is_ldm)
474       {
475         grub_util_warn ("%s", _("Attempting to install GRUB to a partitionless disk or to a partition.  This is a BAD idea."));
476         goto unable_to_embed;
477       }
478     if (ctx.multiple_partmaps || (ctx.dest_partmap && fs) || (is_ldm && fs))
479       {
480         grub_util_warn ("%s", _("Attempting to install GRUB to a disk with multiple partition labels.  This is not supported yet."));
481         goto unable_to_embed;
482       }
483
484     if (ctx.dest_partmap && !ctx.dest_partmap->embed)
485       {
486         grub_util_warn (_("Partition style `%s' doesn't support embedding"),
487                         ctx.dest_partmap->name);
488         goto unable_to_embed;
489       }
490
491     if (fs && !fs->embed)
492       {
493         grub_util_warn (_("File system `%s' doesn't support embedding"),
494                         fs->name);
495         goto unable_to_embed;
496       }
497
498     nsec = core_sectors;
499
500     if (add_rs_codes)
501       maxsec = 2 * core_sectors;
502     else
503       maxsec = core_sectors;
504
505     if (maxsec > ((0x78000 - GRUB_KERNEL_I386_PC_LINK_ADDR)
506                 >> GRUB_DISK_SECTOR_BITS))
507       maxsec = ((0x78000 - GRUB_KERNEL_I386_PC_LINK_ADDR)
508                 >> GRUB_DISK_SECTOR_BITS);
509
510     if (is_ldm)
511       err = grub_util_ldm_embed (dest_dev->disk, &nsec, maxsec,
512                                  GRUB_EMBED_PCBIOS, &sectors);
513     else if (ctx.dest_partmap)
514       err = ctx.dest_partmap->embed (dest_dev->disk, &nsec, maxsec,
515                                      GRUB_EMBED_PCBIOS, &sectors);
516     else
517       err = fs->embed (dest_dev, &nsec, maxsec,
518                        GRUB_EMBED_PCBIOS, &sectors);
519     if (!err && nsec < core_sectors)
520       {
521         err = grub_error (GRUB_ERR_OUT_OF_RANGE,
522                           N_("Your embedding area is unusually small.  "
523                              "core.img won't fit in it."));
524       }
525     
526     if (err)
527       {
528         grub_util_warn ("%s", grub_errmsg);
529         grub_errno = GRUB_ERR_NONE;
530         goto unable_to_embed;
531       }
532
533     assert (nsec <= maxsec);
534
535     /* Clean out the blocklists.  */
536     bl.block = bl.first_block;
537     while (bl.block->len)
538       {
539         grub_memset (bl.block, 0, sizeof (*bl.block));
540       
541         bl.block--;
542
543         if ((char *) bl.block <= core_img)
544           grub_util_error ("%s", _("no terminator in the core image"));
545       }
546
547     bl.block = bl.first_block;
548     for (i = 0; i < nsec; i++)
549       save_blocklists (sectors[i] + grub_partition_get_start (ctx.container),
550                        0, GRUB_DISK_SECTOR_SIZE, &bl);
551
552     /* Make sure that the last blocklist is a terminator.  */
553     if (bl.block == bl.first_block)
554       bl.block--;
555     bl.block->start = 0;
556     bl.block->len = 0;
557     bl.block->segment = 0;
558
559     write_rootdev (root_dev, boot_img, bl.first_sector);
560
561     /* Round up to the nearest sector boundary, and zero the extra memory */
562     core_img = xrealloc (core_img, nsec * GRUB_DISK_SECTOR_SIZE);
563     assert (core_img && (nsec * GRUB_DISK_SECTOR_SIZE >= core_size));
564     memset (core_img + core_size, 0, nsec * GRUB_DISK_SECTOR_SIZE - core_size);
565
566     bl.first_block = (struct grub_boot_blocklist *) (core_img
567                                                      + GRUB_DISK_SECTOR_SIZE
568                                                      - sizeof (*bl.block));
569
570     grub_size_t no_rs_length;
571     no_rs_length = grub_target_to_host16 
572       (grub_get_unaligned16 (core_img
573                              + GRUB_DISK_SECTOR_SIZE
574                              + GRUB_KERNEL_I386_PC_NO_REED_SOLOMON_LENGTH));
575
576     if (no_rs_length == 0xffff)
577       grub_util_error ("%s", _("core.img version mismatch"));
578
579     if (add_rs_codes)
580       {
581         grub_set_unaligned32 ((core_img + GRUB_DISK_SECTOR_SIZE
582                                + GRUB_KERNEL_I386_PC_REED_SOLOMON_REDUNDANCY),
583                               grub_host_to_target32 (nsec * GRUB_DISK_SECTOR_SIZE - core_size));
584
585         void *tmp = xmalloc (core_size);
586         grub_memcpy (tmp, core_img, core_size);
587         grub_reed_solomon_add_redundancy (core_img + no_rs_length + GRUB_DISK_SECTOR_SIZE,
588                                           core_size - no_rs_length - GRUB_DISK_SECTOR_SIZE,
589                                           nsec * GRUB_DISK_SECTOR_SIZE
590                                           - core_size);
591         assert (grub_memcmp (tmp, core_img, core_size) == 0);
592         free (tmp);
593       }
594
595     /* Write the core image onto the disk.  */
596     for (i = 0; i < nsec; i++)
597       grub_disk_write (dest_dev->disk, sectors[i], 0,
598                        GRUB_DISK_SECTOR_SIZE,
599                        core_img + i * GRUB_DISK_SECTOR_SIZE);
600
601     grub_free (sectors);
602
603     goto finish;
604   }
605
606 unable_to_embed:
607 #endif
608
609   if (dest_dev->disk->dev->id != root_dev->disk->dev->id)
610     grub_util_error ("%s", _("embedding is not possible, but this is required for "
611                              "RAID and LVM install"));
612
613   {
614     grub_fs_t fs;
615     fs = grub_fs_probe (root_dev);
616     if (!fs)
617       grub_util_error (_("can't determine filesystem on %s"), root);
618
619     if (!fs->blocklist_install)
620       grub_util_error (_("filesystem `%s' doesn't support blocklists"),
621                        fs->name);
622   }
623
624 #ifdef GRUB_SETUP_BIOS
625   if (dest_dev->disk->id != root_dev->disk->id
626       || dest_dev->disk->dev->id != root_dev->disk->dev->id)
627     /* TRANSLATORS: cross-disk refers to /boot being on one disk
628        but MBR on another.  */
629     grub_util_error ("%s", _("embedding is not possible, but this is required for "
630                              "cross-disk install"));
631 #else
632   core_dev = root_dev;
633 #endif
634
635   grub_util_warn ("%s", _("Embedding is not possible.  GRUB can only be installed in this "
636                           "setup by using blocklists.  However, blocklists are UNRELIABLE and "
637                           "their use is discouraged."));
638   if (! force)
639     /* TRANSLATORS: Here GRUB refuses to continue with blocklist install.  */
640     grub_util_error ("%s", _("will not proceed with blocklists"));
641
642   /* The core image must be put on a filesystem unfortunately.  */
643   grub_util_info ("will leave the core image on the filesystem");
644
645   grub_util_biosdisk_flush (root_dev->disk);
646
647   /* Clean out the blocklists.  */
648   bl.block = bl.first_block;
649   while (bl.block->len)
650     {
651       bl.block->start = 0;
652       bl.block->len = 0;
653 #ifdef GRUB_SETUP_BIOS
654       bl.block->segment = 0;
655 #endif
656
657       bl.block--;
658
659       if ((char *) bl.block <= core_img)
660         grub_util_error ("%s", _("no terminator in the core image"));
661     }
662
663   bl.block = bl.first_block;
664
665   grub_install_get_blocklist (root_dev, core_path, core_img, core_size,
666                               save_blocklists, &bl);
667
668   if (bl.first_sector == (grub_disk_addr_t)-1)
669     grub_util_error ("%s", _("can't retrieve blocklists"));
670
671 #ifdef GRUB_SETUP_SPARC64
672   {
673     char *boot_devpath;
674     boot_devpath = (char *) (boot_img
675                              + GRUB_BOOT_AOUT_HEADER_SIZE
676                              + GRUB_BOOT_MACHINE_BOOT_DEVPATH);
677     if (dest_dev->disk->id != root_dev->disk->id
678         || dest_dev->disk->dev->id != root_dev->disk->dev->id)
679       {
680         char *dest_ofpath;
681         dest_ofpath
682           = grub_util_devname_to_ofpath (grub_util_biosdisk_get_osdev (root_dev->disk));
683         /* FIXME handle NULL result */
684         grub_util_info ("dest_ofpath is `%s'", dest_ofpath);
685         strncpy (boot_devpath, dest_ofpath,
686                  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         free (dest_ofpath);
691       }
692     else
693       {
694         grub_util_info ("non cross-disk install");
695         memset (boot_devpath, 0, GRUB_BOOT_MACHINE_BOOT_DEVPATH_END
696                 - GRUB_BOOT_MACHINE_BOOT_DEVPATH);
697       }
698     grub_util_info ("boot device path %s", boot_devpath);
699   }
700 #endif
701
702   write_rootdev (root_dev, boot_img, bl.first_sector);
703
704   /* Write the first two sectors of the core image onto the disk.  */
705   grub_util_info ("opening the core image `%s'", core_path);
706   fp = grub_util_fd_open (core_path, GRUB_UTIL_FD_O_WRONLY);
707   if (! GRUB_UTIL_FD_IS_VALID (fp))
708     grub_util_error (_("cannot open `%s': %s"), core_path,
709                      grub_util_fd_strerror ());
710
711   if (grub_util_fd_write (fp, core_img, GRUB_DISK_SECTOR_SIZE * 2)
712       != GRUB_DISK_SECTOR_SIZE * 2)
713     grub_util_error (_("cannot write to `%s': %s"),
714                      core_path, strerror (errno));
715   grub_util_fd_sync (fp);
716   grub_util_fd_close (fp);
717   grub_util_biosdisk_flush (root_dev->disk);
718
719   grub_disk_cache_invalidate_all ();
720
721   {
722     char *buf, *ptr = core_img;
723     size_t len = core_size;
724     grub_uint64_t blk;
725     grub_partition_t container = core_dev->disk->partition;
726     grub_err_t err;
727
728     core_dev->disk->partition = 0;
729
730     buf = xmalloc (core_size);
731     blk = bl.first_sector;
732     err = grub_disk_read (core_dev->disk, blk, 0, GRUB_DISK_SECTOR_SIZE, buf);
733     if (err)
734       grub_util_error (_("cannot read `%s': %s"), core_dev->disk->name,
735                        grub_errmsg);
736     if (grub_memcmp (buf, ptr, GRUB_DISK_SECTOR_SIZE) != 0)
737       grub_util_error ("%s", _("blocklists are invalid"));
738
739     ptr += GRUB_DISK_SECTOR_SIZE;
740     len -= GRUB_DISK_SECTOR_SIZE;
741
742     bl.block = bl.first_block;
743     while (bl.block->len)
744       {
745         size_t cur = grub_target_to_host16 (bl.block->len) << GRUB_DISK_SECTOR_BITS;
746         blk = grub_target_to_host64 (bl.block->start);
747
748         if (cur > len)
749           cur = len;
750
751         err = grub_disk_read (core_dev->disk, blk, 0, cur, buf);
752         if (err)
753           grub_util_error (_("cannot read `%s': %s"), core_dev->disk->name,
754                            grub_errmsg);
755
756         if (grub_memcmp (buf, ptr, cur) != 0)
757           grub_util_error ("%s", _("blocklists are invalid"));
758
759         ptr += cur;
760         len -= cur;
761         bl.block--;
762         
763         if ((char *) bl.block <= core_img)
764           grub_util_error ("%s", _("no terminator in the core image"));
765       }
766     if (len)
767       grub_util_error ("%s", _("blocklists are incomplete"));
768     core_dev->disk->partition = container;
769     free (buf);
770   }
771
772 #ifdef GRUB_SETUP_BIOS
773  finish:
774 #endif
775
776   /* Write the boot image onto the disk.  */
777   if (grub_disk_write (dest_dev->disk, BOOT_SECTOR,
778                        0, GRUB_DISK_SECTOR_SIZE, boot_img))
779     grub_util_error ("%s", grub_errmsg);
780
781   grub_util_biosdisk_flush (root_dev->disk);
782   grub_util_biosdisk_flush (dest_dev->disk);
783
784   free (core_path);
785   free (core_img);
786   free (boot_img);
787   grub_device_close (dest_dev);
788   grub_device_close (root_dev);
789 }
790