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) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2012 Milan Jurik. All rights reserved.
24 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
25 */
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <libgen.h>
30 #include <malloc.h>
31 #include <string.h>
32 #include <fcntl.h>
33 #include <unistd.h>
34 #include <strings.h>
35 #include <libintl.h>
36 #include <locale.h>
37 #include <errno.h>
38 #include <libfdisk.h>
39 #include <stdarg.h>
40 #include <assert.h>
41
42 #include <sys/mount.h>
43 #include <sys/mnttab.h>
44 #include <sys/dktp/fdisk.h>
45 #include <sys/dkio.h>
46 #include <sys/vtoc.h>
47 #include <sys/types.h>
48 #include <sys/stat.h>
49 #include <sys/multiboot.h>
50 #include <sys/sysmacros.h>
51 #include <sys/efi_partition.h>
52
53 #include <libnvpair.h>
54 #include <libfstyp.h>
55
56 #include "message.h"
57 #include "installgrub.h"
58 #include "./../common/bblk_einfo.h"
59 #include "./../common/boot_utils.h"
60 #include "./../common/mboot_extra.h"
61
62 #ifndef TEXT_DOMAIN
63 #define TEXT_DOMAIN "SUNW_OST_OSCMD"
64 #endif
65
66 /*
67 * Variables to track installgrub desired mode of operation.
68 * 'nowrite' and 'boot_debug' come from boot_common.h.
69 */
70 static boolean_t write_mbr = B_FALSE;
71 static boolean_t force_mbr = B_FALSE;
72 static boolean_t force_update = B_FALSE;
73 static boolean_t do_getinfo = B_FALSE;
74 static boolean_t do_version = B_FALSE;
75 static boolean_t do_mirror_bblk = B_FALSE;
76 static boolean_t strip = B_FALSE;
77 static boolean_t verbose_dump = B_FALSE;
78
79 /* Installing the bootblock is the default operation. */
80 static boolean_t do_install = B_TRUE;
81
82 /* Versioning string, if present. */
83 static char *update_str;
84
85 /*
86 * Temporary buffer to store the first 32K of data looking for a multiboot
87 * signature.
88 */
89 char mboot_scan[MBOOT_SCAN_SIZE];
90
91 /* Function prototypes. */
92 static void check_options(char *);
93 static int handle_install(char *, char **);
94 static int handle_mirror(char *, char **);
95 static int handle_getinfo(char *, char **);
96 static int commit_to_disk(ig_data_t *, char *);
97 static int init_device(ig_device_t *, char *path);
98 static void cleanup_device(ig_device_t *);
99 static void cleanup_stage2(ig_stage2_t *);
100 static int get_start_sector(ig_device_t *);
101 static int get_disk_fd(ig_device_t *device);
102 static int get_raw_partition_fd(ig_device_t *);
103 static char *get_raw_partition_path(ig_device_t *);
104 static boolean_t gather_stage2_from_dev(ig_data_t *);
105 static int propagate_bootblock(ig_data_t *, ig_data_t *, char *);
106 static int find_x86_bootpar(struct mboot *, int *, uint32_t *);
107 static int copy_stage2_to_pcfs(ig_data_t *);
108 static int write_stage2(ig_data_t *);
109 static int write_stage1(ig_data_t *);
110 static void usage(char *);
111 static int read_stage1_from_file(char *, ig_data_t *);
112 static int read_stage2_from_file(char *, ig_data_t *);
113 static int read_stage1_from_disk(int, char *);
114 static int read_stage2_from_disk(int, ig_stage2_t *, int);
115 static int prepare_stage1(ig_data_t *);
116 static int prepare_stage2(ig_data_t *, char *);
117 static void prepare_fake_multiboot(ig_stage2_t *);
118 static void add_stage2_einfo(ig_stage2_t *, char *updt_str);
119 static boolean_t is_update_necessary(ig_data_t *, char *);
120
121 extern int read_stage2_blocklist(int, unsigned int *);
122
123 int
main(int argc,char * argv[])124 main(int argc, char *argv[])
125 {
126 int opt;
127 int params = 3;
128 int ret;
129 char **handle_args;
130 char *progname;
131
132 (void) setlocale(LC_ALL, "");
133 (void) textdomain(TEXT_DOMAIN);
134
135 /*
136 * retro-compatibility: installing the bootblock is the default
137 * and there is no switch for it.
138 */
139 do_install = B_TRUE;
140
141 while ((opt = getopt(argc, argv, "dVMFfmneiu:")) != EOF) {
142 switch (opt) {
143 case 'm':
144 write_mbr = B_TRUE;
145 break;
146 case 'n':
147 nowrite = B_TRUE;
148 break;
149 case 'f':
150 force_mbr = B_TRUE;
151 break;
152 case 'i':
153 do_getinfo = B_TRUE;
154 do_install = B_FALSE;
155 params = 1;
156 break;
157 case 'V':
158 verbose_dump = B_TRUE;
159 break;
160 case 'd':
161 boot_debug = B_TRUE;
162 break;
163 case 'F':
164 force_update = B_TRUE;
165 break;
166 case 'e':
167 strip = B_TRUE;
168 break;
169 case 'M':
170 do_mirror_bblk = B_TRUE;
171 do_install = B_FALSE;
172 params = 2;
173 break;
174 case 'u':
175 do_version = B_TRUE;
176
177 update_str = malloc(strlen(optarg) + 1);
178 if (update_str == NULL) {
179 (void) fprintf(stderr, gettext("Unable to "
180 "allocate memory\n"));
181 exit(BC_ERROR);
182 }
183 (void) strlcpy(update_str, optarg, strlen(optarg) + 1);
184 break;
185 default:
186 /* fall through to process non-optional args */
187 break;
188 }
189 }
190
191 /* check arguments */
192 if (argc != optind + params) {
193 usage(argv[0]);
194 exit(BC_ERROR);
195 }
196
197 /*
198 * clean up options (and bail out if an unrecoverable combination is
199 * requested.
200 */
201 progname = argv[0];
202 check_options(progname);
203 handle_args = argv + optind;
204
205 if (nowrite)
206 (void) fprintf(stdout, DRY_RUN);
207
208 if (do_getinfo) {
209 ret = handle_getinfo(progname, handle_args);
210 } else if (do_mirror_bblk) {
211 ret = handle_mirror(progname, handle_args);
212 } else {
213 ret = handle_install(progname, handle_args);
214 }
215 return (ret);
216 }
217
218 #define MEANINGLESS_OPT gettext("%s specified but meaningless, ignoring\n")
219 static void
check_options(char * progname)220 check_options(char *progname)
221 {
222 if (do_getinfo && do_mirror_bblk) {
223 (void) fprintf(stderr, gettext("Only one of -M and -i can be "
224 "specified at the same time\n"));
225 usage(progname);
226 exit(BC_ERROR);
227 }
228
229 if (do_mirror_bblk) {
230 /*
231 * -u and -F may actually reflect a user intent that is not
232 * correct with this command (mirror can be interpreted
233 * "similar" to install. Emit a message and continue.
234 * -e and -V have no meaning, be quiet here and only report the
235 * incongruence if a debug output is requested.
236 */
237 if (do_version) {
238 (void) fprintf(stderr, MEANINGLESS_OPT, "-u");
239 do_version = B_FALSE;
240 }
241 if (force_update) {
242 (void) fprintf(stderr, MEANINGLESS_OPT, "-F");
243 force_update = B_FALSE;
244 }
245 if (strip || verbose_dump) {
246 BOOT_DEBUG(MEANINGLESS_OPT, "-e|-V");
247 strip = B_FALSE;
248 verbose_dump = B_FALSE;
249 }
250 }
251
252 if (do_getinfo) {
253 if (write_mbr || force_mbr || do_version || force_update) {
254 BOOT_DEBUG(MEANINGLESS_OPT, "-m|-f|-u|-F");
255 write_mbr = force_mbr = do_version = B_FALSE;
256 force_update = B_FALSE;
257 }
258 }
259 }
260
261 /*
262 * Install a new stage1/stage2 pair on the specified device. handle_install()
263 * expects argv to contain 3 parameters (the path to stage1, the path to stage2,
264 * the target device).
265 *
266 * Returns: BC_SUCCESS - if the installation is successful
267 * BC_ERROR - if the installation failed
268 * BC_NOUPDT - if no installation was performed because the GRUB
269 * version currently installed is more recent than the
270 * supplied one.
271 *
272 */
273 static int
handle_install(char * progname,char ** argv)274 handle_install(char *progname, char **argv)
275 {
276 ig_data_t install_data;
277 char *stage1_path = NULL;
278 char *stage2_path = NULL;
279 char *device_path = NULL;
280 int ret = BC_ERROR;
281
282 stage1_path = strdup(argv[0]);
283 stage2_path = strdup(argv[1]);
284 device_path = strdup(argv[2]);
285
286 bzero(&install_data, sizeof (ig_data_t));
287
288 if (!stage1_path || !stage2_path || !device_path) {
289 (void) fprintf(stderr, gettext("Missing parameter"));
290 usage(progname);
291 goto out;
292 }
293
294 BOOT_DEBUG("stage1 path: %s, stage2 path: %s, device: %s\n",
295 stage1_path, stage2_path, device_path);
296
297 if (init_device(&install_data.device, device_path) != BC_SUCCESS) {
298 (void) fprintf(stderr, gettext("Unable to gather device "
299 "information for %s\n"), device_path);
300 goto out;
301 }
302
303 /* read in stage1 and stage2. */
304 if (read_stage1_from_file(stage1_path, &install_data) != BC_SUCCESS) {
305 (void) fprintf(stderr, gettext("Error opening %s\n"),
306 stage1_path);
307 goto out_dev;
308 }
309
310 if (read_stage2_from_file(stage2_path, &install_data) != BC_SUCCESS) {
311 (void) fprintf(stderr, gettext("Error opening %s\n"),
312 stage2_path);
313 goto out_dev;
314 }
315
316 /* We do not support versioning on PCFS. */
317 if (is_bootpar(install_data.device.type) && do_version)
318 do_version = B_FALSE;
319
320 /*
321 * is_update_necessary() will take care of checking if versioning and/or
322 * forcing the update have been specified. It will also emit a warning
323 * if a non-versioned update is attempted over a versioned bootblock.
324 */
325 if (!is_update_necessary(&install_data, update_str)) {
326 (void) fprintf(stderr, gettext("GRUB version installed "
327 "on %s is more recent or identical\n"
328 "Use -F to override or install without the -u option\n"),
329 device_path);
330 ret = BC_NOUPDT;
331 goto out_dev;
332 }
333 /*
334 * We get here if:
335 * - the installed GRUB version is older than the one about to be
336 * installed.
337 * - no versioning string has been passed through the command line.
338 * - a forced update is requested (-F).
339 */
340 BOOT_DEBUG("Ready to commit to disk\n");
341 ret = commit_to_disk(&install_data, update_str);
342
343 out_dev:
344 cleanup_device(&install_data.device);
345 out:
346 free(stage1_path);
347 free(stage2_path);
348 free(device_path);
349 return (ret);
350 }
351
352 /*
353 * Retrieves from a device the extended information (einfo) associated to the
354 * installed stage2.
355 * Expects one parameter, the device path, in the form: /dev/rdsk/c?[t?]d?s0.
356 * Returns:
357 * - BC_SUCCESS (and prints out einfo contents depending on 'flags')
358 * - BC_ERROR (on error)
359 * - BC_NOEINFO (no extended information available)
360 */
361 static int
handle_getinfo(char * progname,char ** argv)362 handle_getinfo(char *progname, char **argv)
363 {
364 ig_data_t data;
365 ig_stage2_t *stage2 = &data.stage2;
366 ig_device_t *device = &data.device;
367 bblk_einfo_t *einfo;
368 uint8_t flags = 0;
369 uint32_t size;
370 char *device_path;
371 int retval = BC_ERROR;
372 int ret;
373
374 device_path = strdup(argv[0]);
375 if (!device_path) {
376 (void) fprintf(stderr, gettext("Missing parameter"));
377 usage(progname);
378 goto out;
379 }
380
381 bzero(&data, sizeof (ig_data_t));
382 BOOT_DEBUG("device path: %s\n", device_path);
383
384 if (init_device(device, device_path) != BC_SUCCESS) {
385 (void) fprintf(stderr, gettext("Unable to gather device "
386 "information for %s\n"), device_path);
387 goto out_dev;
388 }
389
390 if (is_bootpar(device->type)) {
391 (void) fprintf(stderr, gettext("Versioning not supported on "
392 "PCFS\n"));
393 goto out_dev;
394 }
395
396 ret = read_stage2_from_disk(device->part_fd, stage2, device->type);
397 if (ret == BC_ERROR) {
398 (void) fprintf(stderr, gettext("Error reading stage2 from "
399 "%s\n"), device_path);
400 goto out_dev;
401 }
402
403 if (ret == BC_NOEXTRA) {
404 (void) fprintf(stdout, gettext("No multiboot header found on "
405 "%s, unable to locate extra information area\n"),
406 device_path);
407 retval = BC_NOEINFO;
408 goto out_dev;
409 }
410
411 einfo = find_einfo(stage2->extra, stage2->extra_size);
412 if (einfo == NULL) {
413 retval = BC_NOEINFO;
414 (void) fprintf(stderr, gettext("No extended information "
415 "found\n"));
416 goto out_dev;
417 }
418
419 /* Print the extended information. */
420 if (strip)
421 flags |= EINFO_EASY_PARSE;
422 if (verbose_dump)
423 flags |= EINFO_PRINT_HEADER;
424
425 size = stage2->buf_size - P2ROUNDUP(stage2->file_size, 8);
426 print_einfo(flags, einfo, size);
427 retval = BC_SUCCESS;
428
429 out_dev:
430 cleanup_device(&data.device);
431 out:
432 free(device_path);
433 return (retval);
434 }
435
436 /*
437 * Attempt to mirror (propagate) the current stage2 over the attaching disk.
438 *
439 * Returns:
440 * - BC_SUCCESS (a successful propagation happened)
441 * - BC_ERROR (an error occurred)
442 * - BC_NOEXTRA (it is not possible to dump the current bootblock since
443 * there is no multiboot information)
444 */
445 static int
handle_mirror(char * progname,char ** argv)446 handle_mirror(char *progname, char **argv)
447 {
448 ig_data_t curr_data;
449 ig_data_t attach_data;
450 ig_device_t *curr_device = &curr_data.device;
451 ig_device_t *attach_device = &attach_data.device;
452 ig_stage2_t *stage2_curr = &curr_data.stage2;
453 ig_stage2_t *stage2_attach = &attach_data.stage2;
454 bblk_einfo_t *einfo_curr = NULL;
455 char *curr_device_path;
456 char *attach_device_path;
457 char *updt_str = NULL;
458 int retval = BC_ERROR;
459 int ret;
460
461 curr_device_path = strdup(argv[0]);
462 attach_device_path = strdup(argv[1]);
463
464 if (!curr_device_path || !attach_device_path) {
465 (void) fprintf(stderr, gettext("Missing parameter"));
466 usage(progname);
467 goto out;
468 }
469 BOOT_DEBUG("Current device path is: %s, attaching device path is: "
470 " %s\n", curr_device_path, attach_device_path);
471
472 bzero(&curr_data, sizeof (ig_data_t));
473 bzero(&attach_data, sizeof (ig_data_t));
474
475 if (init_device(curr_device, curr_device_path) != BC_SUCCESS) {
476 (void) fprintf(stderr, gettext("Unable to gather device "
477 "information for %s (current device)\n"), curr_device_path);
478 goto out_currdev;
479 }
480
481 if (init_device(attach_device, attach_device_path) != BC_SUCCESS) {
482 (void) fprintf(stderr, gettext("Unable to gather device "
483 "information for %s (attaching device)\n"),
484 attach_device_path);
485 goto out_devs;
486 }
487
488 if (is_bootpar(curr_device->type) || is_bootpar(attach_device->type)) {
489 (void) fprintf(stderr, gettext("boot block mirroring is not "
490 "supported on PCFS\n"));
491 goto out_devs;
492 }
493
494 ret = read_stage2_from_disk(curr_device->part_fd, stage2_curr,
495 curr_device->type);
496 if (ret == BC_ERROR) {
497 BOOT_DEBUG("Error reading first stage2 blocks from %s\n",
498 curr_device->path);
499 retval = BC_ERROR;
500 goto out_devs;
501 }
502
503 if (ret == BC_NOEXTRA) {
504 BOOT_DEBUG("No multiboot header found on %s, unable to grab "
505 "stage2\n", curr_device->path);
506 retval = BC_NOEXTRA;
507 goto out_devs;
508 }
509
510 einfo_curr = find_einfo(stage2_curr->extra, stage2_curr->extra_size);
511 if (einfo_curr != NULL)
512 updt_str = einfo_get_string(einfo_curr);
513
514 write_mbr = B_TRUE;
515 force_mbr = B_TRUE;
516 retval = propagate_bootblock(&curr_data, &attach_data, updt_str);
517 cleanup_stage2(stage2_curr);
518 cleanup_stage2(stage2_attach);
519
520 out_devs:
521 cleanup_device(attach_device);
522 out_currdev:
523 cleanup_device(curr_device);
524 out:
525 free(curr_device_path);
526 free(attach_device_path);
527 return (retval);
528 }
529
530 static int
commit_to_disk(ig_data_t * install,char * updt_str)531 commit_to_disk(ig_data_t *install, char *updt_str)
532 {
533 assert(install != NULL);
534 /*
535 * vanilla stage1 and stage2 need to be updated at runtime.
536 * Update stage2 before stage1 because stage1 needs to know the first
537 * sector stage2 will be written to.
538 */
539 if (prepare_stage2(install, updt_str) != BC_SUCCESS) {
540 (void) fprintf(stderr, gettext("Error building stage2\n"));
541 return (BC_ERROR);
542 }
543 if (prepare_stage1(install) != BC_SUCCESS) {
544 (void) fprintf(stderr, gettext("Error building stage1\n"));
545 return (BC_ERROR);
546 }
547
548 /* Write stage2 out to disk. */
549 if (write_stage2(install) != BC_SUCCESS) {
550 (void) fprintf(stderr, gettext("Error writing stage2 to "
551 "disk\n"));
552 return (BC_ERROR);
553 }
554
555 /* Write stage1 to disk and, if requested, to the MBR. */
556 if (write_stage1(install) != BC_SUCCESS) {
557 (void) fprintf(stderr, gettext("Error writing stage1 to "
558 "disk\n"));
559 return (BC_ERROR);
560 }
561
562 return (BC_SUCCESS);
563 }
564
565 /*
566 * Propagate the bootblock on the source disk to the destination disk and
567 * version it with 'updt_str' in the process. Since we cannot trust any data
568 * on the attaching disk, we do not perform any specific check on a potential
569 * target extended information structure and we just blindly update.
570 */
571 static int
propagate_bootblock(ig_data_t * source,ig_data_t * target,char * updt_str)572 propagate_bootblock(ig_data_t *source, ig_data_t *target, char *updt_str)
573 {
574 ig_device_t *src_device = &source->device;
575 ig_device_t *dest_device = &target->device;
576 ig_stage2_t *src_stage2 = &source->stage2;
577 ig_stage2_t *dest_stage2 = &target->stage2;
578 uint32_t buf_size;
579 int retval;
580
581 assert(source != NULL);
582 assert(target != NULL);
583
584 /* read in stage1 from the source disk. */
585 if (read_stage1_from_disk(src_device->part_fd, target->stage1_buf)
586 != BC_SUCCESS)
587 return (BC_ERROR);
588
589 /* Prepare target stage2 for commit_to_disk. */
590 cleanup_stage2(dest_stage2);
591
592 if (updt_str != NULL)
593 do_version = B_TRUE;
594 else
595 do_version = B_FALSE;
596
597 buf_size = src_stage2->file_size + SECTOR_SIZE;
598
599 dest_stage2->buf_size = P2ROUNDUP(buf_size, SECTOR_SIZE);
600 dest_stage2->buf = malloc(dest_stage2->buf_size);
601 if (dest_stage2->buf == NULL) {
602 perror(gettext("Memory allocation failed"));
603 return (BC_ERROR);
604 }
605 dest_stage2->file = dest_stage2->buf;
606 dest_stage2->file_size = src_stage2->file_size;
607 memcpy(dest_stage2->file, src_stage2->file, dest_stage2->file_size);
608 dest_stage2->extra = dest_stage2->buf +
609 P2ROUNDUP(dest_stage2->file_size, 8);
610
611 /* If we get down here we do have a mboot structure. */
612 assert(src_stage2->mboot);
613
614 dest_stage2->mboot_off = src_stage2->mboot_off;
615 dest_stage2->mboot = (multiboot_header_t *)(dest_stage2->buf +
616 dest_stage2->mboot_off);
617
618 (void) fprintf(stdout, gettext("Propagating %s stage1/stage2 to %s\n"),
619 src_device->path, dest_device->path);
620 retval = commit_to_disk(target, updt_str);
621
622 return (retval);
623 }
624
625 /*
626 * open the device and fill the various members of ig_device_t.
627 */
628 static int
init_device(ig_device_t * device,char * path)629 init_device(ig_device_t *device, char *path)
630 {
631 struct dk_gpt *vtoc;
632 fstyp_handle_t fhdl;
633 const char *fident;
634
635 bzero(device, sizeof (*device));
636 device->part_fd = -1;
637 device->disk_fd = -1;
638 device->path_p0 = NULL;
639
640 device->path = strdup(path);
641 if (device->path == NULL) {
642 perror(gettext("Memory allocation failed"));
643 return (BC_ERROR);
644 }
645
646 if (strstr(device->path, "diskette")) {
647 (void) fprintf(stderr, gettext("installing GRUB to a floppy "
648 "disk is no longer supported\n"));
649 return (BC_ERROR);
650 }
651
652 /* Detect if the target device is a pcfs partition. */
653 if (strstr(device->path, "p0:boot"))
654 device->type = IG_DEV_X86BOOTPAR;
655
656 if (get_disk_fd(device) != BC_SUCCESS)
657 return (BC_ERROR);
658
659 /* read in the device boot sector. */
660 if (read(device->disk_fd, device->boot_sector, SECTOR_SIZE)
661 != SECTOR_SIZE) {
662 (void) fprintf(stderr, gettext("Error reading boot sector\n"));
663 perror("read");
664 return (BC_ERROR);
665 }
666
667 if (efi_alloc_and_read(device->disk_fd, &vtoc) > 0) {
668 device->type = IG_DEV_EFI;
669 efi_free(vtoc);
670 }
671
672 if (get_raw_partition_fd(device) != BC_SUCCESS)
673 return (BC_ERROR);
674
675 if (is_efi(device->type)) {
676 if (fstyp_init(device->part_fd, 0, NULL, &fhdl) != 0)
677 return (BC_ERROR);
678
679 if (fstyp_ident(fhdl, "zfs", &fident) != 0) {
680 fstyp_fini(fhdl);
681 (void) fprintf(stderr, gettext("Booting of EFI labeled "
682 "disks is only supported with ZFS\n"));
683 return (BC_ERROR);
684 }
685 fstyp_fini(fhdl);
686 }
687
688 if (get_start_sector(device) != BC_SUCCESS)
689 return (BC_ERROR);
690
691 return (BC_SUCCESS);
692 }
693
694 static void
cleanup_device(ig_device_t * device)695 cleanup_device(ig_device_t *device)
696 {
697 if (device->path)
698 free(device->path);
699 if (device->path_p0)
700 free(device->path_p0);
701
702 if (device->part_fd != -1)
703 (void) close(device->part_fd);
704 if (device->disk_fd != -1)
705 (void) close(device->disk_fd);
706
707 bzero(device, sizeof (ig_device_t));
708 device->part_fd = -1;
709 device->disk_fd = -1;
710 }
711
712 static void
cleanup_stage2(ig_stage2_t * stage2)713 cleanup_stage2(ig_stage2_t *stage2)
714 {
715 if (stage2->buf)
716 free(stage2->buf);
717 bzero(stage2, sizeof (ig_stage2_t));
718 }
719
720 static int
get_start_sector(ig_device_t * device)721 get_start_sector(ig_device_t *device)
722 {
723 uint32_t secnum = 0, numsec = 0;
724 int i, pno, rval, log_part = 0;
725 struct mboot *mboot;
726 struct ipart *part;
727 ext_part_t *epp;
728 struct part_info dkpi;
729 struct extpart_info edkpi;
730
731 if (is_efi(device->type)) {
732 struct dk_gpt *vtoc;
733
734 if (efi_alloc_and_read(device->disk_fd, &vtoc) <= 0)
735 return (BC_ERROR);
736
737 device->start_sector = vtoc->efi_parts[device->slice].p_start;
738 /* GPT doesn't use traditional slice letters */
739 device->slice = 0xff;
740 device->partition = 0;
741
742 efi_free(vtoc);
743 goto found_part;
744 }
745
746 mboot = (struct mboot *)device->boot_sector;
747
748 if (is_bootpar(device->type)) {
749 if (find_x86_bootpar(mboot, &pno, &secnum) != BC_SUCCESS) {
750 (void) fprintf(stderr, NOBOOTPAR);
751 return (BC_ERROR);
752 } else {
753 device->start_sector = secnum;
754 device->partition = pno;
755 goto found_part;
756 }
757 }
758
759 /*
760 * Search for Solaris fdisk partition
761 * Get the solaris partition information from the device
762 * and compare the offset of S2 with offset of solaris partition
763 * from fdisk partition table.
764 */
765 if (ioctl(device->part_fd, DKIOCEXTPARTINFO, &edkpi) < 0) {
766 if (ioctl(device->part_fd, DKIOCPARTINFO, &dkpi) < 0) {
767 (void) fprintf(stderr, PART_FAIL);
768 return (BC_ERROR);
769 } else {
770 edkpi.p_start = dkpi.p_start;
771 }
772 }
773
774 for (i = 0; i < FD_NUMPART; i++) {
775 part = (struct ipart *)mboot->parts + i;
776
777 if (part->relsect == 0) {
778 (void) fprintf(stderr, BAD_PART, i);
779 return (BC_ERROR);
780 }
781
782 if (edkpi.p_start >= part->relsect &&
783 edkpi.p_start < (part->relsect + part->numsect)) {
784 /* Found the partition */
785 break;
786 }
787 }
788
789 if (i == FD_NUMPART) {
790 /* No solaris fdisk partitions (primary or logical) */
791 (void) fprintf(stderr, NOSOLPAR);
792 return (BC_ERROR);
793 }
794
795 /*
796 * We have found a Solaris fdisk partition (primary or extended)
797 * Handle the simple case first: Solaris in a primary partition
798 */
799 if (!fdisk_is_dos_extended(part->systid)) {
800 device->start_sector = part->relsect;
801 device->partition = i;
802 goto found_part;
803 }
804
805 /*
806 * Solaris in a logical partition. Find that partition in the
807 * extended part.
808 */
809 if ((rval = libfdisk_init(&epp, device->path_p0, NULL, FDISK_READ_DISK))
810 != FDISK_SUCCESS) {
811 switch (rval) {
812 /*
813 * The first 3 cases are not an error per-se, just that
814 * there is no Solaris logical partition
815 */
816 case FDISK_EBADLOGDRIVE:
817 case FDISK_ENOLOGDRIVE:
818 case FDISK_EBADMAGIC:
819 (void) fprintf(stderr, NOSOLPAR);
820 return (BC_ERROR);
821 case FDISK_ENOVGEOM:
822 (void) fprintf(stderr, NO_VIRT_GEOM);
823 return (BC_ERROR);
824 case FDISK_ENOPGEOM:
825 (void) fprintf(stderr, NO_PHYS_GEOM);
826 return (BC_ERROR);
827 case FDISK_ENOLGEOM:
828 (void) fprintf(stderr, NO_LABEL_GEOM);
829 return (BC_ERROR);
830 default:
831 (void) fprintf(stderr, LIBFDISK_INIT_FAIL);
832 return (BC_ERROR);
833 }
834 }
835
836 rval = fdisk_get_solaris_part(epp, &pno, &secnum, &numsec);
837 libfdisk_fini(&epp);
838 if (rval != FDISK_SUCCESS) {
839 /* No solaris logical partition */
840 (void) fprintf(stderr, NOSOLPAR);
841 return (BC_ERROR);
842 }
843
844 device->start_sector = secnum;
845 device->partition = pno - 1;
846 log_part = 1;
847
848 found_part:
849 /* get confirmation for -m */
850 if (write_mbr && !force_mbr) {
851 (void) fprintf(stdout, MBOOT_PROMPT);
852 if (getchar() != 'y') {
853 write_mbr = 0;
854 (void) fprintf(stdout, MBOOT_NOT_UPDATED);
855 return (BC_ERROR);
856 }
857 }
858
859 /*
860 * Currently if Solaris is in an extended partition we need to
861 * write GRUB to the MBR. Check for this.
862 */
863 if (log_part && !write_mbr) {
864 (void) fprintf(stdout, gettext("Installing Solaris on an "
865 "extended partition... forcing MBR update\n"));
866 write_mbr = 1;
867 }
868
869 /*
870 * warn, if Solaris in primary partition and GRUB not in MBR and
871 * partition is not active
872 */
873 if (!log_part && part->bootid != 128 && !write_mbr) {
874 (void) fprintf(stdout, SOLPAR_INACTIVE, device->partition + 1);
875 }
876
877 return (BC_SUCCESS);
878 }
879
880 static int
get_disk_fd(ig_device_t * device)881 get_disk_fd(ig_device_t *device)
882 {
883 int i;
884 char save[2];
885 char *end = NULL;
886
887 assert(device != NULL);
888 assert(device->path != NULL);
889
890 if (is_bootpar(device->type)) {
891 end = strstr(device->path, "p0:boot");
892 /* tested at the start of init_device() */
893 assert(end != NULL);
894 /* chop off :boot */
895 save[0] = end[2];
896 end[2] = '\0';
897 } else {
898 i = strlen(device->path);
899 save[0] = device->path[i - 2];
900 save[1] = device->path[i - 1];
901 device->path[i - 2] = 'p';
902 device->path[i - 1] = '0';
903 }
904
905 if (nowrite)
906 device->disk_fd = open(device->path, O_RDONLY);
907 else
908 device->disk_fd = open(device->path, O_RDWR);
909
910 device->path_p0 = strdup(device->path);
911 if (device->path_p0 == NULL) {
912 perror("strdup");
913 return (BC_ERROR);
914 }
915
916 if (is_bootpar(device->type)) {
917 end[2] = save[0];
918 } else {
919 device->path[i - 2] = save[0];
920 device->path[i - 1] = save[1];
921 }
922
923 if (device->disk_fd == -1) {
924 perror("open");
925 return (BC_ERROR);
926 }
927
928 return (BC_SUCCESS);
929 }
930
931 static void
prepare_fake_multiboot(ig_stage2_t * stage2)932 prepare_fake_multiboot(ig_stage2_t *stage2)
933 {
934 multiboot_header_t *mboot;
935
936 assert(stage2 != NULL);
937 assert(stage2->mboot != NULL);
938 assert(stage2->buf != NULL);
939
940 mboot = stage2->mboot;
941
942 /*
943 * Currently we expect find_multiboot() to have located a multiboot
944 * header with the AOUT kludge flag set.
945 */
946 assert(mboot->flags & BB_MBOOT_AOUT_FLAG);
947
948 /* Insert the information necessary to locate stage2. */
949 mboot->header_addr = stage2->mboot_off;
950 mboot->load_addr = 0;
951 mboot->load_end_addr = stage2->file_size;
952 }
953
954 static void
add_stage2_einfo(ig_stage2_t * stage2,char * updt_str)955 add_stage2_einfo(ig_stage2_t *stage2, char *updt_str)
956 {
957 bblk_hs_t hs;
958 uint32_t avail_space;
959
960 assert(stage2 != NULL);
961
962 /* Fill bootblock hashing source information. */
963 hs.src_buf = (unsigned char *)stage2->file;
964 hs.src_size = stage2->file_size;
965 /* How much space for the extended information structure? */
966 avail_space = stage2->buf_size - P2ROUNDUP(stage2->file_size, 8);
967 add_einfo(stage2->extra, updt_str, &hs, avail_space);
968 }
969
970
971 static int
write_stage2(ig_data_t * install)972 write_stage2(ig_data_t *install)
973 {
974 ig_device_t *device = &install->device;
975 ig_stage2_t *stage2 = &install->stage2;
976 off_t offset;
977
978 assert(install != NULL);
979
980 if (is_bootpar(device->type)) {
981 /*
982 * stage2 is already on the filesystem, we only need to update
983 * the first two blocks (that we have modified during
984 * prepare_stage2())
985 */
986 if (write_out(device->part_fd, stage2->file, SECTOR_SIZE,
987 stage2->pcfs_first_sectors[0] * SECTOR_SIZE)
988 != BC_SUCCESS ||
989 write_out(device->part_fd, stage2->file + SECTOR_SIZE,
990 SECTOR_SIZE, stage2->pcfs_first_sectors[1] * SECTOR_SIZE)
991 != BC_SUCCESS) {
992 (void) fprintf(stderr, WRITE_FAIL_STAGE2);
993 return (BC_ERROR);
994 }
995 (void) fprintf(stdout, WRITE_STAGE2_PCFS);
996 return (BC_SUCCESS);
997 }
998
999 /*
1000 * For disk, write stage2 starting at STAGE2_BLKOFF sector.
1001 * Note that we use stage2->buf rather than stage2->file, because we
1002 * may have extended information after the latter.
1003 *
1004 * If we're writing to an EFI-labeled disk where stage2 lives in the
1005 * 3.5MB boot loader gap following the ZFS vdev labels, make sure the
1006 * size of the buffer doesn't exceed the size of the gap.
1007 */
1008 if (is_efi(device->type) && stage2->buf_size > STAGE2_MAXSIZE) {
1009 (void) fprintf(stderr, WRITE_FAIL_STAGE2);
1010 return (BC_ERROR);
1011 }
1012
1013 offset = STAGE2_BLKOFF(device->type) * SECTOR_SIZE;
1014
1015 if (write_out(device->part_fd, stage2->buf, stage2->buf_size,
1016 offset) != BC_SUCCESS) {
1017 perror("write");
1018 return (BC_ERROR);
1019 }
1020
1021 /* Simulate the "old" installgrub output. */
1022 (void) fprintf(stdout, WRITE_STAGE2_DISK, device->partition,
1023 (stage2->buf_size / SECTOR_SIZE) + 1, STAGE2_BLKOFF(device->type),
1024 stage2->first_sector);
1025
1026 return (BC_SUCCESS);
1027 }
1028
1029 static int
write_stage1(ig_data_t * install)1030 write_stage1(ig_data_t *install)
1031 {
1032 ig_device_t *device = &install->device;
1033
1034 assert(install != NULL);
1035
1036 if (write_out(device->part_fd, install->stage1_buf,
1037 sizeof (install->stage1_buf), 0) != BC_SUCCESS) {
1038 (void) fprintf(stdout, WRITE_FAIL_PBOOT);
1039 perror("write");
1040 return (BC_ERROR);
1041 }
1042
1043 /* Simulate "old" installgrub output. */
1044 (void) fprintf(stdout, WRITE_PBOOT, device->partition,
1045 device->start_sector);
1046
1047 if (write_mbr) {
1048 if (write_out(device->disk_fd, install->stage1_buf,
1049 sizeof (install->stage1_buf), 0) != BC_SUCCESS) {
1050 (void) fprintf(stdout, WRITE_FAIL_BOOTSEC);
1051 perror("write");
1052 return (BC_ERROR);
1053 }
1054 /* Simulate "old" installgrub output. */
1055 (void) fprintf(stdout, WRITE_MBOOT);
1056 }
1057
1058 return (BC_SUCCESS);
1059 }
1060
1061 #define USAGE_STRING "%s [-m|-f|-n|-F|-u verstr] stage1 stage2 device\n" \
1062 "%s -M [-n] device1 device2\n" \
1063 "%s [-V|-e] -i device\n" \
1064
1065 #define CANON_USAGE_STR gettext(USAGE_STRING)
1066
1067 static void
usage(char * progname)1068 usage(char *progname)
1069 {
1070 (void) fprintf(stdout, CANON_USAGE_STR, progname, progname, progname);
1071 }
1072
1073
1074 static int
read_stage1_from_file(char * path,ig_data_t * dest)1075 read_stage1_from_file(char *path, ig_data_t *dest)
1076 {
1077 int fd;
1078
1079 assert(dest);
1080
1081 /* read the stage1 file from filesystem */
1082 fd = open(path, O_RDONLY);
1083 if (fd == -1 ||
1084 read(fd, dest->stage1_buf, SECTOR_SIZE) != SECTOR_SIZE) {
1085 (void) fprintf(stderr, READ_FAIL_STAGE1, path);
1086 return (BC_ERROR);
1087 }
1088 (void) close(fd);
1089 return (BC_SUCCESS);
1090 }
1091
1092 static int
read_stage2_from_file(char * path,ig_data_t * dest)1093 read_stage2_from_file(char *path, ig_data_t *dest)
1094 {
1095 int fd;
1096 struct stat sb;
1097 ig_stage2_t *stage2 = &dest->stage2;
1098 ig_device_t *device = &dest->device;
1099 uint32_t buf_size;
1100
1101 assert(dest);
1102 assert(stage2->buf == NULL);
1103
1104 fd = open(path, O_RDONLY);
1105 if (fstat(fd, &sb) == -1) {
1106 perror("fstat");
1107 goto out;
1108 }
1109
1110 stage2->file_size = sb.st_size;
1111
1112 if (!is_bootpar(device->type)) {
1113 /*
1114 * buffer size needs to account for stage2 plus the extra
1115 * versioning information at the end of it. We reserve one
1116 * extra sector (plus we round up to the next sector boundary).
1117 */
1118 buf_size = stage2->file_size + SECTOR_SIZE;
1119 } else {
1120 /* In the PCFS case we only need to read in stage2. */
1121 buf_size = stage2->file_size;
1122 }
1123
1124 stage2->buf_size = P2ROUNDUP(buf_size, SECTOR_SIZE);
1125
1126 BOOT_DEBUG("stage2 buffer size = %d (%d sectors)\n", stage2->buf_size,
1127 stage2->buf_size / SECTOR_SIZE);
1128
1129 stage2->buf = malloc(stage2->buf_size);
1130 if (stage2->buf == NULL) {
1131 perror(gettext("Memory allocation failed"));
1132 goto out_fd;
1133 }
1134
1135 stage2->file = stage2->buf;
1136
1137 /*
1138 * Extra information (e.g. the versioning structure) is placed at the
1139 * end of stage2, aligned on a 8-byte boundary.
1140 */
1141 if (!(is_bootpar(device->type)))
1142 stage2->extra = stage2->file + P2ROUNDUP(stage2->file_size, 8);
1143
1144 if (lseek(fd, 0, SEEK_SET) == -1) {
1145 perror("lseek");
1146 goto out_alloc;
1147 }
1148
1149 if (read(fd, stage2->file, stage2->file_size) < 0) {
1150 perror(gettext("unable to read stage2"));
1151 goto out_alloc;
1152 }
1153
1154 (void) close(fd);
1155 return (BC_SUCCESS);
1156
1157 out_alloc:
1158 free(stage2->buf);
1159 stage2->buf = NULL;
1160 out_fd:
1161 (void) close(fd);
1162 out:
1163 return (BC_ERROR);
1164 }
1165
1166 static int
prepare_stage1(ig_data_t * install)1167 prepare_stage1(ig_data_t *install)
1168 {
1169 ig_device_t *device = &install->device;
1170
1171 assert(install != NULL);
1172
1173 /* If PCFS add the BIOS Parameter Block. */
1174 if (is_bootpar(device->type)) {
1175 char bpb_sect[SECTOR_SIZE];
1176
1177 if (pread(device->part_fd, bpb_sect, SECTOR_SIZE, 0)
1178 != SECTOR_SIZE) {
1179 (void) fprintf(stderr, READ_FAIL_BPB);
1180 return (BC_ERROR);
1181 }
1182 bcopy(bpb_sect + STAGE1_BPB_OFFSET,
1183 install->stage1_buf + STAGE1_BPB_OFFSET, STAGE1_BPB_SIZE);
1184 }
1185
1186 /* copy MBR to stage1 in case of overwriting MBR sector. */
1187 bcopy(device->boot_sector + BOOTSZ, install->stage1_buf + BOOTSZ,
1188 SECTOR_SIZE - BOOTSZ);
1189 /* modify default stage1 file generated by GRUB. */
1190 *((unsigned char *)(install->stage1_buf + STAGE1_FORCE_LBA)) = 1;
1191 *((ulong_t *)(install->stage1_buf + STAGE1_STAGE2_SECTOR))
1192 = install->stage2.first_sector;
1193 *((ushort_t *)(install->stage1_buf + STAGE1_STAGE2_ADDRESS))
1194 = STAGE2_MEMADDR;
1195 *((ushort_t *)(install->stage1_buf + STAGE1_STAGE2_SEGMENT))
1196 = STAGE2_MEMADDR >> 4;
1197
1198 return (BC_SUCCESS);
1199 }
1200
1201 /*
1202 * Grab stage1 from the specified device file descriptor.
1203 */
1204 static int
read_stage1_from_disk(int dev_fd,char * stage1_buf)1205 read_stage1_from_disk(int dev_fd, char *stage1_buf)
1206 {
1207 assert(stage1_buf != NULL);
1208
1209 if (read_in(dev_fd, stage1_buf, SECTOR_SIZE, 0) != BC_SUCCESS) {
1210 perror(gettext("Unable to read stage1 from disk"));
1211 return (BC_ERROR);
1212 }
1213 return (BC_SUCCESS);
1214 }
1215
1216 static int
read_stage2_from_disk(int dev_fd,ig_stage2_t * stage2,int type)1217 read_stage2_from_disk(int dev_fd, ig_stage2_t *stage2, int type)
1218 {
1219 uint32_t size;
1220 uint32_t buf_size;
1221 uint32_t mboot_off;
1222 multiboot_header_t *mboot;
1223
1224 assert(stage2 != NULL);
1225 assert(dev_fd != -1);
1226
1227 if (read_in(dev_fd, mboot_scan, sizeof (mboot_scan),
1228 STAGE2_BLKOFF(type) * SECTOR_SIZE) != BC_SUCCESS) {
1229 perror(gettext("Error reading stage2 sectors"));
1230 return (BC_ERROR);
1231 }
1232
1233 /* No multiboot means no chance of knowing stage2 size */
1234 if (find_multiboot(mboot_scan, sizeof (mboot_scan), &mboot_off)
1235 != BC_SUCCESS) {
1236 BOOT_DEBUG("Unable to find multiboot header\n");
1237 return (BC_NOEXTRA);
1238 }
1239 mboot = (multiboot_header_t *)(mboot_scan + mboot_off);
1240
1241 /*
1242 * Unfilled mboot values mean an older version of installgrub installed
1243 * the stage2. Again we have no chance of knowing stage2 size.
1244 */
1245 if (mboot->load_end_addr == 0 ||
1246 mboot->load_end_addr < mboot->load_addr)
1247 return (BC_NOEXTRA);
1248
1249 /*
1250 * Currently, the amount of space reserved for extra information
1251 * is "fixed". We may have to scan for the terminating extra payload
1252 * in the future.
1253 */
1254 size = mboot->load_end_addr - mboot->load_addr;
1255 buf_size = P2ROUNDUP(size + SECTOR_SIZE, SECTOR_SIZE);
1256
1257 stage2->buf = malloc(buf_size);
1258 if (stage2->buf == NULL) {
1259 perror(gettext("Memory allocation failed"));
1260 return (BC_ERROR);
1261 }
1262 stage2->buf_size = buf_size;
1263
1264 if (read_in(dev_fd, stage2->buf, buf_size, STAGE2_BLKOFF(type) *
1265 SECTOR_SIZE) != BC_SUCCESS) {
1266 perror("read");
1267 free(stage2->buf);
1268 return (BC_ERROR);
1269 }
1270
1271 /* Update pointers. */
1272 stage2->file = stage2->buf;
1273 stage2->file_size = size;
1274 stage2->mboot_off = mboot_off;
1275 stage2->mboot = (multiboot_header_t *)(stage2->buf + stage2->mboot_off);
1276 stage2->extra = stage2->buf + P2ROUNDUP(stage2->file_size, 8);
1277 stage2->extra_size = stage2->buf_size - P2ROUNDUP(stage2->file_size, 8);
1278
1279 return (BC_SUCCESS);
1280 }
1281
1282 static boolean_t
is_update_necessary(ig_data_t * data,char * updt_str)1283 is_update_necessary(ig_data_t *data, char *updt_str)
1284 {
1285 bblk_einfo_t *einfo;
1286 bblk_hs_t stage2_hs;
1287 ig_stage2_t stage2_disk;
1288 ig_stage2_t *stage2_file = &data->stage2;
1289 ig_device_t *device = &data->device;
1290 int dev_fd = device->part_fd;
1291
1292 assert(data != NULL);
1293 assert(device->part_fd != -1);
1294
1295 bzero(&stage2_disk, sizeof (ig_stage2_t));
1296
1297 /* Gather stage2 (if present) from the target device. */
1298 if (read_stage2_from_disk(dev_fd, &stage2_disk, device->type)
1299 != BC_SUCCESS) {
1300 BOOT_DEBUG("Unable to read stage2 from %s\n", device->path);
1301 BOOT_DEBUG("No multiboot wrapped stage2 on %s\n", device->path);
1302 return (B_TRUE);
1303 }
1304
1305 /*
1306 * Look for the extended information structure in the extra payload
1307 * area.
1308 */
1309 einfo = find_einfo(stage2_disk.extra, stage2_disk.extra_size);
1310 if (einfo == NULL) {
1311 BOOT_DEBUG("No extended information available\n");
1312 return (B_TRUE);
1313 }
1314
1315 if (!do_version || updt_str == NULL) {
1316 (void) fprintf(stdout, "WARNING: target device %s has a "
1317 "versioned stage2 that is going to be overwritten by a non "
1318 "versioned one\n", device->path);
1319 return (B_TRUE);
1320 }
1321
1322 if (force_update) {
1323 BOOT_DEBUG("Forcing update of %s bootblock\n", device->path);
1324 return (B_TRUE);
1325 }
1326
1327 /* Compare the two extended information structures. */
1328 stage2_hs.src_buf = (unsigned char *)stage2_file->file;
1329 stage2_hs.src_size = stage2_file->file_size;
1330
1331 return (einfo_should_update(einfo, &stage2_hs, updt_str));
1332 }
1333
1334
1335 #define START_BLOCK(pos) (*(ulong_t *)(pos))
1336 #define NUM_BLOCK(pos) (*(ushort_t *)((pos) + 4))
1337 #define START_SEG(pos) (*(ushort_t *)((pos) + 6))
1338
1339 static int
prepare_stage2(ig_data_t * install,char * updt_str)1340 prepare_stage2(ig_data_t *install, char *updt_str)
1341 {
1342 ig_device_t *device = &install->device;
1343 ig_stage2_t *stage2 = &install->stage2;
1344 uint32_t mboot_off = 0;
1345
1346 assert(install != NULL);
1347 assert(stage2->file != NULL);
1348
1349 /* New stage2 files come with an embedded stage2. */
1350 if (find_multiboot(stage2->file, stage2->file_size, &mboot_off)
1351 != BC_SUCCESS) {
1352 BOOT_DEBUG("WARNING: no multiboot structure found in stage2, "
1353 "are you using an old GRUB stage2?\n");
1354 if (do_version == B_TRUE) {
1355 (void) fprintf(stderr, gettext("Versioning requested "
1356 "but stage2 does not support it.. skipping.\n"));
1357 do_version = B_FALSE;
1358 }
1359 } else {
1360 /* Keep track of where the multiboot header is. */
1361 stage2->mboot_off = mboot_off;
1362 stage2->mboot = (multiboot_header_t *)(stage2->file +
1363 mboot_off);
1364 if (do_version) {
1365 /*
1366 * Adding stage2 information needs to happen before
1367 * we modify the copy of stage2 we have in memory, so
1368 * that the hashing reflects the one of the file.
1369 * An error here is not fatal.
1370 */
1371 add_stage2_einfo(stage2, updt_str);
1372 }
1373 /*
1374 * Fill multiboot information. We add them even without
1375 * versioning to support as much as possible mirroring.
1376 */
1377 prepare_fake_multiboot(stage2);
1378 }
1379
1380 if (is_bootpar(device->type)) {
1381 uint32_t blocklist[SECTOR_SIZE / sizeof (uint32_t)];
1382 uint32_t install_addr = STAGE2_MEMADDR + SECTOR_SIZE;
1383 int i = 0;
1384 uchar_t *pos;
1385
1386 bzero(blocklist, sizeof (blocklist));
1387 if (read_stage2_blocklist(device->part_fd, blocklist) != 0) {
1388 (void) fprintf(stderr, gettext("Error reading pcfs "
1389 "stage2 blocklist\n"));
1390 return (BC_ERROR);
1391 }
1392
1393 pos = (uchar_t *)stage2->file + STAGE2_BLOCKLIST;
1394 stage2->first_sector = device->start_sector + blocklist[0];
1395 stage2->pcfs_first_sectors[0] = blocklist[0];
1396 BOOT_DEBUG("stage2 first sector: %d\n", stage2->first_sector);
1397
1398
1399 if (blocklist[1] > 1) {
1400 blocklist[0]++;
1401 blocklist[1]--;
1402 } else {
1403 i += 2;
1404 }
1405
1406 stage2->pcfs_first_sectors[1] = blocklist[i];
1407
1408 while (blocklist[i]) {
1409 if (START_BLOCK(pos - 8) != 0 &&
1410 START_BLOCK(pos - 8) != blocklist[i + 2]) {
1411 (void) fprintf(stderr, PCFS_FRAGMENTED);
1412 return (BC_ERROR);
1413 }
1414 START_BLOCK(pos) = blocklist[i] + device->start_sector;
1415 START_SEG(pos) = (ushort_t)(install_addr >> 4);
1416 NUM_BLOCK(pos) = blocklist[i + 1];
1417 install_addr += blocklist[i + 1] * SECTOR_SIZE;
1418 pos -= 8;
1419 i += 2;
1420 }
1421 } else {
1422 /* Solaris VTOC */
1423 stage2->first_sector = device->start_sector +
1424 STAGE2_BLKOFF(device->type);
1425 BOOT_DEBUG("stage2 first sector: %d\n", stage2->first_sector);
1426 /*
1427 * In a solaris partition, stage2 is written to contiguous
1428 * blocks. So we update the starting block only.
1429 */
1430 *((ulong_t *)(stage2->file + STAGE2_BLOCKLIST)) =
1431 stage2->first_sector + 1;
1432 }
1433
1434 /* force lba and set disk partition */
1435 *((unsigned char *) (stage2->file + STAGE2_FORCE_LBA)) = 1;
1436 *((long *)(stage2->file + STAGE2_INSTALLPART))
1437 = (device->partition << 16) | (device->slice << 8) | 0xff;
1438
1439 return (BC_SUCCESS);
1440 }
1441
1442 static int
find_x86_bootpar(struct mboot * mboot,int * part_num,uint32_t * start_sect)1443 find_x86_bootpar(struct mboot *mboot, int *part_num, uint32_t *start_sect)
1444 {
1445 int i;
1446
1447 for (i = 0; i < FD_NUMPART; i++) {
1448 struct ipart *part;
1449
1450 part = (struct ipart *)mboot->parts + i;
1451 if (part->systid == 0xbe) {
1452 if (start_sect)
1453 *start_sect = part->relsect;
1454 if (part_num)
1455 *part_num = i;
1456 /* solaris boot part */
1457 return (BC_SUCCESS);
1458 }
1459 }
1460 return (BC_ERROR);
1461 }
1462
1463 static char *
get_raw_partition_path(ig_device_t * device)1464 get_raw_partition_path(ig_device_t *device)
1465 {
1466 char *raw;
1467 int len;
1468
1469 if (is_bootpar(device->type)) {
1470 int part;
1471 struct mboot *mboot;
1472
1473 mboot = (struct mboot *)device->boot_sector;
1474 if (find_x86_bootpar(mboot, &part, NULL) != BC_SUCCESS) {
1475 (void) fprintf(stderr, BOOTPAR_NOTFOUND,
1476 device->path_p0);
1477 return (NULL);
1478 }
1479
1480 raw = strdup(device->path_p0);
1481 if (raw == NULL) {
1482 perror(gettext("Memory allocation failed"));
1483 return (NULL);
1484 }
1485
1486 raw[strlen(raw) - 2] = '1' + part;
1487 return (raw);
1488 }
1489
1490 /* For disk, remember slice and return whole fdisk partition */
1491 raw = strdup(device->path);
1492 if (raw == NULL) {
1493 perror(gettext("Memory allocation failed"));
1494 return (NULL);
1495 }
1496
1497 len = strlen(raw);
1498 if (!is_efi(device->type) &&
1499 (raw[len - 2] != 's' || raw[len - 1] == '2')) {
1500 (void) fprintf(stderr, NOT_ROOT_SLICE);
1501 free(raw);
1502 return (NULL);
1503 }
1504 device->slice = atoi(&raw[len - 1]);
1505
1506 if (!is_efi(device->type)) {
1507 raw[len - 2] = 's';
1508 raw[len - 1] = '2';
1509 }
1510
1511 return (raw);
1512 }
1513
1514 static int
get_raw_partition_fd(ig_device_t * device)1515 get_raw_partition_fd(ig_device_t *device)
1516 {
1517 struct stat stat = {0};
1518 char *raw;
1519
1520 raw = get_raw_partition_path(device);
1521 if (raw == NULL)
1522 return (BC_ERROR);
1523
1524 if (nowrite)
1525 device->part_fd = open(raw, O_RDONLY);
1526 else
1527 device->part_fd = open(raw, O_RDWR);
1528
1529 if (device->part_fd < 0 || fstat(device->part_fd, &stat) != 0) {
1530 (void) fprintf(stderr, OPEN_FAIL, raw);
1531 free(raw);
1532 return (BC_ERROR);
1533 }
1534
1535 if (S_ISCHR(stat.st_mode) == 0) {
1536 (void) fprintf(stderr, NOT_RAW_DEVICE, raw);
1537 (void) close(device->part_fd);
1538 device->part_fd = -1;
1539 free(raw);
1540 return (BC_ERROR);
1541 }
1542
1543 free(raw);
1544 return (BC_SUCCESS);
1545 }
1546
1547 #define TMP_MNTPT "/tmp/installgrub_pcfs"
1548 static int
copy_stage2_to_pcfs(ig_data_t * install)1549 copy_stage2_to_pcfs(ig_data_t *install)
1550 {
1551 FILE *mntfp;
1552 int pcfs_fp;
1553 int status = BC_ERROR;
1554 char buf[SECTOR_SIZE];
1555 char *cp;
1556 struct mnttab mp = {0}, mpref = {0};
1557 ig_device_t *device = &install->device;
1558 ig_stage2_t *stage2 = &install->stage2;
1559
1560 /* convert raw to block device name by removing the first 'r' */
1561 (void) strncpy(buf, device->path, sizeof (buf));
1562 buf[sizeof (buf) - 1] = 0;
1563 cp = strchr(buf, 'r');
1564 if (cp == NULL) {
1565 (void) fprintf(stderr, CONVERT_FAIL, device->path);
1566 return (BC_ERROR);
1567 }
1568 do {
1569 *cp = *(cp + 1);
1570 } while (*(++cp));
1571
1572 /* get the mount point, if any */
1573 mntfp = fopen("/etc/mnttab", "r");
1574 if (mntfp == NULL) {
1575 (void) fprintf(stderr, OPEN_FAIL_FILE, "/etc/mnttab");
1576 return (BC_ERROR);
1577 }
1578
1579 mpref.mnt_special = buf;
1580 if (getmntany(mntfp, &mp, &mpref) != 0) {
1581 char cmd[128];
1582
1583 /* not mounted, try remount */
1584 (void) mkdir(TMP_MNTPT, S_IRWXU);
1585 (void) snprintf(cmd, sizeof (cmd), "mount -F pcfs %s %s",
1586 buf, TMP_MNTPT);
1587 (void) system(cmd);
1588 rewind(mntfp);
1589 bzero(&mp, sizeof (mp));
1590 if (getmntany(mntfp, &mp, &mpref) != 0) {
1591 (void) fprintf(stderr, MOUNT_FAIL, buf);
1592 return (BC_ERROR);
1593 }
1594 }
1595
1596 (void) snprintf(buf, sizeof (buf),
1597 "%s/boot", mp.mnt_mountp);
1598 (void) mkdir(buf, S_IRWXU);
1599 (void) strcat(buf, "/grub");
1600 (void) mkdir(buf, S_IRWXU);
1601
1602 (void) strcat(buf, "/stage2");
1603 pcfs_fp = open(buf, O_WRONLY | O_CREAT, S_IRWXU);
1604 if (pcfs_fp == -1) {
1605 (void) fprintf(stderr, OPEN_FAIL_FILE, buf);
1606 perror("open:");
1607 goto out;
1608 }
1609
1610 /* write stage2 to the pcfs mounted filesystem. */
1611 if (write(pcfs_fp, stage2->file, stage2->file_size)
1612 != stage2->file_size) {
1613 perror(gettext("Error writing stage2"));
1614 goto out;
1615 }
1616
1617 status = BC_SUCCESS;
1618 out_fd:
1619 (void) close(pcfs_fp);
1620 out:
1621 (void) umount(TMP_MNTPT);
1622 (void) rmdir(TMP_MNTPT);
1623 return (status);
1624 }
1625