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