Print this page
3027 installgrub can segfault when encountering bogus data on disk
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/boot/installboot/installboot.c
+++ new/usr/src/cmd/boot/installboot/installboot.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) 2010, Oracle and/or its affiliates. All rights reserved.
23 23 */
24 24
25 25 #include <stdio.h>
26 26 #include <errno.h>
27 27 #include <unistd.h>
28 28 #include <fcntl.h>
29 29 #include <assert.h>
30 30 #include <locale.h>
31 31 #include <strings.h>
32 32 #include <sys/types.h>
33 33 #include <sys/stat.h>
34 34 #include <sys/multiboot.h>
35 35 #include <sys/sysmacros.h>
36 36
37 37 #include "installboot.h"
38 38 #include "./../common/bblk_einfo.h"
39 39 #include "./../common/boot_utils.h"
40 40 #include "./../common/mboot_extra.h"
41 41
42 42 #ifndef TEXT_DOMAIN
43 43 #define TEXT_DOMAIN "SUNW_OST_OSCMD"
44 44 #endif
45 45
46 46 /*
47 47 * SPARC bootblock installation:
48 48 *
49 49 * The bootblock resides in blocks 1 to 15 (disk label is at block 0).
50 50 * The ZFS boot block is larger than what will fit into these first 7.5K so we
51 51 * break it up and write the remaining portion into the ZFS provided boot block
52 52 * region at offset 512K. If versioning is requested, we add a multiboot
53 53 * header at the end of the bootblock, followed by the extra payload area and
54 54 * place the extended information structure within the latter.
55 55 */
56 56
57 57 static boolean_t force_update = B_FALSE;
58 58 static boolean_t do_getinfo = B_FALSE;
59 59 static boolean_t do_version = B_FALSE;
60 60 static boolean_t do_mirror_bblk = B_FALSE;
61 61 static boolean_t strip = B_FALSE;
62 62 static boolean_t verbose_dump = B_FALSE;
63 63
64 64 static char *update_str;
65 65 static int tgt_fs_type = TARGET_IS_UFS;
66 66 char mboot_scan[MBOOT_SCAN_SIZE];
67 67
68 68 /* Function prototypes. */
69 69 static int read_bootblock_from_file(char *, ib_data_t *data);
70 70 static int read_bootblock_from_disk(int, ib_bootblock_t *);
71 71 static void add_bootblock_einfo(ib_bootblock_t *, char *);
72 72 static int prepare_bootblock(ib_data_t *, char *);
73 73 static int write_zfs_bootblock(ib_data_t *);
74 74 static int write_bootblock(ib_data_t *);
75 75 static int open_device(ib_device_t *);
76 76 static int init_device(ib_device_t *, char *);
77 77 static void cleanup_device(ib_device_t *);
78 78 static int commit_to_disk(ib_data_t *, char *);
79 79 static int handle_install(char *, char **);
80 80 static int handle_getinfo(char *, char **);
81 81 static int handle_mirror(char *, char **);
82 82 static boolean_t is_update_necessary(ib_data_t *, char *);
83 83 static int propagate_bootblock(ib_data_t *, ib_data_t *, char *);
84 84 static void usage(char *);
85 85
86 86 static int
87 87 read_bootblock_from_file(char *file, ib_data_t *data)
88 88 {
89 89 ib_device_t *device = &data->device;
90 90 ib_bootblock_t *bblock = &data->bootblock;
91 91 struct stat sb;
92 92 uint32_t buf_size;
93 93 int fd = -1;
94 94 int retval = BC_ERROR;
95 95
96 96 assert(data != NULL);
97 97 assert(file != NULL);
98 98
99 99 fd = open(file, O_RDONLY);
100 100 if (fd == -1) {
101 101 BOOT_DEBUG("Error opening %s\n", file);
102 102 perror("open");
103 103 goto out;
104 104 }
105 105
106 106 if (fstat(fd, &sb) == -1) {
107 107 BOOT_DEBUG("Error getting information (stat) about %s", file);
108 108 perror("stat");
109 109 goto outfd;
110 110 }
111 111
112 112 bblock->file_size = sb.st_size;
113 113 BOOT_DEBUG("bootblock file size is %x\n", bblock->file_size);
114 114
115 115 /* UFS and HSFS bootblocks need to fit in the reserved 7.5K. */
116 116 if (!is_zfs(device->type)) {
117 117 buf_size = P2ROUNDUP(bblock->file_size, SECTOR_SIZE);
118 118 if (buf_size > BBLK_DATA_RSVD_SIZE) {
119 119 BOOT_DEBUG("boot block size is bigger than allowed\n");
120 120 goto outfd;
121 121 }
122 122 } else {
123 123 buf_size = P2ROUNDUP(bblock->file_size + SECTOR_SIZE,
124 124 SECTOR_SIZE);
125 125 if (buf_size > BBLK_DATA_RSVD_SIZE + MBOOT_SCAN_SIZE) {
126 126 (void) fprintf(stderr, gettext("WARNING, bootblock size"
127 127 " does not allow to place extended versioning "
128 128 "information.. skipping\n"));
129 129 do_version = B_FALSE;
130 130 }
131 131 }
132 132
133 133 bblock->buf_size = buf_size;
134 134 BOOT_DEBUG("bootblock in-memory buffer size is %x\n",
135 135 bblock->buf_size);
136 136
137 137 bblock->buf = malloc(buf_size);
138 138 if (bblock->buf == NULL) {
139 139 perror(gettext("Memory allocation failure"));
140 140 goto outbuf;
141 141 }
142 142 bblock->file = bblock->buf;
143 143
144 144 if (read(fd, bblock->file, bblock->file_size) != bblock->file_size) {
145 145 BOOT_DEBUG("Read from %s failed\n", file);
146 146 perror("read");
147 147 goto outfd;
148 148 }
149 149
150 150 /* If not on ZFS, we are done here. */
151 151 if (!is_zfs(device->type)) {
152 152 BOOT_DEBUG("Reading of the bootblock done\n");
153 153 retval = BC_SUCCESS;
154 154 goto outfd;
155 155 }
156 156 /*
157 157 * We place the multiboot header right after the file, followed by
158 158 * the extended information structure.
159 159 */
160 160 bblock->mboot = (multiboot_header_t *)(bblock->file +
161 161 P2ROUNDUP(bblock->file_size, 8));
162 162 bblock->extra = (char *)bblock->mboot + sizeof (multiboot_header_t);
163 163 BOOT_DEBUG("mboot at %p, extra at %p, buf=%p (size=%d)\n",
164 164 bblock->mboot, bblock->extra, bblock->buf, bblock->buf_size);
165 165
166 166 (void) close(fd);
167 167 return (BC_SUCCESS);
168 168
169 169 outbuf:
170 170 (void) free(bblock->buf);
171 171 bblock->buf = NULL;
172 172 outfd:
173 173 (void) close(fd);
174 174 out:
175 175 return (retval);
176 176 }
177 177
178 178 static int
179 179 read_bootblock_from_disk(int dev_fd, ib_bootblock_t *bblock)
180 180 {
181 181 char *dest;
182 182 uint32_t size;
183 183 uint32_t buf_size;
184 184 uint32_t mboot_off;
185 185 multiboot_header_t *mboot;
186 186
187 187 assert(bblock != NULL);
188 188 assert(dev_fd != -1);
189 189
190 190 /*
191 191 * The ZFS bootblock is divided in two parts, but the fake multiboot
192 192 * header can only be in the second part (the one contained in the ZFS
193 193 * reserved area).
194 194 */
195 195 if (read_in(dev_fd, mboot_scan, sizeof (mboot_scan),
196 196 BBLK_ZFS_EXTRA_OFF) != BC_SUCCESS) {
197 197 BOOT_DEBUG("Error reading ZFS reserved area\n");
198 198 perror("read");
199 199 return (BC_ERROR);
200 200 }
201 201
202 202 /* No multiboot means no chance of knowing bootblock size */
203 203 if (find_multiboot(mboot_scan, sizeof (mboot_scan), &mboot_off)
204 204 != BC_SUCCESS) {
205 205 BOOT_DEBUG("Unable to find multiboot header\n");
206 206 return (BC_NOEXTRA);
207 207 }
208 208 mboot = (multiboot_header_t *)(mboot_scan + mboot_off);
209 209
210 210 /*
211 211 * Currently, the amount of space reserved for extra information
212 212 * is "fixed". We may have to scan for the terminating extra payload
213 213 * in the future.
214 214 */
215 215 size = mboot->load_end_addr - mboot->load_addr;
216 216 buf_size = P2ROUNDUP(size + SECTOR_SIZE, SECTOR_SIZE);
217 217 bblock->file_size = size;
218 218
219 219 bblock->buf = malloc(buf_size);
220 220 if (bblock->buf == NULL) {
221 221 BOOT_DEBUG("Unable to allocate enough memory to read"
222 222 " the extra bootblock from the disk\n");
223 223 perror(gettext("Memory allocation failure"));
224 224 return (BC_ERROR);
225 225 }
226 226 bblock->buf_size = buf_size;
227 227
228 228 dest = bblock->buf;
229 229 size = BBLK_DATA_RSVD_SIZE;
230 230
231 231 if (read_in(dev_fd, dest, size, SECTOR_SIZE) != BC_SUCCESS) {
232 232 BOOT_DEBUG("Error reading first %d bytes of the bootblock\n",
233 233 size);
234 234 (void) free(bblock->buf);
235 235 bblock->buf = NULL;
236 236 return (BC_ERROR);
237 237 }
238 238
239 239 dest += BBLK_DATA_RSVD_SIZE;
240 240 size = bblock->buf_size - BBLK_DATA_RSVD_SIZE;
241 241
242 242 if (read_in(dev_fd, dest, size, BBLK_ZFS_EXTRA_OFF) != BC_SUCCESS) {
243 243 BOOT_DEBUG("Error reading ZFS reserved area the second time\n");
244 244 (void) free(bblock->buf);
↓ open down ↓ |
244 lines elided |
↑ open up ↑ |
245 245 bblock->buf = NULL;
246 246 return (BC_ERROR);
247 247 }
248 248
249 249 /* Update pointers. */
250 250 bblock->file = bblock->buf;
251 251 bblock->mboot_off = mboot_off;
252 252 bblock->mboot = (multiboot_header_t *)(bblock->buf + bblock->mboot_off
253 253 + BBLK_DATA_RSVD_SIZE);
254 254 bblock->extra = (char *)bblock->mboot + sizeof (multiboot_header_t);
255 + bblock->extra_size = bblock->buf_size - bblock->mboot_off
256 + - BBLK_DATA_RSVD_SIZE - sizeof (multiboot_header_t);
255 257 return (BC_SUCCESS);
256 258 }
257 259
258 260 static boolean_t
259 261 is_update_necessary(ib_data_t *data, char *updt_str)
260 262 {
261 263 bblk_einfo_t *einfo;
262 264 bblk_hs_t bblock_hs;
263 265 ib_bootblock_t bblock_disk;
264 266 ib_bootblock_t *bblock_file = &data->bootblock;
265 267 ib_device_t *device = &data->device;
266 268 int dev_fd = device->fd;
267 269
268 270 assert(data != NULL);
269 271 assert(device->fd != -1);
270 272
271 273 /* Nothing to do if we are not updating a ZFS bootblock. */
↓ open down ↓ |
7 lines elided |
↑ open up ↑ |
272 274 if (!is_zfs(device->type))
273 275 return (B_TRUE);
274 276
275 277 bzero(&bblock_disk, sizeof (ib_bootblock_t));
276 278
277 279 if (read_bootblock_from_disk(dev_fd, &bblock_disk) != BC_SUCCESS) {
278 280 BOOT_DEBUG("Unable to read bootblock from %s\n", device->path);
279 281 return (B_TRUE);
280 282 }
281 283
282 - einfo = find_einfo(bblock_disk.extra);
284 + einfo = find_einfo(bblock_disk.extra, bblock_disk.extra_size);
283 285 if (einfo == NULL) {
284 286 BOOT_DEBUG("No extended information available\n");
285 287 return (B_TRUE);
286 288 }
287 289
288 290 if (!do_version || updt_str == NULL) {
289 291 (void) fprintf(stdout, "WARNING: target device %s has a "
290 292 "versioned bootblock that is going to be overwritten by a "
291 293 "non versioned one\n", device->path);
292 294 return (B_TRUE);
293 295 }
294 296
295 297 if (force_update) {
296 298 BOOT_DEBUG("Forcing update of %s bootblock\n", device->path);
297 299 return (B_TRUE);
298 300 }
299 301
300 302 BOOT_DEBUG("Ready to check installed version vs %s\n", updt_str);
301 303
302 304 bblock_hs.src_buf = (unsigned char *)bblock_file->file;
303 305 bblock_hs.src_size = bblock_file->file_size;
304 306
305 307 return (einfo_should_update(einfo, &bblock_hs, updt_str));
306 308 }
307 309
308 310 static void
309 311 add_bootblock_einfo(ib_bootblock_t *bblock, char *updt_str)
310 312 {
311 313 bblk_hs_t hs;
312 314 uint32_t avail_space;
313 315
314 316 assert(bblock != NULL);
315 317
316 318 if (updt_str == NULL) {
317 319 BOOT_DEBUG("WARNING: no update string passed to "
318 320 "add_bootblock_einfo()\n");
319 321 return;
320 322 }
321 323
322 324 /* Fill bootblock hashing source information. */
323 325 hs.src_buf = (unsigned char *)bblock->file;
324 326 hs.src_size = bblock->file_size;
325 327 /* How much space for the extended information structure? */
326 328 avail_space = bblock->buf_size - P2ROUNDUP(bblock->file_size, 8);
327 329 /* Place the extended information structure. */
328 330 add_einfo(bblock->extra, updt_str, &hs, avail_space);
329 331 }
330 332
331 333
332 334 static int
333 335 prepare_bootblock(ib_data_t *data, char *updt_str)
334 336 {
335 337 ib_device_t *device = &data->device;
336 338 ib_bootblock_t *bblock = &data->bootblock;
337 339 multiboot_header_t *mboot;
338 340
339 341 assert(data != NULL);
340 342
341 343 /* Nothing to do if we are not on ZFS. */
342 344 if (!is_zfs(device->type))
343 345 return (BC_SUCCESS);
344 346
345 347 /*
346 348 * Write the fake multiboot structure followed by the extra information
347 349 * data. Both mboot and extra pointers have already been filled up to
348 350 * point to the right location in the buffer. We prepare the fake
349 351 * multiboot regardless if versioning was requested or not because
350 352 * we need it for mirroring support.
351 353 */
352 354 assert(bblock->mboot != NULL);
353 355 assert(bblock->extra != NULL);
354 356
355 357 mboot = bblock->mboot;
356 358
357 359 mboot->magic = MB_HEADER_MAGIC;
358 360 mboot->flags = MB_HEADER_FLAGS_64;
359 361 mboot->checksum = -(mboot->flags + mboot->magic);
360 362 /*
361 363 * Flags include the AOUT_KLUDGE and we use the extra members to specify
362 364 * the size of the bootblock.
363 365 */
364 366 mboot->header_addr = bblock->mboot_off;
365 367 mboot->load_addr = 0;
366 368 mboot->load_end_addr = bblock->file_size;
367 369
368 370 /*
369 371 * Now that we have the mboot header in place, we can add the extended
370 372 * versioning information. Since the multiboot header has been placed
371 373 * after the file image, the hashing will still reflect the one of the
372 374 * file on the disk.
373 375 */
374 376 if (do_version)
375 377 add_bootblock_einfo(bblock, updt_str);
376 378
377 379 return (BC_SUCCESS);
378 380 }
379 381
380 382 static int
381 383 write_zfs_bootblock(ib_data_t *data)
382 384 {
383 385 ib_device_t *device = &data->device;
384 386 ib_bootblock_t *bblock = &data->bootblock;
385 387 char *bufptr;
386 388 uint32_t size;
387 389
388 390 assert(data != NULL);
389 391 assert(device->fd != -1);
390 392
391 393 /*
392 394 * In the ZFS case we actually perform two different steps:
393 395 * - write the first 15 blocks of the bootblock to the reserved disk
394 396 * blocks.
395 397 * - write the remaining blocks in the ZFS reserved area at offset
396 398 * 512K.
397 399 */
398 400 bufptr = bblock->buf;
399 401 size = BBLK_DATA_RSVD_SIZE;
400 402
401 403 if (write_out(device->fd, bufptr, size, SECTOR_SIZE) != BC_SUCCESS) {
402 404 BOOT_DEBUG("Error writing first 15 blocks of %s\n",
403 405 device->path);
404 406 perror("write");
405 407 return (BC_ERROR);
406 408 }
407 409
408 410 bufptr += BBLK_DATA_RSVD_SIZE;
409 411 size = bblock->buf_size - BBLK_DATA_RSVD_SIZE;
410 412
411 413 if (write_out(device->fd, bufptr, size, BBLK_ZFS_EXTRA_OFF)
412 414 != BC_SUCCESS) {
413 415 BOOT_DEBUG("Error writing the second part of ZFS bootblock "
414 416 "to %s at offset %d\n", device->path, BBLK_ZFS_EXTRA_OFF);
415 417 return (BC_ERROR);
416 418 }
417 419 return (BC_SUCCESS);
418 420 }
419 421
420 422 static int
421 423 write_bootblock(ib_data_t *data)
422 424 {
423 425 ib_device_t *device = &data->device;
424 426 ib_bootblock_t *bblock = &data->bootblock;
425 427 int ret;
426 428
427 429 assert(data != NULL);
428 430
429 431 /*
430 432 * If we are on UFS or HSFS we simply write out to the reserved
431 433 * blocks (1 to 15) the boot block.
432 434 */
433 435 if (!is_zfs(device->type)) {
434 436 if (write_out(device->fd, bblock->buf, bblock->buf_size,
435 437 SECTOR_SIZE) != BC_SUCCESS) {
436 438 BOOT_DEBUG("Error writing bootblock to %s\n",
437 439 device->path);
438 440 return (BC_ERROR);
439 441 } else {
440 442 return (BC_SUCCESS);
441 443 }
442 444 } else {
443 445 ret = write_zfs_bootblock(data);
444 446 return (ret);
445 447 }
446 448 }
447 449
448 450 static int
449 451 open_device(ib_device_t *device)
450 452 {
451 453 struct stat statbuf;
452 454
453 455 device->fd = open(device->path, O_RDWR);
454 456 if (device->fd == -1) {
455 457 BOOT_DEBUG("Unable to open %s\n", device->path);
456 458 perror("open");
457 459 return (BC_ERROR);
458 460 }
459 461
460 462 if (fstat(device->fd, &statbuf) != 0) {
461 463 BOOT_DEBUG("Unable to stat %s\n", device->path);
462 464 perror("stat");
463 465 (void) close(device->fd);
464 466 return (BC_ERROR);
465 467 }
466 468
467 469 if (S_ISCHR(statbuf.st_mode) == 0) {
468 470 (void) fprintf(stderr, gettext("%s: Not a character device\n"),
469 471 device->path);
470 472 return (BC_ERROR);
471 473 }
472 474
473 475 return (BC_SUCCESS);
474 476 }
475 477
476 478 static int
477 479 init_device(ib_device_t *device, char *path)
478 480 {
479 481 bzero(device, sizeof (*device));
480 482 device->fd = -1;
481 483
482 484 device->path = strdup(path);
483 485 if (path == NULL) {
484 486 perror(gettext("Memory allocation failure"));
485 487 return (BC_ERROR);
486 488 }
487 489
488 490 device->type = tgt_fs_type;
489 491 if (open_device(device) != BC_SUCCESS)
490 492 return (BC_ERROR);
491 493
492 494 return (BC_SUCCESS);
493 495 }
494 496
495 497 static void
496 498 cleanup_device(ib_device_t *device)
497 499 {
498 500 free(device->path);
499 501 bzero(device, sizeof (*device));
500 502
501 503 if (device->fd != -1)
502 504 (void) close(device->fd);
503 505 }
504 506
505 507 static void
506 508 cleanup_bootblock(ib_bootblock_t *bblock)
507 509 {
508 510 free(bblock->buf);
509 511 bzero(bblock, sizeof (ib_bootblock_t));
510 512 }
511 513
512 514 /*
513 515 * Propagate the bootblock on the source disk to the destination disk and
514 516 * version it with 'updt_str' in the process. Since we cannot trust any data
515 517 * on the attaching disk, we do not perform any specific check on a potential
516 518 * target extended information structure and we just blindly update.
517 519 */
518 520 static int
519 521 propagate_bootblock(ib_data_t *src, ib_data_t *dest, char *updt_str)
520 522 {
521 523 ib_bootblock_t *src_bblock = &src->bootblock;
522 524 ib_bootblock_t *dest_bblock = &dest->bootblock;
523 525 uint32_t buf_size;
524 526
525 527 assert(src != NULL);
526 528 assert(dest != NULL);
527 529
528 530 cleanup_bootblock(dest_bblock);
529 531
530 532 if (updt_str != NULL) {
531 533 do_version = B_TRUE;
532 534 } else {
533 535 do_version = B_FALSE;
534 536 }
535 537
536 538 buf_size = src_bblock->file_size + SECTOR_SIZE;
537 539
538 540 dest_bblock->buf_size = P2ROUNDUP(buf_size, SECTOR_SIZE);
539 541 dest_bblock->buf = malloc(dest_bblock->buf_size);
540 542 if (dest_bblock->buf == NULL) {
541 543 perror(gettext("Memory Allocation Failure"));
542 544 return (BC_ERROR);
543 545 }
544 546 dest_bblock->file = dest_bblock->buf;
545 547 dest_bblock->file_size = src_bblock->file_size;
546 548 (void) memcpy(dest_bblock->file, src_bblock->file,
547 549 dest_bblock->file_size);
548 550
549 551 dest_bblock->mboot = (multiboot_header_t *)(dest_bblock->file +
550 552 P2ROUNDUP(dest_bblock->file_size, 8));
551 553 dest_bblock->extra = (char *)dest_bblock->mboot +
552 554 sizeof (multiboot_header_t);
553 555
554 556 (void) fprintf(stdout, gettext("Propagating %s bootblock to %s\n"),
555 557 src->device.path, dest->device.path);
556 558
557 559 return (commit_to_disk(dest, updt_str));
558 560 }
559 561
560 562 static int
561 563 commit_to_disk(ib_data_t *data, char *update_str)
562 564 {
563 565 assert(data != NULL);
564 566
565 567 if (prepare_bootblock(data, update_str) != BC_SUCCESS) {
566 568 (void) fprintf(stderr, gettext("Error updating the bootblock "
567 569 "image\n"));
568 570 return (BC_ERROR);
569 571 }
570 572
571 573 if (write_bootblock(data) != BC_SUCCESS) {
572 574 (void) fprintf(stderr, gettext("Error writing bootblock to "
573 575 "disk\n"));
574 576 return (BC_ERROR);
575 577 }
576 578
577 579 return (BC_SUCCESS);
578 580 }
579 581
580 582
581 583 /*
582 584 * Install a new bootblock on the given device. handle_install() expects argv
583 585 * to contain 2 parameters (the target device path and the path to the
584 586 * bootblock.
585 587 *
586 588 * Returns: BC_SUCCESS - if the installation is successful
587 589 * BC_ERROR - if the installation failed
588 590 * BC_NOUPDT - if no installation was performed because the
589 591 * version currently installed is more recent than the
590 592 * supplied one.
591 593 *
592 594 */
593 595 static int
594 596 handle_install(char *progname, char **argv)
595 597 {
596 598 ib_data_t install_data;
597 599 char *bootblock = NULL;
598 600 char *device_path = NULL;
599 601 int ret = BC_ERROR;
600 602
601 603 bootblock = strdup(argv[0]);
602 604 device_path = strdup(argv[1]);
603 605
604 606 if (!device_path || !bootblock) {
605 607 (void) fprintf(stderr, gettext("Missing parameter"));
606 608 usage(progname);
607 609 goto out;
608 610 }
609 611
610 612 BOOT_DEBUG("device path: %s, bootblock file path: %s\n", device_path,
611 613 bootblock);
612 614 bzero(&install_data, sizeof (ib_data_t));
613 615
614 616 if (init_device(&install_data.device, device_path) != BC_SUCCESS) {
615 617 (void) fprintf(stderr, gettext("Unable to open device %s\n"),
616 618 device_path);
617 619 goto out;
618 620 }
619 621
620 622 if (read_bootblock_from_file(bootblock, &install_data) != BC_SUCCESS) {
621 623 (void) fprintf(stderr, gettext("Error reading %s\n"),
622 624 bootblock);
623 625 goto out_dev;
624 626 }
625 627 /* Versioning is only supported for the ZFS bootblock. */
626 628 if (do_version && !is_zfs(install_data.device.type)) {
627 629 (void) fprintf(stderr, gettext("Versioning is only supported on"
628 630 " ZFS... skipping.\n"));
629 631 do_version = B_FALSE;
630 632 }
631 633
632 634 /*
633 635 * is_update_necessary() will take care of checking if versioning and/or
634 636 * forcing the update have been specified. It will also emit a warning
635 637 * if a non-versioned update is attempted over a versioned bootblock.
636 638 */
637 639 if (!is_update_necessary(&install_data, update_str)) {
638 640 (void) fprintf(stderr, gettext("bootblock version installed "
639 641 "on %s is more recent or identical\n"
640 642 "Use -F to override or install without the -u option\n"),
641 643 device_path);
642 644 ret = BC_NOUPDT;
643 645 goto out_dev;
644 646 }
645 647
646 648 BOOT_DEBUG("Ready to commit to disk\n");
647 649 ret = commit_to_disk(&install_data, update_str);
648 650
649 651 out_dev:
650 652 cleanup_device(&install_data.device);
651 653 out:
652 654 free(bootblock);
653 655 free(device_path);
654 656 return (ret);
655 657 }
656 658
657 659 /*
658 660 * Retrieves from a device the extended information (einfo) associated to the
659 661 * installed bootblock.
660 662 * Expects one parameter, the device path, in the form: /dev/rdsk/c?[t?]d?s0.
661 663 * Returns:
662 664 * - BC_SUCCESS (and prints out einfo contents depending on 'flags')
663 665 * - BC_ERROR (on error)
664 666 * - BC_NOEINFO (no extended information available)
665 667 */
666 668 static int
667 669 handle_getinfo(char *progname, char **argv)
668 670 {
669 671
670 672 ib_data_t data;
671 673 ib_bootblock_t *bblock = &data.bootblock;
672 674 ib_device_t *device = &data.device;
673 675 bblk_einfo_t *einfo;
674 676 uint8_t flags = 0;
675 677 uint32_t size;
676 678 char *device_path;
677 679 int retval = BC_ERROR;
678 680 int ret;
679 681
680 682 device_path = strdup(argv[0]);
681 683 if (!device_path) {
682 684 (void) fprintf(stderr, gettext("Missing parameter"));
683 685 usage(progname);
684 686 goto out;
685 687 }
686 688
687 689 bzero(&data, sizeof (ib_data_t));
688 690 BOOT_DEBUG("device path: %s\n", device_path);
689 691
690 692 if (init_device(device, device_path) != BC_SUCCESS) {
691 693 (void) fprintf(stderr, gettext("Unable to gather device "
692 694 "information from %s\n"), device_path);
693 695 goto out_dev;
694 696 }
695 697
696 698 if (!is_zfs(device->type)) {
697 699 (void) fprintf(stderr, gettext("Versioning only supported on "
698 700 "ZFS\n"));
699 701 goto out_dev;
700 702 }
701 703
702 704 ret = read_bootblock_from_disk(device->fd, bblock);
703 705 if (ret == BC_ERROR) {
704 706 (void) fprintf(stderr, gettext("Error reading bootblock from "
705 707 "%s\n"), device_path);
706 708 goto out_dev;
707 709 }
708 710
↓ open down ↓ |
416 lines elided |
↑ open up ↑ |
709 711 if (ret == BC_NOEXTRA) {
710 712 BOOT_DEBUG("No multiboot header found on %s, unable "
711 713 "to locate extra information area (old/non versioned "
712 714 "bootblock?) \n", device_path);
713 715 (void) fprintf(stderr, gettext("No extended information "
714 716 "found\n"));
715 717 retval = BC_NOEINFO;
716 718 goto out_dev;
717 719 }
718 720
719 - einfo = find_einfo(bblock->extra);
721 + einfo = find_einfo(bblock->extra, bblock->extra_size);
720 722 if (einfo == NULL) {
721 723 retval = BC_NOEINFO;
722 724 (void) fprintf(stderr, gettext("No extended information "
723 725 "found\n"));
724 726 goto out_dev;
725 727 }
726 728
727 729 /* Print the extended information. */
728 730 if (strip)
729 731 flags |= EINFO_EASY_PARSE;
730 732 if (verbose_dump)
731 733 flags |= EINFO_PRINT_HEADER;
732 734
733 735 size = bblock->buf_size - P2ROUNDUP(bblock->file_size, 8) -
734 736 sizeof (multiboot_header_t);
735 737 print_einfo(flags, einfo, size);
736 738 retval = BC_SUCCESS;
737 739
738 740 out_dev:
739 741 cleanup_device(&data.device);
740 742 out:
741 743 free(device_path);
742 744 return (retval);
743 745
744 746 }
745 747
746 748 /*
747 749 * Attempt to mirror (propagate) the current bootblock over the attaching disk.
748 750 *
749 751 * Returns:
750 752 * - BC_SUCCESS (a successful propagation happened)
751 753 * - BC_ERROR (an error occurred)
752 754 * - BC_NOEXTRA (it is not possible to dump the current bootblock since
753 755 * there is no multiboot information)
754 756 */
755 757 static int
756 758 handle_mirror(char *progname, char **argv)
757 759 {
758 760 ib_data_t curr_data;
759 761 ib_data_t attach_data;
760 762 ib_device_t *curr_device = &curr_data.device;
761 763 ib_device_t *attach_device = &attach_data.device;
762 764 ib_bootblock_t *bblock_curr = &curr_data.bootblock;
763 765 ib_bootblock_t *bblock_attach = &attach_data.bootblock;
764 766 bblk_einfo_t *einfo_curr = NULL;
765 767 char *curr_device_path;
766 768 char *attach_device_path;
767 769 char *updt_str = NULL;
768 770 int retval = BC_ERROR;
769 771 int ret;
770 772
771 773 curr_device_path = strdup(argv[0]);
772 774 attach_device_path = strdup(argv[1]);
773 775
774 776 if (!curr_device_path || !attach_device_path) {
775 777 (void) fprintf(stderr, gettext("Missing parameter"));
776 778 usage(progname);
777 779 goto out;
778 780 }
779 781 BOOT_DEBUG("Current device path is: %s, attaching device path is: "
780 782 " %s\n", curr_device_path, attach_device_path);
781 783
782 784 bzero(&curr_data, sizeof (ib_data_t));
783 785 bzero(&attach_data, sizeof (ib_data_t));
784 786
785 787 if (tgt_fs_type != TARGET_IS_ZFS) {
786 788 (void) fprintf(stderr, gettext("Mirroring is only supported on "
787 789 "ZFS\n"));
788 790 return (BC_ERROR);
789 791 }
790 792
791 793 if (init_device(curr_device, curr_device_path) != BC_SUCCESS) {
792 794 (void) fprintf(stderr, gettext("Unable to gather device "
793 795 "information from %s (current device)\n"),
794 796 curr_device_path);
795 797 goto out_currdev;
796 798 }
797 799
798 800 if (init_device(attach_device, attach_device_path) != BC_SUCCESS) {
799 801 (void) fprintf(stderr, gettext("Unable to gather device "
800 802 "information from %s (attaching device)\n"),
801 803 attach_device_path);
802 804 goto out_devs;
803 805 }
804 806
805 807 ret = read_bootblock_from_disk(curr_device->fd, bblock_curr);
806 808 if (ret == BC_ERROR) {
807 809 BOOT_DEBUG("Error reading bootblock from %s\n",
808 810 curr_device->path);
809 811 retval = BC_ERROR;
↓ open down ↓ |
80 lines elided |
↑ open up ↑ |
810 812 goto out_devs;
811 813 }
812 814
813 815 if (ret == BC_NOEXTRA) {
814 816 BOOT_DEBUG("No multiboot header found on %s, unable to retrieve"
815 817 " the bootblock\n", curr_device->path);
816 818 retval = BC_NOEXTRA;
817 819 goto out_devs;
818 820 }
819 821
820 - einfo_curr = find_einfo(bblock_curr->extra);
822 + einfo_curr = find_einfo(bblock_curr->extra, bblock_curr->extra_size);
821 823 if (einfo_curr != NULL)
822 824 updt_str = einfo_get_string(einfo_curr);
823 825
824 826 retval = propagate_bootblock(&curr_data, &attach_data, updt_str);
825 827 cleanup_bootblock(bblock_curr);
826 828 cleanup_bootblock(bblock_attach);
827 829 out_devs:
828 830 cleanup_device(attach_device);
829 831 out_currdev:
830 832 cleanup_device(curr_device);
831 833 out:
832 834 free(curr_device_path);
833 835 free(attach_device_path);
834 836 return (retval);
835 837 }
836 838
837 839 #define USAGE_STRING "Usage: %s [-h|-f|-F fstype|-u verstr] bootblk " \
838 840 "raw-device\n" \
839 841 "\t%s [-e|-V] -i -F zfs raw-device\n" \
840 842 "\t%s -M -F zfs raw-device attach-raw-device\n" \
841 843 "\tfstype is one of: 'ufs', 'hsfs' or 'zfs'\n"
842 844
843 845 #define CANON_USAGE_STR gettext(USAGE_STRING)
844 846
845 847 static void
846 848 usage(char *progname)
847 849 {
848 850 (void) fprintf(stdout, CANON_USAGE_STR, progname, progname, progname);
849 851 }
850 852
851 853 int
852 854 main(int argc, char **argv)
853 855 {
854 856 int opt;
855 857 int params = 2;
856 858 int ret;
857 859 char *progname;
858 860 char **handle_args;
859 861
860 862 (void) setlocale(LC_ALL, "");
861 863 (void) textdomain(TEXT_DOMAIN);
862 864
863 865 while ((opt = getopt(argc, argv, "F:efiVMndhu:")) != EOF) {
864 866 switch (opt) {
865 867 case 'F':
866 868 if (strcmp(optarg, "ufs") == 0) {
867 869 tgt_fs_type = TARGET_IS_UFS;
868 870 } else if (strcmp(optarg, "hsfs") == 0) {
869 871 tgt_fs_type = TARGET_IS_HSFS;
870 872 } else if (strcmp(optarg, "zfs") == 0) {
871 873 tgt_fs_type = TARGET_IS_ZFS;
872 874 } else {
873 875 (void) fprintf(stderr, gettext("Wrong "
874 876 "filesystem specified\n\n"));
875 877 usage(argv[0]);
876 878 exit(BC_ERROR);
877 879 }
878 880 break;
879 881 case 'e':
880 882 strip = B_TRUE;
881 883 break;
882 884 case 'f':
883 885 force_update = B_TRUE;
884 886 break;
885 887 case 'V':
886 888 verbose_dump = B_TRUE;
887 889 break;
888 890 case 'i':
889 891 do_getinfo = B_TRUE;
890 892 params = 1;
891 893 break;
892 894 case 'u':
893 895 do_version = B_TRUE;
894 896
895 897 update_str = malloc(strlen(optarg) + 1);
896 898 if (update_str == NULL) {
897 899 perror(gettext("Memory allocation failure"));
898 900 exit(BC_ERROR);
899 901 }
900 902 (void) strlcpy(update_str, optarg, strlen(optarg) + 1);
901 903 break;
902 904 case 'M':
903 905 do_mirror_bblk = B_TRUE;
904 906 break;
905 907 case 'h':
906 908 usage(argv[0]);
907 909 exit(BC_SUCCESS);
908 910 break;
909 911 case 'd':
910 912 boot_debug = B_TRUE;
911 913 break;
912 914 case 'n':
913 915 nowrite = B_TRUE;
914 916 break;
915 917 default:
916 918 /* fall through to process non-optional args */
917 919 break;
918 920 }
919 921 }
920 922
921 923 /* check arguments */
922 924 if (argc != optind + params) {
923 925 usage(argv[0]);
924 926 exit(BC_ERROR);
925 927 }
926 928 progname = argv[0];
927 929 handle_args = argv + optind;
928 930
929 931 /* check options. */
930 932 if (do_getinfo && do_mirror_bblk) {
931 933 (void) fprintf(stderr, gettext("Only one of -M and -i can be "
932 934 "specified at the same time\n"));
933 935 usage(progname);
934 936 exit(BC_ERROR);
935 937 }
936 938
937 939 if (nowrite)
938 940 (void) fprintf(stdout, gettext("Dry run requested. Nothing will"
939 941 " be written to disk.\n"));
940 942
941 943 if (do_getinfo) {
942 944 ret = handle_getinfo(progname, handle_args);
943 945 } else if (do_mirror_bblk) {
944 946 ret = handle_mirror(progname, handle_args);
945 947 } else {
946 948 ret = handle_install(progname, handle_args);
947 949 }
948 950 return (ret);
949 951 }
↓ open down ↓ |
119 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX