1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
24 * Copyright 2017 Toomas Soome <tsoome@me.com>
25 */
26
27 #include <stdio.h>
28 #include <errno.h>
29 #include <unistd.h>
30 #include <fcntl.h>
31 #include <assert.h>
32 #include <locale.h>
33 #include <strings.h>
34 #include <libfdisk.h>
35 #include <libgen.h>
36
37 #include <sys/dktp/fdisk.h>
38 #include <sys/dkio.h>
39 #include <sys/vtoc.h>
40 #include <sys/multiboot.h>
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #include <sys/sysmacros.h>
44 #include <sys/efi_partition.h>
45 #include <libfstyp.h>
46 #include <uuid/uuid.h>
47
48 #include "installboot.h"
49 #include "../../common/bblk_einfo.h"
50 #include "../../common/boot_utils.h"
51 #include "../../common/mboot_extra.h"
52 #include "getresponse.h"
53
54 #ifndef TEXT_DOMAIN
55 #define TEXT_DOMAIN "SUNW_OST_OSCMD"
56 #endif
57
58 /*
59 * BIOS bootblock installation:
60 *
61 * 1. MBR is first sector of the disk. If the file system on target is
62 * ufs or zfs, the same MBR code is installed on first sector of the
63 * partition as well; this will allow to have real MBR sector to be
64 * replaced by some other boot loader and have illumos chainloaded.
65 *
66 * installboot will record the start LBA and size of stage2 code in MBR code.
67 * On boot, the MBR code will read the stage2 code and executes it.
68 *
69 * 2. Stage2 location depends on file system type;
70 * In case of zfs, installboot will store stage2 to zfs bootblk area,
71 * which is 512k bytes from partition start and size is 3.5MB.
72 *
73 * In case of ufs, the stage2 location is 50 512B sectors from
74 * Solaris2 MBR partition start, within boot slice, boot slice size is
75 * one cylinder.
76 *
77 * In case of pcfs, the stage2 location is 50 512B sectors from beginning
78 * of the disk, filling the space between MBR and first partition.
79 * This location assumes no other bootloader and the space is one cylinder,
80 * as first partition is starting from cylinder 1.
81 *
82 * In case of GPT partitioning and if file system is not zfs, the boot
83 * support is only possible with dedicated boot partition. For GPT,
84 * the current implementation is using BOOT partition, which must exist.
85 * BOOT partition does only contain raw boot blocks, without any file system.
86 *
87 * Loader stage2 is created with embedded version, by using fake multiboot (MB)
88 * header within first 32k and EINFO block is at the end of the actual
89 * boot block. MB header load_addr is set to 0 and load_end_addr is set to
90 * actual block end, so the EINFO size is (file size - load_end_addr).
91 * installboot does also store the illumos boot partition LBA to MB space,
92 * starting from bss_end_addr structure member location; stage2 will
93 * detect the partition and file system based on this value.
94 *
95 * Stored location values in MBR/stage2 also mean the bootblocks must be
96 * reinstalled in case the partition content is relocated.
97 *
98 * EFI boot program installation:
99 * EFI boot requires EFI System partition with following directory
100 * hierarchy:
101 * EFI/VENDOR/file
102 * EFI/BOOT/BOOTx64.EFI
103 * Where EFI/BOOT is fallback directory. While we have no mechanism to set
104 * EFI variable values to define vendor specific boot program location, we
105 * will just use EFI/BOOT/BOOTx64.EFI; also this setup is only possible
106 * solution for removable media.
107 * For now the boot1.efi is used for boot program, boot1.efi is also
108 * versioned as is gptzfsboot.
109 */
110
111 static boolean_t write_mbr = B_FALSE;
112 static boolean_t force_mbr = B_FALSE;
113 static boolean_t force_update = B_FALSE;
114 static boolean_t do_getinfo = B_FALSE;
115 static boolean_t do_version = B_FALSE;
116 static boolean_t do_mirror_bblk = B_FALSE;
117 static boolean_t strip = B_FALSE;
118 static boolean_t verbose_dump = B_FALSE;
119
120 #define EFIBOOT64 "bootx64.efi"
121 #define EFIBOOT32 "bootia32.efi"
122
123 /* Versioning string, if present. */
124 static char *update_str;
125
126 /*
127 * Temporary buffer to store the first 32K of data looking for a multiboot
128 * signature.
129 */
130 char mboot_scan[MBOOT_SCAN_SIZE];
131
132 /* Function prototypes. */
133 static void check_options(char *);
134 static int get_start_sector(ib_device_t *);
135
136 static int read_stage1_from_file(char *, ib_data_t *);
137 static int read_bootblock_from_file(char *, ib_bootblock_t *);
138 static int read_bootblock_from_disk(ib_device_t *, ib_bootblock_t *, char **);
139 static void add_bootblock_einfo(ib_bootblock_t *, char *);
140 static int prepare_stage1(ib_data_t *);
141 static int prepare_bootblock(ib_data_t *, char *);
142 static int write_stage1(ib_data_t *);
143 static int write_bootblock(ib_data_t *);
144 static int init_device(ib_device_t *, char *);
145 static void cleanup_device(ib_device_t *);
146 static int commit_to_disk(ib_data_t *, char *);
147 static int handle_install(char *, char **);
148 static int handle_getinfo(char *, char **);
149 static int handle_mirror(char *, char **);
150 static boolean_t is_update_necessary(ib_data_t *, char *);
151 static int propagate_bootblock(ib_data_t *, ib_data_t *, char *);
152 static void usage(char *);
153
154 static int
155 read_stage1_from_file(char *path, ib_data_t *dest)
156 {
157 int fd;
158
159 assert(dest != NULL);
160
161 /* read the stage1 file from filesystem */
162 fd = open(path, O_RDONLY);
163 if (fd == -1 ||
164 read(fd, dest->stage1, SECTOR_SIZE) != SECTOR_SIZE) {
165 (void) fprintf(stderr, gettext("cannot read stage1 file %s\n"),
166 path);
167 return (BC_ERROR);
168 }
169 (void) close(fd);
170 return (BC_SUCCESS);
171 }
172
173 static int
174 read_bootblock_from_file(char *file, ib_bootblock_t *bblock)
175 {
176 struct stat sb;
177 uint32_t buf_size;
178 uint32_t mboot_off;
179 int fd = -1;
180 int retval = BC_ERROR;
181
182 assert(bblock != NULL);
183 assert(file != NULL);
184
185 fd = open(file, O_RDONLY);
186 if (fd == -1) {
187 BOOT_DEBUG("Error opening %s\n", file);
188 perror("open");
189 goto out;
190 }
191
192 if (fstat(fd, &sb) == -1) {
193 BOOT_DEBUG("Error getting information (stat) about %s", file);
194 perror("stat");
195 goto outfd;
196 }
197
198 /* loader bootblock has version built in */
199 buf_size = sb.st_size;
200
201 bblock->buf_size = buf_size;
202 BOOT_DEBUG("bootblock in-memory buffer size is %d\n",
203 bblock->buf_size);
204
205 bblock->buf = malloc(buf_size);
206 if (bblock->buf == NULL) {
207 perror(gettext("Memory allocation failure"));
208 goto outbuf;
209 }
210 bblock->file = bblock->buf;
211
212 if (read(fd, bblock->file, bblock->buf_size) != bblock->buf_size) {
213 BOOT_DEBUG("Read from %s failed\n", file);
214 perror("read");
215 goto outfd;
216 }
217
218 if (find_multiboot(bblock->file, MBOOT_SCAN_SIZE, &mboot_off)
219 != BC_SUCCESS) {
220 (void) fprintf(stderr,
221 gettext("Unable to find multiboot header\n"));
222 goto outfd;
223 }
224
225 bblock->mboot = (multiboot_header_t *)(bblock->file + mboot_off);
226 bblock->mboot_off = mboot_off;
227
228 bblock->file_size =
229 bblock->mboot->load_end_addr - bblock->mboot->load_addr;
230 BOOT_DEBUG("bootblock file size is %d\n", bblock->file_size);
231
232 bblock->extra = bblock->buf + P2ROUNDUP(bblock->file_size, 8);
233 bblock->extra_size = bblock->buf_size - P2ROUNDUP(bblock->file_size, 8);
234
235 BOOT_DEBUG("mboot at %p offset %d, extra at %p size %d, buf=%p "
236 "(size=%d)\n", bblock->mboot, bblock->mboot_off, bblock->extra,
237 bblock->extra_size, bblock->buf, bblock->buf_size);
238
239 (void) close(fd);
240 return (BC_SUCCESS);
241
242 outbuf:
243 (void) free(bblock->buf);
244 bblock->buf = NULL;
245 outfd:
246 (void) close(fd);
247 out:
248 return (retval);
249 }
250
251 static int
252 read_bootblock_from_disk(ib_device_t *device, ib_bootblock_t *bblock,
253 char **path)
254 {
255 int dev_fd;
256 uint32_t size, offset;
257 uint32_t buf_size;
258 uint32_t mboot_off;
259 multiboot_header_t *mboot;
260
261 assert(device != NULL);
262 assert(bblock != NULL);
263
264 if (device->target.fstype == IG_FS_ZFS) {
265 dev_fd = device->target.fd;
266 offset = BBLK_ZFS_BLK_OFF * SECTOR_SIZE;
267 *path = device->target.path;
268 } else {
269 dev_fd = device->stage.fd;
270 offset = device->stage.offset * SECTOR_SIZE;
271 *path = device->stage.path;
272 }
273
274 if (read_in(dev_fd, mboot_scan, sizeof (mboot_scan), offset)
275 != BC_SUCCESS) {
276 BOOT_DEBUG("Error reading bootblock area\n");
277 perror("read");
278 return (BC_ERROR);
279 }
280
281 /* No multiboot means no chance of knowing bootblock size */
282 if (find_multiboot(mboot_scan, sizeof (mboot_scan), &mboot_off)
283 != BC_SUCCESS) {
284 BOOT_DEBUG("Unable to find multiboot header\n");
285 return (BC_NOEXTRA);
286 }
287 mboot = (multiboot_header_t *)(mboot_scan + mboot_off);
288
289 /*
290 * make sure mboot has sane values
291 */
292 if (mboot->load_end_addr == 0 ||
293 mboot->load_end_addr < mboot->load_addr)
294 return (BC_NOEXTRA);
295
296 /*
297 * Currently, the amount of space reserved for extra information
298 * is "fixed". We may have to scan for the terminating extra payload
299 * in the future.
300 */
301 size = mboot->load_end_addr - mboot->load_addr;
302 buf_size = P2ROUNDUP(size + SECTOR_SIZE, SECTOR_SIZE);
303 bblock->file_size = size;
304
305 bblock->buf = malloc(buf_size);
306 if (bblock->buf == NULL) {
307 BOOT_DEBUG("Unable to allocate enough memory to read"
308 " the extra bootblock from the disk\n");
309 perror(gettext("Memory allocation failure"));
310 return (BC_ERROR);
311 }
312 bblock->buf_size = buf_size;
313
314 if (read_in(dev_fd, bblock->buf, buf_size, offset) != BC_SUCCESS) {
315 BOOT_DEBUG("Error reading the bootblock\n");
316 (void) free(bblock->buf);
317 bblock->buf = NULL;
318 return (BC_ERROR);
319 }
320
321 /* Update pointers. */
322 bblock->file = bblock->buf;
323 bblock->mboot_off = mboot_off;
324 bblock->mboot = (multiboot_header_t *)(bblock->buf + bblock->mboot_off);
325 bblock->extra = bblock->buf + P2ROUNDUP(bblock->file_size, 8);
326 bblock->extra_size = bblock->buf_size - P2ROUNDUP(bblock->file_size, 8);
327
328 BOOT_DEBUG("mboot at %p offset %d, extra at %p size %d, buf=%p "
329 "(size=%d)\n", bblock->mboot, bblock->mboot_off, bblock->extra,
330 bblock->extra_size, bblock->buf, bblock->buf_size);
331
332 return (BC_SUCCESS);
333 }
334
335 static boolean_t
336 is_update_necessary(ib_data_t *data, char *updt_str)
337 {
338 bblk_einfo_t *einfo;
339 bblk_einfo_t *einfo_file;
340 bblk_hs_t bblock_hs;
341 ib_bootblock_t bblock_disk;
342 ib_bootblock_t *bblock_file = &data->bootblock;
343 ib_device_t *device = &data->device;
344 int ret;
345 char *path;
346
347 assert(data != NULL);
348
349 bzero(&bblock_disk, sizeof (ib_bootblock_t));
350
351 ret = read_bootblock_from_disk(device, &bblock_disk, &path);
352 if (ret != BC_SUCCESS) {
353 BOOT_DEBUG("Unable to read bootblock from %s\n", path);
354 return (B_TRUE);
355 }
356
357 einfo = find_einfo(bblock_disk.extra, bblock_disk.extra_size);
358 if (einfo == NULL) {
359 BOOT_DEBUG("No extended information available on disk\n");
360 return (B_TRUE);
361 }
362
363 einfo_file = find_einfo(bblock_file->extra, bblock_file->extra_size);
364 if (einfo_file == NULL) {
365 /*
366 * loader bootblock is versioned. missing version means
367 * probably incompatible block. installboot can not install
368 * grub, for example.
369 */
370 (void) fprintf(stderr,
371 gettext("ERROR: non versioned bootblock in file\n"));
372 return (B_FALSE);
373 } else {
374 if (updt_str == NULL) {
375 updt_str = einfo_get_string(einfo_file);
376 do_version = B_TRUE;
377 }
378 }
379
380 if (!do_version || updt_str == NULL) {
381 (void) fprintf(stderr,
382 gettext("WARNING: target device %s has a "
383 "versioned bootblock that is going to be overwritten by a "
384 "non versioned one\n"), device->path);
385 return (B_TRUE);
386 }
387
388 if (force_update) {
389 BOOT_DEBUG("Forcing update of %s bootblock\n", device->path);
390 return (B_TRUE);
391 }
392
393 BOOT_DEBUG("Ready to check installed version vs %s\n", updt_str);
394
395 bblock_hs.src_buf = (unsigned char *)bblock_file->file;
396 bblock_hs.src_size = bblock_file->file_size;
397
398 return (einfo_should_update(einfo, &bblock_hs, updt_str));
399 }
400
401 static void
402 add_bootblock_einfo(ib_bootblock_t *bblock, char *updt_str)
403 {
404 bblk_hs_t hs;
405 uint32_t avail_space;
406
407 assert(bblock != NULL);
408
409 if (updt_str == NULL) {
410 BOOT_DEBUG("WARNING: no update string passed to "
411 "add_bootblock_einfo()\n");
412 return;
413 }
414
415 /* Fill bootblock hashing source information. */
416 hs.src_buf = (unsigned char *)bblock->file;
417 hs.src_size = bblock->file_size;
418 /* How much space for the extended information structure? */
419 avail_space = bblock->buf_size - P2ROUNDUP(bblock->file_size, 8);
420 /* Place the extended information structure. */
421 add_einfo(bblock->extra, updt_str, &hs, avail_space);
422 }
423
424 /*
425 * set up data for case stage1 is installed as MBR
426 * set up location and size of bootblock
427 * set disk guid to provide unique information for biosdev command
428 */
429 static int
430 prepare_stage1(ib_data_t *data)
431 {
432 ib_device_t *device;
433
434 assert(data != NULL);
435 device = &data->device;
436
437 /* copy BPB */
438 bcopy(device->mbr + STAGE1_BPB_OFFSET,
439 data->stage1 + STAGE1_BPB_OFFSET, STAGE1_BPB_SIZE);
440
441
442 /* copy MBR, note STAGE1_SIG == BOOTSZ */
443 bcopy(device->mbr + STAGE1_SIG, data->stage1 + STAGE1_SIG,
444 SECTOR_SIZE - STAGE1_SIG);
445
446 /* set stage2 size */
447 *((uint16_t *)(data->stage1 + STAGE1_STAGE2_SIZE)) =
448 (uint16_t)(data->bootblock.buf_size / SECTOR_SIZE);
449
450 /*
451 * set stage2 location.
452 * for zfs always use zfs embedding, for ufs/pcfs use partition_start
453 * as base for stage2 location, for ufs/pcfs in MBR partition, use
454 * free space after MBR record.
455 */
456 if (device->target.fstype == IG_FS_ZFS)
457 *((uint64_t *)(data->stage1 + STAGE1_STAGE2_LBA)) =
458 device->target.start + device->target.offset;
459 else {
460 *((uint64_t *)(data->stage1 + STAGE1_STAGE2_LBA)) =
461 device->stage.start + device->stage.offset;
462 }
463
464 /*
465 * set disk uuid. we only need reasonable amount of uniqueness
466 * to allow biosdev to identify disk based on mbr differences.
467 */
468 uuid_generate(data->stage1 + STAGE1_STAGE2_UUID);
469
470 return (BC_SUCCESS);
471 }
472
473 static int
474 prepare_bootblock(ib_data_t *data, char *updt_str)
475 {
476 ib_bootblock_t *bblock;
477 ib_device_t *device;
478 uint64_t *ptr;
479
480 assert(data != NULL);
481
482 bblock = &data->bootblock;
483 device = &data->device;
484
485 ptr = (uint64_t *)(&bblock->mboot->bss_end_addr);
486 *ptr = device->target.start;
487
488 /*
489 * the loader bootblock has built in version, if custom
490 * version was provided, update it.
491 */
492 if (do_version)
493 add_bootblock_einfo(bblock, updt_str);
494
495 return (BC_SUCCESS);
496 }
497
498 static int
499 write_bootblock(ib_data_t *data)
500 {
501 ib_device_t *device = &data->device;
502 ib_bootblock_t *bblock = &data->bootblock;
503 uint64_t abs;
504 int dev_fd, ret;
505 off_t offset;
506 char *path;
507
508 assert(data != NULL);
509
510 /*
511 * ZFS bootblock area is 3.5MB, make sure we can fit.
512 * buf_size is size of bootblk+EINFO.
513 */
514 if (bblock->buf_size > BBLK_ZFS_BLK_SIZE) {
515 (void) fprintf(stderr, gettext("bootblock is too large\n"));
516 return (BC_ERROR);
517 }
518
519 if (device->target.fstype == IG_FS_ZFS) {
520 dev_fd = device->target.fd;
521 abs = device->target.start + device->target.offset;
522 offset = BBLK_ZFS_BLK_OFF * SECTOR_SIZE;
523 path = device->target.path;
524 } else {
525 dev_fd = device->stage.fd;
526 abs = device->stage.start + device->stage.offset;
527 offset = device->stage.offset * SECTOR_SIZE;
528 path = device->stage.path;
529 if (bblock->buf_size >
530 (device->stage.size - device->stage.offset) * SECTOR_SIZE) {
531 (void) fprintf(stderr, gettext("Device %s is "
532 "too small to fit the stage2\n"), path);
533 return (BC_ERROR);
534 }
535 }
536 ret = write_out(dev_fd, bblock->buf, bblock->buf_size, offset);
537 if (ret != BC_SUCCESS) {
538 BOOT_DEBUG("Error writing the ZFS bootblock "
539 "to %s at offset %d\n", path, offset);
540 return (BC_ERROR);
541 }
542
543 (void) fprintf(stdout, gettext("bootblock written for %s,"
544 " %d sectors starting at %d (abs %lld)\n"), path,
545 (bblock->buf_size / SECTOR_SIZE) + 1, offset / SECTOR_SIZE, abs);
546
547 return (BC_SUCCESS);
548 }
549
550 /*
551 * Partition boot block or volume boot record (VBR). The VBR is
552 * stored on partition relative sector 0 and allows chainloading
553 * to read boot program from partition.
554 *
555 * As the VBR will use the first sector of the partition,
556 * this means, we need to be sure the space is not used.
557 * We do support three partitioning chemes:
558 * 1. GPT: zfs and ufs have reserved space for first 8KB, but
559 * only zfs does have space for boot2. The pcfs has support
560 * for VBR, but no space for boot2. So with GPT, to support
561 * ufs or pcfs boot, we must have separate dedicated boot
562 * partition and we will store VBR on it.
563 * 2. MBR: we have almost the same situation as with GPT, except that
564 * if the partitions start from cylinder 1, we will have space
565 * between MBR and cylinder 0. If so, we do not require separate
566 * boot partition.
567 * 3. MBR+VTOC: with this combination we store VBR in sector 0 of the
568 * solaris2 MBR partition. The slice 0 will start from cylinder 1,
569 * and we do have space for boot2, so we do not require separate
570 * boot partition.
571 */
572 static int
573 write_stage1(ib_data_t *data)
574 {
575 ib_device_t *device = &data->device;
576 uint64_t start = 0;
577
578 assert(data != NULL);
579
580 /*
581 * We have separate partition for boot programs and the stage1
582 * location is not absolute sector 0.
583 * We will write VBR and trigger MBR to read 1 sector from VBR.
584 * This case does also cover MBR+VTOC case, as the solaris 2 partition
585 * name and the root file system slice names are different.
586 */
587 if (device->stage.start != 0 &&
588 strcmp(device->target.path, device->stage.path)) {
589 /* we got separate stage area, use it */
590 if (write_out(device->stage.fd, data->stage1,
591 sizeof (data->stage1), 0) != BC_SUCCESS) {
592 (void) fprintf(stdout, gettext("cannot write "
593 "partition boot sector\n"));
594 perror("write");
595 return (BC_ERROR);
596 }
597
598 (void) fprintf(stdout, gettext("stage1 written to "
599 "%s %d sector 0 (abs %d)\n"),
600 device->devtype == IG_DEV_MBR? "partition":"slice",
601 device->stage.id, device->stage.start);
602 start = device->stage.start;
603 }
604
605 /*
606 * We have either GPT or MBR (without VTOC) and if the root
607 * file system is not pcfs, we can store VBR. Also trigger
608 * MBR to read 1 sector from VBR.
609 */
610 if (device->devtype != IG_DEV_VTOC &&
611 device->target.fstype != IG_FS_PCFS) {
612 if (write_out(device->target.fd, data->stage1,
613 sizeof (data->stage1), 0) != BC_SUCCESS) {
614 (void) fprintf(stdout, gettext("cannot write "
615 "partition boot sector\n"));
616 perror("write");
617 return (BC_ERROR);
618 }
619
620 (void) fprintf(stdout, gettext("stage1 written to "
621 "%s %d sector 0 (abs %d)\n"),
622 device->devtype == IG_DEV_MBR? "partition":"slice",
623 device->target.id, device->target.start);
624 start = device->target.start;
625 }
626
627 if (write_mbr) {
628 /*
629 * If we did write partition boot block, update MBR to
630 * read partition boot block, not boot2.
631 */
632 if (start != 0) {
633 *((uint16_t *)(data->stage1 + STAGE1_STAGE2_SIZE)) = 1;
634 *((uint64_t *)(data->stage1 + STAGE1_STAGE2_LBA)) =
635 start;
636 }
637 if (write_out(device->fd, data->stage1,
638 sizeof (data->stage1), 0) != BC_SUCCESS) {
639 (void) fprintf(stdout,
640 gettext("cannot write master boot sector\n"));
641 perror("write");
642 return (BC_ERROR);
643 }
644 (void) fprintf(stdout,
645 gettext("stage1 written to master boot sector\n"));
646 }
647
648 return (BC_SUCCESS);
649 }
650
651 /*
652 * find partition/slice start sector. will be recorded in stage2 and used
653 * by stage2 to identify partition with boot file system.
654 */
655 static int
656 get_start_sector(ib_device_t *device)
657 {
658 uint32_t secnum = 0, numsec = 0;
659 int i, pno, rval, log_part = 0;
660 struct mboot *mboot;
661 struct ipart *part = NULL;
662 ext_part_t *epp;
663 struct part_info dkpi;
664 struct extpart_info edkpi;
665
666 if (device->devtype == IG_DEV_EFI) {
667 struct dk_gpt *vtoc;
668
669 if (efi_alloc_and_read(device->fd, &vtoc) < 0)
670 return (BC_ERROR);
671
672 if (device->stage.start == 0) {
673 /* zero size means the fstype must be zfs */
674 assert(device->target.fstype == IG_FS_ZFS);
675
676 device->stage.start =
677 vtoc->efi_parts[device->stage.id].p_start;
678 device->stage.size =
679 vtoc->efi_parts[device->stage.id].p_size;
680 device->stage.offset = BBLK_ZFS_BLK_OFF;
681 device->target.offset = BBLK_ZFS_BLK_OFF;
682 }
683
684 device->target.start =
685 vtoc->efi_parts[device->target.id].p_start;
686 device->target.size =
687 vtoc->efi_parts[device->target.id].p_size;
688
689 /* with pcfs we always write MBR */
690 if (device->target.fstype == IG_FS_PCFS) {
691 force_mbr = 1;
692 write_mbr = 1;
693 }
694
695 efi_free(vtoc);
696 goto found_part;
697 }
698
699 mboot = (struct mboot *)device->mbr;
700
701 /* For MBR we have device->stage filled already. */
702 if (device->devtype == IG_DEV_MBR) {
703 /* MBR partition starts from 0 */
704 pno = device->target.id - 1;
705 part = (struct ipart *)mboot->parts + pno;
706
707 if (part->relsect == 0) {
708 (void) fprintf(stderr, gettext("Partition %d of the "
709 "disk has an incorrect offset\n"),
710 device->target.id);
711 return (BC_ERROR);
712 }
713 device->target.start = part->relsect;
714 device->target.size = part->numsect;
715
716 /* with pcfs we always write MBR */
717 if (device->target.fstype == IG_FS_PCFS) {
718 force_mbr = 1;
719 write_mbr = 1;
720 }
721 if (device->target.fstype == IG_FS_ZFS)
722 device->target.offset = BBLK_ZFS_BLK_OFF;
723
724 goto found_part;
725 }
726
727 /*
728 * Search for Solaris fdisk partition
729 * Get the solaris partition information from the device
730 * and compare the offset of S2 with offset of solaris partition
731 * from fdisk partition table.
732 */
733 if (ioctl(device->target.fd, DKIOCEXTPARTINFO, &edkpi) < 0) {
734 if (ioctl(device->target.fd, DKIOCPARTINFO, &dkpi) < 0) {
735 (void) fprintf(stderr, gettext("cannot get the "
736 "slice information of the disk\n"));
737 return (BC_ERROR);
738 } else {
739 edkpi.p_start = dkpi.p_start;
740 edkpi.p_length = dkpi.p_length;
741 }
742 }
743
744 device->target.start = edkpi.p_start;
745 device->target.size = edkpi.p_length;
746 if (device->target.fstype == IG_FS_ZFS)
747 device->target.offset = BBLK_ZFS_BLK_OFF;
748
749 for (i = 0; i < FD_NUMPART; i++) {
750 part = (struct ipart *)mboot->parts + i;
751
752 if (part->relsect == 0) {
753 (void) fprintf(stderr, gettext("Partition %d of the "
754 "disk has an incorrect offset\n"), i+1);
755 return (BC_ERROR);
756 }
757
758 if (edkpi.p_start >= part->relsect &&
759 edkpi.p_start < (part->relsect + part->numsect)) {
760 /* Found the partition */
761 break;
762 }
763 }
764
765 if (i == FD_NUMPART) {
766 /* No solaris fdisk partitions (primary or logical) */
767 (void) fprintf(stderr, gettext("Solaris partition not found. "
768 "Aborting operation.\n"));
769 return (BC_ERROR);
770 }
771
772 /*
773 * We have found a Solaris fdisk partition (primary or extended)
774 * Handle the simple case first: Solaris in a primary partition
775 */
776 if (!fdisk_is_dos_extended(part->systid)) {
777 device->stage.start = part->relsect;
778 device->stage.size = part->numsect;
779 if (device->target.fstype == IG_FS_ZFS)
780 device->stage.offset = BBLK_ZFS_BLK_OFF;
781 else
782 device->stage.offset = BBLK_BLKLIST_OFF;
783 device->stage.id = i + 1;
784 goto found_part;
785 }
786
787 /*
788 * Solaris in a logical partition. Find that partition in the
789 * extended part.
790 */
791
792 if ((rval = libfdisk_init(&epp, device->path, NULL, FDISK_READ_DISK))
793 != FDISK_SUCCESS) {
794 switch (rval) {
795 /*
796 * The first 3 cases are not an error per-se, just that
797 * there is no Solaris logical partition
798 */
799 case FDISK_EBADLOGDRIVE:
800 case FDISK_ENOLOGDRIVE:
801 case FDISK_EBADMAGIC:
802 (void) fprintf(stderr, gettext("Solaris "
803 "partition not found. "
804 "Aborting operation.\n"));
805 return (BC_ERROR);
806 case FDISK_ENOVGEOM:
807 (void) fprintf(stderr, gettext("Could not get "
808 "virtual geometry\n"));
809 return (BC_ERROR);
810 case FDISK_ENOPGEOM:
811 (void) fprintf(stderr, gettext("Could not get "
812 "physical geometry\n"));
813 return (BC_ERROR);
814 case FDISK_ENOLGEOM:
815 (void) fprintf(stderr, gettext("Could not get "
816 "label geometry\n"));
817 return (BC_ERROR);
818 default:
819 (void) fprintf(stderr, gettext("Failed to "
820 "initialize libfdisk.\n"));
821 return (BC_ERROR);
822 }
823 }
824
825 rval = fdisk_get_solaris_part(epp, &pno, &secnum, &numsec);
826 libfdisk_fini(&epp);
827 if (rval != FDISK_SUCCESS) {
828 /* No solaris logical partition */
829 (void) fprintf(stderr, gettext("Solaris partition not found. "
830 "Aborting operation.\n"));
831 return (BC_ERROR);
832 }
833
834 device->stage.start = secnum;
835 device->stage.size = numsec;
836 device->stage.id = pno;
837 log_part = 1;
838
839 found_part:
840 /* get confirmation for -m */
841 if (write_mbr && !force_mbr) {
842 (void) fprintf(stdout, gettext("Updating master boot sector "
843 "destroys existing boot managers (if any).\n"
844 "continue (y/n)? "));
845 if (!yes()) {
846 write_mbr = 0;
847 (void) fprintf(stdout, gettext("master boot sector "
848 "not updated\n"));
849 return (BC_ERROR);
850 }
851 }
852
853 /*
854 * warn, if illumos in primary partition and loader not in MBR and
855 * partition is not active
856 */
857 if (device->devtype != IG_DEV_EFI) {
858 if (!log_part && part->bootid != 128 && !write_mbr) {
859 (void) fprintf(stdout, gettext("Solaris fdisk "
860 "partition is inactive.\n"), device->stage.id);
861 }
862 }
863
864 return (BC_SUCCESS);
865 }
866
867 static int
868 open_device(char *path)
869 {
870 struct stat statbuf = {0};
871 int fd = -1;
872
873 if (nowrite)
874 fd = open(path, O_RDONLY);
875 else
876 fd = open(path, O_RDWR);
877
878 if (fd == -1) {
879 BOOT_DEBUG("Unable to open %s\n", path);
880 perror("open");
881 return (-1);
882 }
883
884 if (fstat(fd, &statbuf) != 0) {
885 BOOT_DEBUG("Unable to stat %s\n", path);
886 perror("stat");
887 (void) close(fd);
888 return (-1);
889 }
890
891 if (S_ISCHR(statbuf.st_mode) == 0) {
892 (void) fprintf(stderr, gettext("%s: Not a character device\n"),
893 path);
894 (void) close(fd);
895 return (-1);
896 }
897
898 return (fd);
899 }
900
901 static int
902 get_boot_partition(ib_device_t *device, struct mboot *mbr)
903 {
904 struct ipart *part;
905 char *path, *ptr;
906 int i;
907
908 part = (struct ipart *)mbr->parts;
909 for (i = 0; i < FD_NUMPART; i++) {
910 if (part[i].systid == X86BOOT)
911 break;
912 }
913
914 /* no X86BOOT, try to use space between MBR and first partition */
915 if (i == FD_NUMPART) {
916 device->stage.path = strdup(device->path);
917 if (device->stage.path == NULL) {
918 perror(gettext("Memory allocation failure"));
919 return (BC_ERROR);
920 }
921 device->stage.fd = dup(device->fd);
922 device->stage.id = 0;
923 device->stage.devtype = IG_DEV_MBR;
924 device->stage.fstype = IG_FS_NONE;
925 device->stage.start = 0;
926 device->stage.size = part[0].relsect;
927 device->stage.offset = BBLK_BLKLIST_OFF;
928 return (BC_SUCCESS);
929 }
930
931 if ((path = strdup(device->path)) == NULL) {
932 perror(gettext("Memory allocation failure"));
933 return (BC_ERROR);
934 }
935
936 ptr = strrchr(path, 'p');
937 ptr++;
938 *ptr = '\0';
939 (void) asprintf(&ptr, "%s%d", path, i+1); /* partitions are p1..p4 */
940 free(path);
941 if (ptr == NULL) {
942 perror(gettext("Memory allocation failure"));
943 return (BC_ERROR);
944 }
945 device->stage.path = ptr;
946 device->stage.fd = open_device(ptr);
947 device->stage.id = i + 1;
948 device->stage.devtype = IG_DEV_MBR;
949 device->stage.fstype = IG_FS_NONE;
950 device->stage.start = part[i].relsect;
951 device->stage.size = part[i].numsect;
952 device->stage.offset = 1; /* leave sector 0 for VBR */
953 return (BC_SUCCESS);
954 }
955
956 static int
957 get_boot_slice(ib_device_t *device, struct dk_gpt *vtoc)
958 {
959 uint_t i;
960 char *path, *ptr;
961
962 for (i = 0; i < vtoc->efi_nparts; i++) {
963 if (vtoc->efi_parts[i].p_tag == V_SYSTEM) {
964 if ((path = strdup(device->target.path)) == NULL) {
965 perror(gettext("Memory allocation failure"));
966 return (BC_ERROR);
967 }
968 ptr = strrchr(path, 's');
969 ptr++;
970 *ptr = '\0';
971 (void) asprintf(&ptr, "%s%d", path, i);
972 free(path);
973 if (ptr == NULL) {
974 perror(gettext("Memory allocation failure"));
975 return (BC_ERROR);
976 }
977 device->system.path = ptr;
978 device->system.fd = open_device(ptr);
979 device->system.id = i;
980 device->system.devtype = IG_DEV_EFI;
981 device->system.fstype = IG_FS_PCFS;
982 device->system.start = vtoc->efi_parts[i].p_start;
983 device->system.size = vtoc->efi_parts[i].p_size;
984 device->system.offset = 0;
985 } else if (vtoc->efi_parts[i].p_tag == V_BOOT) {
986 if ((path = strdup(device->target.path)) == NULL) {
987 perror(gettext("Memory allocation failure"));
988 return (BC_ERROR);
989 }
990 ptr = strrchr(path, 's');
991 ptr++;
992 *ptr = '\0';
993 (void) asprintf(&ptr, "%s%d", path, i);
994 free(path);
995 if (ptr == NULL) {
996 perror(gettext("Memory allocation failure"));
997 return (BC_ERROR);
998 }
999 device->stage.path = ptr;
1000 device->stage.fd = open_device(ptr);
1001 device->stage.id = i;
1002 device->stage.devtype = IG_DEV_EFI;
1003 device->stage.fstype = IG_FS_NONE;
1004 device->stage.start = vtoc->efi_parts[i].p_start;
1005 device->stage.size = vtoc->efi_parts[i].p_size;
1006 device->stage.offset = 1; /* leave sector 0 for VBR */
1007 }
1008 }
1009 return (BC_SUCCESS);
1010 }
1011
1012 static int
1013 init_device(ib_device_t *device, char *path)
1014 {
1015 struct dk_gpt *vtoc;
1016 fstyp_handle_t fhdl;
1017 const char *fident;
1018 char *p;
1019 int pathlen = strlen(path);
1020 int ret;
1021
1022 bzero(device, sizeof (*device));
1023 device->fd = -1; /* whole disk fd */
1024 device->stage.fd = -1; /* bootblock partition fd */
1025 device->system.fd = -1; /* efi system partition fd */
1026 device->target.fd = -1; /* target fs partition fd */
1027
1028 /* basic check, whole disk is not allowed */
1029 if ((p = strrchr(path, '/')) == NULL)
1030 p = path;
1031 if ((strrchr(p, 'p') == NULL && strrchr(p, 's') == NULL) ||
1032 (path[pathlen-2] == 'p' && path[pathlen-1] == '0')) {
1033 (void) fprintf(stderr, gettext("installing loader to "
1034 "whole disk device is not supported\n"));
1035 }
1036
1037 device->target.path = strdup(path);
1038 if (device->target.path == NULL) {
1039 perror(gettext("Memory allocation failure"));
1040 return (BC_ERROR);
1041 }
1042 device->path = strdup(path);
1043 if (device->path == NULL) {
1044 perror(gettext("Memory allocation failure"));
1045 return (BC_ERROR);
1046 }
1047
1048 /* change device name to p0 */
1049 device->path[pathlen - 2] = 'p';
1050 device->path[pathlen - 1] = '0';
1051
1052 if (strstr(device->target.path, "diskette")) {
1053 (void) fprintf(stderr, gettext("installing loader to a floppy "
1054 "disk is not supported\n"));
1055 return (BC_ERROR);
1056 }
1057
1058 /* Detect if the target device is a pcfs partition. */
1059 if (strstr(device->target.path, "p0:boot")) {
1060 (void) fprintf(stderr, gettext("installing loader to x86 boot "
1061 "partition is not supported\n"));
1062 return (BC_ERROR);
1063 }
1064
1065 if ((device->fd = open_device(device->path)) == -1)
1066 return (BC_ERROR);
1067
1068 /* read in the device boot sector. */
1069 if (read(device->fd, device->mbr, SECTOR_SIZE) != SECTOR_SIZE) {
1070 (void) fprintf(stderr, gettext("Error reading boot sector\n"));
1071 perror("read");
1072 return (BC_ERROR);
1073 }
1074
1075 device->devtype = IG_DEV_VTOC;
1076 if (efi_alloc_and_read(device->fd, &vtoc) >= 0) {
1077 ret = get_boot_slice(device, vtoc);
1078 device->devtype = IG_DEV_EFI;
1079 efi_free(vtoc);
1080 if (ret == BC_ERROR)
1081 return (BC_ERROR);
1082 } else if (device->target.path[pathlen - 2] == 'p') {
1083 device->devtype = IG_DEV_MBR;
1084 ret = get_boot_partition(device, (struct mboot *)device->mbr);
1085 if (ret == BC_ERROR)
1086 return (BC_ERROR);
1087 } else if (device->target.path[pathlen - 1] == '2') {
1088 /*
1089 * NOTE: we could relax there and allow zfs boot on
1090 * slice 2 for instance, but lets keep traditional limits.
1091 */
1092 (void) fprintf(stderr,
1093 gettext("raw device must be a root slice (not s2)\n"));
1094 return (BC_ERROR);
1095 }
1096
1097 /* fill stage partition for case there is no boot partition */
1098 if (device->stage.path == NULL) {
1099 if ((device->stage.path = strdup(path)) == NULL) {
1100 perror(gettext("Memory allocation failure"));
1101 return (BC_ERROR);
1102 }
1103 if (device->devtype == IG_DEV_VTOC) {
1104 /* use slice 2 */
1105 device->stage.path[pathlen - 2] = 's';
1106 device->stage.path[pathlen - 1] = '2';
1107 device->stage.id = 2;
1108 } else {
1109 p = strrchr(device->stage.path, 'p');
1110 if (p == NULL)
1111 p = strrchr(device->stage.path, 's');
1112 device->stage.id = atoi(++p);
1113 }
1114 device->stage.devtype = device->devtype;
1115 device->stage.fd = open_device(device->stage.path);
1116 }
1117
1118 p = strrchr(device->target.path, 'p');
1119 if (p == NULL)
1120 p = strrchr(device->target.path, 's');
1121 device->target.id = atoi(++p);
1122
1123 if (strcmp(device->stage.path, device->target.path) == 0)
1124 device->target.fd = dup(device->stage.fd);
1125 else
1126 device->target.fd = open_device(device->target.path);
1127
1128 if (fstyp_init(device->target.fd, 0, NULL, &fhdl) != 0)
1129 return (BC_ERROR);
1130
1131 if (fstyp_ident(fhdl, NULL, &fident) != 0) {
1132 fstyp_fini(fhdl);
1133 (void) fprintf(stderr, gettext("Failed to detect file "
1134 "system type\n"));
1135 return (BC_ERROR);
1136 }
1137
1138 /* at this moment non-boot partition has no size set, use this fact */
1139 if (device->devtype == IG_DEV_EFI && strcmp(fident, "zfs") &&
1140 device->stage.size == 0) {
1141 fstyp_fini(fhdl);
1142 (void) fprintf(stderr, gettext("Booting %s of EFI labeled "
1143 "disks requires the boot partition.\n"), fident);
1144 return (BC_ERROR);
1145 }
1146 if (strcmp(fident, "zfs") == 0)
1147 device->target.fstype = IG_FS_ZFS;
1148 else if (strcmp(fident, "ufs") == 0) {
1149 device->target.fstype = IG_FS_UFS;
1150 } else if (strcmp(fident, "pcfs") == 0) {
1151 device->target.fstype = IG_FS_PCFS;
1152 } else {
1153 (void) fprintf(stderr, gettext("File system %s is not "
1154 "supported by loader\n"), fident);
1155 fstyp_fini(fhdl);
1156 return (BC_ERROR);
1157 }
1158 fstyp_fini(fhdl);
1159
1160 /* check for boot partition content */
1161 if (device->stage.size) {
1162 if (fstyp_init(device->stage.fd, 0, NULL, &fhdl) != 0)
1163 return (BC_ERROR);
1164
1165 if (fstyp_ident(fhdl, NULL, &fident) == 0) {
1166 (void) fprintf(stderr, gettext("Unexpected %s file "
1167 "system on boot partition\n"), fident);
1168 fstyp_fini(fhdl);
1169 return (BC_ERROR);
1170 }
1171 fstyp_fini(fhdl);
1172 }
1173 return (get_start_sector(device));
1174 }
1175
1176 static void
1177 cleanup_device(ib_device_t *device)
1178 {
1179 if (device->path)
1180 free(device->path);
1181 if (device->stage.path)
1182 free(device->stage.path);
1183 if (device->system.path)
1184 free(device->system.path);
1185 if (device->target.path)
1186 free(device->target.path);
1187
1188 if (device->fd != -1)
1189 (void) close(device->fd);
1190 if (device->stage.fd != -1)
1191 (void) close(device->stage.fd);
1192 if (device->system.fd != -1)
1193 (void) close(device->system.fd);
1194 if (device->target.fd != -1)
1195 (void) close(device->target.fd);
1196 bzero(device, sizeof (*device));
1197 }
1198
1199 static void
1200 cleanup_bootblock(ib_bootblock_t *bblock)
1201 {
1202 free(bblock->buf);
1203 bzero(bblock, sizeof (ib_bootblock_t));
1204 }
1205
1206 /*
1207 * Propagate the bootblock on the source disk to the destination disk and
1208 * version it with 'updt_str' in the process. Since we cannot trust any data
1209 * on the attaching disk, we do not perform any specific check on a potential
1210 * target extended information structure and we just blindly update.
1211 */
1212 static int
1213 propagate_bootblock(ib_data_t *src, ib_data_t *dest, char *updt_str)
1214 {
1215 ib_bootblock_t *src_bblock = &src->bootblock;
1216 ib_bootblock_t *dest_bblock = &dest->bootblock;
1217
1218 assert(src != NULL);
1219 assert(dest != NULL);
1220
1221 /* read the stage1 file from source disk */
1222 if (read(src->device.fd, dest->stage1, SECTOR_SIZE) != SECTOR_SIZE) {
1223 (void) fprintf(stderr, gettext("cannot read stage1 from %s\n"),
1224 src->device.path);
1225 return (BC_ERROR);
1226 }
1227
1228 cleanup_bootblock(dest_bblock);
1229
1230 dest_bblock->buf_size = src_bblock->buf_size;
1231 dest_bblock->buf = malloc(dest_bblock->buf_size);
1232 if (dest_bblock->buf == NULL) {
1233 perror(gettext("Memory Allocation Failure"));
1234 return (BC_ERROR);
1235 }
1236 dest_bblock->file = dest_bblock->buf;
1237 dest_bblock->file_size = src_bblock->file_size;
1238 (void) memcpy(dest_bblock->buf, src_bblock->buf,
1239 dest_bblock->buf_size);
1240
1241 dest_bblock->mboot = (multiboot_header_t *)(dest_bblock->file +
1242 src_bblock->mboot_off);
1243 dest_bblock->mboot_off = src_bblock->mboot_off;
1244 dest_bblock->extra = (char *)dest_bblock->file +
1245 P2ROUNDUP(dest_bblock->file_size, 8);
1246 dest_bblock->extra_size = src_bblock->extra_size;
1247
1248 (void) fprintf(stdout, gettext("Propagating %s bootblock to %s\n"),
1249 src->device.path, dest->device.path);
1250
1251 return (commit_to_disk(dest, updt_str));
1252 }
1253
1254 static int
1255 commit_to_disk(ib_data_t *data, char *update_str)
1256 {
1257 assert(data != NULL);
1258
1259 if (prepare_bootblock(data, update_str) != BC_SUCCESS) {
1260 (void) fprintf(stderr, gettext("Error updating the bootblock "
1261 "image\n"));
1262 return (BC_ERROR);
1263 }
1264
1265 if (prepare_stage1(data) != BC_SUCCESS) {
1266 (void) fprintf(stderr, gettext("Error updating the stage1 "
1267 "image\n"));
1268 return (BC_ERROR);
1269 }
1270
1271 if (write_bootblock(data) != BC_SUCCESS) {
1272 (void) fprintf(stderr, gettext("Error writing bootblock to "
1273 "disk\n"));
1274 return (BC_ERROR);
1275 }
1276
1277 return (write_stage1(data));
1278 }
1279
1280 /*
1281 * Install a new bootblock on the given device. handle_install() expects argv
1282 * to contain 3 parameters (the target device path and the path to the
1283 * bootblock.
1284 *
1285 * Returns: BC_SUCCESS - if the installation is successful
1286 * BC_ERROR - if the installation failed
1287 * BC_NOUPDT - if no installation was performed because the
1288 * version currently installed is more recent than the
1289 * supplied one.
1290 *
1291 */
1292 static int
1293 handle_install(char *progname, char **argv)
1294 {
1295 ib_data_t install_data;
1296 ib_bootblock_t *bblock = &install_data.bootblock;
1297 ib_bootblock_t *eblock = &install_data.efiblock;
1298 char *stage1 = NULL;
1299 char *bootblock = NULL;
1300 char *efiboot = NULL;
1301 char *device_path = NULL;
1302 char *tmp;
1303 int ret = BC_ERROR;
1304
1305 stage1 = strdup(argv[0]);
1306 bootblock = strdup(argv[1]);
1307 device_path = strdup(argv[2]);
1308
1309 if (!device_path || !bootblock || !stage1) {
1310 (void) fprintf(stderr, gettext("Missing parameter"));
1311 usage(progname);
1312 goto out;
1313 }
1314
1315 tmp = strdup(argv[1]);
1316 if (tmp == NULL) {
1317 perror(gettext("Memory allocation failure"));
1318 goto out;
1319 }
1320 (void) asprintf(&efiboot, "%s/" EFIBOOT64, dirname(tmp));
1321 free(tmp);
1322 if (efiboot == NULL) {
1323 perror(gettext("Memory allocation failure"));
1324 goto out;
1325 }
1326
1327 BOOT_DEBUG("device path: %s, stage1 path: %s bootblock path: %s\n",
1328 device_path, stage1, bootblock);
1329 bzero(&install_data, sizeof (ib_data_t));
1330
1331 if (init_device(&install_data.device, device_path) != BC_SUCCESS) {
1332 (void) fprintf(stderr, gettext("Unable to open device %s\n"),
1333 device_path);
1334 goto out;
1335 }
1336
1337 if (read_stage1_from_file(stage1, &install_data) != BC_SUCCESS) {
1338 (void) fprintf(stderr, gettext("Error opening %s\n"), stage1);
1339 goto out_dev;
1340 }
1341
1342 if (read_bootblock_from_file(bootblock, bblock) != BC_SUCCESS) {
1343 (void) fprintf(stderr, gettext("Error reading %s\n"),
1344 bootblock);
1345 goto out_dev;
1346 }
1347
1348 /* only read EFI boot program if there is system partition */
1349 if (install_data.device.system.fd != -1) {
1350 if (read_bootblock_from_file(efiboot, eblock) != BC_SUCCESS) {
1351 (void) fprintf(stderr, gettext("Error reading %s\n"),
1352 efiboot);
1353 goto out_dev;
1354 }
1355 }
1356
1357 /*
1358 * is_update_necessary() will take care of checking if versioning and/or
1359 * forcing the update have been specified. It will also emit a warning
1360 * if a non-versioned update is attempted over a versioned bootblock.
1361 */
1362 if (!is_update_necessary(&install_data, update_str)) {
1363 (void) fprintf(stderr, gettext("bootblock version installed "
1364 "on %s is more recent or identical\n"
1365 "Use -F to override or install without the -u option\n"),
1366 device_path);
1367 ret = BC_NOUPDT;
1368 goto out_dev;
1369 }
1370
1371 BOOT_DEBUG("Ready to commit to disk\n");
1372 ret = commit_to_disk(&install_data, update_str);
1373
1374 out_dev:
1375 cleanup_device(&install_data.device);
1376 out:
1377 free(efiboot);
1378 free(stage1);
1379 free(bootblock);
1380 free(device_path);
1381 return (ret);
1382 }
1383
1384 /*
1385 * Retrieves from a device the extended information (einfo) associated to the
1386 * file or installed stage2.
1387 * Expects one parameter, the device path, in the form: /dev/rdsk/c?[t?]d?s0
1388 * or file name.
1389 * Returns:
1390 * - BC_SUCCESS (and prints out einfo contents depending on 'flags')
1391 * - BC_ERROR (on error)
1392 * - BC_NOEINFO (no extended information available)
1393 */
1394 static int
1395 handle_getinfo(char *progname, char **argv)
1396 {
1397 struct stat sb;
1398 ib_bootblock_t bblock;
1399 ib_device_t device;
1400 bblk_einfo_t *einfo;
1401 uint8_t flags = 0;
1402 char *device_path, *path;
1403 int retval = BC_ERROR;
1404 int ret;
1405
1406 device_path = strdup(argv[0]);
1407 if (!device_path) {
1408 (void) fprintf(stderr, gettext("Missing parameter"));
1409 usage(progname);
1410 goto out;
1411 }
1412
1413 if (stat(device_path, &sb) == -1) {
1414 perror("stat");
1415 goto out;
1416 }
1417
1418 bzero(&bblock, sizeof (bblock));
1419 bzero(&device, sizeof (device));
1420 BOOT_DEBUG("device path: %s\n", device_path);
1421
1422 if (S_ISREG(sb.st_mode) != 0) {
1423 path = device_path;
1424 ret = read_bootblock_from_file(device_path, &bblock);
1425 } else {
1426 if (init_device(&device, device_path) != BC_SUCCESS) {
1427 (void) fprintf(stderr, gettext("Unable to gather "
1428 "device information from %s\n"), device_path);
1429 goto out_dev;
1430 }
1431 ret = read_bootblock_from_disk(&device, &bblock, &path);
1432 }
1433
1434 if (ret == BC_ERROR) {
1435 (void) fprintf(stderr, gettext("Error reading bootblock from "
1436 "%s\n"), path);
1437 goto out_dev;
1438 }
1439
1440 if (ret == BC_NOEXTRA) {
1441 BOOT_DEBUG("No multiboot header found on %s, unable "
1442 "to locate extra information area (old/non versioned "
1443 "bootblock?) \n", device_path);
1444 (void) fprintf(stderr, gettext("No extended information "
1445 "found\n"));
1446 retval = BC_NOEINFO;
1447 goto out_dev;
1448 }
1449
1450 einfo = find_einfo(bblock.extra, bblock.extra_size);
1451 if (einfo == NULL) {
1452 retval = BC_NOEINFO;
1453 (void) fprintf(stderr, gettext("No extended information "
1454 "found\n"));
1455 goto out_dev;
1456 }
1457
1458 /* Print the extended information. */
1459 if (strip)
1460 flags |= EINFO_EASY_PARSE;
1461 if (verbose_dump)
1462 flags |= EINFO_PRINT_HEADER;
1463
1464 print_einfo(flags, einfo, bblock.extra_size);
1465 retval = BC_SUCCESS;
1466
1467 out_dev:
1468 if (S_ISREG(sb.st_mode) == 0)
1469 cleanup_device(&device);
1470 out:
1471 free(device_path);
1472 return (retval);
1473 }
1474
1475 /*
1476 * Attempt to mirror (propagate) the current bootblock over the attaching disk.
1477 *
1478 * Returns:
1479 * - BC_SUCCESS (a successful propagation happened)
1480 * - BC_ERROR (an error occurred)
1481 * - BC_NOEXTRA (it is not possible to dump the current bootblock since
1482 * there is no multiboot information)
1483 */
1484 static int
1485 handle_mirror(char *progname, char **argv)
1486 {
1487 ib_data_t curr_data;
1488 ib_data_t attach_data;
1489 ib_device_t *curr_device = &curr_data.device;
1490 ib_device_t *attach_device = &attach_data.device;
1491 ib_bootblock_t *bblock_curr = &curr_data.bootblock;
1492 ib_bootblock_t *bblock_attach = &attach_data.bootblock;
1493 bblk_einfo_t *einfo_curr = NULL;
1494 char *curr_device_path;
1495 char *attach_device_path;
1496 char *updt_str = NULL;
1497 char *path;
1498 int retval = BC_ERROR;
1499 int ret;
1500
1501 curr_device_path = strdup(argv[0]);
1502 attach_device_path = strdup(argv[1]);
1503
1504 if (!curr_device_path || !attach_device_path) {
1505 (void) fprintf(stderr, gettext("Missing parameter"));
1506 usage(progname);
1507 goto out;
1508 }
1509 BOOT_DEBUG("Current device path is: %s, attaching device path is: "
1510 " %s\n", curr_device_path, attach_device_path);
1511
1512 bzero(&curr_data, sizeof (ib_data_t));
1513 bzero(&attach_data, sizeof (ib_data_t));
1514
1515 if (init_device(curr_device, curr_device_path) != BC_SUCCESS) {
1516 (void) fprintf(stderr, gettext("Unable to gather device "
1517 "information from %s (current device)\n"),
1518 curr_device_path);
1519 goto out_currdev;
1520 }
1521
1522 if (init_device(attach_device, attach_device_path) != BC_SUCCESS) {
1523 (void) fprintf(stderr, gettext("Unable to gather device "
1524 "information from %s (attaching device)\n"),
1525 attach_device_path);
1526 goto out_devs;
1527 }
1528
1529 ret = read_bootblock_from_disk(curr_device, bblock_curr, &path);
1530 if (ret == BC_ERROR) {
1531 BOOT_DEBUG("Error reading bootblock from %s\n", path);
1532 retval = BC_ERROR;
1533 goto out_devs;
1534 }
1535
1536 if (ret == BC_NOEXTRA) {
1537 BOOT_DEBUG("No multiboot header found on %s, unable to retrieve"
1538 " the bootblock\n", path);
1539 retval = BC_NOEXTRA;
1540 goto out_devs;
1541 }
1542
1543 write_mbr = B_TRUE;
1544 force_mbr = B_TRUE;
1545 einfo_curr = find_einfo(bblock_curr->extra, bblock_curr->extra_size);
1546 if (einfo_curr != NULL)
1547 updt_str = einfo_get_string(einfo_curr);
1548
1549 retval = propagate_bootblock(&curr_data, &attach_data, updt_str);
1550 cleanup_bootblock(bblock_curr);
1551 cleanup_bootblock(bblock_attach);
1552 out_devs:
1553 cleanup_device(attach_device);
1554 out_currdev:
1555 cleanup_device(curr_device);
1556 out:
1557 free(curr_device_path);
1558 free(attach_device_path);
1559 return (retval);
1560 }
1561
1562 #define USAGE_STRING "Usage:\t%s [-h|-m|-f|-n|-F|-u verstr] stage1 stage2 " \
1563 "raw-device\n" \
1564 "\t%s -M [-n] raw-device attach-raw-device\n" \
1565 "\t%s [-e|-V] -i raw-device | file\n"
1566
1567 #define CANON_USAGE_STR gettext(USAGE_STRING)
1568
1569 static void
1570 usage(char *progname)
1571 {
1572 (void) fprintf(stdout, CANON_USAGE_STR, progname, progname, progname);
1573 }
1574
1575 int
1576 main(int argc, char **argv)
1577 {
1578 int opt;
1579 int params = 3;
1580 int ret;
1581 char *progname;
1582 char **handle_args;
1583
1584 (void) setlocale(LC_ALL, "");
1585 (void) textdomain(TEXT_DOMAIN);
1586 if (init_yes() < 0) {
1587 (void) fprintf(stderr, gettext(ERR_MSG_INIT_YES),
1588 strerror(errno));
1589 exit(BC_ERROR);
1590 }
1591
1592 while ((opt = getopt(argc, argv, "deFfhiMmnu:V")) != EOF) {
1593 switch (opt) {
1594 case 'd':
1595 boot_debug = B_TRUE;
1596 break;
1597 case 'e':
1598 strip = B_TRUE;
1599 break;
1600 case 'F':
1601 force_update = B_TRUE;
1602 break;
1603 case 'f':
1604 force_mbr = B_TRUE;
1605 break;
1606 case 'h':
1607 usage(argv[0]);
1608 exit(BC_SUCCESS);
1609 break;
1610 case 'i':
1611 do_getinfo = B_TRUE;
1612 params = 1;
1613 break;
1614 case 'M':
1615 do_mirror_bblk = B_TRUE;
1616 params = 2;
1617 break;
1618 case 'm':
1619 write_mbr = B_TRUE;
1620 break;
1621 case 'n':
1622 nowrite = B_TRUE;
1623 break;
1624 case 'u':
1625 do_version = B_TRUE;
1626
1627 update_str = malloc(strlen(optarg) + 1);
1628 if (update_str == NULL) {
1629 perror(gettext("Memory allocation failure"));
1630 exit(BC_ERROR);
1631 }
1632 (void) strlcpy(update_str, optarg, strlen(optarg) + 1);
1633 break;
1634 case 'V':
1635 verbose_dump = B_TRUE;
1636 break;
1637 default:
1638 /* fall through to process non-optional args */
1639 break;
1640 }
1641 }
1642
1643 /* check arguments */
1644 if (argc != optind + params) {
1645 usage(argv[0]);
1646 exit(BC_ERROR);
1647 }
1648 progname = argv[0];
1649 check_options(progname);
1650 handle_args = argv + optind;
1651
1652 if (nowrite)
1653 (void) fprintf(stdout, gettext("Dry run requested. Nothing will"
1654 " be written to disk.\n"));
1655
1656 if (do_getinfo) {
1657 ret = handle_getinfo(progname, handle_args);
1658 } else if (do_mirror_bblk) {
1659 ret = handle_mirror(progname, handle_args);
1660 } else {
1661 ret = handle_install(progname, handle_args);
1662 }
1663 return (ret);
1664 }
1665
1666 #define MEANINGLESS_OPT gettext("%s specified but meaningless, ignoring\n")
1667 static void
1668 check_options(char *progname)
1669 {
1670 if (do_getinfo && do_mirror_bblk) {
1671 (void) fprintf(stderr, gettext("Only one of -M and -i can be "
1672 "specified at the same time\n"));
1673 usage(progname);
1674 exit(BC_ERROR);
1675 }
1676
1677 if (do_mirror_bblk) {
1678 /*
1679 * -u and -F may actually reflect a user intent that is not
1680 * correct with this command (mirror can be interpreted
1681 * "similar" to install. Emit a message and continue.
1682 * -e and -V have no meaning, be quiet here and only report the
1683 * incongruence if a debug output is requested.
1684 */
1685 if (do_version) {
1686 (void) fprintf(stderr, MEANINGLESS_OPT, "-u");
1687 do_version = B_FALSE;
1688 }
1689 if (force_update) {
1690 (void) fprintf(stderr, MEANINGLESS_OPT, "-F");
1691 force_update = B_FALSE;
1692 }
1693 if (strip || verbose_dump) {
1694 BOOT_DEBUG(MEANINGLESS_OPT, "-e|-V");
1695 strip = B_FALSE;
1696 verbose_dump = B_FALSE;
1697 }
1698 }
1699
1700 if (do_getinfo) {
1701 if (write_mbr || force_mbr || do_version || force_update) {
1702 BOOT_DEBUG(MEANINGLESS_OPT, "-m|-f|-u|-F");
1703 write_mbr = force_mbr = do_version = B_FALSE;
1704 force_update = B_FALSE;
1705 }
1706 }
1707 }