Print this page
NEX-16819 loader UEFI support
Includes work by Toomas Soome <tsoome@me.com>
Upstream commits:
loader: pxe receive cleanup
9475 libefi: Do not return only if ReceiveFilter
installboot: should support efi system partition
8931 boot1.efi: scan all display modes rather than
loader: spinconsole updates
loader: gfx experiment to try GOP Blt() function.
sha1 build test
loader: add sha1 hash calculation
common/sha1: update for loader build
loader: biosdisk rework
uts: 32-bit kernel FB needs mapping in low memory
uts: add diag-device
uts: boot console mirror with diag-device
uts: enable very early console on ttya
kmdb: add diag-device as input/output device
uts: test VGA memory exclusion from mapping
uts: clear boot mapping and protect boot pages test
uts: add dboot map debug printf
uts: need to release FB pages in release_bootstrap()
uts: add screenmap ioctl
uts: update sys/queue.h
loader: add illumos uts/common to include path
loader: tem/gfx font cleanup
loader: vbe checks
uts: gfx_private set KD_TEXT when KD_RESETTEXT is
uts: gfx 8-bit update
loader: gfx 8-bit fix
loader: always set media size from partition.
uts: MB2 support for 32-bit kernel
loader: x86 should have tem 80x25
uts: x86 should have tem 80x25
uts: font update
loader: font update
uts: tem attributes
loader: tem.c comment added
uts: use font module
loader: add font module
loader: build rules for new font setup
uts: gfx_private update for new font structure
uts: early boot update for new font structure
uts: font update
uts: font build rules update for new fonts
uts: tem update to new font structure
loader: module.c needs to include tem_impl.h
uts: gfx_private 8x16 font rework
uts: make font_lookup public
loader: font rework
uts: font rework
9259 libefi: efi_alloc_and_read should check for PMBR
uts: tem utf-8 support
loader: implement tem utf-8 support
loader: tem should be able to display UTF-8
7784 uts: console input should support utf-8
7796 uts: ldterm default to utf-8
uts: do not reset serial console
uts: set up colors even if tem is not console
uts: add type for early boot properties
uts: gfx_private experiment with drm and vga
uts: gfx_private should use setmode drm callback.
uts: identify FB types and set up gfx_private based
loader: replace gop and vesa with framebuffer
uts: boot needs simple tem to support mdb
uts: boot_keyboard should emit esc sequences for
uts: gfx_private FB showuld be written by line
kmdb: set terminal window size
uts: gfx_private needs to keep track of early boot FB
pnglite: move pnglite to usr/src/common
loader: gfx_fb
ficl-sys: add gfx primitives
loader: add illumos.png logo
ficl: add fb-putimage
loader: add png support
loader: add alpha blending for gfx_fb
loader: use term-drawrect for menu frame
ficl: add simple gfx words
uts: provide fb_info via fbgattr dev_specific array.
uts: gfx_private add alpha blending
uts: update sys/ascii.h
uts: tem OSC support (incomplete)
uts: implement env module support and use data from
uts: tem get colors from early boot data
loader: use crc32 from libstand (libz)
loader: optimize for size
loader: pass tem info to the environment
loader: import tem for loader console
loader: UEFI loader needs to set ISADIR based on
loader: need UEFI32 support
8918 loader.efi: add vesa edid support
uts: tem_safe_pix_clear_prom_output() should only
uts: tem_safe_pix_clear_entire_screen() should use
uts: tem_safe_check_first_time() should query cursor
uts: tem implement cls callback & visual_io v4
uts: gfx_vgatext use block cursor for vgatext
uts: gfx_private implement cls callback & visual_io
uts: gfx_private bitmap framebuffer implementation
uts: early start frame buffer console support
uts: font functions should check the input char
uts: font rendering should support 16/24/32bit depths
uts: use smallest font as fallback default.
uts: update terminal dimensions based on selected
7834 uts: vgatext should use gfx_private
uts: add spacing property to 8859-1.bdf
terminfo: add underline for sun-color
terminfo: sun-color has 16 colors
uts: add font load callback type
loader: do not repeat int13 calls with error 0x20 and
8905 loader: add skein/edonr support
8904 common/crypto: make skein and edonr loader
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Revert "NEX-16819 loader UEFI support"
This reverts commit ec06b9fc617b99234e538bf2e7e4d02a24993e0c.
Reverting due to failures in the zfs-tests and the sharefs-tests
NEX-16819 loader UEFI support
Includes work by Toomas Soome <tsoome@me.com>
Upstream commits:
loader: pxe receive cleanup
9475 libefi: Do not return only if ReceiveFilter
installboot: should support efi system partition
8931 boot1.efi: scan all display modes rather than
loader: spinconsole updates
loader: gfx experiment to try GOP Blt() function.
sha1 build test
loader: add sha1 hash calculation
common/sha1: update for loader build
loader: biosdisk rework
uts: 32-bit kernel FB needs mapping in low memory
uts: add diag-device
uts: boot console mirror with diag-device
uts: enable very early console on ttya
kmdb: add diag-device as input/output device
uts: test VGA memory exclusion from mapping
uts: clear boot mapping and protect boot pages test
uts: add dboot map debug printf
uts: need to release FB pages in release_bootstrap()
uts: add screenmap ioctl
uts: update sys/queue.h
loader: add illumos uts/common to include path
loader: tem/gfx font cleanup
loader: vbe checks
uts: gfx_private set KD_TEXT when KD_RESETTEXT is
uts: gfx 8-bit update
loader: gfx 8-bit fix
loader: always set media size from partition.
uts: MB2 support for 32-bit kernel
loader: x86 should have tem 80x25
uts: x86 should have tem 80x25
uts: font update
loader: font update
uts: tem attributes
loader: tem.c comment added
uts: use font module
loader: add font module
loader: build rules for new font setup
uts: gfx_private update for new font structure
uts: early boot update for new font structure
uts: font update
uts: font build rules update for new fonts
uts: tem update to new font structure
loader: module.c needs to include tem_impl.h
uts: gfx_private 8x16 font rework
uts: make font_lookup public
loader: font rework
uts: font rework
libefi: efi_alloc_and_read should check for PMBR
uts: tem utf-8 support
loader: implement tem utf-8 support
loader: tem should be able to display UTF-8
7784 uts: console input should support utf-8
7796 uts: ldterm default to utf-8
uts: do not reset serial console
uts: set up colors even if tem is not console
uts: add type for early boot properties
uts: gfx_private experiment with drm and vga
uts: gfx_private should use setmode drm callback.
uts: identify FB types and set up gfx_private based
loader: replace gop and vesa with framebuffer
uts: boot needs simple tem to support mdb
uts: boot_keyboard should emit esc sequences for
uts: gfx_private FB showuld be written by line
kmdb: set terminal window size
uts: gfx_private needs to keep track of early boot FB
pnglite: move pnglite to usr/src/common
loader: gfx_fb
ficl-sys: add gfx primitives
loader: add illumos.png logo
ficl: add fb-putimage
loader: add png support
loader: add alpha blending for gfx_fb
loader: use term-drawrect for menu frame
ficl: add simple gfx words
uts: provide fb_info via fbgattr dev_specific array.
uts: gfx_private add alpha blending
uts: update sys/ascii.h
uts: tem OSC support (incomplete)
uts: implement env module support and use data from
uts: tem get colors from early boot data
loader: use crc32 from libstand (libz)
loader: optimize for size
loader: pass tem info to the environment
loader: import tem for loader console
loader: UEFI loader needs to set ISADIR based on
loader: need UEFI32 support
8918 loader.efi: add vesa edid support
uts: tem_safe_pix_clear_prom_output() should only
uts: tem_safe_pix_clear_entire_screen() should use
uts: tem_safe_check_first_time() should query cursor
uts: tem implement cls callback & visual_io v4
uts: gfx_vgatext use block cursor for vgatext
uts: gfx_private implement cls callback & visual_io
uts: gfx_private bitmap framebuffer implementation
uts: early start frame buffer console support
uts: font functions should check the input char
uts: font rendering should support 16/24/32bit depths
uts: use smallest font as fallback default.
uts: update terminal dimensions based on selected
7834 uts: vgatext should use gfx_private
uts: add spacing property to 8859-1.bdf
terminfo: add underline for sun-color
terminfo: sun-color has 16 colors
uts: add font load callback type
loader: do not repeat int13 calls with error 0x20 and
8905 loader: add skein/edonr support
8904 common/crypto: make skein and edonr loader
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/cmd/boot/installboot/i386/installboot.c
+++ new/usr/src/cmd/boot/installboot/i386/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 * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
24 24 * Copyright 2017 Toomas Soome <tsoome@me.com>
|
↓ open down ↓ |
24 lines elided |
↑ open up ↑ |
25 25 */
26 26
27 27 #include <stdio.h>
28 28 #include <errno.h>
29 29 #include <unistd.h>
30 30 #include <fcntl.h>
31 31 #include <assert.h>
32 32 #include <locale.h>
33 33 #include <strings.h>
34 34 #include <libfdisk.h>
35 +#include <libgen.h>
35 36
36 37 #include <sys/dktp/fdisk.h>
37 38 #include <sys/dkio.h>
38 39 #include <sys/vtoc.h>
39 40 #include <sys/multiboot.h>
40 41 #include <sys/types.h>
41 42 #include <sys/stat.h>
42 43 #include <sys/sysmacros.h>
43 44 #include <sys/efi_partition.h>
44 45 #include <libfstyp.h>
45 46 #include <uuid/uuid.h>
46 47
47 48 #include "installboot.h"
48 49 #include "../../common/bblk_einfo.h"
49 50 #include "../../common/boot_utils.h"
50 51 #include "../../common/mboot_extra.h"
51 52 #include "getresponse.h"
52 53
53 54 #ifndef TEXT_DOMAIN
54 55 #define TEXT_DOMAIN "SUNW_OST_OSCMD"
55 56 #endif
56 57
57 58 /*
58 59 * BIOS bootblock installation:
59 60 *
60 61 * 1. MBR is first sector of the disk. If the file system on target is
61 62 * ufs or zfs, the same MBR code is installed on first sector of the
62 63 * partition as well; this will allow to have real MBR sector to be
63 64 * replaced by some other boot loader and have illumos chainloaded.
64 65 *
65 66 * installboot will record the start LBA and size of stage2 code in MBR code.
66 67 * On boot, the MBR code will read the stage2 code and executes it.
67 68 *
68 69 * 2. Stage2 location depends on file system type;
69 70 * In case of zfs, installboot will store stage2 to zfs bootblk area,
70 71 * which is 512k bytes from partition start and size is 3.5MB.
71 72 *
72 73 * In case of ufs, the stage2 location is 50 512B sectors from
73 74 * Solaris2 MBR partition start, within boot slice, boot slice size is
74 75 * one cylinder.
75 76 *
76 77 * In case of pcfs, the stage2 location is 50 512B sectors from beginning
77 78 * of the disk, filling the space between MBR and first partition.
78 79 * This location assumes no other bootloader and the space is one cylinder,
79 80 * as first partition is starting from cylinder 1.
80 81 *
81 82 * In case of GPT partitioning and if file system is not zfs, the boot
82 83 * support is only possible with dedicated boot partition. For GPT,
83 84 * the current implementation is using BOOT partition, which must exist.
84 85 * BOOT partition does only contain raw boot blocks, without any file system.
85 86 *
|
↓ open down ↓ |
41 lines elided |
↑ open up ↑ |
86 87 * Loader stage2 is created with embedded version, by using fake multiboot (MB)
87 88 * header within first 32k and EINFO block is at the end of the actual
88 89 * boot block. MB header load_addr is set to 0 and load_end_addr is set to
89 90 * actual block end, so the EINFO size is (file size - load_end_addr).
90 91 * installboot does also store the illumos boot partition LBA to MB space,
91 92 * starting from bss_end_addr structure member location; stage2 will
92 93 * detect the partition and file system based on this value.
93 94 *
94 95 * Stored location values in MBR/stage2 also mean the bootblocks must be
95 96 * reinstalled in case the partition content is relocated.
97 + *
98 + * EFI boot program installation:
99 + * EFI boot requires EFI System partition with following directory
100 + * hierarchy:
101 + * EFI/VENDOR/file
102 + * EFI/BOOT/BOOTx64.EFI
103 + * Where EFI/BOOT is fallback directory. While we have no mechanism to set
104 + * EFI variable values to define vendor specific boot program location, we
105 + * will just use EFI/BOOT/BOOTx64.EFI; also this setup is only possible
106 + * solution for removable media.
107 + * For now the boot1.efi is used for boot program, boot1.efi is also
108 + * versioned as is gptzfsboot.
96 109 */
97 110
98 111 static boolean_t write_mbr = B_FALSE;
99 112 static boolean_t force_mbr = B_FALSE;
100 113 static boolean_t force_update = B_FALSE;
101 114 static boolean_t do_getinfo = B_FALSE;
102 115 static boolean_t do_version = B_FALSE;
103 116 static boolean_t do_mirror_bblk = B_FALSE;
104 117 static boolean_t strip = B_FALSE;
105 118 static boolean_t verbose_dump = B_FALSE;
106 119
120 +#define EFIBOOT64 "bootx64.efi"
121 +#define EFIBOOT32 "bootia32.efi"
122 +
107 123 /* Versioning string, if present. */
108 124 static char *update_str;
109 125
110 126 /*
111 127 * Temporary buffer to store the first 32K of data looking for a multiboot
112 128 * signature.
113 129 */
114 130 char mboot_scan[MBOOT_SCAN_SIZE];
115 131
116 132 /* Function prototypes. */
117 133 static void check_options(char *);
118 134 static int get_start_sector(ib_device_t *);
119 135
120 136 static int read_stage1_from_file(char *, ib_data_t *);
121 137 static int read_bootblock_from_file(char *, ib_bootblock_t *);
122 138 static int read_bootblock_from_disk(ib_device_t *, ib_bootblock_t *, char **);
123 139 static void add_bootblock_einfo(ib_bootblock_t *, char *);
124 140 static int prepare_stage1(ib_data_t *);
125 141 static int prepare_bootblock(ib_data_t *, char *);
126 142 static int write_stage1(ib_data_t *);
127 143 static int write_bootblock(ib_data_t *);
128 144 static int init_device(ib_device_t *, char *);
129 145 static void cleanup_device(ib_device_t *);
130 146 static int commit_to_disk(ib_data_t *, char *);
131 147 static int handle_install(char *, char **);
132 148 static int handle_getinfo(char *, char **);
133 149 static int handle_mirror(char *, char **);
134 150 static boolean_t is_update_necessary(ib_data_t *, char *);
135 151 static int propagate_bootblock(ib_data_t *, ib_data_t *, char *);
136 152 static void usage(char *);
137 153
138 154 static int
139 155 read_stage1_from_file(char *path, ib_data_t *dest)
140 156 {
141 157 int fd;
142 158
143 159 assert(dest != NULL);
144 160
145 161 /* read the stage1 file from filesystem */
146 162 fd = open(path, O_RDONLY);
147 163 if (fd == -1 ||
148 164 read(fd, dest->stage1, SECTOR_SIZE) != SECTOR_SIZE) {
149 165 (void) fprintf(stderr, gettext("cannot read stage1 file %s\n"),
150 166 path);
151 167 return (BC_ERROR);
152 168 }
153 169 (void) close(fd);
154 170 return (BC_SUCCESS);
155 171 }
156 172
157 173 static int
158 174 read_bootblock_from_file(char *file, ib_bootblock_t *bblock)
159 175 {
160 176 struct stat sb;
161 177 uint32_t buf_size;
162 178 uint32_t mboot_off;
163 179 int fd = -1;
164 180 int retval = BC_ERROR;
165 181
166 182 assert(bblock != NULL);
167 183 assert(file != NULL);
168 184
169 185 fd = open(file, O_RDONLY);
170 186 if (fd == -1) {
171 187 BOOT_DEBUG("Error opening %s\n", file);
172 188 perror("open");
173 189 goto out;
174 190 }
175 191
176 192 if (fstat(fd, &sb) == -1) {
177 193 BOOT_DEBUG("Error getting information (stat) about %s", file);
178 194 perror("stat");
179 195 goto outfd;
180 196 }
181 197
182 198 /* loader bootblock has version built in */
183 199 buf_size = sb.st_size;
184 200
185 201 bblock->buf_size = buf_size;
186 202 BOOT_DEBUG("bootblock in-memory buffer size is %d\n",
187 203 bblock->buf_size);
188 204
189 205 bblock->buf = malloc(buf_size);
190 206 if (bblock->buf == NULL) {
191 207 perror(gettext("Memory allocation failure"));
192 208 goto outbuf;
193 209 }
194 210 bblock->file = bblock->buf;
195 211
196 212 if (read(fd, bblock->file, bblock->buf_size) != bblock->buf_size) {
197 213 BOOT_DEBUG("Read from %s failed\n", file);
198 214 perror("read");
199 215 goto outfd;
200 216 }
201 217
202 218 if (find_multiboot(bblock->file, MBOOT_SCAN_SIZE, &mboot_off)
203 219 != BC_SUCCESS) {
204 220 (void) fprintf(stderr,
205 221 gettext("Unable to find multiboot header\n"));
206 222 goto outfd;
207 223 }
208 224
209 225 bblock->mboot = (multiboot_header_t *)(bblock->file + mboot_off);
210 226 bblock->mboot_off = mboot_off;
211 227
212 228 bblock->file_size =
213 229 bblock->mboot->load_end_addr - bblock->mboot->load_addr;
214 230 BOOT_DEBUG("bootblock file size is %d\n", bblock->file_size);
215 231
216 232 bblock->extra = bblock->buf + P2ROUNDUP(bblock->file_size, 8);
217 233 bblock->extra_size = bblock->buf_size - P2ROUNDUP(bblock->file_size, 8);
218 234
219 235 BOOT_DEBUG("mboot at %p offset %d, extra at %p size %d, buf=%p "
220 236 "(size=%d)\n", bblock->mboot, bblock->mboot_off, bblock->extra,
221 237 bblock->extra_size, bblock->buf, bblock->buf_size);
222 238
223 239 (void) close(fd);
224 240 return (BC_SUCCESS);
225 241
226 242 outbuf:
227 243 (void) free(bblock->buf);
228 244 bblock->buf = NULL;
229 245 outfd:
230 246 (void) close(fd);
231 247 out:
232 248 return (retval);
233 249 }
234 250
235 251 static int
236 252 read_bootblock_from_disk(ib_device_t *device, ib_bootblock_t *bblock,
237 253 char **path)
238 254 {
239 255 int dev_fd;
240 256 uint32_t size, offset;
241 257 uint32_t buf_size;
242 258 uint32_t mboot_off;
243 259 multiboot_header_t *mboot;
244 260
245 261 assert(device != NULL);
246 262 assert(bblock != NULL);
247 263
248 264 if (device->target.fstype == IG_FS_ZFS) {
249 265 dev_fd = device->target.fd;
250 266 offset = BBLK_ZFS_BLK_OFF * SECTOR_SIZE;
251 267 *path = device->target.path;
252 268 } else {
253 269 dev_fd = device->stage.fd;
254 270 offset = device->stage.offset * SECTOR_SIZE;
255 271 *path = device->stage.path;
256 272 }
257 273
258 274 if (read_in(dev_fd, mboot_scan, sizeof (mboot_scan), offset)
259 275 != BC_SUCCESS) {
260 276 BOOT_DEBUG("Error reading bootblock area\n");
261 277 perror("read");
262 278 return (BC_ERROR);
263 279 }
264 280
265 281 /* No multiboot means no chance of knowing bootblock size */
266 282 if (find_multiboot(mboot_scan, sizeof (mboot_scan), &mboot_off)
267 283 != BC_SUCCESS) {
268 284 BOOT_DEBUG("Unable to find multiboot header\n");
269 285 return (BC_NOEXTRA);
270 286 }
271 287 mboot = (multiboot_header_t *)(mboot_scan + mboot_off);
272 288
273 289 /*
274 290 * make sure mboot has sane values
275 291 */
276 292 if (mboot->load_end_addr == 0 ||
277 293 mboot->load_end_addr < mboot->load_addr)
278 294 return (BC_NOEXTRA);
279 295
280 296 /*
281 297 * Currently, the amount of space reserved for extra information
282 298 * is "fixed". We may have to scan for the terminating extra payload
283 299 * in the future.
284 300 */
285 301 size = mboot->load_end_addr - mboot->load_addr;
286 302 buf_size = P2ROUNDUP(size + SECTOR_SIZE, SECTOR_SIZE);
287 303 bblock->file_size = size;
288 304
289 305 bblock->buf = malloc(buf_size);
290 306 if (bblock->buf == NULL) {
291 307 BOOT_DEBUG("Unable to allocate enough memory to read"
292 308 " the extra bootblock from the disk\n");
293 309 perror(gettext("Memory allocation failure"));
294 310 return (BC_ERROR);
295 311 }
296 312 bblock->buf_size = buf_size;
297 313
298 314 if (read_in(dev_fd, bblock->buf, buf_size, offset) != BC_SUCCESS) {
299 315 BOOT_DEBUG("Error reading the bootblock\n");
300 316 (void) free(bblock->buf);
301 317 bblock->buf = NULL;
302 318 return (BC_ERROR);
303 319 }
304 320
305 321 /* Update pointers. */
306 322 bblock->file = bblock->buf;
307 323 bblock->mboot_off = mboot_off;
308 324 bblock->mboot = (multiboot_header_t *)(bblock->buf + bblock->mboot_off);
309 325 bblock->extra = bblock->buf + P2ROUNDUP(bblock->file_size, 8);
310 326 bblock->extra_size = bblock->buf_size - P2ROUNDUP(bblock->file_size, 8);
311 327
312 328 BOOT_DEBUG("mboot at %p offset %d, extra at %p size %d, buf=%p "
313 329 "(size=%d)\n", bblock->mboot, bblock->mboot_off, bblock->extra,
314 330 bblock->extra_size, bblock->buf, bblock->buf_size);
315 331
316 332 return (BC_SUCCESS);
317 333 }
318 334
319 335 static boolean_t
320 336 is_update_necessary(ib_data_t *data, char *updt_str)
321 337 {
322 338 bblk_einfo_t *einfo;
323 339 bblk_einfo_t *einfo_file;
324 340 bblk_hs_t bblock_hs;
325 341 ib_bootblock_t bblock_disk;
326 342 ib_bootblock_t *bblock_file = &data->bootblock;
327 343 ib_device_t *device = &data->device;
328 344 int ret;
329 345 char *path;
330 346
331 347 assert(data != NULL);
332 348
333 349 bzero(&bblock_disk, sizeof (ib_bootblock_t));
334 350
335 351 ret = read_bootblock_from_disk(device, &bblock_disk, &path);
336 352 if (ret != BC_SUCCESS) {
337 353 BOOT_DEBUG("Unable to read bootblock from %s\n", path);
338 354 return (B_TRUE);
339 355 }
340 356
341 357 einfo = find_einfo(bblock_disk.extra, bblock_disk.extra_size);
342 358 if (einfo == NULL) {
343 359 BOOT_DEBUG("No extended information available on disk\n");
344 360 return (B_TRUE);
345 361 }
346 362
347 363 einfo_file = find_einfo(bblock_file->extra, bblock_file->extra_size);
348 364 if (einfo_file == NULL) {
349 365 /*
350 366 * loader bootblock is versioned. missing version means
351 367 * probably incompatible block. installboot can not install
352 368 * grub, for example.
353 369 */
354 370 (void) fprintf(stderr,
355 371 gettext("ERROR: non versioned bootblock in file\n"));
356 372 return (B_FALSE);
357 373 } else {
358 374 if (updt_str == NULL) {
359 375 updt_str = einfo_get_string(einfo_file);
360 376 do_version = B_TRUE;
361 377 }
362 378 }
363 379
364 380 if (!do_version || updt_str == NULL) {
365 381 (void) fprintf(stderr,
366 382 gettext("WARNING: target device %s has a "
367 383 "versioned bootblock that is going to be overwritten by a "
368 384 "non versioned one\n"), device->path);
369 385 return (B_TRUE);
370 386 }
371 387
372 388 if (force_update) {
373 389 BOOT_DEBUG("Forcing update of %s bootblock\n", device->path);
374 390 return (B_TRUE);
375 391 }
376 392
377 393 BOOT_DEBUG("Ready to check installed version vs %s\n", updt_str);
378 394
379 395 bblock_hs.src_buf = (unsigned char *)bblock_file->file;
380 396 bblock_hs.src_size = bblock_file->file_size;
381 397
382 398 return (einfo_should_update(einfo, &bblock_hs, updt_str));
383 399 }
384 400
385 401 static void
386 402 add_bootblock_einfo(ib_bootblock_t *bblock, char *updt_str)
387 403 {
388 404 bblk_hs_t hs;
389 405 uint32_t avail_space;
390 406
391 407 assert(bblock != NULL);
392 408
393 409 if (updt_str == NULL) {
394 410 BOOT_DEBUG("WARNING: no update string passed to "
395 411 "add_bootblock_einfo()\n");
396 412 return;
397 413 }
398 414
399 415 /* Fill bootblock hashing source information. */
400 416 hs.src_buf = (unsigned char *)bblock->file;
401 417 hs.src_size = bblock->file_size;
402 418 /* How much space for the extended information structure? */
403 419 avail_space = bblock->buf_size - P2ROUNDUP(bblock->file_size, 8);
404 420 /* Place the extended information structure. */
405 421 add_einfo(bblock->extra, updt_str, &hs, avail_space);
406 422 }
407 423
408 424 /*
409 425 * set up data for case stage1 is installed as MBR
410 426 * set up location and size of bootblock
411 427 * set disk guid to provide unique information for biosdev command
412 428 */
413 429 static int
414 430 prepare_stage1(ib_data_t *data)
415 431 {
416 432 ib_device_t *device;
417 433
418 434 assert(data != NULL);
419 435 device = &data->device;
420 436
421 437 /* copy BPB */
422 438 bcopy(device->mbr + STAGE1_BPB_OFFSET,
423 439 data->stage1 + STAGE1_BPB_OFFSET, STAGE1_BPB_SIZE);
424 440
425 441
426 442 /* copy MBR, note STAGE1_SIG == BOOTSZ */
427 443 bcopy(device->mbr + STAGE1_SIG, data->stage1 + STAGE1_SIG,
428 444 SECTOR_SIZE - STAGE1_SIG);
429 445
430 446 /* set stage2 size */
431 447 *((uint16_t *)(data->stage1 + STAGE1_STAGE2_SIZE)) =
432 448 (uint16_t)(data->bootblock.buf_size / SECTOR_SIZE);
433 449
434 450 /*
435 451 * set stage2 location.
436 452 * for zfs always use zfs embedding, for ufs/pcfs use partition_start
437 453 * as base for stage2 location, for ufs/pcfs in MBR partition, use
438 454 * free space after MBR record.
439 455 */
440 456 if (device->target.fstype == IG_FS_ZFS)
441 457 *((uint64_t *)(data->stage1 + STAGE1_STAGE2_LBA)) =
442 458 device->target.start + device->target.offset;
443 459 else {
444 460 *((uint64_t *)(data->stage1 + STAGE1_STAGE2_LBA)) =
445 461 device->stage.start + device->stage.offset;
446 462 }
447 463
448 464 /*
449 465 * set disk uuid. we only need reasonable amount of uniqueness
450 466 * to allow biosdev to identify disk based on mbr differences.
451 467 */
452 468 uuid_generate(data->stage1 + STAGE1_STAGE2_UUID);
453 469
454 470 return (BC_SUCCESS);
455 471 }
456 472
457 473 static int
458 474 prepare_bootblock(ib_data_t *data, char *updt_str)
459 475 {
460 476 ib_bootblock_t *bblock;
461 477 ib_device_t *device;
462 478 uint64_t *ptr;
463 479
464 480 assert(data != NULL);
465 481
466 482 bblock = &data->bootblock;
467 483 device = &data->device;
468 484
469 485 ptr = (uint64_t *)(&bblock->mboot->bss_end_addr);
470 486 *ptr = device->target.start;
471 487
472 488 /*
473 489 * the loader bootblock has built in version, if custom
474 490 * version was provided, update it.
475 491 */
476 492 if (do_version)
477 493 add_bootblock_einfo(bblock, updt_str);
478 494
479 495 return (BC_SUCCESS);
480 496 }
481 497
482 498 static int
483 499 write_bootblock(ib_data_t *data)
484 500 {
485 501 ib_device_t *device = &data->device;
486 502 ib_bootblock_t *bblock = &data->bootblock;
487 503 uint64_t abs;
488 504 int dev_fd, ret;
489 505 off_t offset;
490 506 char *path;
491 507
492 508 assert(data != NULL);
493 509
494 510 /*
495 511 * ZFS bootblock area is 3.5MB, make sure we can fit.
496 512 * buf_size is size of bootblk+EINFO.
497 513 */
498 514 if (bblock->buf_size > BBLK_ZFS_BLK_SIZE) {
499 515 (void) fprintf(stderr, gettext("bootblock is too large\n"));
500 516 return (BC_ERROR);
501 517 }
502 518
503 519 if (device->target.fstype == IG_FS_ZFS) {
504 520 dev_fd = device->target.fd;
505 521 abs = device->target.start + device->target.offset;
506 522 offset = BBLK_ZFS_BLK_OFF * SECTOR_SIZE;
507 523 path = device->target.path;
508 524 } else {
509 525 dev_fd = device->stage.fd;
510 526 abs = device->stage.start + device->stage.offset;
511 527 offset = device->stage.offset * SECTOR_SIZE;
512 528 path = device->stage.path;
513 529 if (bblock->buf_size >
514 530 (device->stage.size - device->stage.offset) * SECTOR_SIZE) {
515 531 (void) fprintf(stderr, gettext("Device %s is "
516 532 "too small to fit the stage2\n"), path);
517 533 return (BC_ERROR);
518 534 }
519 535 }
520 536 ret = write_out(dev_fd, bblock->buf, bblock->buf_size, offset);
521 537 if (ret != BC_SUCCESS) {
522 538 BOOT_DEBUG("Error writing the ZFS bootblock "
523 539 "to %s at offset %d\n", path, offset);
524 540 return (BC_ERROR);
525 541 }
526 542
527 543 (void) fprintf(stdout, gettext("bootblock written for %s,"
528 544 " %d sectors starting at %d (abs %lld)\n"), path,
529 545 (bblock->buf_size / SECTOR_SIZE) + 1, offset / SECTOR_SIZE, abs);
530 546
531 547 return (BC_SUCCESS);
532 548 }
533 549
534 550 /*
535 551 * Partition boot block or volume boot record (VBR). The VBR is
536 552 * stored on partition relative sector 0 and allows chainloading
537 553 * to read boot program from partition.
538 554 *
539 555 * As the VBR will use the first sector of the partition,
540 556 * this means, we need to be sure the space is not used.
541 557 * We do support three partitioning chemes:
542 558 * 1. GPT: zfs and ufs have reserved space for first 8KB, but
543 559 * only zfs does have space for boot2. The pcfs has support
544 560 * for VBR, but no space for boot2. So with GPT, to support
545 561 * ufs or pcfs boot, we must have separate dedicated boot
546 562 * partition and we will store VBR on it.
547 563 * 2. MBR: we have almost the same situation as with GPT, except that
548 564 * if the partitions start from cylinder 1, we will have space
549 565 * between MBR and cylinder 0. If so, we do not require separate
550 566 * boot partition.
551 567 * 3. MBR+VTOC: with this combination we store VBR in sector 0 of the
552 568 * solaris2 MBR partition. The slice 0 will start from cylinder 1,
553 569 * and we do have space for boot2, so we do not require separate
554 570 * boot partition.
555 571 */
556 572 static int
557 573 write_stage1(ib_data_t *data)
558 574 {
559 575 ib_device_t *device = &data->device;
560 576 uint64_t start = 0;
561 577
562 578 assert(data != NULL);
563 579
564 580 /*
565 581 * We have separate partition for boot programs and the stage1
566 582 * location is not absolute sector 0.
567 583 * We will write VBR and trigger MBR to read 1 sector from VBR.
568 584 * This case does also cover MBR+VTOC case, as the solaris 2 partition
569 585 * name and the root file system slice names are different.
570 586 */
571 587 if (device->stage.start != 0 &&
572 588 strcmp(device->target.path, device->stage.path)) {
573 589 /* we got separate stage area, use it */
574 590 if (write_out(device->stage.fd, data->stage1,
575 591 sizeof (data->stage1), 0) != BC_SUCCESS) {
576 592 (void) fprintf(stdout, gettext("cannot write "
577 593 "partition boot sector\n"));
578 594 perror("write");
579 595 return (BC_ERROR);
580 596 }
581 597
582 598 (void) fprintf(stdout, gettext("stage1 written to "
583 599 "%s %d sector 0 (abs %d)\n"),
584 600 device->devtype == IG_DEV_MBR? "partition":"slice",
585 601 device->stage.id, device->stage.start);
586 602 start = device->stage.start;
587 603 }
588 604
589 605 /*
590 606 * We have either GPT or MBR (without VTOC) and if the root
591 607 * file system is not pcfs, we can store VBR. Also trigger
592 608 * MBR to read 1 sector from VBR.
593 609 */
594 610 if (device->devtype != IG_DEV_VTOC &&
595 611 device->target.fstype != IG_FS_PCFS) {
596 612 if (write_out(device->target.fd, data->stage1,
597 613 sizeof (data->stage1), 0) != BC_SUCCESS) {
598 614 (void) fprintf(stdout, gettext("cannot write "
599 615 "partition boot sector\n"));
600 616 perror("write");
601 617 return (BC_ERROR);
602 618 }
603 619
604 620 (void) fprintf(stdout, gettext("stage1 written to "
605 621 "%s %d sector 0 (abs %d)\n"),
606 622 device->devtype == IG_DEV_MBR? "partition":"slice",
607 623 device->target.id, device->target.start);
608 624 start = device->target.start;
609 625 }
610 626
611 627 if (write_mbr) {
612 628 /*
613 629 * If we did write partition boot block, update MBR to
614 630 * read partition boot block, not boot2.
615 631 */
616 632 if (start != 0) {
617 633 *((uint16_t *)(data->stage1 + STAGE1_STAGE2_SIZE)) = 1;
618 634 *((uint64_t *)(data->stage1 + STAGE1_STAGE2_LBA)) =
619 635 start;
620 636 }
621 637 if (write_out(device->fd, data->stage1,
622 638 sizeof (data->stage1), 0) != BC_SUCCESS) {
623 639 (void) fprintf(stdout,
624 640 gettext("cannot write master boot sector\n"));
625 641 perror("write");
626 642 return (BC_ERROR);
627 643 }
628 644 (void) fprintf(stdout,
629 645 gettext("stage1 written to master boot sector\n"));
630 646 }
631 647
632 648 return (BC_SUCCESS);
633 649 }
634 650
635 651 /*
636 652 * find partition/slice start sector. will be recorded in stage2 and used
637 653 * by stage2 to identify partition with boot file system.
638 654 */
639 655 static int
640 656 get_start_sector(ib_device_t *device)
641 657 {
642 658 uint32_t secnum = 0, numsec = 0;
643 659 int i, pno, rval, log_part = 0;
644 660 struct mboot *mboot;
645 661 struct ipart *part = NULL;
646 662 ext_part_t *epp;
647 663 struct part_info dkpi;
648 664 struct extpart_info edkpi;
649 665
650 666 if (device->devtype == IG_DEV_EFI) {
651 667 struct dk_gpt *vtoc;
652 668
653 669 if (efi_alloc_and_read(device->fd, &vtoc) < 0)
654 670 return (BC_ERROR);
655 671
656 672 if (device->stage.start == 0) {
657 673 /* zero size means the fstype must be zfs */
658 674 assert(device->target.fstype == IG_FS_ZFS);
659 675
660 676 device->stage.start =
661 677 vtoc->efi_parts[device->stage.id].p_start;
662 678 device->stage.size =
663 679 vtoc->efi_parts[device->stage.id].p_size;
664 680 device->stage.offset = BBLK_ZFS_BLK_OFF;
665 681 device->target.offset = BBLK_ZFS_BLK_OFF;
666 682 }
667 683
668 684 device->target.start =
669 685 vtoc->efi_parts[device->target.id].p_start;
670 686 device->target.size =
671 687 vtoc->efi_parts[device->target.id].p_size;
672 688
673 689 /* with pcfs we always write MBR */
674 690 if (device->target.fstype == IG_FS_PCFS) {
675 691 force_mbr = 1;
676 692 write_mbr = 1;
677 693 }
678 694
679 695 efi_free(vtoc);
680 696 goto found_part;
681 697 }
682 698
683 699 mboot = (struct mboot *)device->mbr;
684 700
685 701 /* For MBR we have device->stage filled already. */
686 702 if (device->devtype == IG_DEV_MBR) {
687 703 /* MBR partition starts from 0 */
688 704 pno = device->target.id - 1;
689 705 part = (struct ipart *)mboot->parts + pno;
690 706
691 707 if (part->relsect == 0) {
692 708 (void) fprintf(stderr, gettext("Partition %d of the "
693 709 "disk has an incorrect offset\n"),
694 710 device->target.id);
695 711 return (BC_ERROR);
696 712 }
697 713 device->target.start = part->relsect;
698 714 device->target.size = part->numsect;
699 715
700 716 /* with pcfs we always write MBR */
701 717 if (device->target.fstype == IG_FS_PCFS) {
702 718 force_mbr = 1;
703 719 write_mbr = 1;
704 720 }
705 721 if (device->target.fstype == IG_FS_ZFS)
706 722 device->target.offset = BBLK_ZFS_BLK_OFF;
707 723
708 724 goto found_part;
709 725 }
710 726
711 727 /*
712 728 * Search for Solaris fdisk partition
713 729 * Get the solaris partition information from the device
714 730 * and compare the offset of S2 with offset of solaris partition
715 731 * from fdisk partition table.
716 732 */
717 733 if (ioctl(device->target.fd, DKIOCEXTPARTINFO, &edkpi) < 0) {
718 734 if (ioctl(device->target.fd, DKIOCPARTINFO, &dkpi) < 0) {
719 735 (void) fprintf(stderr, gettext("cannot get the "
720 736 "slice information of the disk\n"));
721 737 return (BC_ERROR);
722 738 } else {
723 739 edkpi.p_start = dkpi.p_start;
724 740 edkpi.p_length = dkpi.p_length;
725 741 }
726 742 }
727 743
728 744 device->target.start = edkpi.p_start;
729 745 device->target.size = edkpi.p_length;
730 746 if (device->target.fstype == IG_FS_ZFS)
731 747 device->target.offset = BBLK_ZFS_BLK_OFF;
732 748
733 749 for (i = 0; i < FD_NUMPART; i++) {
734 750 part = (struct ipart *)mboot->parts + i;
735 751
736 752 if (part->relsect == 0) {
737 753 (void) fprintf(stderr, gettext("Partition %d of the "
738 754 "disk has an incorrect offset\n"), i+1);
739 755 return (BC_ERROR);
740 756 }
741 757
742 758 if (edkpi.p_start >= part->relsect &&
743 759 edkpi.p_start < (part->relsect + part->numsect)) {
744 760 /* Found the partition */
745 761 break;
746 762 }
747 763 }
748 764
749 765 if (i == FD_NUMPART) {
750 766 /* No solaris fdisk partitions (primary or logical) */
751 767 (void) fprintf(stderr, gettext("Solaris partition not found. "
752 768 "Aborting operation.\n"));
753 769 return (BC_ERROR);
754 770 }
755 771
756 772 /*
757 773 * We have found a Solaris fdisk partition (primary or extended)
758 774 * Handle the simple case first: Solaris in a primary partition
759 775 */
760 776 if (!fdisk_is_dos_extended(part->systid)) {
761 777 device->stage.start = part->relsect;
762 778 device->stage.size = part->numsect;
763 779 if (device->target.fstype == IG_FS_ZFS)
764 780 device->stage.offset = BBLK_ZFS_BLK_OFF;
765 781 else
766 782 device->stage.offset = BBLK_BLKLIST_OFF;
767 783 device->stage.id = i + 1;
768 784 goto found_part;
769 785 }
770 786
771 787 /*
772 788 * Solaris in a logical partition. Find that partition in the
773 789 * extended part.
774 790 */
775 791
776 792 if ((rval = libfdisk_init(&epp, device->path, NULL, FDISK_READ_DISK))
777 793 != FDISK_SUCCESS) {
778 794 switch (rval) {
779 795 /*
780 796 * The first 3 cases are not an error per-se, just that
781 797 * there is no Solaris logical partition
782 798 */
783 799 case FDISK_EBADLOGDRIVE:
784 800 case FDISK_ENOLOGDRIVE:
785 801 case FDISK_EBADMAGIC:
786 802 (void) fprintf(stderr, gettext("Solaris "
787 803 "partition not found. "
788 804 "Aborting operation.\n"));
789 805 return (BC_ERROR);
790 806 case FDISK_ENOVGEOM:
791 807 (void) fprintf(stderr, gettext("Could not get "
792 808 "virtual geometry\n"));
793 809 return (BC_ERROR);
794 810 case FDISK_ENOPGEOM:
795 811 (void) fprintf(stderr, gettext("Could not get "
796 812 "physical geometry\n"));
797 813 return (BC_ERROR);
798 814 case FDISK_ENOLGEOM:
799 815 (void) fprintf(stderr, gettext("Could not get "
800 816 "label geometry\n"));
801 817 return (BC_ERROR);
802 818 default:
803 819 (void) fprintf(stderr, gettext("Failed to "
804 820 "initialize libfdisk.\n"));
805 821 return (BC_ERROR);
806 822 }
807 823 }
808 824
809 825 rval = fdisk_get_solaris_part(epp, &pno, &secnum, &numsec);
810 826 libfdisk_fini(&epp);
811 827 if (rval != FDISK_SUCCESS) {
812 828 /* No solaris logical partition */
813 829 (void) fprintf(stderr, gettext("Solaris partition not found. "
814 830 "Aborting operation.\n"));
815 831 return (BC_ERROR);
816 832 }
817 833
818 834 device->stage.start = secnum;
819 835 device->stage.size = numsec;
820 836 device->stage.id = pno;
821 837 log_part = 1;
822 838
823 839 found_part:
824 840 /* get confirmation for -m */
825 841 if (write_mbr && !force_mbr) {
826 842 (void) fprintf(stdout, gettext("Updating master boot sector "
827 843 "destroys existing boot managers (if any).\n"
828 844 "continue (y/n)? "));
829 845 if (!yes()) {
830 846 write_mbr = 0;
831 847 (void) fprintf(stdout, gettext("master boot sector "
832 848 "not updated\n"));
833 849 return (BC_ERROR);
834 850 }
835 851 }
836 852
837 853 /*
838 854 * warn, if illumos in primary partition and loader not in MBR and
839 855 * partition is not active
840 856 */
841 857 if (device->devtype != IG_DEV_EFI) {
842 858 if (!log_part && part->bootid != 128 && !write_mbr) {
843 859 (void) fprintf(stdout, gettext("Solaris fdisk "
844 860 "partition is inactive.\n"), device->stage.id);
845 861 }
846 862 }
847 863
848 864 return (BC_SUCCESS);
849 865 }
850 866
851 867 static int
852 868 open_device(char *path)
853 869 {
854 870 struct stat statbuf = {0};
855 871 int fd = -1;
856 872
857 873 if (nowrite)
858 874 fd = open(path, O_RDONLY);
859 875 else
860 876 fd = open(path, O_RDWR);
861 877
862 878 if (fd == -1) {
863 879 BOOT_DEBUG("Unable to open %s\n", path);
864 880 perror("open");
865 881 return (-1);
866 882 }
867 883
868 884 if (fstat(fd, &statbuf) != 0) {
869 885 BOOT_DEBUG("Unable to stat %s\n", path);
870 886 perror("stat");
871 887 (void) close(fd);
872 888 return (-1);
873 889 }
874 890
875 891 if (S_ISCHR(statbuf.st_mode) == 0) {
876 892 (void) fprintf(stderr, gettext("%s: Not a character device\n"),
877 893 path);
878 894 (void) close(fd);
879 895 return (-1);
880 896 }
881 897
882 898 return (fd);
883 899 }
884 900
885 901 static int
886 902 get_boot_partition(ib_device_t *device, struct mboot *mbr)
887 903 {
888 904 struct ipart *part;
889 905 char *path, *ptr;
890 906 int i;
891 907
892 908 part = (struct ipart *)mbr->parts;
893 909 for (i = 0; i < FD_NUMPART; i++) {
894 910 if (part[i].systid == X86BOOT)
895 911 break;
896 912 }
897 913
898 914 /* no X86BOOT, try to use space between MBR and first partition */
899 915 if (i == FD_NUMPART) {
900 916 device->stage.path = strdup(device->path);
901 917 if (device->stage.path == NULL) {
902 918 perror(gettext("Memory allocation failure"));
903 919 return (BC_ERROR);
904 920 }
905 921 device->stage.fd = dup(device->fd);
906 922 device->stage.id = 0;
907 923 device->stage.devtype = IG_DEV_MBR;
908 924 device->stage.fstype = IG_FS_NONE;
909 925 device->stage.start = 0;
910 926 device->stage.size = part[0].relsect;
911 927 device->stage.offset = BBLK_BLKLIST_OFF;
912 928 return (BC_SUCCESS);
913 929 }
914 930
915 931 if ((path = strdup(device->path)) == NULL) {
916 932 perror(gettext("Memory allocation failure"));
917 933 return (BC_ERROR);
918 934 }
919 935
920 936 ptr = strrchr(path, 'p');
921 937 ptr++;
922 938 *ptr = '\0';
923 939 (void) asprintf(&ptr, "%s%d", path, i+1); /* partitions are p1..p4 */
924 940 free(path);
925 941 if (ptr == NULL) {
926 942 perror(gettext("Memory allocation failure"));
927 943 return (BC_ERROR);
928 944 }
929 945 device->stage.path = ptr;
930 946 device->stage.fd = open_device(ptr);
931 947 device->stage.id = i + 1;
932 948 device->stage.devtype = IG_DEV_MBR;
933 949 device->stage.fstype = IG_FS_NONE;
934 950 device->stage.start = part[i].relsect;
935 951 device->stage.size = part[i].numsect;
936 952 device->stage.offset = 1; /* leave sector 0 for VBR */
|
↓ open down ↓ |
820 lines elided |
↑ open up ↑ |
937 953 return (BC_SUCCESS);
938 954 }
939 955
940 956 static int
941 957 get_boot_slice(ib_device_t *device, struct dk_gpt *vtoc)
942 958 {
943 959 uint_t i;
944 960 char *path, *ptr;
945 961
946 962 for (i = 0; i < vtoc->efi_nparts; i++) {
947 - if (vtoc->efi_parts[i].p_tag == V_BOOT) {
963 + if (vtoc->efi_parts[i].p_tag == V_SYSTEM) {
948 964 if ((path = strdup(device->target.path)) == NULL) {
949 965 perror(gettext("Memory allocation failure"));
950 966 return (BC_ERROR);
951 967 }
952 968 ptr = strrchr(path, 's');
953 969 ptr++;
954 970 *ptr = '\0';
955 971 (void) asprintf(&ptr, "%s%d", path, i);
956 972 free(path);
957 973 if (ptr == NULL) {
958 974 perror(gettext("Memory allocation failure"));
959 975 return (BC_ERROR);
960 976 }
977 + device->system.path = ptr;
978 + device->system.fd = open_device(ptr);
979 + device->system.id = i;
980 + device->system.devtype = IG_DEV_EFI;
981 + device->system.fstype = IG_FS_PCFS;
982 + device->system.start = vtoc->efi_parts[i].p_start;
983 + device->system.size = vtoc->efi_parts[i].p_size;
984 + device->system.offset = 0;
985 + } else if (vtoc->efi_parts[i].p_tag == V_BOOT) {
986 + if ((path = strdup(device->target.path)) == NULL) {
987 + perror(gettext("Memory allocation failure"));
988 + return (BC_ERROR);
989 + }
990 + ptr = strrchr(path, 's');
991 + ptr++;
992 + *ptr = '\0';
993 + (void) asprintf(&ptr, "%s%d", path, i);
994 + free(path);
995 + if (ptr == NULL) {
996 + perror(gettext("Memory allocation failure"));
997 + return (BC_ERROR);
998 + }
961 999 device->stage.path = ptr;
962 1000 device->stage.fd = open_device(ptr);
963 1001 device->stage.id = i;
964 1002 device->stage.devtype = IG_DEV_EFI;
965 1003 device->stage.fstype = IG_FS_NONE;
966 1004 device->stage.start = vtoc->efi_parts[i].p_start;
967 1005 device->stage.size = vtoc->efi_parts[i].p_size;
968 1006 device->stage.offset = 1; /* leave sector 0 for VBR */
969 - return (BC_SUCCESS);
970 1007 }
971 1008 }
972 1009 return (BC_SUCCESS);
973 1010 }
974 1011
975 1012 static int
976 1013 init_device(ib_device_t *device, char *path)
977 1014 {
978 1015 struct dk_gpt *vtoc;
979 1016 fstyp_handle_t fhdl;
980 1017 const char *fident;
981 1018 char *p;
982 1019 int pathlen = strlen(path);
983 1020 int ret;
984 1021
985 1022 bzero(device, sizeof (*device));
986 1023 device->fd = -1; /* whole disk fd */
987 1024 device->stage.fd = -1; /* bootblock partition fd */
1025 + device->system.fd = -1; /* efi system partition fd */
988 1026 device->target.fd = -1; /* target fs partition fd */
989 1027
990 1028 /* basic check, whole disk is not allowed */
991 1029 if ((p = strrchr(path, '/')) == NULL)
992 1030 p = path;
993 1031 if ((strrchr(p, 'p') == NULL && strrchr(p, 's') == NULL) ||
994 1032 (path[pathlen-2] == 'p' && path[pathlen-1] == '0')) {
995 1033 (void) fprintf(stderr, gettext("installing loader to "
996 1034 "whole disk device is not supported\n"));
997 1035 }
998 1036
999 1037 device->target.path = strdup(path);
1000 1038 if (device->target.path == NULL) {
1001 1039 perror(gettext("Memory allocation failure"));
1002 1040 return (BC_ERROR);
1003 1041 }
1004 1042 device->path = strdup(path);
1005 1043 if (device->path == NULL) {
1006 1044 perror(gettext("Memory allocation failure"));
1007 1045 return (BC_ERROR);
1008 1046 }
1009 1047
1010 1048 /* change device name to p0 */
1011 1049 device->path[pathlen - 2] = 'p';
1012 1050 device->path[pathlen - 1] = '0';
1013 1051
1014 1052 if (strstr(device->target.path, "diskette")) {
1015 1053 (void) fprintf(stderr, gettext("installing loader to a floppy "
1016 1054 "disk is not supported\n"));
1017 1055 return (BC_ERROR);
1018 1056 }
1019 1057
1020 1058 /* Detect if the target device is a pcfs partition. */
1021 1059 if (strstr(device->target.path, "p0:boot")) {
1022 1060 (void) fprintf(stderr, gettext("installing loader to x86 boot "
1023 1061 "partition is not supported\n"));
1024 1062 return (BC_ERROR);
1025 1063 }
1026 1064
1027 1065 if ((device->fd = open_device(device->path)) == -1)
1028 1066 return (BC_ERROR);
1029 1067
1030 1068 /* read in the device boot sector. */
1031 1069 if (read(device->fd, device->mbr, SECTOR_SIZE) != SECTOR_SIZE) {
1032 1070 (void) fprintf(stderr, gettext("Error reading boot sector\n"));
1033 1071 perror("read");
1034 1072 return (BC_ERROR);
1035 1073 }
1036 1074
1037 1075 device->devtype = IG_DEV_VTOC;
1038 1076 if (efi_alloc_and_read(device->fd, &vtoc) >= 0) {
1039 1077 ret = get_boot_slice(device, vtoc);
1040 1078 device->devtype = IG_DEV_EFI;
1041 1079 efi_free(vtoc);
1042 1080 if (ret == BC_ERROR)
1043 1081 return (BC_ERROR);
1044 1082 } else if (device->target.path[pathlen - 2] == 'p') {
1045 1083 device->devtype = IG_DEV_MBR;
1046 1084 ret = get_boot_partition(device, (struct mboot *)device->mbr);
1047 1085 if (ret == BC_ERROR)
1048 1086 return (BC_ERROR);
1049 1087 } else if (device->target.path[pathlen - 1] == '2') {
1050 1088 /*
1051 1089 * NOTE: we could relax there and allow zfs boot on
1052 1090 * slice 2 for instance, but lets keep traditional limits.
1053 1091 */
1054 1092 (void) fprintf(stderr,
1055 1093 gettext("raw device must be a root slice (not s2)\n"));
1056 1094 return (BC_ERROR);
1057 1095 }
1058 1096
1059 1097 /* fill stage partition for case there is no boot partition */
1060 1098 if (device->stage.path == NULL) {
1061 1099 if ((device->stage.path = strdup(path)) == NULL) {
1062 1100 perror(gettext("Memory allocation failure"));
1063 1101 return (BC_ERROR);
1064 1102 }
1065 1103 if (device->devtype == IG_DEV_VTOC) {
1066 1104 /* use slice 2 */
1067 1105 device->stage.path[pathlen - 2] = 's';
1068 1106 device->stage.path[pathlen - 1] = '2';
1069 1107 device->stage.id = 2;
1070 1108 } else {
1071 1109 p = strrchr(device->stage.path, 'p');
1072 1110 if (p == NULL)
1073 1111 p = strrchr(device->stage.path, 's');
1074 1112 device->stage.id = atoi(++p);
1075 1113 }
1076 1114 device->stage.devtype = device->devtype;
1077 1115 device->stage.fd = open_device(device->stage.path);
1078 1116 }
1079 1117
1080 1118 p = strrchr(device->target.path, 'p');
1081 1119 if (p == NULL)
1082 1120 p = strrchr(device->target.path, 's');
1083 1121 device->target.id = atoi(++p);
1084 1122
1085 1123 if (strcmp(device->stage.path, device->target.path) == 0)
1086 1124 device->target.fd = dup(device->stage.fd);
1087 1125 else
1088 1126 device->target.fd = open_device(device->target.path);
1089 1127
1090 1128 if (fstyp_init(device->target.fd, 0, NULL, &fhdl) != 0)
1091 1129 return (BC_ERROR);
1092 1130
1093 1131 if (fstyp_ident(fhdl, NULL, &fident) != 0) {
1094 1132 fstyp_fini(fhdl);
1095 1133 (void) fprintf(stderr, gettext("Failed to detect file "
1096 1134 "system type\n"));
1097 1135 return (BC_ERROR);
1098 1136 }
1099 1137
1100 1138 /* at this moment non-boot partition has no size set, use this fact */
1101 1139 if (device->devtype == IG_DEV_EFI && strcmp(fident, "zfs") &&
1102 1140 device->stage.size == 0) {
1103 1141 fstyp_fini(fhdl);
1104 1142 (void) fprintf(stderr, gettext("Booting %s of EFI labeled "
1105 1143 "disks requires the boot partition.\n"), fident);
1106 1144 return (BC_ERROR);
1107 1145 }
1108 1146 if (strcmp(fident, "zfs") == 0)
1109 1147 device->target.fstype = IG_FS_ZFS;
1110 1148 else if (strcmp(fident, "ufs") == 0) {
1111 1149 device->target.fstype = IG_FS_UFS;
1112 1150 } else if (strcmp(fident, "pcfs") == 0) {
1113 1151 device->target.fstype = IG_FS_PCFS;
1114 1152 } else {
1115 1153 (void) fprintf(stderr, gettext("File system %s is not "
1116 1154 "supported by loader\n"), fident);
1117 1155 fstyp_fini(fhdl);
1118 1156 return (BC_ERROR);
1119 1157 }
1120 1158 fstyp_fini(fhdl);
1121 1159
1122 1160 /* check for boot partition content */
1123 1161 if (device->stage.size) {
1124 1162 if (fstyp_init(device->stage.fd, 0, NULL, &fhdl) != 0)
1125 1163 return (BC_ERROR);
1126 1164
1127 1165 if (fstyp_ident(fhdl, NULL, &fident) == 0) {
1128 1166 (void) fprintf(stderr, gettext("Unexpected %s file "
1129 1167 "system on boot partition\n"), fident);
1130 1168 fstyp_fini(fhdl);
1131 1169 return (BC_ERROR);
1132 1170 }
1133 1171 fstyp_fini(fhdl);
1134 1172 }
|
↓ open down ↓ |
137 lines elided |
↑ open up ↑ |
1135 1173 return (get_start_sector(device));
1136 1174 }
1137 1175
1138 1176 static void
1139 1177 cleanup_device(ib_device_t *device)
1140 1178 {
1141 1179 if (device->path)
1142 1180 free(device->path);
1143 1181 if (device->stage.path)
1144 1182 free(device->stage.path);
1183 + if (device->system.path)
1184 + free(device->system.path);
1145 1185 if (device->target.path)
1146 1186 free(device->target.path);
1147 1187
1148 1188 if (device->fd != -1)
1149 1189 (void) close(device->fd);
1150 1190 if (device->stage.fd != -1)
1151 1191 (void) close(device->stage.fd);
1192 + if (device->system.fd != -1)
1193 + (void) close(device->system.fd);
1152 1194 if (device->target.fd != -1)
1153 1195 (void) close(device->target.fd);
1154 1196 bzero(device, sizeof (*device));
1155 1197 }
1156 1198
1157 1199 static void
1158 1200 cleanup_bootblock(ib_bootblock_t *bblock)
1159 1201 {
1160 1202 free(bblock->buf);
1161 1203 bzero(bblock, sizeof (ib_bootblock_t));
1162 1204 }
1163 1205
1164 1206 /*
1165 1207 * Propagate the bootblock on the source disk to the destination disk and
1166 1208 * version it with 'updt_str' in the process. Since we cannot trust any data
1167 1209 * on the attaching disk, we do not perform any specific check on a potential
1168 1210 * target extended information structure and we just blindly update.
1169 1211 */
1170 1212 static int
1171 1213 propagate_bootblock(ib_data_t *src, ib_data_t *dest, char *updt_str)
1172 1214 {
1173 1215 ib_bootblock_t *src_bblock = &src->bootblock;
1174 1216 ib_bootblock_t *dest_bblock = &dest->bootblock;
1175 1217
1176 1218 assert(src != NULL);
1177 1219 assert(dest != NULL);
1178 1220
1179 1221 /* read the stage1 file from source disk */
1180 1222 if (read(src->device.fd, dest->stage1, SECTOR_SIZE) != SECTOR_SIZE) {
1181 1223 (void) fprintf(stderr, gettext("cannot read stage1 from %s\n"),
1182 1224 src->device.path);
1183 1225 return (BC_ERROR);
1184 1226 }
1185 1227
1186 1228 cleanup_bootblock(dest_bblock);
1187 1229
1188 1230 dest_bblock->buf_size = src_bblock->buf_size;
1189 1231 dest_bblock->buf = malloc(dest_bblock->buf_size);
1190 1232 if (dest_bblock->buf == NULL) {
1191 1233 perror(gettext("Memory Allocation Failure"));
1192 1234 return (BC_ERROR);
1193 1235 }
1194 1236 dest_bblock->file = dest_bblock->buf;
1195 1237 dest_bblock->file_size = src_bblock->file_size;
1196 1238 (void) memcpy(dest_bblock->buf, src_bblock->buf,
1197 1239 dest_bblock->buf_size);
1198 1240
1199 1241 dest_bblock->mboot = (multiboot_header_t *)(dest_bblock->file +
1200 1242 src_bblock->mboot_off);
1201 1243 dest_bblock->mboot_off = src_bblock->mboot_off;
1202 1244 dest_bblock->extra = (char *)dest_bblock->file +
1203 1245 P2ROUNDUP(dest_bblock->file_size, 8);
1204 1246 dest_bblock->extra_size = src_bblock->extra_size;
1205 1247
1206 1248 (void) fprintf(stdout, gettext("Propagating %s bootblock to %s\n"),
1207 1249 src->device.path, dest->device.path);
1208 1250
1209 1251 return (commit_to_disk(dest, updt_str));
1210 1252 }
1211 1253
1212 1254 static int
1213 1255 commit_to_disk(ib_data_t *data, char *update_str)
1214 1256 {
1215 1257 assert(data != NULL);
1216 1258
1217 1259 if (prepare_bootblock(data, update_str) != BC_SUCCESS) {
1218 1260 (void) fprintf(stderr, gettext("Error updating the bootblock "
1219 1261 "image\n"));
1220 1262 return (BC_ERROR);
1221 1263 }
1222 1264
1223 1265 if (prepare_stage1(data) != BC_SUCCESS) {
1224 1266 (void) fprintf(stderr, gettext("Error updating the stage1 "
1225 1267 "image\n"));
1226 1268 return (BC_ERROR);
1227 1269 }
1228 1270
1229 1271 if (write_bootblock(data) != BC_SUCCESS) {
1230 1272 (void) fprintf(stderr, gettext("Error writing bootblock to "
1231 1273 "disk\n"));
1232 1274 return (BC_ERROR);
1233 1275 }
1234 1276
1235 1277 return (write_stage1(data));
1236 1278 }
1237 1279
1238 1280 /*
1239 1281 * Install a new bootblock on the given device. handle_install() expects argv
1240 1282 * to contain 3 parameters (the target device path and the path to the
1241 1283 * bootblock.
1242 1284 *
1243 1285 * Returns: BC_SUCCESS - if the installation is successful
1244 1286 * BC_ERROR - if the installation failed
|
↓ open down ↓ |
83 lines elided |
↑ open up ↑ |
1245 1287 * BC_NOUPDT - if no installation was performed because the
1246 1288 * version currently installed is more recent than the
1247 1289 * supplied one.
1248 1290 *
1249 1291 */
1250 1292 static int
1251 1293 handle_install(char *progname, char **argv)
1252 1294 {
1253 1295 ib_data_t install_data;
1254 1296 ib_bootblock_t *bblock = &install_data.bootblock;
1297 + ib_bootblock_t *eblock = &install_data.efiblock;
1255 1298 char *stage1 = NULL;
1256 1299 char *bootblock = NULL;
1300 + char *efiboot = NULL;
1257 1301 char *device_path = NULL;
1302 + char *tmp;
1258 1303 int ret = BC_ERROR;
1259 1304
1260 1305 stage1 = strdup(argv[0]);
1261 1306 bootblock = strdup(argv[1]);
1262 1307 device_path = strdup(argv[2]);
1263 1308
1264 1309 if (!device_path || !bootblock || !stage1) {
1265 1310 (void) fprintf(stderr, gettext("Missing parameter"));
1266 1311 usage(progname);
1267 1312 goto out;
1268 1313 }
1269 1314
1315 + tmp = strdup(argv[1]);
1316 + if (tmp == NULL) {
1317 + perror(gettext("Memory allocation failure"));
1318 + goto out;
1319 + }
1320 + (void) asprintf(&efiboot, "%s/" EFIBOOT64, dirname(tmp));
1321 + free(tmp);
1322 + if (efiboot == NULL) {
1323 + perror(gettext("Memory allocation failure"));
1324 + goto out;
1325 + }
1326 +
1270 1327 BOOT_DEBUG("device path: %s, stage1 path: %s bootblock path: %s\n",
1271 1328 device_path, stage1, bootblock);
1272 1329 bzero(&install_data, sizeof (ib_data_t));
1273 1330
1274 1331 if (init_device(&install_data.device, device_path) != BC_SUCCESS) {
1275 1332 (void) fprintf(stderr, gettext("Unable to open device %s\n"),
1276 1333 device_path);
1277 1334 goto out;
1278 1335 }
1279 1336
1280 1337 if (read_stage1_from_file(stage1, &install_data) != BC_SUCCESS) {
|
↓ open down ↓ |
1 lines elided |
↑ open up ↑ |
1281 1338 (void) fprintf(stderr, gettext("Error opening %s\n"), stage1);
1282 1339 goto out_dev;
1283 1340 }
1284 1341
1285 1342 if (read_bootblock_from_file(bootblock, bblock) != BC_SUCCESS) {
1286 1343 (void) fprintf(stderr, gettext("Error reading %s\n"),
1287 1344 bootblock);
1288 1345 goto out_dev;
1289 1346 }
1290 1347
1348 + /* only read EFI boot program if there is system partition */
1349 + if (install_data.device.system.fd != -1) {
1350 + if (read_bootblock_from_file(efiboot, eblock) != BC_SUCCESS) {
1351 + (void) fprintf(stderr, gettext("Error reading %s\n"),
1352 + efiboot);
1353 + goto out_dev;
1354 + }
1355 + }
1356 +
1291 1357 /*
1292 1358 * is_update_necessary() will take care of checking if versioning and/or
1293 1359 * forcing the update have been specified. It will also emit a warning
1294 1360 * if a non-versioned update is attempted over a versioned bootblock.
1295 1361 */
1296 1362 if (!is_update_necessary(&install_data, update_str)) {
1297 1363 (void) fprintf(stderr, gettext("bootblock version installed "
1298 1364 "on %s is more recent or identical\n"
1299 1365 "Use -F to override or install without the -u option\n"),
1300 1366 device_path);
1301 1367 ret = BC_NOUPDT;
1302 1368 goto out_dev;
1303 1369 }
1304 1370
1305 1371 BOOT_DEBUG("Ready to commit to disk\n");
1306 1372 ret = commit_to_disk(&install_data, update_str);
1307 1373
1308 1374 out_dev:
1309 1375 cleanup_device(&install_data.device);
1310 1376 out:
1377 + free(efiboot);
1311 1378 free(stage1);
1312 1379 free(bootblock);
1313 1380 free(device_path);
1314 1381 return (ret);
1315 1382 }
1316 1383
1317 1384 /*
1318 1385 * Retrieves from a device the extended information (einfo) associated to the
1319 1386 * file or installed stage2.
1320 1387 * Expects one parameter, the device path, in the form: /dev/rdsk/c?[t?]d?s0
1321 1388 * or file name.
1322 1389 * Returns:
1323 1390 * - BC_SUCCESS (and prints out einfo contents depending on 'flags')
1324 1391 * - BC_ERROR (on error)
1325 1392 * - BC_NOEINFO (no extended information available)
1326 1393 */
1327 1394 static int
1328 1395 handle_getinfo(char *progname, char **argv)
1329 1396 {
1330 1397 struct stat sb;
1331 1398 ib_bootblock_t bblock;
1332 1399 ib_device_t device;
1333 1400 bblk_einfo_t *einfo;
1334 1401 uint8_t flags = 0;
1335 1402 char *device_path, *path;
1336 1403 int retval = BC_ERROR;
1337 1404 int ret;
1338 1405
1339 1406 device_path = strdup(argv[0]);
1340 1407 if (!device_path) {
1341 1408 (void) fprintf(stderr, gettext("Missing parameter"));
1342 1409 usage(progname);
1343 1410 goto out;
1344 1411 }
1345 1412
1346 1413 if (stat(device_path, &sb) == -1) {
1347 1414 perror("stat");
1348 1415 goto out;
1349 1416 }
1350 1417
1351 1418 bzero(&bblock, sizeof (bblock));
1352 1419 bzero(&device, sizeof (device));
1353 1420 BOOT_DEBUG("device path: %s\n", device_path);
1354 1421
1355 1422 if (S_ISREG(sb.st_mode) != 0) {
1356 1423 path = device_path;
1357 1424 ret = read_bootblock_from_file(device_path, &bblock);
1358 1425 } else {
1359 1426 if (init_device(&device, device_path) != BC_SUCCESS) {
1360 1427 (void) fprintf(stderr, gettext("Unable to gather "
1361 1428 "device information from %s\n"), device_path);
1362 1429 goto out_dev;
1363 1430 }
1364 1431 ret = read_bootblock_from_disk(&device, &bblock, &path);
1365 1432 }
1366 1433
1367 1434 if (ret == BC_ERROR) {
1368 1435 (void) fprintf(stderr, gettext("Error reading bootblock from "
1369 1436 "%s\n"), path);
1370 1437 goto out_dev;
1371 1438 }
1372 1439
1373 1440 if (ret == BC_NOEXTRA) {
1374 1441 BOOT_DEBUG("No multiboot header found on %s, unable "
1375 1442 "to locate extra information area (old/non versioned "
1376 1443 "bootblock?) \n", device_path);
1377 1444 (void) fprintf(stderr, gettext("No extended information "
1378 1445 "found\n"));
1379 1446 retval = BC_NOEINFO;
1380 1447 goto out_dev;
1381 1448 }
1382 1449
1383 1450 einfo = find_einfo(bblock.extra, bblock.extra_size);
1384 1451 if (einfo == NULL) {
1385 1452 retval = BC_NOEINFO;
1386 1453 (void) fprintf(stderr, gettext("No extended information "
1387 1454 "found\n"));
1388 1455 goto out_dev;
1389 1456 }
1390 1457
1391 1458 /* Print the extended information. */
1392 1459 if (strip)
1393 1460 flags |= EINFO_EASY_PARSE;
1394 1461 if (verbose_dump)
1395 1462 flags |= EINFO_PRINT_HEADER;
1396 1463
1397 1464 print_einfo(flags, einfo, bblock.extra_size);
1398 1465 retval = BC_SUCCESS;
1399 1466
1400 1467 out_dev:
1401 1468 if (S_ISREG(sb.st_mode) == 0)
1402 1469 cleanup_device(&device);
1403 1470 out:
1404 1471 free(device_path);
1405 1472 return (retval);
1406 1473 }
1407 1474
1408 1475 /*
1409 1476 * Attempt to mirror (propagate) the current bootblock over the attaching disk.
1410 1477 *
1411 1478 * Returns:
1412 1479 * - BC_SUCCESS (a successful propagation happened)
1413 1480 * - BC_ERROR (an error occurred)
1414 1481 * - BC_NOEXTRA (it is not possible to dump the current bootblock since
1415 1482 * there is no multiboot information)
1416 1483 */
1417 1484 static int
1418 1485 handle_mirror(char *progname, char **argv)
1419 1486 {
1420 1487 ib_data_t curr_data;
1421 1488 ib_data_t attach_data;
1422 1489 ib_device_t *curr_device = &curr_data.device;
1423 1490 ib_device_t *attach_device = &attach_data.device;
1424 1491 ib_bootblock_t *bblock_curr = &curr_data.bootblock;
1425 1492 ib_bootblock_t *bblock_attach = &attach_data.bootblock;
1426 1493 bblk_einfo_t *einfo_curr = NULL;
1427 1494 char *curr_device_path;
1428 1495 char *attach_device_path;
1429 1496 char *updt_str = NULL;
1430 1497 char *path;
1431 1498 int retval = BC_ERROR;
1432 1499 int ret;
1433 1500
1434 1501 curr_device_path = strdup(argv[0]);
1435 1502 attach_device_path = strdup(argv[1]);
1436 1503
1437 1504 if (!curr_device_path || !attach_device_path) {
1438 1505 (void) fprintf(stderr, gettext("Missing parameter"));
1439 1506 usage(progname);
1440 1507 goto out;
1441 1508 }
1442 1509 BOOT_DEBUG("Current device path is: %s, attaching device path is: "
1443 1510 " %s\n", curr_device_path, attach_device_path);
1444 1511
1445 1512 bzero(&curr_data, sizeof (ib_data_t));
1446 1513 bzero(&attach_data, sizeof (ib_data_t));
1447 1514
1448 1515 if (init_device(curr_device, curr_device_path) != BC_SUCCESS) {
1449 1516 (void) fprintf(stderr, gettext("Unable to gather device "
1450 1517 "information from %s (current device)\n"),
1451 1518 curr_device_path);
1452 1519 goto out_currdev;
1453 1520 }
1454 1521
1455 1522 if (init_device(attach_device, attach_device_path) != BC_SUCCESS) {
1456 1523 (void) fprintf(stderr, gettext("Unable to gather device "
1457 1524 "information from %s (attaching device)\n"),
1458 1525 attach_device_path);
1459 1526 goto out_devs;
1460 1527 }
1461 1528
1462 1529 ret = read_bootblock_from_disk(curr_device, bblock_curr, &path);
1463 1530 if (ret == BC_ERROR) {
1464 1531 BOOT_DEBUG("Error reading bootblock from %s\n", path);
1465 1532 retval = BC_ERROR;
1466 1533 goto out_devs;
1467 1534 }
1468 1535
1469 1536 if (ret == BC_NOEXTRA) {
1470 1537 BOOT_DEBUG("No multiboot header found on %s, unable to retrieve"
1471 1538 " the bootblock\n", path);
1472 1539 retval = BC_NOEXTRA;
1473 1540 goto out_devs;
1474 1541 }
1475 1542
1476 1543 write_mbr = B_TRUE;
1477 1544 force_mbr = B_TRUE;
1478 1545 einfo_curr = find_einfo(bblock_curr->extra, bblock_curr->extra_size);
1479 1546 if (einfo_curr != NULL)
1480 1547 updt_str = einfo_get_string(einfo_curr);
1481 1548
1482 1549 retval = propagate_bootblock(&curr_data, &attach_data, updt_str);
1483 1550 cleanup_bootblock(bblock_curr);
1484 1551 cleanup_bootblock(bblock_attach);
1485 1552 out_devs:
1486 1553 cleanup_device(attach_device);
1487 1554 out_currdev:
1488 1555 cleanup_device(curr_device);
1489 1556 out:
1490 1557 free(curr_device_path);
1491 1558 free(attach_device_path);
1492 1559 return (retval);
1493 1560 }
1494 1561
1495 1562 #define USAGE_STRING "Usage:\t%s [-h|-m|-f|-n|-F|-u verstr] stage1 stage2 " \
1496 1563 "raw-device\n" \
1497 1564 "\t%s -M [-n] raw-device attach-raw-device\n" \
1498 1565 "\t%s [-e|-V] -i raw-device | file\n"
1499 1566
1500 1567 #define CANON_USAGE_STR gettext(USAGE_STRING)
1501 1568
1502 1569 static void
1503 1570 usage(char *progname)
1504 1571 {
1505 1572 (void) fprintf(stdout, CANON_USAGE_STR, progname, progname, progname);
1506 1573 }
1507 1574
1508 1575 int
1509 1576 main(int argc, char **argv)
1510 1577 {
1511 1578 int opt;
1512 1579 int params = 3;
1513 1580 int ret;
1514 1581 char *progname;
1515 1582 char **handle_args;
1516 1583
1517 1584 (void) setlocale(LC_ALL, "");
1518 1585 (void) textdomain(TEXT_DOMAIN);
1519 1586 if (init_yes() < 0) {
1520 1587 (void) fprintf(stderr, gettext(ERR_MSG_INIT_YES),
1521 1588 strerror(errno));
1522 1589 exit(BC_ERROR);
1523 1590 }
1524 1591
1525 1592 while ((opt = getopt(argc, argv, "deFfhiMmnu:V")) != EOF) {
1526 1593 switch (opt) {
1527 1594 case 'd':
1528 1595 boot_debug = B_TRUE;
1529 1596 break;
1530 1597 case 'e':
1531 1598 strip = B_TRUE;
1532 1599 break;
1533 1600 case 'F':
1534 1601 force_update = B_TRUE;
1535 1602 break;
1536 1603 case 'f':
1537 1604 force_mbr = B_TRUE;
1538 1605 break;
1539 1606 case 'h':
1540 1607 usage(argv[0]);
1541 1608 exit(BC_SUCCESS);
1542 1609 break;
1543 1610 case 'i':
1544 1611 do_getinfo = B_TRUE;
1545 1612 params = 1;
1546 1613 break;
1547 1614 case 'M':
1548 1615 do_mirror_bblk = B_TRUE;
1549 1616 params = 2;
1550 1617 break;
1551 1618 case 'm':
1552 1619 write_mbr = B_TRUE;
1553 1620 break;
1554 1621 case 'n':
1555 1622 nowrite = B_TRUE;
1556 1623 break;
1557 1624 case 'u':
1558 1625 do_version = B_TRUE;
1559 1626
1560 1627 update_str = malloc(strlen(optarg) + 1);
1561 1628 if (update_str == NULL) {
1562 1629 perror(gettext("Memory allocation failure"));
1563 1630 exit(BC_ERROR);
1564 1631 }
1565 1632 (void) strlcpy(update_str, optarg, strlen(optarg) + 1);
1566 1633 break;
1567 1634 case 'V':
1568 1635 verbose_dump = B_TRUE;
1569 1636 break;
1570 1637 default:
1571 1638 /* fall through to process non-optional args */
1572 1639 break;
1573 1640 }
1574 1641 }
1575 1642
1576 1643 /* check arguments */
1577 1644 if (argc != optind + params) {
1578 1645 usage(argv[0]);
1579 1646 exit(BC_ERROR);
1580 1647 }
1581 1648 progname = argv[0];
1582 1649 check_options(progname);
1583 1650 handle_args = argv + optind;
1584 1651
1585 1652 if (nowrite)
1586 1653 (void) fprintf(stdout, gettext("Dry run requested. Nothing will"
1587 1654 " be written to disk.\n"));
1588 1655
1589 1656 if (do_getinfo) {
1590 1657 ret = handle_getinfo(progname, handle_args);
1591 1658 } else if (do_mirror_bblk) {
1592 1659 ret = handle_mirror(progname, handle_args);
1593 1660 } else {
1594 1661 ret = handle_install(progname, handle_args);
1595 1662 }
1596 1663 return (ret);
1597 1664 }
1598 1665
1599 1666 #define MEANINGLESS_OPT gettext("%s specified but meaningless, ignoring\n")
1600 1667 static void
1601 1668 check_options(char *progname)
1602 1669 {
1603 1670 if (do_getinfo && do_mirror_bblk) {
1604 1671 (void) fprintf(stderr, gettext("Only one of -M and -i can be "
1605 1672 "specified at the same time\n"));
1606 1673 usage(progname);
1607 1674 exit(BC_ERROR);
1608 1675 }
1609 1676
1610 1677 if (do_mirror_bblk) {
1611 1678 /*
1612 1679 * -u and -F may actually reflect a user intent that is not
1613 1680 * correct with this command (mirror can be interpreted
1614 1681 * "similar" to install. Emit a message and continue.
1615 1682 * -e and -V have no meaning, be quiet here and only report the
1616 1683 * incongruence if a debug output is requested.
1617 1684 */
1618 1685 if (do_version) {
1619 1686 (void) fprintf(stderr, MEANINGLESS_OPT, "-u");
1620 1687 do_version = B_FALSE;
1621 1688 }
1622 1689 if (force_update) {
1623 1690 (void) fprintf(stderr, MEANINGLESS_OPT, "-F");
1624 1691 force_update = B_FALSE;
1625 1692 }
1626 1693 if (strip || verbose_dump) {
1627 1694 BOOT_DEBUG(MEANINGLESS_OPT, "-e|-V");
1628 1695 strip = B_FALSE;
1629 1696 verbose_dump = B_FALSE;
1630 1697 }
1631 1698 }
1632 1699
1633 1700 if (do_getinfo) {
1634 1701 if (write_mbr || force_mbr || do_version || force_update) {
1635 1702 BOOT_DEBUG(MEANINGLESS_OPT, "-m|-f|-u|-F");
1636 1703 write_mbr = force_mbr = do_version = B_FALSE;
1637 1704 force_update = B_FALSE;
1638 1705 }
1639 1706 }
1640 1707 }
|
↓ open down ↓ |
320 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX