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 2019 Toomas Soome <tsoome@me.com>
25 */
26
27 #include <stdio.h>
28 #include <stdbool.h>
29 #include <errno.h>
30 #include <unistd.h>
31 #include <fcntl.h>
32 #include <assert.h>
33 #include <locale.h>
34 #include <strings.h>
35 #include <libfdisk.h>
36 #include <err.h>
37 #include <time.h>
38 #include <spawn.h>
39
40 #include <sys/dktp/fdisk.h>
41 #include <sys/dkio.h>
42 #include <sys/vtoc.h>
43 #include <sys/multiboot.h>
44 #include <sys/types.h>
45 #include <sys/stat.h>
46 #include <sys/sysmacros.h>
47 #include <sys/efi_partition.h>
48 #include <sys/queue.h>
49 #include <sys/mount.h>
50 #include <sys/mntent.h>
51 #include <sys/mnttab.h>
52 #include <sys/wait.h>
53 #include <libfstyp.h>
54 #include <libgen.h>
55 #include <uuid/uuid.h>
56
57 #include "installboot.h"
58 #include "bblk_einfo.h"
59 #include "boot_utils.h"
60 #include "mboot_extra.h"
61 #include "getresponse.h"
62
63 #ifndef TEXT_DOMAIN
64 #define TEXT_DOMAIN "SUNW_OST_OSCMD"
65 #endif
66
67 /*
68 * BIOS bootblock installation:
69 *
70 * 1. MBR is first sector of the disk. If the file system on target is
71 * ufs or zfs, the same MBR code is installed on first sector of the
72 * partition as well; this will allow to have real MBR sector to be
73 * replaced by some other boot loader and have illumos chainloaded.
74 *
75 * installboot will record the start LBA and size of stage2 code in MBR code.
76 * On boot, the MBR code will read the stage2 code and executes it.
77 *
78 * 2. Stage2 location depends on file system type;
79 * In case of zfs, installboot will store stage2 to zfs bootblk area,
80 * which is 512k bytes from partition start and size is 3.5MB.
81 *
82 * In case of ufs, the stage2 location is 50 512B sectors from
83 * Solaris2 MBR partition start, within boot slice, boot slice size is
84 * one cylinder.
85 *
86 * In case of pcfs, the stage2 location is 50 512B sectors from beginning
87 * of the disk, filling the space between MBR and first partition.
88 * This location assumes no other bootloader and the space is one cylinder,
89 * as first partition is starting from cylinder 1.
90 *
91 * In case of GPT partitioning and if file system is not zfs, the boot
92 * support is only possible with dedicated boot partition. For GPT,
93 * the current implementation is using BOOT partition, which must exist.
94 * BOOT partition does only contain raw boot blocks, without any file system.
95 *
96 * Loader stage2 is created with embedded version, by using fake multiboot (MB)
97 * header within first 32k and EINFO block is at the end of the actual
98 * boot block. MB header load_addr is set to 0 and load_end_addr is set to
99 * actual block end, so the EINFO size is (file size - load_end_addr).
100 * installboot does also store the illumos boot partition LBA to MB space,
101 * starting from bss_end_addr structure member location; stage2 will
102 * detect the partition and file system based on this value.
103 *
104 * Stored location values in MBR/stage2 also mean the bootblocks must be
105 * reinstalled in case the partition content is relocated.
106 */
107
108 static bool write_mbr = false;
109 static bool write_vbr = false;
110 static bool force_mbr = false;
111 static bool force_update = false;
112 static bool do_getinfo = false;
113 static bool do_version = false;
114 static bool do_mirror_bblk = false;
115 static bool strip = false;
116 static bool verbose_dump = false;
117 static size_t sector_size = SECTOR_SIZE;
118
119 /* Versioning string, if present. */
120 static char *update_str;
121
122 /* Default location of boot programs. */
123 static char *boot_dir = "/boot";
124
125 /* Our boot programs */
126 #define STAGE1 "pmbr"
127 #define STAGE2 "gptzfsboot"
128 #define BOOTIA32 "bootia32.efi"
129 #define BOOTX64 "bootx64.efi"
130 #define LOADER32 "loader32.efi"
131 #define LOADER64 "loader64.efi"
132
133 static char *stage1;
134 static char *stage2;
135 static char *efi32;
136 static char *efi64;
137
138 #define GRUB_VERSION_OFF (0x3e)
139 #define GRUB_COMPAT_VERSION_MAJOR 3
140 #define GRUB_COMPAT_VERSION_MINOR 2
141 #define GRUB_VERSION (2 << 8 | 3) /* 3.2 */
142
143 #define LOADER_VERSION (1)
144 #define LOADER_JOYENT_VERSION (2)
145
146 typedef enum {
147 MBR_TYPE_UNKNOWN,
148 MBR_TYPE_GRUB1,
149 MBR_TYPE_LOADER,
150 MBR_TYPE_LOADER_JOYENT,
151 } mbr_type_t;
152
153 /*
154 * Temporary buffer to store the first 32K of data looking for a multiboot
155 * signature.
156 */
157 char mboot_scan[MBOOT_SCAN_SIZE];
158
159 /* Function prototypes. */
160 static void check_options(char *);
161 static int open_device(const char *);
162 static char *make_blkdev(const char *);
163
164 static int read_bootblock_from_file(const char *, ib_bootblock_t *);
165 static void add_bootblock_einfo(ib_bootblock_t *, char *);
166 static void prepare_bootblock(ib_data_t *, struct partlist *, char *);
167 static int handle_install(char *, int, char **);
168 static int handle_getinfo(char *, int, char **);
169 static int handle_mirror(char *, int, char **);
170 static void usage(char *, int) __NORETURN;
171
172 static char *
stagefs_mount(char * blkdev,struct partlist * plist)173 stagefs_mount(char *blkdev, struct partlist *plist)
174 {
175 char *path;
176 char optbuf[MAX_MNTOPT_STR] = { '\0', };
177 char *template = strdup("/tmp/ibootXXXXXX");
178 int ret;
179
180 if (template == NULL)
181 return (NULL);
182
183 if ((path = mkdtemp(template)) == NULL) {
184 free(template);
185 return (NULL);
186 }
187
188 (void) snprintf(optbuf, MAX_MNTOPT_STR, "timezone=%d",
189 timezone);
190 ret = mount(blkdev, path, MS_OPTIONSTR,
191 MNTTYPE_PCFS, NULL, 0, optbuf, MAX_MNTOPT_STR);
192 if (ret != 0) {
193 (void) rmdir(path);
194 free(path);
195 path = NULL;
196 }
197 plist->pl_device->stage.mntpnt = path;
198 return (path);
199 }
200
201 static void
install_stage1_cb(void * data,struct partlist * plist)202 install_stage1_cb(void *data, struct partlist *plist)
203 {
204 int rv, fd;
205 ib_device_t *device = plist->pl_device;
206
207 if (plist->pl_type == IB_BBLK_MBR && !write_mbr)
208 return;
209
210 if ((fd = open_device(plist->pl_devname)) == -1) {
211 (void) fprintf(stdout, gettext("cannot open "
212 "device %s\n"), plist->pl_devname);
213 perror("open");
214 return;
215 }
216
217 rv = write_out(fd, plist->pl_stage, sector_size, 0);
218 if (rv != BC_SUCCESS) {
219 (void) fprintf(stdout, gettext("cannot write "
220 "partition boot sector\n"));
221 perror("write");
222 } else {
223 (void) fprintf(stdout, gettext("stage1 written to "
224 "%s %d sector 0 (abs %d)\n\n"),
225 device->devtype == IB_DEV_MBR? "partition" : "slice",
226 device->stage.id, device->stage.start);
227 }
228 }
229
230 static void
install_stage2_cb(void * data,struct partlist * plist)231 install_stage2_cb(void *data, struct partlist *plist)
232 {
233 ib_bootblock_t *bblock = plist->pl_src_data;
234 int fd, ret;
235 off_t offset;
236 uint64_t abs;
237
238 /*
239 * ZFS bootblock area is 3.5MB, make sure we can fit.
240 * buf_size is size of bootblk+EINFO.
241 */
242 if (bblock->buf_size > BBLK_ZFS_BLK_SIZE) {
243 (void) fprintf(stderr, gettext("bootblock is too large\n"));
244 return;
245 }
246
247 abs = plist->pl_device->stage.start + plist->pl_device->stage.offset;
248
249 if ((fd = open_device(plist->pl_devname)) == -1) {
250 (void) fprintf(stdout, gettext("cannot open "
251 "device %s\n"), plist->pl_devname);
252 perror("open");
253 return;
254 }
255 offset = plist->pl_device->stage.offset * sector_size;
256 ret = write_out(fd, bblock->buf, bblock->buf_size, offset);
257 (void) close(fd);
258 if (ret != BC_SUCCESS) {
259 BOOT_DEBUG("Error writing the ZFS bootblock "
260 "to %s at offset %d\n", plist->pl_devname, offset);
261 return;
262 }
263 (void) fprintf(stdout, gettext("bootblock written for %s,"
264 " %d sectors starting at %d (abs %lld)\n\n"), plist->pl_devname,
265 bblock->buf_size / sector_size, offset / sector_size, abs);
266 }
267
268 static bool
mkfs_pcfs(const char * dev)269 mkfs_pcfs(const char *dev)
270 {
271 pid_t pid, w;
272 posix_spawnattr_t attr;
273 posix_spawn_file_actions_t file_actions;
274 int status;
275 char *cmd[7];
276
277 if (posix_spawnattr_init(&attr))
278 return (false);
279 if (posix_spawn_file_actions_init(&file_actions)) {
280 (void) posix_spawnattr_destroy(&attr);
281 return (false);
282 }
283
284 if (posix_spawnattr_setflags(&attr,
285 POSIX_SPAWN_NOSIGCHLD_NP | POSIX_SPAWN_WAITPID_NP)) {
286 (void) posix_spawnattr_destroy(&attr);
287 (void) posix_spawn_file_actions_destroy(&file_actions);
288 return (false);
289 }
290 if (posix_spawn_file_actions_addopen(&file_actions, 0, "/dev/null",
291 O_RDONLY, 0)) {
292 (void) posix_spawnattr_destroy(&attr);
293 (void) posix_spawn_file_actions_destroy(&file_actions);
294 return (false);
295 }
296
297 cmd[0] = "/usr/sbin/mkfs";
298 cmd[1] = "-F";
299 cmd[2] = "pcfs";
300 cmd[3] = "-o";
301 cmd[4] = "fat=32";
302 cmd[5] = (char *)dev;
303 cmd[6] = NULL;
304
305 if (posix_spawn(&pid, cmd[0], &file_actions, &attr, cmd, NULL))
306 return (false);
307 (void) posix_spawnattr_destroy(&attr);
308 (void) posix_spawn_file_actions_destroy(&file_actions);
309
310 do {
311 w = waitpid(pid, &status, 0);
312 } while (w == -1 && errno == EINTR);
313 if (w == -1)
314 status = -1;
315
316 return (status != -1);
317 }
318
319 static void
install_esp_cb(void * data,struct partlist * plist)320 install_esp_cb(void *data, struct partlist *plist)
321 {
322 fstyp_handle_t fhdl;
323 const char *fident;
324 bool pcfs;
325 char *blkdev, *path, *file;
326 FILE *fp;
327 struct mnttab mp, mpref = { 0 };
328 ib_bootblock_t *bblock = plist->pl_src_data;
329 int fd, ret;
330
331 if ((fd = open_device(plist->pl_devname)) == -1)
332 return;
333
334 if (fstyp_init(fd, 0, NULL, &fhdl) != 0) {
335 (void) close(fd);
336 return;
337 }
338
339 pcfs = false;
340 if (fstyp_ident(fhdl, NULL, &fident) == 0) {
341 if (strcmp(fident, MNTTYPE_PCFS) == 0)
342 pcfs = true;
343 }
344 fstyp_fini(fhdl);
345 (void) close(fd);
346
347 if (!pcfs) {
348 (void) printf(gettext("Creating pcfs on ESP %s\n"),
349 plist->pl_devname);
350
351 if (!mkfs_pcfs(plist->pl_devname)) {
352 (void) fprintf(stderr, gettext("mkfs -F pcfs failed "
353 "on %s\n"), plist->pl_devname);
354 return;
355 }
356 }
357 blkdev = make_blkdev(plist->pl_devname);
358 if (blkdev == NULL)
359 return;
360
361 fp = fopen(MNTTAB, "r");
362 if (fp == NULL) {
363 perror("fopen");
364 free(blkdev);
365 return;
366 }
367
368 mpref.mnt_special = blkdev;
369 ret = getmntany(fp, &mp, &mpref);
370 (void) fclose(fp);
371 if (ret == 0)
372 path = mp.mnt_mountp;
373 else
374 path = stagefs_mount(blkdev, plist);
375
376 free(blkdev);
377 if (path == NULL)
378 return;
379
380 if (asprintf(&file, "%s%s", path, "/EFI") < 0) {
381 perror(gettext("Memory allocation failure"));
382 return;
383 }
384
385 ret = mkdir(file, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
386 if (ret == 0 || errno == EEXIST) {
387 free(file);
388 if (asprintf(&file, "%s%s", path, "/EFI/Boot") < 0) {
389 perror(gettext("Memory allocation failure"));
390 return;
391 }
392 ret = mkdir(file,
393 S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
394 if (errno == EEXIST)
395 ret = 0;
396 }
397 free(file);
398 if (ret < 0) {
399 perror("mkdir");
400 return;
401 }
402
403 if (asprintf(&file, "%s%s", path, plist->pl_device->stage.path) < 0) {
404 perror(gettext("Memory allocation failure"));
405 return;
406 }
407
408 /* Write stage file. Should create temp file and rename. */
409 (void) chmod(file, S_IRUSR | S_IWUSR);
410 fd = open(file, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
411 if (fd != -1) {
412 ret = write_out(fd, bblock->buf, bblock->buf_size, 0);
413 if (ret == BC_SUCCESS) {
414 (void) fprintf(stdout,
415 gettext("bootblock written to %s\n\n"), file);
416 } else {
417 (void) fprintf(stdout,
418 gettext("error while writing %s\n"), file);
419 }
420 (void) fchmod(fd, S_IRUSR | S_IRGRP | S_IROTH);
421 (void) close(fd);
422 }
423 free(file);
424 }
425
426 /*
427 * MBR setup only depends on write_mbr toggle.
428 */
429 static bool
compare_mbr_cb(struct partlist * plist)430 compare_mbr_cb(struct partlist *plist)
431 {
432 /* get confirmation for -m */
433 if (write_mbr && !force_mbr) {
434 (void) fprintf(stdout, gettext("Updating master boot sector "
435 "destroys existing boot managers (if any).\n"
436 "continue (y/n)? "));
437 if (!yes()) {
438 write_mbr = false;
439 (void) fprintf(stdout, gettext("master boot sector "
440 "not updated\n"));
441 }
442 }
443 if (write_mbr)
444 (void) printf("%s is newer than one in %s\n",
445 plist->pl_src_name, plist->pl_devname);
446 return (write_mbr);
447 }
448
449 /*
450 * VBR setup is done in pair with stage2.
451 */
452 static bool
compare_stage1_cb(struct partlist * plist)453 compare_stage1_cb(struct partlist *plist)
454 {
455 if (write_vbr) {
456 (void) printf("%s is newer than one in %s\n",
457 plist->pl_src_name, plist->pl_devname);
458 }
459 return (write_vbr);
460 }
461
462 /*
463 * Return true if we can update, false if not.
464 */
465 static bool
compare_einfo_cb(struct partlist * plist)466 compare_einfo_cb(struct partlist *plist)
467 {
468 ib_bootblock_t *bblock, *bblock_file;
469 bblk_einfo_t *einfo, *einfo_file;
470 bblk_hs_t bblock_hs;
471 bool rv;
472
473 bblock_file = plist->pl_src_data;
474 if (bblock_file == NULL)
475 return (false); /* source is missing, cannot update */
476
477 bblock = plist->pl_stage;
478 if (bblock == NULL ||
479 bblock->extra == NULL ||
480 bblock->extra_size == 0) {
481 if (plist->pl_type == IB_BBLK_STAGE2)
482 write_vbr = true;
483 return (true);
484 }
485
486 einfo = find_einfo(bblock->extra, bblock->extra_size);
487 if (einfo == NULL) {
488 BOOT_DEBUG("No extended information available on disk\n");
489 if (plist->pl_type == IB_BBLK_STAGE2)
490 write_vbr = true;
491 return (true);
492 }
493
494 einfo_file = find_einfo(bblock_file->extra, bblock_file->extra_size);
495 if (einfo_file == NULL) {
496 /*
497 * loader bootblock is versioned. missing version means
498 * probably incompatible block. installboot can not install
499 * grub, for example.
500 */
501 (void) fprintf(stderr,
502 gettext("ERROR: non versioned bootblock in file\n"));
503 return (false);
504 } else {
505 if (update_str == NULL) {
506 update_str = einfo_get_string(einfo_file);
507 do_version = true;
508 }
509 }
510
511 if (!do_version || update_str == NULL) {
512 (void) fprintf(stderr,
513 gettext("WARNING: target device %s has a "
514 "versioned bootblock that is going to be overwritten by a "
515 "non versioned one\n"), plist->pl_devname);
516 if (plist->pl_type == IB_BBLK_STAGE2)
517 write_vbr = true;
518 return (true);
519 }
520
521 if (force_update) {
522 BOOT_DEBUG("Forcing update of %s bootblock\n",
523 plist->pl_devname);
524 if (plist->pl_type == IB_BBLK_STAGE2)
525 write_vbr = true;
526 return (true);
527 }
528
529 BOOT_DEBUG("Ready to check installed version vs %s\n", update_str);
530
531 bblock_hs.src_buf = (unsigned char *)bblock_file->file;
532 bblock_hs.src_size = bblock_file->file_size;
533
534 rv = einfo_should_update(einfo, &bblock_hs, update_str);
535 if (rv == false) {
536 (void) fprintf(stderr, gettext("Bootblock version installed "
537 "on %s is more recent or identical to\n%s\n"
538 "Use -F to override or install without the -u option.\n\n"),
539 plist->pl_devname, plist->pl_src_name);
540 } else {
541 (void) printf("%s is newer than one in %s\n",
542 plist->pl_src_name, plist->pl_devname);
543 if (plist->pl_type == IB_BBLK_STAGE2)
544 write_vbr = true;
545 }
546 return (rv);
547 }
548
549 static bool
read_stage1_cb(struct partlist * plist)550 read_stage1_cb(struct partlist *plist)
551 {
552 int fd;
553 bool rv = false;
554
555 if ((fd = open_device(plist->pl_devname)) == -1)
556 return (rv);
557
558 if (plist->pl_stage == NULL)
559 plist->pl_stage = calloc(1, sector_size);
560
561 if (plist->pl_stage == NULL) {
562 perror("calloc");
563 goto done;
564 }
565
566 if (pread(fd, plist->pl_stage, sector_size, 0) == -1) {
567 perror("pread");
568 goto done;
569 }
570 rv = true;
571 done:
572 (void) close(fd);
573 return (rv);
574 }
575
576 static bool
read_stage1_bbl_cb(struct partlist * plist)577 read_stage1_bbl_cb(struct partlist *plist)
578 {
579 int fd;
580 void *data;
581 bool rv = false;
582
583 /* Allocate actual sector size. */
584 data = calloc(1, sector_size);
585 if (data == NULL)
586 return (rv);
587
588 /* read the stage1 file from filesystem */
589 fd = open(plist->pl_src_name, O_RDONLY);
590 if (fd == -1 ||
591 read(fd, data, SECTOR_SIZE) != SECTOR_SIZE) {
592 (void) fprintf(stderr, gettext("cannot read stage1 file %s\n"),
593 plist->pl_src_name);
594 free(data);
595 if (fd != -1)
596 (void) close(fd);
597 return (rv);
598 }
599
600 plist->pl_src_data = data;
601 (void) close(fd);
602 return (true);
603 }
604
605 static bool
read_stage2_cb(struct partlist * plist)606 read_stage2_cb(struct partlist *plist)
607 {
608 ib_device_t *device;
609 ib_bootblock_t *bblock;
610 int fd;
611 uint32_t size, offset;
612 uint32_t buf_size;
613 uint32_t mboot_off;
614 multiboot_header_t *mboot;
615 size_t scan_size;
616
617 bblock = calloc(1, sizeof (ib_bootblock_t));
618 if (bblock == NULL)
619 return (false);
620
621 if ((fd = open_device(plist->pl_devname)) == -1) {
622 free(bblock);
623 return (false);
624 }
625
626 device = plist->pl_device;
627 plist->pl_stage = bblock;
628 offset = device->stage.offset * sector_size;
629 scan_size = MIN(sizeof (mboot_scan),
630 (device->stage.size - device->stage.offset) * sector_size);
631
632 if (read_in(fd, mboot_scan, scan_size, offset)
633 != BC_SUCCESS) {
634 BOOT_DEBUG("Error reading bootblock area\n");
635 perror("read");
636 (void) close(fd);
637 return (false);
638 }
639
640 /* No multiboot means no chance of knowing bootblock size */
641 if (find_multiboot(mboot_scan, scan_size, &mboot_off)
642 != BC_SUCCESS) {
643 BOOT_DEBUG("Unable to find multiboot header\n");
644 (void) close(fd);
645 return (false);
646 }
647 mboot = (multiboot_header_t *)(mboot_scan + mboot_off);
648
649 /*
650 * make sure mboot has sane values
651 */
652 if (mboot->load_end_addr == 0 ||
653 mboot->load_end_addr < mboot->load_addr) {
654 (void) close(fd);
655 return (false);
656 }
657
658 /*
659 * Currently, the amount of space reserved for extra information
660 * is "fixed". We may have to scan for the terminating extra payload
661 * in the future.
662 */
663 size = mboot->load_end_addr - mboot->load_addr;
664 buf_size = P2ROUNDUP(size + sector_size, sector_size);
665 bblock->file_size = size;
666
667 bblock->buf = malloc(buf_size);
668 if (bblock->buf == NULL) {
669 BOOT_DEBUG("Unable to allocate enough memory to read"
670 " the extra bootblock from the disk\n");
671 perror(gettext("Memory allocation failure"));
672 (void) close(fd);
673 return (false);
674 }
675 bblock->buf_size = buf_size;
676
677 if (read_in(fd, bblock->buf, buf_size, offset) != BC_SUCCESS) {
678 BOOT_DEBUG("Error reading the bootblock\n");
679 (void) free(bblock->buf);
680 bblock->buf = NULL;
681 (void) close(fd);
682 return (false);
683 }
684
685 /* Update pointers. */
686 bblock->file = bblock->buf;
687 bblock->mboot_off = mboot_off;
688 bblock->mboot = (multiboot_header_t *)(bblock->buf + bblock->mboot_off);
689 bblock->extra = bblock->buf + P2ROUNDUP(bblock->file_size, 8);
690 bblock->extra_size = bblock->buf_size - P2ROUNDUP(bblock->file_size, 8);
691
692 BOOT_DEBUG("mboot at %p offset %d, extra at %p size %d, buf=%p "
693 "(size=%d)\n", bblock->mboot, bblock->mboot_off, bblock->extra,
694 bblock->extra_size, bblock->buf, bblock->buf_size);
695
696 return (true);
697 }
698
699 static bool
read_einfo_file_cb(struct partlist * plist)700 read_einfo_file_cb(struct partlist *plist)
701 {
702 int rc;
703 void *stage;
704
705 stage = calloc(1, sizeof (ib_bootblock_t));
706 if (stage == NULL)
707 return (false);
708
709 rc = read_bootblock_from_file(plist->pl_devname, stage);
710 if (rc != BC_SUCCESS) {
711 free(stage);
712 stage = NULL;
713 }
714 plist->pl_stage = stage;
715 return (rc == BC_SUCCESS);
716 }
717
718 static bool
read_stage2_file_cb(struct partlist * plist)719 read_stage2_file_cb(struct partlist *plist)
720 {
721 int rc;
722 void *data;
723
724 data = calloc(1, sizeof (ib_bootblock_t));
725 if (data == NULL)
726 return (false);
727
728 rc = read_bootblock_from_file(plist->pl_src_name, data);
729 if (rc != BC_SUCCESS) {
730 free(data);
731 data = NULL;
732 }
733 plist->pl_src_data = data;
734 return (rc == BC_SUCCESS);
735 }
736
737 /*
738 * convert /dev/rdsk/... to /dev/dsk/...
739 */
740 static char *
make_blkdev(const char * path)741 make_blkdev(const char *path)
742 {
743 char *tmp;
744 char *ptr = strdup(path);
745
746 if (ptr == NULL)
747 return (ptr);
748
749 tmp = strstr(ptr, "rdsk");
750 if (tmp == NULL) {
751 free(ptr);
752 return (NULL); /* Something is very wrong */
753 }
754 /* This is safe because we do shorten the string */
755 (void) memmove(tmp, tmp + 1, strlen(tmp));
756 return (ptr);
757 }
758
759 /*
760 * Try to mount ESP and read boot program.
761 */
762 static bool
read_einfo_esp_cb(struct partlist * plist)763 read_einfo_esp_cb(struct partlist *plist)
764 {
765 fstyp_handle_t fhdl;
766 const char *fident;
767 char *blkdev, *path, *file;
768 bool rv = false;
769 FILE *fp;
770 struct mnttab mp, mpref = { 0 };
771 int fd, ret;
772
773 if ((fd = open_device(plist->pl_devname)) == -1)
774 return (rv);
775
776 if (fstyp_init(fd, 0, NULL, &fhdl) != 0) {
777 (void) close(fd);
778 return (rv);
779 }
780
781 if (fstyp_ident(fhdl, NULL, &fident) != 0) {
782 fstyp_fini(fhdl);
783 (void) close(fd);
784 (void) fprintf(stderr, gettext("Failed to detect file "
785 "system type\n"));
786 return (rv);
787 }
788
789 /* We only do expect pcfs. */
790 if (strcmp(fident, MNTTYPE_PCFS) != 0) {
791 (void) fprintf(stderr,
792 gettext("File system %s is not supported.\n"), fident);
793 fstyp_fini(fhdl);
794 (void) close(fd);
795 return (rv);
796 }
797 fstyp_fini(fhdl);
798 (void) close(fd);
799
800 blkdev = make_blkdev(plist->pl_devname);
801 if (blkdev == NULL)
802 return (rv);
803
804 /* mount ESP if needed, read boot program(s) and unmount. */
805 fp = fopen(MNTTAB, "r");
806 if (fp == NULL) {
807 perror("fopen");
808 free(blkdev);
809 return (rv);
810 }
811
812 mpref.mnt_special = blkdev;
813 ret = getmntany(fp, &mp, &mpref);
814 (void) fclose(fp);
815 if (ret == 0)
816 path = mp.mnt_mountp;
817 else
818 path = stagefs_mount(blkdev, plist);
819
820 free(blkdev);
821 if (path == NULL)
822 return (rv);
823
824 if (asprintf(&file, "%s%s", path, plist->pl_device->stage.path) < 0) {
825 return (rv);
826 }
827
828 plist->pl_stage = calloc(1, sizeof (ib_bootblock_t));
829 if (plist->pl_stage == NULL) {
830 free(file);
831 return (rv);
832 }
833 if (read_bootblock_from_file(file, plist->pl_stage) != BC_SUCCESS) {
834 free(plist->pl_stage);
835 plist->pl_stage = NULL;
836 } else {
837 rv = true;
838 }
839
840 free(file);
841 return (rv);
842 }
843
844 static void
print_stage1_cb(struct partlist * plist)845 print_stage1_cb(struct partlist *plist)
846 {
847 struct mboot *mbr;
848 struct ipart *part;
849 mbr_type_t type = MBR_TYPE_UNKNOWN;
850 bool pmbr = false;
851 char *label;
852
853 mbr = plist->pl_stage;
854
855 if (*((uint16_t *)&mbr->bootinst[GRUB_VERSION_OFF]) == GRUB_VERSION) {
856 type = MBR_TYPE_GRUB1;
857 } else if (mbr->bootinst[STAGE1_MBR_VERSION] == LOADER_VERSION) {
858 type = MBR_TYPE_LOADER;
859 } else if (mbr->bootinst[STAGE1_MBR_VERSION] == LOADER_JOYENT_VERSION) {
860 type = MBR_TYPE_LOADER_JOYENT;
861 }
862
863 part = (struct ipart *)mbr->parts;
864 for (int i = 0; i < FD_NUMPART; i++) {
865 if (part[i].systid == EFI_PMBR)
866 pmbr = true;
867 }
868
869 if (plist->pl_type == IB_BBLK_MBR)
870 label = pmbr ? "PMBR" : "MBR";
871 else
872 label = "VBR";
873
874 printf("%s block from %s:\n", label, plist->pl_devname);
875
876 switch (type) {
877 case MBR_TYPE_UNKNOWN:
878 printf("Format: unknown\n");
879 break;
880 case MBR_TYPE_GRUB1:
881 printf("Format: grub1\n");
882 break;
883 case MBR_TYPE_LOADER:
884 printf("Format: loader (illumos)\n");
885 break;
886 case MBR_TYPE_LOADER_JOYENT:
887 printf("Format: loader (joyent)\n");
888 break;
889 }
890
891 printf("Signature: 0x%hx (%s)\n", mbr->signature,
892 mbr->signature == MBB_MAGIC ? "valid" : "invalid");
893
894 printf("UniqueMBRDiskSignature: %#lx\n",
895 *(uint32_t *)&mbr->bootinst[STAGE1_SIG]);
896
897 if (type == MBR_TYPE_LOADER || type == MBR_TYPE_LOADER_JOYENT) {
898 char uuid[UUID_PRINTABLE_STRING_LENGTH];
899
900 printf("Loader STAGE1_STAGE2_LBA: %llu\n",
901 *(uint64_t *)&mbr->bootinst[STAGE1_STAGE2_LBA]);
902
903 printf("Loader STAGE1_STAGE2_SIZE: %hu\n",
904 *(uint16_t *)&mbr->bootinst[STAGE1_STAGE2_SIZE]);
905
906 uuid_unparse((uchar_t *)&mbr->bootinst[STAGE1_STAGE2_UUID],
907 uuid);
908
909 printf("Loader STAGE1_STAGE2_UUID: %s\n", uuid);
910 }
911 printf("\n");
912 }
913
914 static void
print_einfo_cb(struct partlist * plist)915 print_einfo_cb(struct partlist *plist)
916 {
917 uint8_t flags = 0;
918 ib_bootblock_t *bblock;
919 bblk_einfo_t *einfo = NULL;
920 const char *filepath;
921
922 /* No stage, get out. */
923 bblock = plist->pl_stage;
924 if (bblock == NULL)
925 return;
926
927 if (plist->pl_device->stage.path == NULL)
928 filepath = "";
929 else
930 filepath = plist->pl_device->stage.path;
931
932 printf("Boot block from %s:%s\n", plist->pl_devname, filepath);
933
934 if (bblock->extra != NULL)
935 einfo = find_einfo(bblock->extra, bblock->extra_size);
936
937 if (einfo == NULL) {
938 (void) fprintf(stderr,
939 gettext("No extended information found.\n\n"));
940 return;
941 }
942
943 /* Print the extended information. */
944 if (strip)
945 flags |= EINFO_EASY_PARSE;
946 if (verbose_dump)
947 flags |= EINFO_PRINT_HEADER;
948
949 print_einfo(flags, einfo, bblock->extra_size);
950 printf("\n");
951 }
952
953 static size_t
get_media_info(int fd)954 get_media_info(int fd)
955 {
956 struct dk_minfo disk_info;
957
958 if ((ioctl(fd, DKIOCGMEDIAINFO, (caddr_t)&disk_info)) == -1)
959 return (SECTOR_SIZE);
960
961 return (disk_info.dki_lbsize);
962 }
963
964 static struct partlist *
partlist_alloc(void)965 partlist_alloc(void)
966 {
967 struct partlist *pl;
968
969 if ((pl = calloc(1, sizeof (*pl))) == NULL) {
970 perror("calloc");
971 return (NULL);
972 }
973
974 pl->pl_device = calloc(1, sizeof (*pl->pl_device));
975 if (pl->pl_device == NULL) {
976 perror("calloc");
977 free(pl);
978 return (NULL);
979 }
980
981 return (pl);
982 }
983
984 static void
partlist_free(struct partlist * pl)985 partlist_free(struct partlist *pl)
986 {
987 ib_bootblock_t *bblock;
988 ib_device_t *device;
989
990 switch (pl->pl_type) {
991 case IB_BBLK_MBR:
992 case IB_BBLK_STAGE1:
993 free(pl->pl_stage);
994 break;
995 default:
996 if (pl->pl_stage != NULL) {
997 bblock = pl->pl_stage;
998 free(bblock->buf);
999 free(bblock);
1000 }
1001 }
1002
1003 /* umount the stage fs. */
1004 if (pl->pl_device->stage.mntpnt != NULL) {
1005 if (umount(pl->pl_device->stage.mntpnt) == 0)
1006 (void) rmdir(pl->pl_device->stage.mntpnt);
1007 free(pl->pl_device->stage.mntpnt);
1008 }
1009 device = pl->pl_device;
1010 free(device->target.path);
1011 free(pl->pl_device);
1012
1013 free(pl->pl_src_data);
1014 free(pl->pl_devname);
1015 free(pl);
1016 }
1017
1018 static bool
probe_fstyp(ib_data_t * data)1019 probe_fstyp(ib_data_t *data)
1020 {
1021 fstyp_handle_t fhdl;
1022 const char *fident;
1023 char *ptr;
1024 int fd;
1025 bool rv = false;
1026
1027 /* Record partition id */
1028 ptr = strrchr(data->target.path, 'p');
1029 if (ptr == NULL)
1030 ptr = strrchr(data->target.path, 's');
1031 data->target.id = atoi(++ptr);
1032 if ((fd = open_device(data->target.path)) == -1)
1033 return (rv);
1034
1035 if (fstyp_init(fd, 0, NULL, &fhdl) != 0) {
1036 (void) close(fd);
1037 return (rv);
1038 }
1039
1040 if (fstyp_ident(fhdl, NULL, &fident) != 0) {
1041 fstyp_fini(fhdl);
1042 (void) fprintf(stderr, gettext("Failed to detect file "
1043 "system type\n"));
1044 (void) close(fd);
1045 return (rv);
1046 }
1047
1048 rv = true;
1049 if (strcmp(fident, MNTTYPE_ZFS) == 0)
1050 data->target.fstype = IB_FS_ZFS;
1051 else if (strcmp(fident, MNTTYPE_UFS) == 0) {
1052 data->target.fstype = IB_FS_UFS;
1053 } else if (strcmp(fident, MNTTYPE_PCFS) == 0) {
1054 data->target.fstype = IB_FS_PCFS;
1055 /* with pcfs we always write MBR */
1056 force_mbr = true;
1057 write_mbr = true;
1058 } else {
1059 (void) fprintf(stderr, gettext("File system %s is not "
1060 "supported by loader\n"), fident);
1061 rv = false;
1062 }
1063 fstyp_fini(fhdl);
1064 (void) close(fd);
1065 return (rv);
1066 }
1067
1068 static bool
get_slice(ib_data_t * data,struct partlist * pl,struct dk_gpt * vtoc,uint16_t tag)1069 get_slice(ib_data_t *data, struct partlist *pl, struct dk_gpt *vtoc,
1070 uint16_t tag)
1071 {
1072 uint_t i;
1073 ib_device_t *device = pl->pl_device;
1074 char *path, *ptr;
1075
1076 if (tag != V_BOOT && tag != V_SYSTEM)
1077 return (false);
1078
1079 for (i = 0; i < vtoc->efi_nparts; i++) {
1080 if (vtoc->efi_parts[i].p_tag == tag) {
1081 if ((path = strdup(data->target.path)) == NULL) {
1082 perror(gettext("Memory allocation failure"));
1083 return (false);
1084 }
1085 ptr = strrchr(path, 's');
1086 ptr++;
1087 *ptr = '\0';
1088 (void) asprintf(&ptr, "%s%d", path, i);
1089 free(path);
1090 if (ptr == NULL) {
1091 perror(gettext("Memory allocation failure"));
1092 return (false);
1093 }
1094 pl->pl_devname = ptr;
1095 device->stage.id = i;
1096 device->stage.devtype = IB_DEV_EFI;
1097 switch (vtoc->efi_parts[i].p_tag) {
1098 case V_BOOT:
1099 device->stage.fstype = IB_FS_NONE;
1100 /* leave sector 0 for VBR */
1101 device->stage.offset = 1;
1102 break;
1103 case V_SYSTEM:
1104 device->stage.fstype = IB_FS_PCFS;
1105 break;
1106 }
1107 device->stage.tag = vtoc->efi_parts[i].p_tag;
1108 device->stage.start = vtoc->efi_parts[i].p_start;
1109 device->stage.size = vtoc->efi_parts[i].p_size;
1110 break;
1111 }
1112 }
1113 return (true);
1114 }
1115
1116 static bool
allocate_slice(ib_data_t * data,struct dk_gpt * vtoc,uint16_t tag,struct partlist ** plp)1117 allocate_slice(ib_data_t *data, struct dk_gpt *vtoc, uint16_t tag,
1118 struct partlist **plp)
1119 {
1120 struct partlist *pl;
1121
1122 *plp = NULL;
1123 if ((pl = partlist_alloc()) == NULL)
1124 return (false);
1125
1126 pl->pl_device = calloc(1, sizeof (*pl->pl_device));
1127 if (pl->pl_device == NULL) {
1128 perror("calloc");
1129 partlist_free(pl);
1130 return (false);
1131 }
1132 if (!get_slice(data, pl, vtoc, tag)) {
1133 partlist_free(pl);
1134 return (false);
1135 }
1136
1137 /* tag was not found */
1138 if (pl->pl_devname == NULL)
1139 partlist_free(pl);
1140 else
1141 *plp = pl;
1142
1143 return (true);
1144 }
1145
1146 static bool
probe_gpt(ib_data_t * data)1147 probe_gpt(ib_data_t *data)
1148 {
1149 struct partlist *pl;
1150 struct dk_gpt *vtoc;
1151 ib_device_t *device;
1152 int slice, fd;
1153 bool rv = false;
1154
1155 if ((fd = open_device(data->target.path)) < 0)
1156 return (rv);
1157
1158 slice = efi_alloc_and_read(fd, &vtoc);
1159 (void) close(fd);
1160 if (slice < 0)
1161 return (rv);
1162
1163 data->device.devtype = IB_DEV_EFI;
1164 data->target.start = vtoc->efi_parts[slice].p_start;
1165 data->target.size = vtoc->efi_parts[slice].p_size;
1166
1167 /* Always update PMBR. */
1168 force_mbr = true;
1169 write_mbr = true;
1170
1171 /*
1172 * With GPT we can have boot partition and ESP.
1173 * Boot partition can have both stage 1 and stage 2.
1174 */
1175 if (!allocate_slice(data, vtoc, V_BOOT, &pl))
1176 goto done;
1177 if (pl != NULL) {
1178 pl->pl_src_name = stage1;
1179 pl->pl_type = IB_BBLK_STAGE1;
1180 pl->pl_cb.compare = compare_stage1_cb;
1181 pl->pl_cb.install = install_stage1_cb;
1182 pl->pl_cb.read = read_stage1_cb;
1183 pl->pl_cb.read_bbl = read_stage1_bbl_cb;
1184 pl->pl_cb.print = print_stage1_cb;
1185 STAILQ_INSERT_TAIL(data->plist, pl, pl_next);
1186 } else if (data->target.fstype != IB_FS_ZFS) {
1187 (void) fprintf(stderr, gettext("Booting %s from EFI "
1188 "labeled disks requires the boot partition.\n"),
1189 data->target.fstype == IB_FS_UFS?
1190 MNTTYPE_UFS : MNTTYPE_PCFS);
1191 goto done;
1192 }
1193 /* Add stage 2 */
1194 if (!allocate_slice(data, vtoc, V_BOOT, &pl))
1195 goto done;
1196 if (pl != NULL) {
1197 pl->pl_src_name = stage2;
1198 pl->pl_type = IB_BBLK_STAGE2;
1199 pl->pl_cb.compare = compare_einfo_cb;
1200 pl->pl_cb.install = install_stage2_cb;
1201 pl->pl_cb.read = read_stage2_cb;
1202 pl->pl_cb.read_bbl = read_stage2_file_cb;
1203 pl->pl_cb.print = print_einfo_cb;
1204 STAILQ_INSERT_TAIL(data->plist, pl, pl_next);
1205 }
1206
1207 /* ESP can have 32- and 64-bit boot code. */
1208 if (!allocate_slice(data, vtoc, V_SYSTEM, &pl))
1209 goto done;
1210 if (pl != NULL) {
1211 pl->pl_device->stage.path = "/EFI/Boot/" BOOTIA32;
1212 pl->pl_src_name = efi32;
1213 pl->pl_type = IB_BBLK_EFI;
1214 pl->pl_cb.compare = compare_einfo_cb;
1215 pl->pl_cb.install = install_esp_cb;
1216 pl->pl_cb.read = read_einfo_esp_cb;
1217 pl->pl_cb.read_bbl = read_stage2_file_cb;
1218 pl->pl_cb.print = print_einfo_cb;
1219 STAILQ_INSERT_TAIL(data->plist, pl, pl_next);
1220 }
1221 if (!allocate_slice(data, vtoc, V_SYSTEM, &pl))
1222 goto done;
1223 if (pl != NULL) {
1224 pl->pl_device->stage.path = "/EFI/Boot/" BOOTX64;
1225 pl->pl_src_name = efi64;
1226 pl->pl_type = IB_BBLK_EFI;
1227 pl->pl_cb.compare = compare_einfo_cb;
1228 pl->pl_cb.install = install_esp_cb;
1229 pl->pl_cb.read = read_einfo_esp_cb;
1230 pl->pl_cb.read_bbl = read_stage2_file_cb;
1231 pl->pl_cb.print = print_einfo_cb;
1232 STAILQ_INSERT_TAIL(data->plist, pl, pl_next);
1233 }
1234
1235 /* add stage for our target file system slice */
1236 pl = partlist_alloc();
1237 if (pl == NULL)
1238 goto done;
1239
1240 device = pl->pl_device;
1241 device->stage.devtype = data->device.devtype;
1242 if ((pl->pl_devname = strdup(data->target.path)) == NULL) {
1243 perror(gettext("Memory allocation failure"));
1244 partlist_free(pl);
1245 goto done;
1246 }
1247
1248 device->stage.id = slice;
1249 device->stage.start = vtoc->efi_parts[slice].p_start;
1250 device->stage.size = vtoc->efi_parts[slice].p_size;
1251
1252 /* ZFS and UFS can have stage1 in boot area. */
1253 if (data->target.fstype == IB_FS_ZFS ||
1254 data->target.fstype == IB_FS_UFS) {
1255 pl->pl_src_name = stage1;
1256 pl->pl_type = IB_BBLK_STAGE1;
1257 pl->pl_cb.compare = compare_stage1_cb;
1258 pl->pl_cb.install = install_stage1_cb;
1259 pl->pl_cb.read = read_stage1_cb;
1260 pl->pl_cb.read_bbl = read_stage1_bbl_cb;
1261 pl->pl_cb.print = print_stage1_cb;
1262 STAILQ_INSERT_TAIL(data->plist, pl, pl_next);
1263 }
1264
1265 if (data->target.fstype == IB_FS_ZFS) {
1266 pl = partlist_alloc();
1267 if (pl == NULL)
1268 goto done;
1269
1270 device = pl->pl_device;
1271 device->stage.devtype = data->device.devtype;
1272
1273 if ((pl->pl_devname = strdup(data->target.path)) == NULL) {
1274 perror(gettext("Memory allocation failure"));
1275 goto done;
1276 }
1277
1278 device->stage.id = slice;
1279 device->stage.start = vtoc->efi_parts[slice].p_start;
1280 device->stage.size = vtoc->efi_parts[slice].p_size;
1281
1282 device->stage.offset = BBLK_ZFS_BLK_OFF / sector_size;
1283 pl->pl_src_name = stage2;
1284 pl->pl_type = IB_BBLK_STAGE2;
1285 pl->pl_cb.compare = compare_einfo_cb;
1286 pl->pl_cb.install = install_stage2_cb;
1287 pl->pl_cb.read = read_stage2_cb;
1288 pl->pl_cb.read_bbl = read_stage2_file_cb;
1289 pl->pl_cb.print = print_einfo_cb;
1290 STAILQ_INSERT_TAIL(data->plist, pl, pl_next);
1291 }
1292 rv = true;
1293 done:
1294 efi_free(vtoc);
1295 return (rv);
1296 }
1297
1298 static bool
get_start_sector(ib_data_t * data,struct extpartition * v_part,diskaddr_t * start)1299 get_start_sector(ib_data_t *data, struct extpartition *v_part,
1300 diskaddr_t *start)
1301 {
1302 struct partlist *pl;
1303 struct mboot *mbr;
1304 struct ipart *part;
1305 struct part_info dkpi;
1306 struct extpart_info edkpi;
1307 uint32_t secnum, numsec;
1308 ext_part_t *epp;
1309 ushort_t i;
1310 int fd, rval, pno;
1311
1312 if ((fd = open_device(data->target.path)) < 0)
1313 return (false);
1314
1315 if (ioctl(fd, DKIOCEXTPARTINFO, &edkpi) < 0) {
1316 if (ioctl(fd, DKIOCPARTINFO, &dkpi) < 0) {
1317 (void) fprintf(stderr, gettext("cannot get the "
1318 "slice information of the disk\n"));
1319 (void) close(fd);
1320 return (false);
1321 } else {
1322 edkpi.p_start = dkpi.p_start;
1323 edkpi.p_length = dkpi.p_length;
1324 }
1325 }
1326 (void) close(fd);
1327
1328 /* Set target file system start and size */
1329 data->target.start = edkpi.p_start;
1330 data->target.size = edkpi.p_length;
1331
1332 /* This is our MBR partition start. */
1333 edkpi.p_start -= v_part->p_start;
1334
1335 /* Head is always MBR */
1336 pl = STAILQ_FIRST(data->plist);
1337 if (!read_stage1_cb(pl))
1338 return (false);
1339
1340 mbr = (struct mboot *)pl->pl_stage;
1341 part = (struct ipart *)mbr->parts;
1342
1343 for (i = 0; i < FD_NUMPART; i++) {
1344 if (part[i].relsect == edkpi.p_start) {
1345 *start = part[i].relsect;
1346 return (true);
1347 }
1348 }
1349
1350 rval = libfdisk_init(&epp, pl->pl_devname, part, FDISK_READ_DISK);
1351 if (rval != FDISK_SUCCESS) {
1352 switch (rval) {
1353 /*
1354 * The first 3 cases are not an error per-se, just that
1355 * there is no Solaris logical partition
1356 */
1357 case FDISK_EBADLOGDRIVE:
1358 case FDISK_ENOLOGDRIVE:
1359 case FDISK_EBADMAGIC:
1360 (void) fprintf(stderr, gettext("Solaris "
1361 "partition not found. "
1362 "Aborting operation. %d\n"), rval);
1363 return (false);
1364 case FDISK_ENOVGEOM:
1365 (void) fprintf(stderr, gettext("Could not get "
1366 "virtual geometry\n"));
1367 return (false);
1368 case FDISK_ENOPGEOM:
1369 (void) fprintf(stderr, gettext("Could not get "
1370 "physical geometry\n"));
1371 return (false);
1372 case FDISK_ENOLGEOM:
1373 (void) fprintf(stderr, gettext("Could not get "
1374 "label geometry\n"));
1375 return (false);
1376 default:
1377 (void) fprintf(stderr, gettext("Failed to "
1378 "initialize libfdisk.\n"));
1379 return (false);
1380 }
1381 }
1382 rval = fdisk_get_solaris_part(epp, &pno, &secnum, &numsec);
1383 libfdisk_fini(&epp);
1384 if (rval != FDISK_SUCCESS) {
1385 /* No solaris logical partition */
1386 (void) fprintf(stderr, gettext("Solaris partition not found. "
1387 "Aborting operation.\n"));
1388 return (false);
1389 }
1390 *start = secnum;
1391 return (true);
1392 }
1393
1394 /*
1395 * On x86 the VTOC table is inside MBR partition and to get
1396 * absolute sectors, we need to add MBR partition start to VTOC slice start.
1397 */
1398 static bool
probe_vtoc(ib_data_t * data)1399 probe_vtoc(ib_data_t *data)
1400 {
1401 struct partlist *pl;
1402 struct extvtoc exvtoc;
1403 ib_device_t *device;
1404 char *path, *ptr;
1405 ushort_t i;
1406 int slice, fd;
1407 diskaddr_t start;
1408 bool rv;
1409
1410 rv = false;
1411
1412 if ((fd = open_device(data->target.path)) < 0)
1413 return (rv);
1414
1415 slice = read_extvtoc(fd, &exvtoc);
1416 (void) close(fd);
1417 if (slice < 0)
1418 return (rv);
1419 data->device.devtype = IB_DEV_VTOC;
1420
1421 if (!get_start_sector(data, exvtoc.v_part + slice, &start))
1422 return (rv);
1423
1424 if (exvtoc.v_part[slice].p_tag == V_BACKUP) {
1425 /*
1426 * NOTE: we could relax there and allow zfs boot on
1427 * slice 2, but lets keep traditional limits.
1428 */
1429 (void) fprintf(stderr, gettext(
1430 "raw device must be a root slice (not backup)\n"));
1431 return (rv);
1432 }
1433
1434 if ((path = strdup(data->target.path)) == NULL) {
1435 perror(gettext("Memory allocation failure"));
1436 return (false);
1437 }
1438
1439 data->target.start = start + exvtoc.v_part[slice].p_start;
1440 data->target.size = exvtoc.v_part[slice].p_size;
1441
1442 /* Search for boot slice. */
1443 for (i = 0; i < exvtoc.v_nparts; i++) {
1444 if (exvtoc.v_part[i].p_tag == V_BOOT)
1445 break;
1446 }
1447
1448 if (i == exvtoc.v_nparts ||
1449 exvtoc.v_part[i].p_size == 0) {
1450 /* fall back to slice V_BACKUP */
1451 for (i = 0; i < exvtoc.v_nparts; i++) {
1452 if (exvtoc.v_part[i].p_tag == V_BACKUP)
1453 break;
1454 }
1455 /* Still nothing? Error out. */
1456 if (i == exvtoc.v_nparts ||
1457 exvtoc.v_part[i].p_size == 0) {
1458 free(path);
1459 return (false);
1460 }
1461 }
1462
1463 /* Create path. */
1464 ptr = strrchr(path, 's');
1465 ptr++;
1466 *ptr = '\0';
1467 (void) asprintf(&ptr, "%s%d", path, i);
1468 free(path);
1469 if (ptr == NULL) {
1470 perror(gettext("Memory allocation failure"));
1471 return (false);
1472 }
1473
1474 pl = partlist_alloc();
1475 if (pl == NULL) {
1476 free(ptr);
1477 return (false);
1478 }
1479 pl->pl_devname = ptr;
1480 device = pl->pl_device;
1481 device->stage.devtype = data->device.devtype;
1482 device->stage.id = i;
1483 device->stage.tag = exvtoc.v_part[i].p_tag;
1484 device->stage.start = start + exvtoc.v_part[i].p_start;
1485 device->stage.size = exvtoc.v_part[i].p_size;
1486
1487 /* Fix size if this slice is in fact V_BACKUP */
1488 if (exvtoc.v_part[i].p_tag == V_BACKUP) {
1489 for (i = 0; i < exvtoc.v_nparts; i++) {
1490 if (exvtoc.v_part[i].p_start == 0)
1491 continue;
1492 if (exvtoc.v_part[i].p_size == 0)
1493 continue;
1494 if (exvtoc.v_part[i].p_start <
1495 device->stage.size)
1496 device->stage.size =
1497 exvtoc.v_part[i].p_start;
1498 }
1499 }
1500
1501 pl->pl_src_name = stage1;
1502 pl->pl_type = IB_BBLK_STAGE1;
1503 pl->pl_cb.compare = compare_stage1_cb;
1504 pl->pl_cb.install = install_stage1_cb;
1505 pl->pl_cb.read = read_stage1_cb;
1506 pl->pl_cb.read_bbl = read_stage1_bbl_cb;
1507 pl->pl_cb.print = print_stage1_cb;
1508 STAILQ_INSERT_TAIL(data->plist, pl, pl_next);
1509
1510 /* Create instance for stage 2 */
1511 pl = partlist_alloc();
1512 if (pl == NULL) {
1513 free(ptr);
1514 return (false);
1515 }
1516 pl->pl_devname = strdup(ptr);
1517 if (pl->pl_devname == NULL) {
1518 partlist_free(pl);
1519 return (false);
1520 }
1521 pl->pl_device->stage.devtype = data->device.devtype;
1522 pl->pl_device->stage.id = device->stage.id;
1523 pl->pl_device->stage.offset = BBLK_BLKLIST_OFF;
1524 pl->pl_device->stage.tag = device->stage.tag;
1525 pl->pl_device->stage.start = device->stage.start;
1526 pl->pl_device->stage.size = device->stage.size;
1527 pl->pl_src_name = stage2;
1528 pl->pl_type = IB_BBLK_STAGE2;
1529 pl->pl_cb.compare = compare_einfo_cb;
1530 pl->pl_cb.install = install_stage2_cb;
1531 pl->pl_cb.read = read_stage2_cb;
1532 pl->pl_cb.read_bbl = read_stage2_file_cb;
1533 pl->pl_cb.print = print_einfo_cb;
1534 STAILQ_INSERT_TAIL(data->plist, pl, pl_next);
1535
1536 /* And we are done. */
1537 rv = true;
1538 return (rv);
1539 }
1540
1541 static bool
probe_mbr(ib_data_t * data)1542 probe_mbr(ib_data_t *data)
1543 {
1544 struct partlist *pl;
1545 struct ipart *part;
1546 struct mboot *mbr;
1547 ib_device_t *device;
1548 char *path, *ptr;
1549 int i, rv;
1550
1551 data->device.devtype = IB_DEV_MBR;
1552
1553 /* Head is always MBR */
1554 pl = STAILQ_FIRST(data->plist);
1555 if (!read_stage1_cb(pl))
1556 return (false);
1557
1558 mbr = (struct mboot *)pl->pl_stage;
1559 part = (struct ipart *)mbr->parts;
1560
1561 /* Set target file system start and size */
1562 data->target.start = part[data->target.id - 1].relsect;
1563 data->target.size = part[data->target.id - 1].numsect;
1564
1565 /* Use X86BOOT partition if we have one. */
1566 for (i = 0; i < FD_NUMPART; i++) {
1567 if (part[i].systid == X86BOOT)
1568 break;
1569 }
1570
1571 /* Keep device name of whole disk device. */
1572 path = (char *)pl->pl_devname;
1573 if ((pl = partlist_alloc()) == NULL)
1574 return (false);
1575 device = pl->pl_device;
1576
1577 /*
1578 * No X86BOOT, try to use space between MBR and first
1579 * partition.
1580 */
1581 if (i == FD_NUMPART) {
1582 pl->pl_devname = strdup(path);
1583 if (pl->pl_devname == NULL) {
1584 perror(gettext("Memory allocation failure"));
1585 partlist_free(pl);
1586 return (false);
1587 }
1588 device->stage.id = 0;
1589 device->stage.devtype = IB_DEV_MBR;
1590 device->stage.fstype = IB_FS_NONE;
1591 device->stage.start = 0;
1592 device->stage.size = part[0].relsect;
1593 device->stage.offset = BBLK_BLKLIST_OFF;
1594 pl->pl_src_name = stage2;
1595 pl->pl_type = IB_BBLK_STAGE2;
1596 pl->pl_cb.compare = compare_einfo_cb;
1597 pl->pl_cb.install = install_stage2_cb;
1598 pl->pl_cb.read = read_stage2_cb;
1599 pl->pl_cb.read_bbl = read_stage2_file_cb;
1600 pl->pl_cb.print = print_einfo_cb;
1601 STAILQ_INSERT_TAIL(data->plist, pl, pl_next);
1602
1603 /* We have MBR for stage1 and gap for stage2, we are done. */
1604 return (true);
1605 }
1606
1607 if ((path = strdup(path)) == NULL) {
1608 perror(gettext("Memory allocation failure"));
1609 partlist_free(pl);
1610 return (false);
1611 }
1612 ptr = strrchr(path, 'p');
1613 ptr++;
1614 *ptr = '\0';
1615 /* partitions are p1..p4 */
1616 rv = asprintf(&ptr, "%s%d", path, i + 1);
1617 free(path);
1618 if (rv < 0) {
1619 perror(gettext("Memory allocation failure"));
1620 partlist_free(pl);
1621 return (false);
1622 }
1623 pl->pl_devname = ptr;
1624 device->stage.id = i + 1;
1625 device->stage.devtype = IB_DEV_MBR;
1626 device->stage.fstype = IB_FS_NONE;
1627 device->stage.start = part[i].relsect;
1628 device->stage.size = part[i].numsect;
1629 pl->pl_src_name = stage1;
1630 pl->pl_type = IB_BBLK_STAGE1;
1631 pl->pl_cb.compare = compare_stage1_cb;
1632 pl->pl_cb.install = install_stage1_cb;
1633 pl->pl_cb.read = read_stage1_cb;
1634 pl->pl_cb.read_bbl = read_stage1_bbl_cb;
1635 pl->pl_cb.print = print_stage1_cb;
1636 STAILQ_INSERT_TAIL(data->plist, pl, pl_next);
1637
1638 pl = partlist_alloc();
1639 if (pl == NULL)
1640 return (false);
1641 device = pl->pl_device;
1642 pl->pl_devname = strdup(ptr);
1643 if (pl->pl_devname == NULL) {
1644 perror(gettext("Memory allocation failure"));
1645 partlist_free(pl);
1646 return (false);
1647 }
1648 device->stage.id = i + 1;
1649 device->stage.devtype = IB_DEV_MBR;
1650 device->stage.fstype = IB_FS_NONE;
1651 device->stage.start = part[i].relsect;
1652 device->stage.size = part[i].numsect;
1653 device->stage.offset = 1;
1654 /* This is boot partition */
1655 device->stage.tag = V_BOOT;
1656 pl->pl_src_name = stage2;
1657 pl->pl_type = IB_BBLK_STAGE2;
1658 pl->pl_cb.compare = compare_einfo_cb;
1659 pl->pl_cb.install = install_stage2_cb;
1660 pl->pl_cb.read = read_stage2_cb;
1661 pl->pl_cb.read_bbl = read_stage2_file_cb;
1662 pl->pl_cb.print = print_einfo_cb;
1663 STAILQ_INSERT_TAIL(data->plist, pl, pl_next);
1664
1665 return (true);
1666 }
1667
1668 static bool
probe_device(ib_data_t * data,const char * dev)1669 probe_device(ib_data_t *data, const char *dev)
1670 {
1671 struct partlist *pl;
1672 struct stat sb;
1673 const char *ptr;
1674 char *p0;
1675 int fd, len;
1676
1677 if (dev == NULL)
1678 return (NULL);
1679
1680 len = strlen(dev);
1681
1682 if ((pl = partlist_alloc()) == NULL)
1683 return (false);
1684
1685 if (stat(dev, &sb) == -1) {
1686 perror("stat");
1687 partlist_free(pl);
1688 return (false);
1689 }
1690
1691 /* We have regular file, register it and we are done. */
1692 if (S_ISREG(sb.st_mode) != 0) {
1693 pl->pl_devname = (char *)dev;
1694
1695 pl->pl_type = IB_BBLK_FILE;
1696 pl->pl_cb.read = read_einfo_file_cb;
1697 pl->pl_cb.print = print_einfo_cb;
1698 STAILQ_INSERT_TAIL(data->plist, pl, pl_next);
1699 return (true);
1700 }
1701
1702 /*
1703 * This is block device.
1704 * We do not allow to specify whole disk device (cXtYdZp0 or cXtYdZ).
1705 */
1706 if ((ptr = strrchr(dev, '/')) == NULL)
1707 ptr = dev;
1708 if ((strrchr(ptr, 'p') == NULL && strrchr(ptr, 's') == NULL) ||
1709 (dev[len - 2] == 'p' && dev[len - 1] == '0')) {
1710 (void) fprintf(stderr,
1711 gettext("whole disk device is not supported\n"));
1712 partlist_free(pl);
1713 return (false);
1714 }
1715
1716 data->target.path = (char *)dev;
1717 if (!probe_fstyp(data)) {
1718 partlist_free(pl);
1719 return (false);
1720 }
1721
1722 /* We start from identifying the whole disk. */
1723 if ((p0 = strdup(dev)) == NULL) {
1724 perror("calloc");
1725 partlist_free(pl);
1726 return (false);
1727 }
1728
1729 pl->pl_devname = p0;
1730 /* Change device name to p0 */
1731 if ((ptr = strrchr(p0, 'p')) == NULL)
1732 ptr = strrchr(p0, 's');
1733 p0 = (char *)ptr;
1734 p0[0] = 'p';
1735 p0[1] = '0';
1736 p0[2] = '\0';
1737
1738 if ((fd = open_device(pl->pl_devname)) == -1) {
1739 partlist_free(pl);
1740 return (false);
1741 }
1742
1743 sector_size = get_media_info(fd);
1744 (void) close(fd);
1745
1746 pl->pl_src_name = stage1;
1747 pl->pl_type = IB_BBLK_MBR;
1748 pl->pl_cb.compare = compare_mbr_cb;
1749 pl->pl_cb.install = install_stage1_cb;
1750 pl->pl_cb.read = read_stage1_cb;
1751 pl->pl_cb.read_bbl = read_stage1_bbl_cb;
1752 pl->pl_cb.print = print_stage1_cb;
1753 STAILQ_INSERT_TAIL(data->plist, pl, pl_next);
1754
1755 if (probe_gpt(data))
1756 return (true);
1757
1758 /*
1759 * We only do support sector size 512 with MBR and VTOC.
1760 * The 4kn sector size with actual hardware is currently
1761 * available with large disks and MBR/VTOC are not usable
1762 * with such devices.
1763 */
1764 if (sector_size != SECTOR_SIZE)
1765 return (false);
1766
1767 if (data->device.devtype == IB_DEV_UNKNOWN)
1768 if (probe_vtoc(data))
1769 return (true);
1770
1771 if (data->device.devtype == IB_DEV_UNKNOWN)
1772 return (probe_mbr(data));
1773
1774 return (false);
1775 }
1776
1777 static int
read_bootblock_from_file(const char * file,ib_bootblock_t * bblock)1778 read_bootblock_from_file(const char *file, ib_bootblock_t *bblock)
1779 {
1780 struct stat sb;
1781 uint32_t buf_size;
1782 uint32_t mboot_off;
1783 int fd = -1;
1784 int retval = BC_ERROR;
1785
1786 assert(bblock != NULL);
1787 assert(file != NULL);
1788
1789 fd = open(file, O_RDONLY);
1790 if (fd == -1) {
1791 BOOT_DEBUG("Error opening %s\n", file);
1792 goto out;
1793 }
1794
1795 if (fstat(fd, &sb) == -1) {
1796 BOOT_DEBUG("Error getting information (stat) about %s", file);
1797 perror("stat");
1798 goto outfd;
1799 }
1800
1801 /* loader bootblock has version built in */
1802 buf_size = sb.st_size;
1803 if (buf_size == 0)
1804 goto outfd;
1805
1806 /* Round up to sector size for raw disk write */
1807 bblock->buf_size = P2ROUNDUP(buf_size, sector_size);
1808 BOOT_DEBUG("bootblock in-memory buffer size is %d\n",
1809 bblock->buf_size);
1810
1811 bblock->buf = malloc(bblock->buf_size);
1812 if (bblock->buf == NULL) {
1813 perror(gettext("Memory allocation failure"));
1814 goto outbuf;
1815 }
1816 bblock->file = bblock->buf;
1817
1818 if (read(fd, bblock->file, buf_size) != buf_size) {
1819 BOOT_DEBUG("Read from %s failed\n", file);
1820 perror("read");
1821 goto outfd;
1822 }
1823
1824 buf_size = MIN(buf_size, MBOOT_SCAN_SIZE);
1825 if (find_multiboot(bblock->file, buf_size, &mboot_off)
1826 != BC_SUCCESS) {
1827 (void) fprintf(stderr,
1828 gettext("Unable to find multiboot header\n"));
1829 goto outfd;
1830 }
1831
1832 bblock->mboot = (multiboot_header_t *)(bblock->file + mboot_off);
1833 bblock->mboot_off = mboot_off;
1834
1835 bblock->file_size =
1836 bblock->mboot->load_end_addr - bblock->mboot->load_addr;
1837 BOOT_DEBUG("bootblock file size is %d\n", bblock->file_size);
1838
1839 bblock->extra = bblock->buf + P2ROUNDUP(bblock->file_size, 8);
1840 bblock->extra_size = bblock->buf_size - P2ROUNDUP(bblock->file_size, 8);
1841
1842 BOOT_DEBUG("mboot at %p offset %d, extra at %p size %d, buf=%p "
1843 "(size=%d)\n", bblock->mboot, bblock->mboot_off, bblock->extra,
1844 bblock->extra_size, bblock->buf, bblock->buf_size);
1845
1846 (void) close(fd);
1847 return (BC_SUCCESS);
1848
1849 outbuf:
1850 (void) free(bblock->buf);
1851 bblock->buf = NULL;
1852 outfd:
1853 (void) close(fd);
1854 out:
1855 if (retval == BC_ERROR) {
1856 (void) fprintf(stderr,
1857 gettext("Error reading bootblock from %s\n"),
1858 file);
1859 }
1860
1861 if (retval == BC_NOEXTRA) {
1862 BOOT_DEBUG("No multiboot header found on %s, unable to "
1863 "locate extra information area (old/non versioned "
1864 "bootblock?) \n", file);
1865 (void) fprintf(stderr, gettext("No extended information"
1866 " found\n"));
1867 }
1868 return (retval);
1869 }
1870
1871 static void
add_bootblock_einfo(ib_bootblock_t * bblock,char * updt_str)1872 add_bootblock_einfo(ib_bootblock_t *bblock, char *updt_str)
1873 {
1874 bblk_hs_t hs;
1875 uint32_t avail_space;
1876
1877 assert(bblock != NULL);
1878
1879 if (updt_str == NULL) {
1880 BOOT_DEBUG("WARNING: no update string passed to "
1881 "add_bootblock_einfo()\n");
1882 return;
1883 }
1884
1885 /* Fill bootblock hashing source information. */
1886 hs.src_buf = (unsigned char *)bblock->file;
1887 hs.src_size = bblock->file_size;
1888 /* How much space for the extended information structure? */
1889 avail_space = bblock->buf_size - P2ROUNDUP(bblock->file_size, 8);
1890 /* Place the extended information structure. */
1891 add_einfo(bblock->extra, updt_str, &hs, avail_space);
1892 }
1893
1894 /*
1895 * set up data for case stage1 is installed as MBR
1896 * set up location and size of bootblock
1897 * set disk guid to provide unique information for biosdev command
1898 */
1899 static void
prepare_stage1(struct partlist * stage1,struct partlist * stage2,uuid_t uuid)1900 prepare_stage1(struct partlist *stage1, struct partlist *stage2, uuid_t uuid)
1901 {
1902 char *src, *dest;
1903 ib_bootblock_t *bblk;
1904 ib_device_t *device;
1905 uint16_t size;
1906 struct mboot *mbr;
1907
1908 src = stage1->pl_stage;
1909 dest = stage1->pl_src_data;
1910 device = stage2->pl_device;
1911
1912 /* Only copy from valid source. */
1913 mbr = stage1->pl_stage;
1914 if (mbr->signature == MBB_MAGIC) {
1915 /* copy BPB */
1916 bcopy(src + STAGE1_BPB_OFFSET, dest + STAGE1_BPB_OFFSET,
1917 STAGE1_BPB_SIZE);
1918
1919 /* copy MBR, note STAGE1_SIG == BOOTSZ */
1920 bcopy(src + STAGE1_SIG, dest + STAGE1_SIG,
1921 SECTOR_SIZE - STAGE1_SIG);
1922 }
1923
1924 bcopy(uuid, dest + STAGE1_STAGE2_UUID, UUID_LEN);
1925
1926 /* store bytes per sector */
1927 *((uint16_t *)(dest + STAGE1_BPB_BPS)) = sector_size;
1928 /* set stage2 size */
1929 bblk = stage2->pl_src_data;
1930 size = bblk->buf_size / sector_size;
1931 *((uint16_t *)(dest + STAGE1_STAGE2_SIZE)) = size;
1932
1933 /* set stage2 LBA */
1934 *((uint64_t *)(dest + STAGE1_STAGE2_LBA)) =
1935 device->stage.start + device->stage.offset;
1936
1937 /* Copy prepared data to stage1 block read from the disk. */
1938 bcopy(dest, src, SECTOR_SIZE);
1939 }
1940
1941 static void
prepare_bootblock(ib_data_t * data,struct partlist * pl,char * updt_str)1942 prepare_bootblock(ib_data_t *data, struct partlist *pl, char *updt_str)
1943 {
1944 ib_bootblock_t *bblock;
1945 uint64_t *ptr;
1946
1947 assert(pl != NULL);
1948
1949 bblock = pl->pl_src_data;
1950 if (bblock == NULL)
1951 return;
1952
1953 ptr = (uint64_t *)(&bblock->mboot->bss_end_addr);
1954 *ptr = data->target.start;
1955
1956 /*
1957 * the loader bootblock has built in version, if custom
1958 * version was provided, update it.
1959 */
1960 if (do_version)
1961 add_bootblock_einfo(bblock, updt_str);
1962 }
1963
1964 static int
open_device(const char * path)1965 open_device(const char *path)
1966 {
1967 struct stat statbuf = {0};
1968 int fd = -1;
1969
1970 if (nowrite)
1971 fd = open(path, O_RDONLY);
1972 else
1973 fd = open(path, O_RDWR);
1974
1975 if (fd == -1) {
1976 BOOT_DEBUG("Unable to open %s\n", path);
1977 perror("open");
1978 return (-1);
1979 }
1980
1981 if (fstat(fd, &statbuf) != 0) {
1982 BOOT_DEBUG("Unable to stat %s\n", path);
1983 perror("stat");
1984 (void) close(fd);
1985 return (-1);
1986 }
1987
1988 if (S_ISCHR(statbuf.st_mode) == 0) {
1989 (void) fprintf(stderr, gettext("%s: Not a character device\n"),
1990 path);
1991 (void) close(fd);
1992 return (-1);
1993 }
1994
1995 return (fd);
1996 }
1997
1998 /*
1999 * We need to record stage2 location and size into pmbr/vbr.
2000 * We need to record target partiton LBA to stage2.
2001 */
2002 static void
prepare_bblocks(ib_data_t * data)2003 prepare_bblocks(ib_data_t *data)
2004 {
2005 struct partlist *pl;
2006 struct partlist *mbr, *stage1, *stage2;
2007 uuid_t uuid;
2008
2009 /*
2010 * Create disk uuid. We only need reasonable amount of uniqueness
2011 * to allow biosdev to identify disk based on mbr differences.
2012 */
2013 uuid_generate(uuid);
2014
2015 mbr = stage1 = stage2 = NULL;
2016
2017 /* First find stage 2. */
2018 STAILQ_FOREACH(pl, data->plist, pl_next) {
2019 if (pl->pl_type == IB_BBLK_STAGE2) {
2020 stage2 = pl;
2021
2022 /*
2023 * When stage2 needs update, make sure we also
2024 * update stage1.
2025 */
2026 if (pl->pl_cb.compare != NULL &&
2027 pl->pl_cb.compare(pl))
2028 write_vbr = true;
2029 break;
2030 }
2031 }
2032 /*
2033 * Walk list and pick up BIOS boot blocks. EFI boot programs
2034 * can be set in place.
2035 */
2036 STAILQ_FOREACH(pl, data->plist, pl_next) {
2037 switch (pl->pl_type) {
2038 case IB_BBLK_MBR:
2039 mbr = pl;
2040 break;
2041 case IB_BBLK_STAGE1:
2042 stage1 = pl;
2043 if (stage2 != NULL)
2044 prepare_stage1(stage1, stage2, uuid);
2045 break;
2046 case IB_BBLK_STAGE2:
2047 case IB_BBLK_EFI:
2048 prepare_bootblock(data, pl, update_str);
2049 break;
2050 default:
2051 break;
2052 }
2053 }
2054
2055 /* If stage2 is missing, we are done. */
2056 if (stage2 == NULL)
2057 return;
2058
2059 if (mbr != NULL) {
2060 prepare_stage1(mbr, stage2, uuid);
2061
2062 /*
2063 * If we have stage1, we point MBR to read stage 1.
2064 */
2065 if (stage1 != NULL) {
2066 char *dest = mbr->pl_stage;
2067
2068 *((uint16_t *)(dest + STAGE1_STAGE2_SIZE)) = 1;
2069 *((uint64_t *)(dest + STAGE1_STAGE2_LBA)) =
2070 stage1->pl_device->stage.start;
2071 }
2072 }
2073 }
2074
2075 /*
2076 * Install a new bootblock on the given device. handle_install() expects argv
2077 * to contain 3 parameters (the target device path and the path to the
2078 * bootblock.
2079 *
2080 * Returns: BC_SUCCESS - if the installation is successful
2081 * BC_ERROR - if the installation failed
2082 * BC_NOUPDT - if no installation was performed because the
2083 * version currently installed is more recent than the
2084 * supplied one.
2085 *
2086 */
2087 static int
handle_install(char * progname,int argc,char ** argv)2088 handle_install(char *progname, int argc, char **argv)
2089 {
2090 struct partlist *pl;
2091 ib_data_t data = { 0 };
2092 char *device_path = NULL;
2093 int ret = BC_ERROR;
2094
2095 switch (argc) {
2096 case 1:
2097 if ((device_path = strdup(argv[0])) == NULL) {
2098 perror(gettext("Memory Allocation Failure"));
2099 goto done;
2100 }
2101 if (asprintf(&stage1, "%s/%s", boot_dir, STAGE1) < 0) {
2102 perror(gettext("Memory Allocation Failure"));
2103 goto done;
2104 }
2105 if (asprintf(&stage2, "%s/%s", boot_dir, STAGE2) < 0) {
2106 perror(gettext("Memory Allocation Failure"));
2107 goto done;
2108 }
2109 if (asprintf(&efi32, "%s/%s", boot_dir, LOADER32) < 0) {
2110 perror(gettext("Memory Allocation Failure"));
2111 goto done;
2112 }
2113 if (asprintf(&efi64, "%s/%s", boot_dir, LOADER64) < 0) {
2114 perror(gettext("Memory Allocation Failure"));
2115 goto done;
2116 }
2117 break;
2118 case 3:
2119 if ((stage1 = strdup(argv[0])) == NULL) {
2120 perror(gettext("Memory Allocation Failure"));
2121 goto done;
2122 }
2123 if ((stage2 = strdup(argv[1])) == NULL) {
2124 perror(gettext("Memory Allocation Failure"));
2125 goto done;
2126 }
2127 if ((device_path = strdup(argv[2])) == NULL) {
2128 perror(gettext("Memory Allocation Failure"));
2129 goto done;
2130 }
2131 if (asprintf(&efi32, "%s/%s", boot_dir, LOADER32) < 0) {
2132 perror(gettext("Memory Allocation Failure"));
2133 goto done;
2134 }
2135 if (asprintf(&efi64, "%s/%s", boot_dir, LOADER64) < 0) {
2136 perror(gettext("Memory Allocation Failure"));
2137 goto done;
2138 }
2139 break;
2140 default:
2141 usage(progname, ret);
2142 }
2143
2144 data.plist = malloc(sizeof (*data.plist));
2145 if (data.plist == NULL) {
2146 perror(gettext("Memory Allocation Failure"));
2147 goto done;
2148 }
2149 STAILQ_INIT(data.plist);
2150
2151 BOOT_DEBUG("device path: %s, stage1 path: %s bootblock path: %s\n",
2152 device_path, stage1, stage2);
2153
2154 if (probe_device(&data, device_path)) {
2155 /* Read all data. */
2156 STAILQ_FOREACH(pl, data.plist, pl_next) {
2157 if (!pl->pl_cb.read(pl)) {
2158 printf("\n");
2159 }
2160 if (!pl->pl_cb.read_bbl(pl)) {
2161 /*
2162 * We will ignore ESP updates in case of
2163 * older system where we are missing
2164 * loader64.efi and loader32.efi.
2165 */
2166 if (pl->pl_type != IB_BBLK_EFI)
2167 goto cleanup;
2168 }
2169 }
2170
2171 /* Prepare data. */
2172 prepare_bblocks(&data);
2173
2174 /* Commit data to disk. */
2175 while ((pl = STAILQ_LAST(data.plist, partlist, pl_next)) !=
2176 NULL) {
2177 if (pl->pl_cb.compare != NULL &&
2178 pl->pl_cb.compare(pl)) {
2179 if (pl->pl_cb.install != NULL)
2180 pl->pl_cb.install(&data, pl);
2181 }
2182 STAILQ_REMOVE(data.plist, pl, partlist, pl_next);
2183 partlist_free(pl);
2184 }
2185 }
2186 ret = BC_SUCCESS;
2187
2188 cleanup:
2189 while ((pl = STAILQ_LAST(data.plist, partlist, pl_next)) != NULL) {
2190 STAILQ_REMOVE(data.plist, pl, partlist, pl_next);
2191 partlist_free(pl);
2192 }
2193 free(data.plist);
2194 done:
2195 free(stage1);
2196 free(stage2);
2197 free(efi32);
2198 free(efi64);
2199 free(device_path);
2200 return (ret);
2201 }
2202
2203 /*
2204 * Retrieves from a device the extended information (einfo) associated to the
2205 * file or installed stage2.
2206 * Expects one parameter, the device path, in the form: /dev/rdsk/c?[t?]d?s0
2207 * or file name.
2208 * Returns:
2209 * - BC_SUCCESS (and prints out einfo contents depending on 'flags')
2210 * - BC_ERROR (on error)
2211 * - BC_NOEINFO (no extended information available)
2212 */
2213 static int
handle_getinfo(char * progname,int argc,char ** argv)2214 handle_getinfo(char *progname, int argc, char **argv)
2215 {
2216 struct partlist *pl;
2217 ib_data_t data = { 0 };
2218 char *device_path;
2219
2220 if (argc != 1) {
2221 (void) fprintf(stderr, gettext("Missing parameter"));
2222 usage(progname, BC_ERROR);
2223 }
2224
2225 if ((device_path = strdup(argv[0])) == NULL) {
2226 perror(gettext("Memory Allocation Failure"));
2227 return (BC_ERROR);
2228 }
2229
2230 data.plist = malloc(sizeof (*data.plist));
2231 if (data.plist == NULL) {
2232 perror("malloc");
2233 free(device_path);
2234 return (BC_ERROR);
2235 }
2236 STAILQ_INIT(data.plist);
2237
2238 if (probe_device(&data, device_path)) {
2239 STAILQ_FOREACH(pl, data.plist, pl_next) {
2240 if (pl->pl_cb.read(pl))
2241 pl->pl_cb.print(pl);
2242 else
2243 printf("\n");
2244 }
2245 }
2246
2247 while ((pl = STAILQ_LAST(data.plist, partlist, pl_next)) != NULL) {
2248 STAILQ_REMOVE(data.plist, pl, partlist, pl_next);
2249 partlist_free(pl);
2250 }
2251 free(data.plist);
2252
2253 return (BC_SUCCESS);
2254 }
2255
2256 /*
2257 * Attempt to mirror (propagate) the current bootblock over the attaching disk.
2258 *
2259 * Returns:
2260 * - BC_SUCCESS (a successful propagation happened)
2261 * - BC_ERROR (an error occurred)
2262 * - BC_NOEXTRA (it is not possible to dump the current bootblock since
2263 * there is no multiboot information)
2264 */
2265 static int
handle_mirror(char * progname,int argc,char ** argv)2266 handle_mirror(char *progname, int argc, char **argv)
2267 {
2268 ib_data_t src = { 0 };
2269 ib_data_t dest = { 0 };
2270 struct partlist *pl_src, *pl_dest;
2271 char *curr_device_path = NULL;
2272 char *attach_device_path = NULL;
2273 int retval = BC_ERROR;
2274
2275 if (argc == 2) {
2276 curr_device_path = strdup(argv[0]);
2277 attach_device_path = strdup(argv[1]);
2278 }
2279
2280 if (!curr_device_path || !attach_device_path) {
2281 free(curr_device_path);
2282 free(attach_device_path);
2283 (void) fprintf(stderr, gettext("Missing parameter"));
2284 usage(progname, BC_ERROR);
2285 }
2286 BOOT_DEBUG("Current device path is: %s, attaching device path is: "
2287 " %s\n", curr_device_path, attach_device_path);
2288
2289 src.plist = malloc(sizeof (*src.plist));
2290 if (src.plist == NULL) {
2291 perror("malloc");
2292 return (BC_ERROR);
2293 }
2294 STAILQ_INIT(src.plist);
2295
2296 dest.plist = malloc(sizeof (*dest.plist));
2297 if (dest.plist == NULL) {
2298 perror("malloc");
2299 goto out;
2300 }
2301 STAILQ_INIT(dest.plist);
2302
2303 if (!probe_device(&src, curr_device_path)) {
2304 (void) fprintf(stderr, gettext("Unable to gather device "
2305 "information from %s (current device)\n"),
2306 curr_device_path);
2307 goto out;
2308 }
2309
2310 if (!probe_device(&dest, attach_device_path) != BC_SUCCESS) {
2311 (void) fprintf(stderr, gettext("Unable to gather device "
2312 "information from %s (attaching device)\n"),
2313 attach_device_path);
2314 goto cleanup_src;
2315 }
2316
2317 write_vbr = true;
2318 write_mbr = true;
2319 force_mbr = true;
2320
2321 pl_dest = STAILQ_FIRST(dest.plist);
2322 STAILQ_FOREACH(pl_src, src.plist, pl_next) {
2323 if (pl_dest == NULL) {
2324 (void) fprintf(stderr,
2325 gettext("Destination disk layout is different "
2326 "from source, can not mirror.\n"));
2327 goto cleanup;
2328 }
2329 if (!pl_src->pl_cb.read(pl_src)) {
2330 (void) fprintf(stderr, gettext("Failed to read "
2331 "boot block from %s\n"), pl_src->pl_devname);
2332 goto cleanup;
2333 }
2334 if (!pl_dest->pl_cb.read(pl_dest)) {
2335 (void) fprintf(stderr, gettext("Failed to read "
2336 "boot block from %s\n"), pl_dest->pl_devname);
2337 }
2338
2339 /* Set source pl_stage to destination source data */
2340 pl_dest->pl_src_data = pl_src->pl_stage;
2341 pl_src->pl_stage = NULL;
2342
2343 pl_dest = STAILQ_NEXT(pl_dest, pl_next);
2344 }
2345
2346 /* Prepare data. */
2347 prepare_bblocks(&dest);
2348
2349 /* Commit data to disk. */
2350 while ((pl_dest = STAILQ_LAST(dest.plist, partlist, pl_next)) != NULL) {
2351 pl_dest->pl_cb.install(&dest, pl_dest);
2352 STAILQ_REMOVE(dest.plist, pl_dest, partlist, pl_next);
2353 partlist_free(pl_dest);
2354
2355 /* Free source list */
2356 pl_src = STAILQ_LAST(src.plist, partlist, pl_next);
2357 STAILQ_REMOVE(src.plist, pl_src, partlist, pl_next);
2358 partlist_free(pl_src);
2359 }
2360 retval = BC_SUCCESS;
2361
2362 cleanup:
2363 while ((pl_dest = STAILQ_LAST(dest.plist, partlist, pl_next)) != NULL) {
2364 STAILQ_REMOVE(dest.plist, pl_dest, partlist, pl_next);
2365 partlist_free(pl_dest);
2366 }
2367 free(dest.plist);
2368 cleanup_src:
2369 while ((pl_src = STAILQ_LAST(src.plist, partlist, pl_next)) != NULL) {
2370 STAILQ_REMOVE(src.plist, pl_src, partlist, pl_next);
2371 partlist_free(pl_src);
2372 }
2373 free(src.plist);
2374 out:
2375 free(curr_device_path);
2376 free(attach_device_path);
2377 return (retval);
2378 }
2379
2380 #define USAGE_STRING \
2381 "Usage:\t%s [-fFmn] [-b boot_dir] [-u verstr]\n" \
2382 "\t\t[stage1 stage2] raw-device\n" \
2383 "\t%s -M [-n] raw-device attach-raw-device\n" \
2384 "\t%s [-e|-V] -i raw-device | file\n"
2385
2386 #define CANON_USAGE_STR gettext(USAGE_STRING)
2387
2388 static void
usage(char * progname,int rc)2389 usage(char *progname, int rc)
2390 {
2391 (void) fprintf(stdout, CANON_USAGE_STR, progname, progname, progname);
2392 fini_yes();
2393 exit(rc);
2394 }
2395
2396 int
main(int argc,char ** argv)2397 main(int argc, char **argv)
2398 {
2399 int opt;
2400 int ret;
2401 char *progname;
2402 struct stat sb;
2403
2404 (void) setlocale(LC_ALL, "");
2405 (void) textdomain(TEXT_DOMAIN);
2406 if (init_yes() < 0)
2407 errx(BC_ERROR, gettext(ERR_MSG_INIT_YES), strerror(errno));
2408
2409 /* Needed for mount pcfs. */
2410 tzset();
2411
2412 /* Determine our name */
2413 progname = basename(argv[0]);
2414
2415 while ((opt = getopt(argc, argv, "b:deFfhiMmnu:V")) != EOF) {
2416 switch (opt) {
2417 case 'b':
2418 boot_dir = strdup(optarg);
2419 if (boot_dir == NULL) {
2420 err(BC_ERROR,
2421 gettext("Memory allocation failure"));
2422 }
2423 if (lstat(boot_dir, &sb) != 0) {
2424 err(BC_ERROR, boot_dir);
2425 }
2426 if (!S_ISDIR(sb.st_mode)) {
2427 errx(BC_ERROR, gettext("%s: not a directory"),
2428 boot_dir);
2429 }
2430 break;
2431 case 'd':
2432 boot_debug = true;
2433 break;
2434 case 'e':
2435 strip = true;
2436 break;
2437 case 'F':
2438 force_update = true;
2439 break;
2440 case 'f':
2441 force_mbr = true;
2442 break;
2443 case 'h':
2444 usage(progname, BC_SUCCESS);
2445 break;
2446 case 'i':
2447 do_getinfo = true;
2448 break;
2449 case 'M':
2450 do_mirror_bblk = true;
2451 break;
2452 case 'm':
2453 write_mbr = true;
2454 break;
2455 case 'n':
2456 nowrite = true;
2457 break;
2458 case 'u':
2459 do_version = true;
2460
2461 update_str = strdup(optarg);
2462 if (update_str == NULL) {
2463 perror(gettext("Memory allocation failure"));
2464 exit(BC_ERROR);
2465 }
2466 break;
2467 case 'V':
2468 verbose_dump = true;
2469 break;
2470 default:
2471 /* fall through to process non-optional args */
2472 break;
2473 }
2474 }
2475
2476 /* check arguments */
2477 check_options(progname);
2478
2479 if (nowrite)
2480 (void) fprintf(stdout, gettext("Dry run requested. Nothing will"
2481 " be written to disk.\n"));
2482
2483 if (do_getinfo) {
2484 ret = handle_getinfo(progname, argc - optind, argv + optind);
2485 } else if (do_mirror_bblk) {
2486 ret = handle_mirror(progname, argc - optind, argv + optind);
2487 } else {
2488 ret = handle_install(progname, argc - optind, argv + optind);
2489 }
2490 fini_yes();
2491 return (ret);
2492 }
2493
2494 #define MEANINGLESS_OPT gettext("%s specified but meaningless, ignoring\n")
2495 static void
check_options(char * progname)2496 check_options(char *progname)
2497 {
2498 if (do_getinfo && do_mirror_bblk) {
2499 (void) fprintf(stderr, gettext("Only one of -M and -i can be "
2500 "specified at the same time\n"));
2501 usage(progname, BC_ERROR);
2502 }
2503
2504 if (do_mirror_bblk) {
2505 /*
2506 * -u and -F may actually reflect a user intent that is not
2507 * correct with this command (mirror can be interpreted
2508 * "similar" to install. Emit a message and continue.
2509 * -e and -V have no meaning, be quiet here and only report the
2510 * incongruence if a debug output is requested.
2511 */
2512 if (do_version) {
2513 (void) fprintf(stderr, MEANINGLESS_OPT, "-u");
2514 do_version = false;
2515 }
2516 if (force_update) {
2517 (void) fprintf(stderr, MEANINGLESS_OPT, "-F");
2518 force_update = false;
2519 }
2520 if (strip || verbose_dump) {
2521 BOOT_DEBUG(MEANINGLESS_OPT, "-e|-V");
2522 strip = false;
2523 verbose_dump = false;
2524 }
2525 }
2526
2527 if ((strip || verbose_dump) && !do_getinfo)
2528 usage(progname, BC_ERROR);
2529
2530 if (do_getinfo) {
2531 if (write_mbr || force_mbr || do_version || force_update) {
2532 BOOT_DEBUG(MEANINGLESS_OPT, "-m|-f|-u|-F");
2533 write_mbr = force_mbr = do_version = false;
2534 force_update = false;
2535 }
2536 }
2537 }
2538