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) + 1, 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 data = malloc(SECTOR_SIZE);
584 if (data == NULL)
585 return (rv);
586
587 /* read the stage1 file from filesystem */
588 fd = open(plist->pl_src_name, O_RDONLY);
589 if (fd == -1 ||
590 read(fd, data, SECTOR_SIZE) != SECTOR_SIZE) {
591 (void) fprintf(stderr, gettext("cannot read stage1 file %s\n"),
592 plist->pl_src_name);
593 free(data);
594 if (fd != -1)
595 (void) close(fd);
596 return (rv);
597 }
598
599 plist->pl_src_data = data;
600 (void) close(fd);
601 return (true);
602 }
603
604 static bool
read_stage2_cb(struct partlist * plist)605 read_stage2_cb(struct partlist *plist)
606 {
607 ib_device_t *device;
608 ib_bootblock_t *bblock;
609 int fd;
610 uint32_t size, offset;
611 uint32_t buf_size;
612 uint32_t mboot_off;
613 multiboot_header_t *mboot;
614 size_t scan_size;
615
616 bblock = calloc(1, sizeof (ib_bootblock_t));
617 if (bblock == NULL)
618 return (false);
619
620 if ((fd = open_device(plist->pl_devname)) == -1) {
621 free(bblock);
622 return (false);
623 }
624
625 device = plist->pl_device;
626 plist->pl_stage = bblock;
627 offset = device->stage.offset * SECTOR_SIZE;
628 scan_size = MIN(sizeof (mboot_scan),
629 (device->stage.size - device->stage.offset) * sector_size);
630
631 if (read_in(fd, mboot_scan, scan_size, offset)
632 != BC_SUCCESS) {
633 BOOT_DEBUG("Error reading bootblock area\n");
634 perror("read");
635 (void) close(fd);
636 return (false);
637 }
638
639 /* No multiboot means no chance of knowing bootblock size */
640 if (find_multiboot(mboot_scan, scan_size, &mboot_off)
641 != BC_SUCCESS) {
642 BOOT_DEBUG("Unable to find multiboot header\n");
643 (void) close(fd);
644 return (false);
645 }
646 mboot = (multiboot_header_t *)(mboot_scan + mboot_off);
647
648 /*
649 * make sure mboot has sane values
650 */
651 if (mboot->load_end_addr == 0 ||
652 mboot->load_end_addr < mboot->load_addr) {
653 (void) close(fd);
654 return (false);
655 }
656
657 /*
658 * Currently, the amount of space reserved for extra information
659 * is "fixed". We may have to scan for the terminating extra payload
660 * in the future.
661 */
662 size = mboot->load_end_addr - mboot->load_addr;
663 buf_size = P2ROUNDUP(size + SECTOR_SIZE, SECTOR_SIZE);
664 bblock->file_size = size;
665
666 bblock->buf = malloc(buf_size);
667 if (bblock->buf == NULL) {
668 BOOT_DEBUG("Unable to allocate enough memory to read"
669 " the extra bootblock from the disk\n");
670 perror(gettext("Memory allocation failure"));
671 (void) close(fd);
672 return (false);
673 }
674 bblock->buf_size = buf_size;
675
676 if (read_in(fd, bblock->buf, buf_size, offset) != BC_SUCCESS) {
677 BOOT_DEBUG("Error reading the bootblock\n");
678 (void) free(bblock->buf);
679 bblock->buf = NULL;
680 (void) close(fd);
681 return (false);
682 }
683
684 /* Update pointers. */
685 bblock->file = bblock->buf;
686 bblock->mboot_off = mboot_off;
687 bblock->mboot = (multiboot_header_t *)(bblock->buf + bblock->mboot_off);
688 bblock->extra = bblock->buf + P2ROUNDUP(bblock->file_size, 8);
689 bblock->extra_size = bblock->buf_size - P2ROUNDUP(bblock->file_size, 8);
690
691 BOOT_DEBUG("mboot at %p offset %d, extra at %p size %d, buf=%p "
692 "(size=%d)\n", bblock->mboot, bblock->mboot_off, bblock->extra,
693 bblock->extra_size, bblock->buf, bblock->buf_size);
694
695 return (true);
696 }
697
698 static bool
read_einfo_file_cb(struct partlist * plist)699 read_einfo_file_cb(struct partlist *plist)
700 {
701 int rc;
702 void *stage;
703
704 stage = calloc(1, sizeof (ib_bootblock_t));
705 if (stage == NULL)
706 return (false);
707
708 rc = read_bootblock_from_file(plist->pl_devname, stage);
709 if (rc != BC_SUCCESS) {
710 free(stage);
711 stage = NULL;
712 }
713 plist->pl_stage = stage;
714 return (rc == BC_SUCCESS);
715 }
716
717 static bool
read_stage2_file_cb(struct partlist * plist)718 read_stage2_file_cb(struct partlist *plist)
719 {
720 int rc;
721 void *data;
722
723 data = calloc(1, sizeof (ib_bootblock_t));
724 if (data == NULL)
725 return (false);
726
727 rc = read_bootblock_from_file(plist->pl_src_name, data);
728 if (rc != BC_SUCCESS) {
729 free(data);
730 data = NULL;
731 }
732 plist->pl_src_data = data;
733 return (rc == BC_SUCCESS);
734 }
735
736 /*
737 * convert /dev/rdsk/... to /dev/dsk/...
738 */
739 static char *
make_blkdev(const char * path)740 make_blkdev(const char *path)
741 {
742 char *tmp;
743 char *ptr = strdup(path);
744
745 if (ptr == NULL)
746 return (ptr);
747
748 tmp = strstr(ptr, "rdsk");
749 if (tmp == NULL) {
750 free(ptr);
751 return (NULL); /* Something is very wrong */
752 }
753 /* This is safe because we do shorten the string */
754 (void) memmove(tmp, tmp + 1, strlen(tmp));
755 return (ptr);
756 }
757
758 /*
759 * Try to mount ESP and read boot program.
760 */
761 static bool
read_einfo_esp_cb(struct partlist * plist)762 read_einfo_esp_cb(struct partlist *plist)
763 {
764 fstyp_handle_t fhdl;
765 const char *fident;
766 char *blkdev, *path, *file;
767 bool rv = false;
768 FILE *fp;
769 struct mnttab mp, mpref = { 0 };
770 int fd, ret;
771
772 if ((fd = open_device(plist->pl_devname)) == -1)
773 return (rv);
774
775 if (fstyp_init(fd, 0, NULL, &fhdl) != 0) {
776 (void) close(fd);
777 return (rv);
778 }
779
780 if (fstyp_ident(fhdl, NULL, &fident) != 0) {
781 fstyp_fini(fhdl);
782 (void) close(fd);
783 (void) fprintf(stderr, gettext("Failed to detect file "
784 "system type\n"));
785 return (rv);
786 }
787
788 /* We only do expect pcfs. */
789 if (strcmp(fident, MNTTYPE_PCFS) != 0) {
790 (void) fprintf(stderr,
791 gettext("File system %s is not supported.\n"), fident);
792 fstyp_fini(fhdl);
793 (void) close(fd);
794 return (rv);
795 }
796 fstyp_fini(fhdl);
797 (void) close(fd);
798
799 blkdev = make_blkdev(plist->pl_devname);
800 if (blkdev == NULL)
801 return (rv);
802
803 /* mount ESP if needed, read boot program(s) and unmount. */
804 fp = fopen(MNTTAB, "r");
805 if (fp == NULL) {
806 perror("fopen");
807 free(blkdev);
808 return (rv);
809 }
810
811 mpref.mnt_special = blkdev;
812 ret = getmntany(fp, &mp, &mpref);
813 (void) fclose(fp);
814 if (ret == 0)
815 path = mp.mnt_mountp;
816 else
817 path = stagefs_mount(blkdev, plist);
818
819 free(blkdev);
820 if (path == NULL)
821 return (rv);
822
823 if (asprintf(&file, "%s%s", path, plist->pl_device->stage.path) < 0) {
824 return (rv);
825 }
826
827 plist->pl_stage = calloc(1, sizeof (ib_bootblock_t));
828 if (plist->pl_stage == NULL) {
829 free(file);
830 return (rv);
831 }
832 if (read_bootblock_from_file(file, plist->pl_stage) != BC_SUCCESS) {
833 free(plist->pl_stage);
834 plist->pl_stage = NULL;
835 } else {
836 rv = true;
837 }
838
839 free(file);
840 return (rv);
841 }
842
843 static void
print_stage1_cb(struct partlist * plist)844 print_stage1_cb(struct partlist *plist)
845 {
846 struct mboot *mbr;
847 struct ipart *part;
848 mbr_type_t type = MBR_TYPE_UNKNOWN;
849 bool pmbr = false;
850 char *label;
851
852 mbr = plist->pl_stage;
853
854 if (*((uint16_t *)&mbr->bootinst[GRUB_VERSION_OFF]) == GRUB_VERSION) {
855 type = MBR_TYPE_GRUB1;
856 } else if (mbr->bootinst[STAGE1_MBR_VERSION] == LOADER_VERSION) {
857 type = MBR_TYPE_LOADER;
858 } else if (mbr->bootinst[STAGE1_MBR_VERSION] == LOADER_JOYENT_VERSION) {
859 type = MBR_TYPE_LOADER_JOYENT;
860 }
861
862 part = (struct ipart *)mbr->parts;
863 for (int i = 0; i < FD_NUMPART; i++) {
864 if (part[i].systid == EFI_PMBR)
865 pmbr = true;
866 }
867
868 if (plist->pl_type == IB_BBLK_MBR)
869 label = pmbr ? "PMBR" : "MBR";
870 else
871 label = "VBR";
872
873 printf("%s block from %s:\n", label, plist->pl_devname);
874
875 switch (type) {
876 case MBR_TYPE_UNKNOWN:
877 printf("Format: unknown\n");
878 break;
879 case MBR_TYPE_GRUB1:
880 printf("Format: grub1\n");
881 break;
882 case MBR_TYPE_LOADER:
883 printf("Format: loader (illumos)\n");
884 break;
885 case MBR_TYPE_LOADER_JOYENT:
886 printf("Format: loader (joyent)\n");
887 break;
888 }
889
890 printf("Signature: 0x%hx (%s)\n", mbr->signature,
891 mbr->signature == MBB_MAGIC ? "valid" : "invalid");
892
893 printf("UniqueMBRDiskSignature: %#lx\n",
894 *(uint32_t *)&mbr->bootinst[STAGE1_SIG]);
895
896 if (type == MBR_TYPE_LOADER || type == MBR_TYPE_LOADER_JOYENT) {
897 char uuid[UUID_PRINTABLE_STRING_LENGTH];
898
899 printf("Loader STAGE1_STAGE2_LBA: %llu\n",
900 *(uint64_t *)&mbr->bootinst[STAGE1_STAGE2_LBA]);
901
902 printf("Loader STAGE1_STAGE2_SIZE: %hu\n",
903 *(uint16_t *)&mbr->bootinst[STAGE1_STAGE2_SIZE]);
904
905 uuid_unparse((uchar_t *)&mbr->bootinst[STAGE1_STAGE2_UUID],
906 uuid);
907
908 printf("Loader STAGE1_STAGE2_UUID: %s\n", uuid);
909 }
910 printf("\n");
911 }
912
913 static void
print_einfo_cb(struct partlist * plist)914 print_einfo_cb(struct partlist *plist)
915 {
916 uint8_t flags = 0;
917 ib_bootblock_t *bblock;
918 bblk_einfo_t *einfo = NULL;
919 const char *filepath;
920
921 /* No stage, get out. */
922 bblock = plist->pl_stage;
923 if (bblock == NULL)
924 return;
925
926 if (plist->pl_device->stage.path == NULL)
927 filepath = "";
928 else
929 filepath = plist->pl_device->stage.path;
930
931 printf("Boot block from %s:%s\n", plist->pl_devname, filepath);
932
933 if (bblock->extra != NULL)
934 einfo = find_einfo(bblock->extra, bblock->extra_size);
935
936 if (einfo == NULL) {
937 (void) fprintf(stderr,
938 gettext("No extended information found.\n\n"));
939 return;
940 }
941
942 /* Print the extended information. */
943 if (strip)
944 flags |= EINFO_EASY_PARSE;
945 if (verbose_dump)
946 flags |= EINFO_PRINT_HEADER;
947
948 print_einfo(flags, einfo, bblock->extra_size);
949 printf("\n");
950 }
951
952 static size_t
get_media_info(int fd)953 get_media_info(int fd)
954 {
955 struct dk_minfo disk_info;
956
957 if ((ioctl(fd, DKIOCGMEDIAINFO, (caddr_t)&disk_info)) == -1)
958 return (SECTOR_SIZE);
959
960 return (disk_info.dki_lbsize);
961 }
962
963 static struct partlist *
partlist_alloc(void)964 partlist_alloc(void)
965 {
966 struct partlist *pl;
967
968 if ((pl = calloc(1, sizeof (*pl))) == NULL) {
969 perror("calloc");
970 return (NULL);
971 }
972
973 pl->pl_device = calloc(1, sizeof (*pl->pl_device));
974 if (pl->pl_device == NULL) {
975 perror("calloc");
976 free(pl);
977 return (NULL);
978 }
979
980 return (pl);
981 }
982
983 static void
partlist_free(struct partlist * pl)984 partlist_free(struct partlist *pl)
985 {
986 ib_bootblock_t *bblock;
987 ib_device_t *device;
988
989 switch (pl->pl_type) {
990 case IB_BBLK_MBR:
991 case IB_BBLK_STAGE1:
992 free(pl->pl_stage);
993 break;
994 default:
995 if (pl->pl_stage != NULL) {
996 bblock = pl->pl_stage;
997 free(bblock->buf);
998 free(bblock);
999 }
1000 }
1001
1002 /* umount the stage fs. */
1003 if (pl->pl_device->stage.mntpnt != NULL) {
1004 if (umount(pl->pl_device->stage.mntpnt) == 0)
1005 (void) rmdir(pl->pl_device->stage.mntpnt);
1006 free(pl->pl_device->stage.mntpnt);
1007 }
1008 device = pl->pl_device;
1009 free(device->target.path);
1010 free(pl->pl_device);
1011
1012 free(pl->pl_src_data);
1013 free(pl->pl_devname);
1014 free(pl);
1015 }
1016
1017 static bool
probe_fstyp(ib_data_t * data)1018 probe_fstyp(ib_data_t *data)
1019 {
1020 fstyp_handle_t fhdl;
1021 const char *fident;
1022 char *ptr;
1023 int fd;
1024 bool rv = false;
1025
1026 /* Record partition id */
1027 ptr = strrchr(data->target.path, 'p');
1028 if (ptr == NULL)
1029 ptr = strrchr(data->target.path, 's');
1030 data->target.id = atoi(++ptr);
1031 if ((fd = open_device(data->target.path)) == -1)
1032 return (rv);
1033
1034 if (fstyp_init(fd, 0, NULL, &fhdl) != 0) {
1035 (void) close(fd);
1036 return (rv);
1037 }
1038
1039 if (fstyp_ident(fhdl, NULL, &fident) != 0) {
1040 fstyp_fini(fhdl);
1041 (void) fprintf(stderr, gettext("Failed to detect file "
1042 "system type\n"));
1043 (void) close(fd);
1044 return (rv);
1045 }
1046
1047 rv = true;
1048 if (strcmp(fident, MNTTYPE_ZFS) == 0)
1049 data->target.fstype = IB_FS_ZFS;
1050 else if (strcmp(fident, MNTTYPE_UFS) == 0) {
1051 data->target.fstype = IB_FS_UFS;
1052 } else if (strcmp(fident, MNTTYPE_PCFS) == 0) {
1053 data->target.fstype = IB_FS_PCFS;
1054 /* with pcfs we always write MBR */
1055 force_mbr = true;
1056 write_mbr = true;
1057 } else {
1058 (void) fprintf(stderr, gettext("File system %s is not "
1059 "supported by loader\n"), fident);
1060 rv = false;
1061 }
1062 fstyp_fini(fhdl);
1063 (void) close(fd);
1064 return (rv);
1065 }
1066
1067 static bool
get_slice(ib_data_t * data,struct partlist * pl,struct dk_gpt * vtoc,uint16_t tag)1068 get_slice(ib_data_t *data, struct partlist *pl, struct dk_gpt *vtoc,
1069 uint16_t tag)
1070 {
1071 uint_t i;
1072 ib_device_t *device = pl->pl_device;
1073 char *path, *ptr;
1074
1075 if (tag != V_BOOT && tag != V_SYSTEM)
1076 return (false);
1077
1078 for (i = 0; i < vtoc->efi_nparts; i++) {
1079 if (vtoc->efi_parts[i].p_tag == tag) {
1080 if ((path = strdup(data->target.path)) == NULL) {
1081 perror(gettext("Memory allocation failure"));
1082 return (false);
1083 }
1084 ptr = strrchr(path, 's');
1085 ptr++;
1086 *ptr = '\0';
1087 (void) asprintf(&ptr, "%s%d", path, i);
1088 free(path);
1089 if (ptr == NULL) {
1090 perror(gettext("Memory allocation failure"));
1091 return (false);
1092 }
1093 pl->pl_devname = ptr;
1094 device->stage.id = i;
1095 device->stage.devtype = IB_DEV_EFI;
1096 switch (vtoc->efi_parts[i].p_tag) {
1097 case V_BOOT:
1098 device->stage.fstype = IB_FS_NONE;
1099 /* leave sector 0 for VBR */
1100 device->stage.offset = 1;
1101 break;
1102 case V_SYSTEM:
1103 device->stage.fstype = IB_FS_PCFS;
1104 break;
1105 }
1106 device->stage.tag = vtoc->efi_parts[i].p_tag;
1107 device->stage.start = vtoc->efi_parts[i].p_start;
1108 device->stage.size = vtoc->efi_parts[i].p_size;
1109 break;
1110 }
1111 }
1112 return (true);
1113 }
1114
1115 static bool
allocate_slice(ib_data_t * data,struct dk_gpt * vtoc,uint16_t tag,struct partlist ** plp)1116 allocate_slice(ib_data_t *data, struct dk_gpt *vtoc, uint16_t tag,
1117 struct partlist **plp)
1118 {
1119 struct partlist *pl;
1120
1121 *plp = NULL;
1122 if ((pl = partlist_alloc()) == NULL)
1123 return (false);
1124
1125 pl->pl_device = calloc(1, sizeof (*pl->pl_device));
1126 if (pl->pl_device == NULL) {
1127 perror("calloc");
1128 partlist_free(pl);
1129 return (false);
1130 }
1131 if (!get_slice(data, pl, vtoc, tag)) {
1132 partlist_free(pl);
1133 return (false);
1134 }
1135
1136 /* tag was not found */
1137 if (pl->pl_devname == NULL)
1138 partlist_free(pl);
1139 else
1140 *plp = pl;
1141
1142 return (true);
1143 }
1144
1145 static bool
probe_gpt(ib_data_t * data)1146 probe_gpt(ib_data_t *data)
1147 {
1148 struct partlist *pl;
1149 struct dk_gpt *vtoc;
1150 ib_device_t *device;
1151 int slice, fd;
1152 bool rv = false;
1153
1154 if ((fd = open_device(data->target.path)) < 0)
1155 return (rv);
1156
1157 slice = efi_alloc_and_read(fd, &vtoc);
1158 (void) close(fd);
1159 if (slice < 0)
1160 return (rv);
1161
1162 data->device.devtype = IB_DEV_EFI;
1163 data->target.start = vtoc->efi_parts[slice].p_start;
1164 data->target.size = vtoc->efi_parts[slice].p_size;
1165
1166 /* Always update PMBR. */
1167 force_mbr = true;
1168 write_mbr = true;
1169
1170 /*
1171 * With GPT we can have boot partition and ESP.
1172 * Boot partition can have both stage 1 and stage 2.
1173 */
1174 if (!allocate_slice(data, vtoc, V_BOOT, &pl))
1175 goto done;
1176 if (pl != NULL) {
1177 pl->pl_src_name = stage1;
1178 pl->pl_type = IB_BBLK_STAGE1;
1179 pl->pl_cb.compare = compare_stage1_cb;
1180 pl->pl_cb.install = install_stage1_cb;
1181 pl->pl_cb.read = read_stage1_cb;
1182 pl->pl_cb.read_bbl = read_stage1_bbl_cb;
1183 pl->pl_cb.print = print_stage1_cb;
1184 STAILQ_INSERT_TAIL(data->plist, pl, pl_next);
1185 } else if (data->target.fstype != IB_FS_ZFS) {
1186 (void) fprintf(stderr, gettext("Booting %s from EFI "
1187 "labeled disks requires the boot partition.\n"),
1188 data->target.fstype == IB_FS_UFS?
1189 MNTTYPE_UFS : MNTTYPE_PCFS);
1190 goto done;
1191 }
1192 /* Add stage 2 */
1193 if (!allocate_slice(data, vtoc, V_BOOT, &pl))
1194 goto done;
1195 if (pl != NULL) {
1196 pl->pl_src_name = stage2;
1197 pl->pl_type = IB_BBLK_STAGE2;
1198 pl->pl_cb.compare = compare_einfo_cb;
1199 pl->pl_cb.install = install_stage2_cb;
1200 pl->pl_cb.read = read_stage2_cb;
1201 pl->pl_cb.read_bbl = read_stage2_file_cb;
1202 pl->pl_cb.print = print_einfo_cb;
1203 STAILQ_INSERT_TAIL(data->plist, pl, pl_next);
1204 }
1205
1206 /* ESP can have 32- and 64-bit boot code. */
1207 if (!allocate_slice(data, vtoc, V_SYSTEM, &pl))
1208 goto done;
1209 if (pl != NULL) {
1210 pl->pl_device->stage.path = "/EFI/Boot/" BOOTIA32;
1211 pl->pl_src_name = efi32;
1212 pl->pl_type = IB_BBLK_EFI;
1213 pl->pl_cb.compare = compare_einfo_cb;
1214 pl->pl_cb.install = install_esp_cb;
1215 pl->pl_cb.read = read_einfo_esp_cb;
1216 pl->pl_cb.read_bbl = read_stage2_file_cb;
1217 pl->pl_cb.print = print_einfo_cb;
1218 STAILQ_INSERT_TAIL(data->plist, pl, pl_next);
1219 }
1220 if (!allocate_slice(data, vtoc, V_SYSTEM, &pl))
1221 goto done;
1222 if (pl != NULL) {
1223 pl->pl_device->stage.path = "/EFI/Boot/" BOOTX64;
1224 pl->pl_src_name = efi64;
1225 pl->pl_type = IB_BBLK_EFI;
1226 pl->pl_cb.compare = compare_einfo_cb;
1227 pl->pl_cb.install = install_esp_cb;
1228 pl->pl_cb.read = read_einfo_esp_cb;
1229 pl->pl_cb.read_bbl = read_stage2_file_cb;
1230 pl->pl_cb.print = print_einfo_cb;
1231 STAILQ_INSERT_TAIL(data->plist, pl, pl_next);
1232 }
1233
1234 /* add stage for our target file system slice */
1235 pl = partlist_alloc();
1236 if (pl == NULL)
1237 goto done;
1238
1239 device = pl->pl_device;
1240 device->stage.devtype = data->device.devtype;
1241 if ((pl->pl_devname = strdup(data->target.path)) == NULL) {
1242 perror(gettext("Memory allocation failure"));
1243 partlist_free(pl);
1244 goto done;
1245 }
1246
1247 device->stage.id = slice;
1248 device->stage.start = vtoc->efi_parts[slice].p_start;
1249 device->stage.size = vtoc->efi_parts[slice].p_size;
1250
1251 /* ZFS and UFS can have stage1 in boot area. */
1252 if (data->target.fstype == IB_FS_ZFS ||
1253 data->target.fstype == IB_FS_UFS) {
1254 pl->pl_src_name = stage1;
1255 pl->pl_type = IB_BBLK_STAGE1;
1256 pl->pl_cb.compare = compare_stage1_cb;
1257 pl->pl_cb.install = install_stage1_cb;
1258 pl->pl_cb.read = read_stage1_cb;
1259 pl->pl_cb.read_bbl = read_stage1_bbl_cb;
1260 pl->pl_cb.print = print_stage1_cb;
1261 STAILQ_INSERT_TAIL(data->plist, pl, pl_next);
1262 }
1263
1264 if (data->target.fstype == IB_FS_ZFS) {
1265 pl = partlist_alloc();
1266 if (pl == NULL)
1267 goto done;
1268
1269 device = pl->pl_device;
1270 device->stage.devtype = data->device.devtype;
1271
1272 if ((pl->pl_devname = strdup(data->target.path)) == NULL) {
1273 perror(gettext("Memory allocation failure"));
1274 goto done;
1275 }
1276
1277 device->stage.id = slice;
1278 device->stage.start = vtoc->efi_parts[slice].p_start;
1279 device->stage.size = vtoc->efi_parts[slice].p_size;
1280
1281 device->stage.offset = BBLK_ZFS_BLK_OFF;
1282 pl->pl_src_name = stage2;
1283 pl->pl_type = IB_BBLK_STAGE2;
1284 pl->pl_cb.compare = compare_einfo_cb;
1285 pl->pl_cb.install = install_stage2_cb;
1286 pl->pl_cb.read = read_stage2_cb;
1287 pl->pl_cb.read_bbl = read_stage2_file_cb;
1288 pl->pl_cb.print = print_einfo_cb;
1289 STAILQ_INSERT_TAIL(data->plist, pl, pl_next);
1290 }
1291 rv = true;
1292 done:
1293 efi_free(vtoc);
1294 return (rv);
1295 }
1296
1297 static bool
get_start_sector(ib_data_t * data,struct extpartition * v_part,diskaddr_t * start)1298 get_start_sector(ib_data_t *data, struct extpartition *v_part,
1299 diskaddr_t *start)
1300 {
1301 struct partlist *pl;
1302 struct mboot *mbr;
1303 struct ipart *part;
1304 struct part_info dkpi;
1305 struct extpart_info edkpi;
1306 uint32_t secnum, numsec;
1307 ext_part_t *epp;
1308 ushort_t i;
1309 int fd, rval, pno;
1310
1311 if ((fd = open_device(data->target.path)) < 0)
1312 return (false);
1313
1314 if (ioctl(fd, DKIOCEXTPARTINFO, &edkpi) < 0) {
1315 if (ioctl(fd, DKIOCPARTINFO, &dkpi) < 0) {
1316 (void) fprintf(stderr, gettext("cannot get the "
1317 "slice information of the disk\n"));
1318 (void) close(fd);
1319 return (false);
1320 } else {
1321 edkpi.p_start = dkpi.p_start;
1322 edkpi.p_length = dkpi.p_length;
1323 }
1324 }
1325 (void) close(fd);
1326
1327 /* Set target file system start and size */
1328 data->target.start = edkpi.p_start;
1329 data->target.size = edkpi.p_length;
1330
1331 /* This is our MBR partition start. */
1332 edkpi.p_start -= v_part->p_start;
1333
1334 /* Head is always MBR */
1335 pl = STAILQ_FIRST(data->plist);
1336 if (!read_stage1_cb(pl))
1337 return (false);
1338
1339 mbr = (struct mboot *)pl->pl_stage;
1340 part = (struct ipart *)mbr->parts;
1341
1342 for (i = 0; i < FD_NUMPART; i++) {
1343 if (part[i].relsect == edkpi.p_start) {
1344 *start = part[i].relsect;
1345 return (true);
1346 }
1347 }
1348
1349 rval = libfdisk_init(&epp, pl->pl_devname, part, FDISK_READ_DISK);
1350 if (rval != FDISK_SUCCESS) {
1351 switch (rval) {
1352 /*
1353 * The first 3 cases are not an error per-se, just that
1354 * there is no Solaris logical partition
1355 */
1356 case FDISK_EBADLOGDRIVE:
1357 case FDISK_ENOLOGDRIVE:
1358 case FDISK_EBADMAGIC:
1359 (void) fprintf(stderr, gettext("Solaris "
1360 "partition not found. "
1361 "Aborting operation. %d\n"), rval);
1362 return (false);
1363 case FDISK_ENOVGEOM:
1364 (void) fprintf(stderr, gettext("Could not get "
1365 "virtual geometry\n"));
1366 return (false);
1367 case FDISK_ENOPGEOM:
1368 (void) fprintf(stderr, gettext("Could not get "
1369 "physical geometry\n"));
1370 return (false);
1371 case FDISK_ENOLGEOM:
1372 (void) fprintf(stderr, gettext("Could not get "
1373 "label geometry\n"));
1374 return (false);
1375 default:
1376 (void) fprintf(stderr, gettext("Failed to "
1377 "initialize libfdisk.\n"));
1378 return (false);
1379 }
1380 }
1381 rval = fdisk_get_solaris_part(epp, &pno, &secnum, &numsec);
1382 libfdisk_fini(&epp);
1383 if (rval != FDISK_SUCCESS) {
1384 /* No solaris logical partition */
1385 (void) fprintf(stderr, gettext("Solaris partition not found. "
1386 "Aborting operation.\n"));
1387 return (false);
1388 }
1389 *start = secnum;
1390 return (true);
1391 }
1392
1393 /*
1394 * On x86 the VTOC table is inside MBR partition and to get
1395 * absolute sectors, we need to add MBR partition start to VTOC slice start.
1396 */
1397 static bool
probe_vtoc(ib_data_t * data)1398 probe_vtoc(ib_data_t *data)
1399 {
1400 struct partlist *pl;
1401 struct extvtoc exvtoc;
1402 ib_device_t *device;
1403 char *path, *ptr;
1404 ushort_t i;
1405 int slice, fd;
1406 diskaddr_t start;
1407 bool rv;
1408
1409 rv = false;
1410
1411 if ((fd = open_device(data->target.path)) < 0)
1412 return (rv);
1413
1414 slice = read_extvtoc(fd, &exvtoc);
1415 (void) close(fd);
1416 if (slice < 0)
1417 return (rv);
1418 data->device.devtype = IB_DEV_VTOC;
1419
1420 if (!get_start_sector(data, exvtoc.v_part + slice, &start))
1421 return (rv);
1422
1423 if (exvtoc.v_part[slice].p_tag == V_BACKUP) {
1424 /*
1425 * NOTE: we could relax there and allow zfs boot on
1426 * slice 2, but lets keep traditional limits.
1427 */
1428 (void) fprintf(stderr, gettext(
1429 "raw device must be a root slice (not backup)\n"));
1430 return (rv);
1431 }
1432
1433 if ((path = strdup(data->target.path)) == NULL) {
1434 perror(gettext("Memory allocation failure"));
1435 return (false);
1436 }
1437
1438 data->target.start = start + exvtoc.v_part[slice].p_start;
1439 data->target.size = exvtoc.v_part[slice].p_size;
1440
1441 /* Search for boot slice. */
1442 for (i = 0; i < exvtoc.v_nparts; i++) {
1443 if (exvtoc.v_part[i].p_tag == V_BOOT)
1444 break;
1445 }
1446
1447 if (i == exvtoc.v_nparts ||
1448 exvtoc.v_part[i].p_size == 0) {
1449 /* fall back to slice V_BACKUP */
1450 for (i = 0; i < exvtoc.v_nparts; i++) {
1451 if (exvtoc.v_part[i].p_tag == V_BACKUP)
1452 break;
1453 }
1454 /* Still nothing? Error out. */
1455 if (i == exvtoc.v_nparts ||
1456 exvtoc.v_part[i].p_size == 0) {
1457 free(path);
1458 return (false);
1459 }
1460 }
1461
1462 /* Create path. */
1463 ptr = strrchr(path, 's');
1464 ptr++;
1465 *ptr = '\0';
1466 (void) asprintf(&ptr, "%s%d", path, i);
1467 free(path);
1468 if (ptr == NULL) {
1469 perror(gettext("Memory allocation failure"));
1470 return (false);
1471 }
1472
1473 pl = partlist_alloc();
1474 if (pl == NULL) {
1475 free(ptr);
1476 return (false);
1477 }
1478 pl->pl_devname = ptr;
1479 device = pl->pl_device;
1480 device->stage.devtype = data->device.devtype;
1481 device->stage.id = i;
1482 device->stage.tag = exvtoc.v_part[i].p_tag;
1483 device->stage.start = start + exvtoc.v_part[i].p_start;
1484 device->stage.size = exvtoc.v_part[i].p_size;
1485
1486 /* Fix size if this slice is in fact V_BACKUP */
1487 if (exvtoc.v_part[i].p_tag == V_BACKUP) {
1488 for (i = 0; i < exvtoc.v_nparts; i++) {
1489 if (exvtoc.v_part[i].p_start == 0)
1490 continue;
1491 if (exvtoc.v_part[i].p_size == 0)
1492 continue;
1493 if (exvtoc.v_part[i].p_start <
1494 device->stage.size)
1495 device->stage.size =
1496 exvtoc.v_part[i].p_start;
1497 }
1498 }
1499
1500 pl->pl_src_name = stage1;
1501 pl->pl_type = IB_BBLK_STAGE1;
1502 pl->pl_cb.compare = compare_stage1_cb;
1503 pl->pl_cb.install = install_stage1_cb;
1504 pl->pl_cb.read = read_stage1_cb;
1505 pl->pl_cb.read_bbl = read_stage1_bbl_cb;
1506 pl->pl_cb.print = print_stage1_cb;
1507 STAILQ_INSERT_TAIL(data->plist, pl, pl_next);
1508
1509 /* Create instance for stage 2 */
1510 pl = partlist_alloc();
1511 if (pl == NULL) {
1512 free(ptr);
1513 return (false);
1514 }
1515 pl->pl_devname = strdup(ptr);
1516 if (pl->pl_devname == NULL) {
1517 partlist_free(pl);
1518 return (false);
1519 }
1520 pl->pl_device->stage.devtype = data->device.devtype;
1521 pl->pl_device->stage.id = device->stage.id;
1522 pl->pl_device->stage.offset = BBLK_BLKLIST_OFF;
1523 pl->pl_device->stage.tag = device->stage.tag;
1524 pl->pl_device->stage.start = device->stage.start;
1525 pl->pl_device->stage.size = device->stage.size;
1526 pl->pl_src_name = stage2;
1527 pl->pl_type = IB_BBLK_STAGE2;
1528 pl->pl_cb.compare = compare_einfo_cb;
1529 pl->pl_cb.install = install_stage2_cb;
1530 pl->pl_cb.read = read_stage2_cb;
1531 pl->pl_cb.read_bbl = read_stage2_file_cb;
1532 pl->pl_cb.print = print_einfo_cb;
1533 STAILQ_INSERT_TAIL(data->plist, pl, pl_next);
1534
1535 /* And we are done. */
1536 rv = true;
1537 return (rv);
1538 }
1539
1540 static bool
probe_mbr(ib_data_t * data)1541 probe_mbr(ib_data_t *data)
1542 {
1543 struct partlist *pl;
1544 struct ipart *part;
1545 struct mboot *mbr;
1546 ib_device_t *device;
1547 char *path, *ptr;
1548 int i, rv;
1549
1550 data->device.devtype = IB_DEV_MBR;
1551
1552 /* Head is always MBR */
1553 pl = STAILQ_FIRST(data->plist);
1554 if (!read_stage1_cb(pl))
1555 return (false);
1556
1557 mbr = (struct mboot *)pl->pl_stage;
1558 part = (struct ipart *)mbr->parts;
1559
1560 /* Set target file system start and size */
1561 data->target.start = part[data->target.id - 1].relsect;
1562 data->target.size = part[data->target.id - 1].numsect;
1563
1564 /* Use X86BOOT partition if we have one. */
1565 for (i = 0; i < FD_NUMPART; i++) {
1566 if (part[i].systid == X86BOOT)
1567 break;
1568 }
1569
1570 /* Keep device name of whole disk device. */
1571 path = (char *)pl->pl_devname;
1572 if ((pl = partlist_alloc()) == NULL)
1573 return (false);
1574 device = pl->pl_device;
1575
1576 /*
1577 * No X86BOOT, try to use space between MBR and first
1578 * partition.
1579 */
1580 if (i == FD_NUMPART) {
1581 pl->pl_devname = strdup(path);
1582 if (pl->pl_devname == NULL) {
1583 perror(gettext("Memory allocation failure"));
1584 partlist_free(pl);
1585 return (false);
1586 }
1587 device->stage.id = 0;
1588 device->stage.devtype = IB_DEV_MBR;
1589 device->stage.fstype = IB_FS_NONE;
1590 device->stage.start = 0;
1591 device->stage.size = part[0].relsect;
1592 device->stage.offset = BBLK_BLKLIST_OFF;
1593 pl->pl_src_name = stage2;
1594 pl->pl_type = IB_BBLK_STAGE2;
1595 pl->pl_cb.compare = compare_einfo_cb;
1596 pl->pl_cb.install = install_stage2_cb;
1597 pl->pl_cb.read = read_stage2_cb;
1598 pl->pl_cb.read_bbl = read_stage2_file_cb;
1599 pl->pl_cb.print = print_einfo_cb;
1600 STAILQ_INSERT_TAIL(data->plist, pl, pl_next);
1601
1602 /* We have MBR for stage1 and gap for stage2, we are done. */
1603 return (true);
1604 }
1605
1606 if ((path = strdup(path)) == NULL) {
1607 perror(gettext("Memory allocation failure"));
1608 partlist_free(pl);
1609 return (false);
1610 }
1611 ptr = strrchr(path, 'p');
1612 ptr++;
1613 *ptr = '\0';
1614 /* partitions are p1..p4 */
1615 rv = asprintf(&ptr, "%s%d", path, i + 1);
1616 free(path);
1617 if (rv < 0) {
1618 perror(gettext("Memory allocation failure"));
1619 partlist_free(pl);
1620 return (false);
1621 }
1622 pl->pl_devname = ptr;
1623 device->stage.id = i + 1;
1624 device->stage.devtype = IB_DEV_MBR;
1625 device->stage.fstype = IB_FS_NONE;
1626 device->stage.start = part[i].relsect;
1627 device->stage.size = part[i].numsect;
1628 pl->pl_src_name = stage1;
1629 pl->pl_type = IB_BBLK_STAGE1;
1630 pl->pl_cb.compare = compare_stage1_cb;
1631 pl->pl_cb.install = install_stage1_cb;
1632 pl->pl_cb.read = read_stage1_cb;
1633 pl->pl_cb.read_bbl = read_stage1_bbl_cb;
1634 pl->pl_cb.print = print_stage1_cb;
1635 STAILQ_INSERT_TAIL(data->plist, pl, pl_next);
1636
1637 pl = partlist_alloc();
1638 if (pl == NULL)
1639 return (false);
1640 device = pl->pl_device;
1641 pl->pl_devname = strdup(ptr);
1642 if (pl->pl_devname == NULL) {
1643 perror(gettext("Memory allocation failure"));
1644 partlist_free(pl);
1645 return (false);
1646 }
1647 device->stage.id = i + 1;
1648 device->stage.devtype = IB_DEV_MBR;
1649 device->stage.fstype = IB_FS_NONE;
1650 device->stage.start = part[i].relsect;
1651 device->stage.size = part[i].numsect;
1652 device->stage.offset = 1;
1653 /* This is boot partition */
1654 device->stage.tag = V_BOOT;
1655 pl->pl_src_name = stage2;
1656 pl->pl_type = IB_BBLK_STAGE2;
1657 pl->pl_cb.compare = compare_einfo_cb;
1658 pl->pl_cb.install = install_stage2_cb;
1659 pl->pl_cb.read = read_stage2_cb;
1660 pl->pl_cb.read_bbl = read_stage2_file_cb;
1661 pl->pl_cb.print = print_einfo_cb;
1662 STAILQ_INSERT_TAIL(data->plist, pl, pl_next);
1663
1664 return (true);
1665 }
1666
1667 static bool
probe_device(ib_data_t * data,const char * dev)1668 probe_device(ib_data_t *data, const char *dev)
1669 {
1670 struct partlist *pl;
1671 struct stat sb;
1672 const char *ptr;
1673 char *p0;
1674 int fd, len;
1675
1676 if (dev == NULL)
1677 return (NULL);
1678
1679 len = strlen(dev);
1680
1681 if ((pl = partlist_alloc()) == NULL)
1682 return (false);
1683
1684 if (stat(dev, &sb) == -1) {
1685 perror("stat");
1686 partlist_free(pl);
1687 return (false);
1688 }
1689
1690 /* We have regular file, register it and we are done. */
1691 if (S_ISREG(sb.st_mode) != 0) {
1692 pl->pl_devname = (char *)dev;
1693
1694 pl->pl_type = IB_BBLK_FILE;
1695 pl->pl_cb.read = read_einfo_file_cb;
1696 pl->pl_cb.print = print_einfo_cb;
1697 STAILQ_INSERT_TAIL(data->plist, pl, pl_next);
1698 return (true);
1699 }
1700
1701 /*
1702 * This is block device.
1703 * We do not allow to specify whole disk device (cXtYdZp0 or cXtYdZ).
1704 */
1705 if ((ptr = strrchr(dev, '/')) == NULL)
1706 ptr = dev;
1707 if ((strrchr(ptr, 'p') == NULL && strrchr(ptr, 's') == NULL) ||
1708 (dev[len - 2] == 'p' && dev[len - 1] == '0')) {
1709 (void) fprintf(stderr,
1710 gettext("whole disk device is not supported\n"));
1711 partlist_free(pl);
1712 return (false);
1713 }
1714
1715 data->target.path = (char *)dev;
1716 if (!probe_fstyp(data)) {
1717 partlist_free(pl);
1718 return (false);
1719 }
1720
1721 /* We start from identifying the whole disk. */
1722 if ((p0 = strdup(dev)) == NULL) {
1723 perror("calloc");
1724 partlist_free(pl);
1725 return (false);
1726 }
1727
1728 pl->pl_devname = p0;
1729 /* Change device name to p0 */
1730 if ((ptr = strrchr(p0, 'p')) == NULL)
1731 ptr = strrchr(p0, 's');
1732 p0 = (char *)ptr;
1733 p0[0] = 'p';
1734 p0[1] = '0';
1735 p0[2] = '\0';
1736
1737 if ((fd = open_device(pl->pl_devname)) == -1) {
1738 partlist_free(pl);
1739 return (false);
1740 }
1741
1742 sector_size = get_media_info(fd);
1743 (void) close(fd);
1744
1745 pl->pl_src_name = stage1;
1746 pl->pl_type = IB_BBLK_MBR;
1747 pl->pl_cb.compare = compare_mbr_cb;
1748 pl->pl_cb.install = install_stage1_cb;
1749 pl->pl_cb.read = read_stage1_cb;
1750 pl->pl_cb.read_bbl = read_stage1_bbl_cb;
1751 pl->pl_cb.print = print_stage1_cb;
1752 STAILQ_INSERT_TAIL(data->plist, pl, pl_next);
1753
1754 if (probe_gpt(data))
1755 return (true);
1756
1757 if (data->device.devtype == IB_DEV_UNKNOWN)
1758 if (probe_vtoc(data))
1759 return (true);
1760
1761 if (data->device.devtype == IB_DEV_UNKNOWN)
1762 return (probe_mbr(data));
1763
1764 return (false);
1765 }
1766
1767 static int
read_bootblock_from_file(const char * file,ib_bootblock_t * bblock)1768 read_bootblock_from_file(const char *file, ib_bootblock_t *bblock)
1769 {
1770 struct stat sb;
1771 uint32_t buf_size;
1772 uint32_t mboot_off;
1773 int fd = -1;
1774 int retval = BC_ERROR;
1775
1776 assert(bblock != NULL);
1777 assert(file != NULL);
1778
1779 fd = open(file, O_RDONLY);
1780 if (fd == -1) {
1781 BOOT_DEBUG("Error opening %s\n", file);
1782 goto out;
1783 }
1784
1785 if (fstat(fd, &sb) == -1) {
1786 BOOT_DEBUG("Error getting information (stat) about %s", file);
1787 perror("stat");
1788 goto outfd;
1789 }
1790
1791 /* loader bootblock has version built in */
1792 buf_size = sb.st_size;
1793 if (buf_size == 0)
1794 goto outfd;
1795
1796 bblock->buf_size = buf_size;
1797 BOOT_DEBUG("bootblock in-memory buffer size is %d\n",
1798 bblock->buf_size);
1799
1800 bblock->buf = malloc(buf_size);
1801 if (bblock->buf == NULL) {
1802 perror(gettext("Memory allocation failure"));
1803 goto outbuf;
1804 }
1805 bblock->file = bblock->buf;
1806
1807 if (read(fd, bblock->file, bblock->buf_size) != bblock->buf_size) {
1808 BOOT_DEBUG("Read from %s failed\n", file);
1809 perror("read");
1810 goto outfd;
1811 }
1812
1813 buf_size = MIN(buf_size, MBOOT_SCAN_SIZE);
1814 if (find_multiboot(bblock->file, buf_size, &mboot_off)
1815 != BC_SUCCESS) {
1816 (void) fprintf(stderr,
1817 gettext("Unable to find multiboot header\n"));
1818 goto outfd;
1819 }
1820
1821 bblock->mboot = (multiboot_header_t *)(bblock->file + mboot_off);
1822 bblock->mboot_off = mboot_off;
1823
1824 bblock->file_size =
1825 bblock->mboot->load_end_addr - bblock->mboot->load_addr;
1826 BOOT_DEBUG("bootblock file size is %d\n", bblock->file_size);
1827
1828 bblock->extra = bblock->buf + P2ROUNDUP(bblock->file_size, 8);
1829 bblock->extra_size = bblock->buf_size - P2ROUNDUP(bblock->file_size, 8);
1830
1831 BOOT_DEBUG("mboot at %p offset %d, extra at %p size %d, buf=%p "
1832 "(size=%d)\n", bblock->mboot, bblock->mboot_off, bblock->extra,
1833 bblock->extra_size, bblock->buf, bblock->buf_size);
1834
1835 (void) close(fd);
1836 return (BC_SUCCESS);
1837
1838 outbuf:
1839 (void) free(bblock->buf);
1840 bblock->buf = NULL;
1841 outfd:
1842 (void) close(fd);
1843 out:
1844 if (retval == BC_ERROR) {
1845 (void) fprintf(stderr,
1846 gettext("Error reading bootblock from %s\n"),
1847 file);
1848 }
1849
1850 if (retval == BC_NOEXTRA) {
1851 BOOT_DEBUG("No multiboot header found on %s, unable to "
1852 "locate extra information area (old/non versioned "
1853 "bootblock?) \n", file);
1854 (void) fprintf(stderr, gettext("No extended information"
1855 " found\n"));
1856 }
1857 return (retval);
1858 }
1859
1860 static void
add_bootblock_einfo(ib_bootblock_t * bblock,char * updt_str)1861 add_bootblock_einfo(ib_bootblock_t *bblock, char *updt_str)
1862 {
1863 bblk_hs_t hs;
1864 uint32_t avail_space;
1865
1866 assert(bblock != NULL);
1867
1868 if (updt_str == NULL) {
1869 BOOT_DEBUG("WARNING: no update string passed to "
1870 "add_bootblock_einfo()\n");
1871 return;
1872 }
1873
1874 /* Fill bootblock hashing source information. */
1875 hs.src_buf = (unsigned char *)bblock->file;
1876 hs.src_size = bblock->file_size;
1877 /* How much space for the extended information structure? */
1878 avail_space = bblock->buf_size - P2ROUNDUP(bblock->file_size, 8);
1879 /* Place the extended information structure. */
1880 add_einfo(bblock->extra, updt_str, &hs, avail_space);
1881 }
1882
1883 /*
1884 * set up data for case stage1 is installed as MBR
1885 * set up location and size of bootblock
1886 * set disk guid to provide unique information for biosdev command
1887 */
1888 static void
prepare_stage1(struct partlist * stage1,struct partlist * stage2,uuid_t uuid)1889 prepare_stage1(struct partlist *stage1, struct partlist *stage2, uuid_t uuid)
1890 {
1891 char *src, *dest;
1892 ib_bootblock_t *bblk;
1893 ib_device_t *device;
1894 uint16_t size;
1895 struct mboot *mbr;
1896
1897 src = stage1->pl_stage;
1898 dest = stage1->pl_src_data;
1899 device = stage2->pl_device;
1900
1901 /* Only copy from valid source. */
1902 mbr = stage1->pl_stage;
1903 if (mbr->signature == MBB_MAGIC) {
1904 /* copy BPB */
1905 bcopy(src + STAGE1_BPB_OFFSET, dest + STAGE1_BPB_OFFSET,
1906 STAGE1_BPB_SIZE);
1907
1908 /* copy MBR, note STAGE1_SIG == BOOTSZ */
1909 bcopy(src + STAGE1_SIG, dest + STAGE1_SIG,
1910 SECTOR_SIZE - STAGE1_SIG);
1911 }
1912
1913 bcopy(uuid, dest + STAGE1_STAGE2_UUID, UUID_LEN);
1914
1915 /* set stage2 size */
1916 bblk = stage2->pl_src_data;
1917 size = bblk->buf_size / SECTOR_SIZE;
1918 *((uint16_t *)(dest + STAGE1_STAGE2_SIZE)) = size;
1919
1920 /* set stage2 LBA */
1921 *((uint64_t *)(dest + STAGE1_STAGE2_LBA)) =
1922 device->stage.start + device->stage.offset;
1923
1924 /* Copy prepared data to stage1 block read from the disk. */
1925 bcopy(dest, src, SECTOR_SIZE);
1926 }
1927
1928 static void
prepare_bootblock(ib_data_t * data,struct partlist * pl,char * updt_str)1929 prepare_bootblock(ib_data_t *data, struct partlist *pl, char *updt_str)
1930 {
1931 ib_bootblock_t *bblock;
1932 uint64_t *ptr;
1933
1934 assert(pl != NULL);
1935
1936 bblock = pl->pl_src_data;
1937 if (bblock == NULL)
1938 return;
1939
1940 ptr = (uint64_t *)(&bblock->mboot->bss_end_addr);
1941 *ptr = data->target.start;
1942
1943 /*
1944 * the loader bootblock has built in version, if custom
1945 * version was provided, update it.
1946 */
1947 if (do_version)
1948 add_bootblock_einfo(bblock, updt_str);
1949 }
1950
1951 static int
open_device(const char * path)1952 open_device(const char *path)
1953 {
1954 struct stat statbuf = {0};
1955 int fd = -1;
1956
1957 if (nowrite)
1958 fd = open(path, O_RDONLY);
1959 else
1960 fd = open(path, O_RDWR);
1961
1962 if (fd == -1) {
1963 BOOT_DEBUG("Unable to open %s\n", path);
1964 perror("open");
1965 return (-1);
1966 }
1967
1968 if (fstat(fd, &statbuf) != 0) {
1969 BOOT_DEBUG("Unable to stat %s\n", path);
1970 perror("stat");
1971 (void) close(fd);
1972 return (-1);
1973 }
1974
1975 if (S_ISCHR(statbuf.st_mode) == 0) {
1976 (void) fprintf(stderr, gettext("%s: Not a character device\n"),
1977 path);
1978 (void) close(fd);
1979 return (-1);
1980 }
1981
1982 return (fd);
1983 }
1984
1985 /*
1986 * We need to record stage2 location and size into pmbr/vbr.
1987 * We need to record target partiton LBA to stage2.
1988 */
1989 static void
prepare_bblocks(ib_data_t * data)1990 prepare_bblocks(ib_data_t *data)
1991 {
1992 struct partlist *pl;
1993 struct partlist *mbr, *stage1, *stage2;
1994 uuid_t uuid;
1995
1996 /*
1997 * Create disk uuid. We only need reasonable amount of uniqueness
1998 * to allow biosdev to identify disk based on mbr differences.
1999 */
2000 uuid_generate(uuid);
2001
2002 mbr = stage1 = stage2 = NULL;
2003
2004 /* First find stage 2. */
2005 STAILQ_FOREACH(pl, data->plist, pl_next) {
2006 if (pl->pl_type == IB_BBLK_STAGE2) {
2007 stage2 = pl;
2008
2009 /*
2010 * When stage2 needs update, make sure we also
2011 * update stage1.
2012 */
2013 if (pl->pl_cb.compare != NULL &&
2014 pl->pl_cb.compare(pl))
2015 write_vbr = true;
2016 break;
2017 }
2018 }
2019 /*
2020 * Walk list and pick up BIOS boot blocks. EFI boot programs
2021 * can be set in place.
2022 */
2023 STAILQ_FOREACH(pl, data->plist, pl_next) {
2024 switch (pl->pl_type) {
2025 case IB_BBLK_MBR:
2026 mbr = pl;
2027 break;
2028 case IB_BBLK_STAGE1:
2029 stage1 = pl;
2030 if (stage2 != NULL)
2031 prepare_stage1(stage1, stage2, uuid);
2032 break;
2033 case IB_BBLK_STAGE2:
2034 case IB_BBLK_EFI:
2035 prepare_bootblock(data, pl, update_str);
2036 break;
2037 default:
2038 break;
2039 }
2040 }
2041
2042 /* If stage2 is missing, we are done. */
2043 if (stage2 == NULL)
2044 return;
2045
2046 if (mbr != NULL) {
2047 prepare_stage1(mbr, stage2, uuid);
2048
2049 /*
2050 * If we have stage1, we point MBR to read stage 1.
2051 */
2052 if (stage1 != NULL) {
2053 char *dest = mbr->pl_stage;
2054
2055 *((uint16_t *)(dest + STAGE1_STAGE2_SIZE)) = 1;
2056 *((uint64_t *)(dest + STAGE1_STAGE2_LBA)) =
2057 stage1->pl_device->stage.start;
2058 }
2059 }
2060 }
2061
2062 /*
2063 * Install a new bootblock on the given device. handle_install() expects argv
2064 * to contain 3 parameters (the target device path and the path to the
2065 * bootblock.
2066 *
2067 * Returns: BC_SUCCESS - if the installation is successful
2068 * BC_ERROR - if the installation failed
2069 * BC_NOUPDT - if no installation was performed because the
2070 * version currently installed is more recent than the
2071 * supplied one.
2072 *
2073 */
2074 static int
handle_install(char * progname,int argc,char ** argv)2075 handle_install(char *progname, int argc, char **argv)
2076 {
2077 struct partlist *pl;
2078 ib_data_t data = { 0 };
2079 char *device_path = NULL;
2080 int ret = BC_ERROR;
2081
2082 switch (argc) {
2083 case 1:
2084 if ((device_path = strdup(argv[0])) == NULL) {
2085 perror(gettext("Memory Allocation Failure"));
2086 goto done;
2087 }
2088 if (asprintf(&stage1, "%s/%s", boot_dir, STAGE1) < 0) {
2089 perror(gettext("Memory Allocation Failure"));
2090 goto done;
2091 }
2092 if (asprintf(&stage2, "%s/%s", boot_dir, STAGE2) < 0) {
2093 perror(gettext("Memory Allocation Failure"));
2094 goto done;
2095 }
2096 if (asprintf(&efi32, "%s/%s", boot_dir, LOADER32) < 0) {
2097 perror(gettext("Memory Allocation Failure"));
2098 goto done;
2099 }
2100 if (asprintf(&efi64, "%s/%s", boot_dir, LOADER64) < 0) {
2101 perror(gettext("Memory Allocation Failure"));
2102 goto done;
2103 }
2104 break;
2105 case 3:
2106 if ((stage1 = strdup(argv[0])) == NULL) {
2107 perror(gettext("Memory Allocation Failure"));
2108 goto done;
2109 }
2110 if ((stage2 = strdup(argv[1])) == NULL) {
2111 perror(gettext("Memory Allocation Failure"));
2112 goto done;
2113 }
2114 if ((device_path = strdup(argv[2])) == NULL) {
2115 perror(gettext("Memory Allocation Failure"));
2116 goto done;
2117 }
2118 if (asprintf(&efi32, "%s/%s", boot_dir, LOADER32) < 0) {
2119 perror(gettext("Memory Allocation Failure"));
2120 goto done;
2121 }
2122 if (asprintf(&efi64, "%s/%s", boot_dir, LOADER64) < 0) {
2123 perror(gettext("Memory Allocation Failure"));
2124 goto done;
2125 }
2126 break;
2127 default:
2128 usage(progname, ret);
2129 }
2130
2131 data.plist = malloc(sizeof (*data.plist));
2132 if (data.plist == NULL) {
2133 perror(gettext("Memory Allocation Failure"));
2134 goto done;
2135 }
2136 STAILQ_INIT(data.plist);
2137
2138 BOOT_DEBUG("device path: %s, stage1 path: %s bootblock path: %s\n",
2139 device_path, stage1, stage2);
2140
2141 if (probe_device(&data, device_path)) {
2142 /* Read all data. */
2143 STAILQ_FOREACH(pl, data.plist, pl_next) {
2144 if (!pl->pl_cb.read(pl)) {
2145 printf("\n");
2146 }
2147 if (!pl->pl_cb.read_bbl(pl)) {
2148 /*
2149 * We will ignore ESP updates in case of
2150 * older system where we are missing
2151 * loader64.efi and loader32.efi.
2152 */
2153 if (pl->pl_type != IB_BBLK_EFI)
2154 goto cleanup;
2155 }
2156 }
2157
2158 /* Prepare data. */
2159 prepare_bblocks(&data);
2160
2161 /* Commit data to disk. */
2162 while ((pl = STAILQ_LAST(data.plist, partlist, pl_next)) !=
2163 NULL) {
2164 if (pl->pl_cb.compare != NULL &&
2165 pl->pl_cb.compare(pl)) {
2166 if (pl->pl_cb.install != NULL)
2167 pl->pl_cb.install(&data, pl);
2168 }
2169 STAILQ_REMOVE(data.plist, pl, partlist, pl_next);
2170 partlist_free(pl);
2171 }
2172 }
2173 ret = BC_SUCCESS;
2174
2175 cleanup:
2176 while ((pl = STAILQ_LAST(data.plist, partlist, pl_next)) != NULL) {
2177 STAILQ_REMOVE(data.plist, pl, partlist, pl_next);
2178 partlist_free(pl);
2179 }
2180 free(data.plist);
2181 done:
2182 free(stage1);
2183 free(stage2);
2184 free(efi32);
2185 free(efi64);
2186 free(device_path);
2187 return (ret);
2188 }
2189
2190 /*
2191 * Retrieves from a device the extended information (einfo) associated to the
2192 * file or installed stage2.
2193 * Expects one parameter, the device path, in the form: /dev/rdsk/c?[t?]d?s0
2194 * or file name.
2195 * Returns:
2196 * - BC_SUCCESS (and prints out einfo contents depending on 'flags')
2197 * - BC_ERROR (on error)
2198 * - BC_NOEINFO (no extended information available)
2199 */
2200 static int
handle_getinfo(char * progname,int argc,char ** argv)2201 handle_getinfo(char *progname, int argc, char **argv)
2202 {
2203 struct partlist *pl;
2204 ib_data_t data = { 0 };
2205 char *device_path;
2206
2207 if (argc != 1) {
2208 (void) fprintf(stderr, gettext("Missing parameter"));
2209 usage(progname, BC_ERROR);
2210 }
2211
2212 if ((device_path = strdup(argv[0])) == NULL) {
2213 perror(gettext("Memory Allocation Failure"));
2214 return (BC_ERROR);
2215 }
2216
2217 data.plist = malloc(sizeof (*data.plist));
2218 if (data.plist == NULL) {
2219 perror("malloc");
2220 free(device_path);
2221 return (BC_ERROR);
2222 }
2223 STAILQ_INIT(data.plist);
2224
2225 if (probe_device(&data, device_path)) {
2226 STAILQ_FOREACH(pl, data.plist, pl_next) {
2227 if (pl->pl_cb.read(pl))
2228 pl->pl_cb.print(pl);
2229 else
2230 printf("\n");
2231 }
2232 }
2233
2234 while ((pl = STAILQ_LAST(data.plist, partlist, pl_next)) != NULL) {
2235 STAILQ_REMOVE(data.plist, pl, partlist, pl_next);
2236 partlist_free(pl);
2237 }
2238 free(data.plist);
2239
2240 return (BC_SUCCESS);
2241 }
2242
2243 /*
2244 * Attempt to mirror (propagate) the current bootblock over the attaching disk.
2245 *
2246 * Returns:
2247 * - BC_SUCCESS (a successful propagation happened)
2248 * - BC_ERROR (an error occurred)
2249 * - BC_NOEXTRA (it is not possible to dump the current bootblock since
2250 * there is no multiboot information)
2251 */
2252 static int
handle_mirror(char * progname,int argc,char ** argv)2253 handle_mirror(char *progname, int argc, char **argv)
2254 {
2255 ib_data_t src = { 0 };
2256 ib_data_t dest = { 0 };
2257 struct partlist *pl_src, *pl_dest;
2258 char *curr_device_path = NULL;
2259 char *attach_device_path = NULL;
2260 int retval = BC_ERROR;
2261
2262 if (argc == 2) {
2263 curr_device_path = strdup(argv[0]);
2264 attach_device_path = strdup(argv[1]);
2265 }
2266
2267 if (!curr_device_path || !attach_device_path) {
2268 free(curr_device_path);
2269 free(attach_device_path);
2270 (void) fprintf(stderr, gettext("Missing parameter"));
2271 usage(progname, BC_ERROR);
2272 }
2273 BOOT_DEBUG("Current device path is: %s, attaching device path is: "
2274 " %s\n", curr_device_path, attach_device_path);
2275
2276 src.plist = malloc(sizeof (*src.plist));
2277 if (src.plist == NULL) {
2278 perror("malloc");
2279 return (BC_ERROR);
2280 }
2281 STAILQ_INIT(src.plist);
2282
2283 dest.plist = malloc(sizeof (*dest.plist));
2284 if (dest.plist == NULL) {
2285 perror("malloc");
2286 goto out;
2287 }
2288 STAILQ_INIT(dest.plist);
2289
2290 if (!probe_device(&src, curr_device_path)) {
2291 (void) fprintf(stderr, gettext("Unable to gather device "
2292 "information from %s (current device)\n"),
2293 curr_device_path);
2294 goto out;
2295 }
2296
2297 if (!probe_device(&dest, attach_device_path) != BC_SUCCESS) {
2298 (void) fprintf(stderr, gettext("Unable to gather device "
2299 "information from %s (attaching device)\n"),
2300 attach_device_path);
2301 goto cleanup_src;
2302 }
2303
2304 write_vbr = true;
2305 write_mbr = true;
2306 force_mbr = true;
2307
2308 pl_dest = STAILQ_FIRST(dest.plist);
2309 STAILQ_FOREACH(pl_src, src.plist, pl_next) {
2310 if (pl_dest == NULL) {
2311 (void) fprintf(stderr,
2312 gettext("Destination disk layout is different "
2313 "from source, can not mirror.\n"));
2314 goto cleanup;
2315 }
2316 if (!pl_src->pl_cb.read(pl_src)) {
2317 (void) fprintf(stderr, gettext("Failed to read "
2318 "boot block from %s\n"), pl_src->pl_devname);
2319 goto cleanup;
2320 }
2321 if (!pl_dest->pl_cb.read(pl_dest)) {
2322 (void) fprintf(stderr, gettext("Failed to read "
2323 "boot block from %s\n"), pl_dest->pl_devname);
2324 }
2325
2326 /* Set source pl_stage to destination source data */
2327 pl_dest->pl_src_data = pl_src->pl_stage;
2328 pl_src->pl_stage = NULL;
2329
2330 pl_dest = STAILQ_NEXT(pl_dest, pl_next);
2331 }
2332
2333 /* Prepare data. */
2334 prepare_bblocks(&dest);
2335
2336 /* Commit data to disk. */
2337 while ((pl_dest = STAILQ_LAST(dest.plist, partlist, pl_next)) != NULL) {
2338 pl_dest->pl_cb.install(&dest, pl_dest);
2339 STAILQ_REMOVE(dest.plist, pl_dest, partlist, pl_next);
2340 partlist_free(pl_dest);
2341
2342 /* Free source list */
2343 pl_src = STAILQ_LAST(src.plist, partlist, pl_next);
2344 STAILQ_REMOVE(src.plist, pl_src, partlist, pl_next);
2345 partlist_free(pl_src);
2346 }
2347 retval = BC_SUCCESS;
2348
2349 cleanup:
2350 while ((pl_dest = STAILQ_LAST(dest.plist, partlist, pl_next)) != NULL) {
2351 STAILQ_REMOVE(dest.plist, pl_dest, partlist, pl_next);
2352 partlist_free(pl_dest);
2353 }
2354 free(dest.plist);
2355 cleanup_src:
2356 while ((pl_src = STAILQ_LAST(src.plist, partlist, pl_next)) != NULL) {
2357 STAILQ_REMOVE(src.plist, pl_src, partlist, pl_next);
2358 partlist_free(pl_src);
2359 }
2360 free(src.plist);
2361 out:
2362 free(curr_device_path);
2363 free(attach_device_path);
2364 return (retval);
2365 }
2366
2367 #define USAGE_STRING \
2368 "Usage:\t%s [-fFmn] [-b boot_dir] [-u verstr]\n" \
2369 "\t\t[stage1 stage2] raw-device\n" \
2370 "\t%s -M [-n] raw-device attach-raw-device\n" \
2371 "\t%s [-e|-V] -i raw-device | file\n"
2372
2373 #define CANON_USAGE_STR gettext(USAGE_STRING)
2374
2375 static void
usage(char * progname,int rc)2376 usage(char *progname, int rc)
2377 {
2378 (void) fprintf(stdout, CANON_USAGE_STR, progname, progname, progname);
2379 fini_yes();
2380 exit(rc);
2381 }
2382
2383 int
main(int argc,char ** argv)2384 main(int argc, char **argv)
2385 {
2386 int opt;
2387 int ret;
2388 char *progname;
2389 struct stat sb;
2390
2391 (void) setlocale(LC_ALL, "");
2392 (void) textdomain(TEXT_DOMAIN);
2393 if (init_yes() < 0)
2394 errx(BC_ERROR, gettext(ERR_MSG_INIT_YES), strerror(errno));
2395
2396 /* Needed for mount pcfs. */
2397 tzset();
2398
2399 /* Determine our name */
2400 progname = basename(argv[0]);
2401
2402 while ((opt = getopt(argc, argv, "b:deFfhiMmnu:V")) != EOF) {
2403 switch (opt) {
2404 case 'b':
2405 boot_dir = strdup(optarg);
2406 if (boot_dir == NULL) {
2407 err(BC_ERROR,
2408 gettext("Memory allocation failure"));
2409 }
2410 if (lstat(boot_dir, &sb) != 0) {
2411 err(BC_ERROR, boot_dir);
2412 }
2413 if (!S_ISDIR(sb.st_mode)) {
2414 errx(BC_ERROR, gettext("%s: not a directory"),
2415 boot_dir);
2416 }
2417 break;
2418 case 'd':
2419 boot_debug = true;
2420 break;
2421 case 'e':
2422 strip = true;
2423 break;
2424 case 'F':
2425 force_update = true;
2426 break;
2427 case 'f':
2428 force_mbr = true;
2429 break;
2430 case 'h':
2431 usage(progname, BC_SUCCESS);
2432 break;
2433 case 'i':
2434 do_getinfo = true;
2435 break;
2436 case 'M':
2437 do_mirror_bblk = true;
2438 break;
2439 case 'm':
2440 write_mbr = true;
2441 break;
2442 case 'n':
2443 nowrite = true;
2444 break;
2445 case 'u':
2446 do_version = true;
2447
2448 update_str = strdup(optarg);
2449 if (update_str == NULL) {
2450 perror(gettext("Memory allocation failure"));
2451 exit(BC_ERROR);
2452 }
2453 break;
2454 case 'V':
2455 verbose_dump = true;
2456 break;
2457 default:
2458 /* fall through to process non-optional args */
2459 break;
2460 }
2461 }
2462
2463 /* check arguments */
2464 check_options(progname);
2465
2466 if (nowrite)
2467 (void) fprintf(stdout, gettext("Dry run requested. Nothing will"
2468 " be written to disk.\n"));
2469
2470 if (do_getinfo) {
2471 ret = handle_getinfo(progname, argc - optind, argv + optind);
2472 } else if (do_mirror_bblk) {
2473 ret = handle_mirror(progname, argc - optind, argv + optind);
2474 } else {
2475 ret = handle_install(progname, argc - optind, argv + optind);
2476 }
2477 fini_yes();
2478 return (ret);
2479 }
2480
2481 #define MEANINGLESS_OPT gettext("%s specified but meaningless, ignoring\n")
2482 static void
check_options(char * progname)2483 check_options(char *progname)
2484 {
2485 if (do_getinfo && do_mirror_bblk) {
2486 (void) fprintf(stderr, gettext("Only one of -M and -i can be "
2487 "specified at the same time\n"));
2488 usage(progname, BC_ERROR);
2489 }
2490
2491 if (do_mirror_bblk) {
2492 /*
2493 * -u and -F may actually reflect a user intent that is not
2494 * correct with this command (mirror can be interpreted
2495 * "similar" to install. Emit a message and continue.
2496 * -e and -V have no meaning, be quiet here and only report the
2497 * incongruence if a debug output is requested.
2498 */
2499 if (do_version) {
2500 (void) fprintf(stderr, MEANINGLESS_OPT, "-u");
2501 do_version = false;
2502 }
2503 if (force_update) {
2504 (void) fprintf(stderr, MEANINGLESS_OPT, "-F");
2505 force_update = false;
2506 }
2507 if (strip || verbose_dump) {
2508 BOOT_DEBUG(MEANINGLESS_OPT, "-e|-V");
2509 strip = false;
2510 verbose_dump = false;
2511 }
2512 }
2513
2514 if ((strip || verbose_dump) && !do_getinfo)
2515 usage(progname, BC_ERROR);
2516
2517 if (do_getinfo) {
2518 if (write_mbr || force_mbr || do_version || force_update) {
2519 BOOT_DEBUG(MEANINGLESS_OPT, "-m|-f|-u|-F");
2520 write_mbr = force_mbr = do_version = false;
2521 force_update = false;
2522 }
2523 }
2524 }
2525