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