1 | /* ----------------------------------------------------------------------- * |
---|
2 | * |
---|
3 | * Copyright 2003-2009 H. Peter Anvin - All Rights Reserved |
---|
4 | * Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin |
---|
5 | * Copyright 2010 Shao Miller |
---|
6 | * Copyright 2010-2012 Michal Soltys |
---|
7 | * |
---|
8 | * Permission is hereby granted, free of charge, to any person |
---|
9 | * obtaining a copy of this software and associated documentation |
---|
10 | * files (the "Software"), to deal in the Software without |
---|
11 | * restriction, including without limitation the rights to use, |
---|
12 | * copy, modify, merge, publish, distribute, sublicense, and/or |
---|
13 | * sell copies of the Software, and to permit persons to whom |
---|
14 | * the Software is furnished to do so, subject to the following |
---|
15 | * conditions: |
---|
16 | * |
---|
17 | * The above copyright notice and this permission notice shall |
---|
18 | * be included in all copies or substantial portions of the Software. |
---|
19 | * |
---|
20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
---|
21 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES |
---|
22 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
---|
23 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT |
---|
24 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
---|
25 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
---|
26 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
---|
27 | * OTHER DEALINGS IN THE SOFTWARE. |
---|
28 | * |
---|
29 | * ----------------------------------------------------------------------- */ |
---|
30 | |
---|
31 | #include <com32.h> |
---|
32 | #include <stdlib.h> |
---|
33 | #include <stdio.h> |
---|
34 | #include <string.h> |
---|
35 | #include <stdint.h> |
---|
36 | #include <dprintf.h> |
---|
37 | #include <syslinux/config.h> |
---|
38 | #include "chain.h" |
---|
39 | #include "options.h" |
---|
40 | #include "utility.h" |
---|
41 | #include "partiter.h" |
---|
42 | #include "mangle.h" |
---|
43 | |
---|
44 | static const char cmldr_signature[8] = "cmdcons"; |
---|
45 | |
---|
46 | /* Create boot info table: needed when you want to chainload |
---|
47 | * another version of ISOLINUX (or another bootlaoder that needs |
---|
48 | * the -boot-info-table switch of mkisofs) |
---|
49 | * (will only work when run from ISOLINUX) |
---|
50 | */ |
---|
51 | int manglef_isolinux(struct data_area *data) |
---|
52 | { |
---|
53 | const union syslinux_derivative_info *sdi; |
---|
54 | unsigned char *isolinux_bin; |
---|
55 | uint32_t *checksum, *chkhead, *chktail; |
---|
56 | uint32_t file_lba = 0; |
---|
57 | |
---|
58 | if (!(opt.file && opt.isolinux)) |
---|
59 | return 0; |
---|
60 | |
---|
61 | sdi = syslinux_derivative_info(); |
---|
62 | |
---|
63 | if (sdi->c.filesystem != SYSLINUX_FS_ISOLINUX) { |
---|
64 | error("The isolinux= option is only valid when run from ISOLINUX."); |
---|
65 | goto bail; |
---|
66 | } |
---|
67 | |
---|
68 | /* Boot info table info (integers in little endian format) |
---|
69 | |
---|
70 | Offset Name Size Meaning |
---|
71 | 8 bi_pvd 4 bytes LBA of primary volume descriptor |
---|
72 | 12 bi_file 4 bytes LBA of boot file |
---|
73 | 16 bi_length 4 bytes Boot file length in bytes |
---|
74 | 20 bi_csum 4 bytes 32-bit checksum |
---|
75 | 24 bi_reserved 40 bytes Reserved |
---|
76 | |
---|
77 | The 32-bit checksum is the sum of all the 32-bit words in the |
---|
78 | boot file starting at byte offset 64. All linear block |
---|
79 | addresses (LBAs) are given in CD sectors (normally 2048 bytes). |
---|
80 | |
---|
81 | LBA of primary volume descriptor should already be set to 16. |
---|
82 | */ |
---|
83 | |
---|
84 | isolinux_bin = (unsigned char *)data->data; |
---|
85 | |
---|
86 | /* Get LBA address of bootfile */ |
---|
87 | file_lba = get_file_lba(opt.file); |
---|
88 | |
---|
89 | if (file_lba == 0) { |
---|
90 | error("Failed to find LBA offset of the boot file."); |
---|
91 | goto bail; |
---|
92 | } |
---|
93 | /* Set it */ |
---|
94 | *((uint32_t *) & isolinux_bin[12]) = file_lba; |
---|
95 | |
---|
96 | /* Set boot file length */ |
---|
97 | *((uint32_t *) & isolinux_bin[16]) = data->size; |
---|
98 | |
---|
99 | /* Calculate checksum */ |
---|
100 | checksum = (uint32_t *) & isolinux_bin[20]; |
---|
101 | chkhead = (uint32_t *) & isolinux_bin[64]; |
---|
102 | chktail = (uint32_t *) & isolinux_bin[data->size & ~3u]; |
---|
103 | *checksum = 0; |
---|
104 | while (chkhead < chktail) |
---|
105 | *checksum += *chkhead++; |
---|
106 | |
---|
107 | /* |
---|
108 | * Deal with possible fractional dword at the end; |
---|
109 | * this *should* never happen... |
---|
110 | */ |
---|
111 | if (data->size & 3) { |
---|
112 | uint32_t xword = 0; |
---|
113 | memcpy(&xword, chkhead, data->size & 3); |
---|
114 | *checksum += xword; |
---|
115 | } |
---|
116 | return 0; |
---|
117 | bail: |
---|
118 | return -1; |
---|
119 | } |
---|
120 | |
---|
121 | /* |
---|
122 | * Legacy grub's stage2 chainloading |
---|
123 | */ |
---|
124 | int manglef_grub(const struct part_iter *iter, struct data_area *data) |
---|
125 | { |
---|
126 | /* Layout of stage2 file (from byte 0x0 to 0x270) */ |
---|
127 | struct grub_stage2_patch_area { |
---|
128 | /* 0x0 to 0x205 */ |
---|
129 | char unknown[0x206]; |
---|
130 | /* 0x206: compatibility version number major */ |
---|
131 | uint8_t compat_version_major; |
---|
132 | /* 0x207: compatibility version number minor */ |
---|
133 | uint8_t compat_version_minor; |
---|
134 | |
---|
135 | /* 0x208: install_partition variable */ |
---|
136 | struct { |
---|
137 | /* 0x208: sub-partition in sub-partition part2 */ |
---|
138 | uint8_t part3; |
---|
139 | /* 0x209: sub-partition in top-level partition */ |
---|
140 | uint8_t part2; |
---|
141 | /* 0x20a: top-level partiton number */ |
---|
142 | uint8_t part1; |
---|
143 | /* 0x20b: BIOS drive number (must be 0) */ |
---|
144 | uint8_t drive; |
---|
145 | } __attribute__ ((packed)) install_partition; |
---|
146 | |
---|
147 | /* 0x20c: deprecated (historical reason only) */ |
---|
148 | uint32_t saved_entryno; |
---|
149 | /* 0x210: stage2_ID: will always be STAGE2_ID_STAGE2 = 0 in stage2 */ |
---|
150 | uint8_t stage2_id; |
---|
151 | /* 0x211: force LBA */ |
---|
152 | uint8_t force_lba; |
---|
153 | /* 0x212: version string (will probably be 0.97) */ |
---|
154 | char version_string[5]; |
---|
155 | /* 0x217: config filename */ |
---|
156 | char config_file[89]; |
---|
157 | /* 0x270: start of code (after jump from 0x200) */ |
---|
158 | char codestart[1]; |
---|
159 | } __attribute__ ((packed)) *stage2; |
---|
160 | |
---|
161 | if (!(opt.file && opt.grub)) |
---|
162 | return 0; |
---|
163 | |
---|
164 | if (data->size < sizeof *stage2) { |
---|
165 | error("The file specified by grub=<loader> is too small to be stage2 of GRUB Legacy."); |
---|
166 | goto bail; |
---|
167 | } |
---|
168 | stage2 = data->data; |
---|
169 | |
---|
170 | /* |
---|
171 | * Check the compatibility version number to see if we loaded a real |
---|
172 | * stage2 file or a stage2 file that we support. |
---|
173 | */ |
---|
174 | if (stage2->compat_version_major != 3 |
---|
175 | || stage2->compat_version_minor != 2) { |
---|
176 | error("The file specified by grub=<loader> is not a supported stage2 GRUB Legacy binary."); |
---|
177 | goto bail; |
---|
178 | } |
---|
179 | |
---|
180 | /* |
---|
181 | * GRUB Legacy wants the partition number in the install_partition |
---|
182 | * variable, located at offset 0x208 of stage2. |
---|
183 | * When GRUB Legacy is loaded, it is located at memory address 0x8208. |
---|
184 | * |
---|
185 | * It looks very similar to the "boot information format" of the |
---|
186 | * Multiboot specification: |
---|
187 | * http://www.gnu.org/software/grub/manual/multiboot/multiboot.html#Boot-information-format |
---|
188 | * |
---|
189 | * 0x208 = part3: sub-partition in sub-partition part2 |
---|
190 | * 0x209 = part2: sub-partition in top-level partition |
---|
191 | * 0x20a = part1: top-level partition number |
---|
192 | * 0x20b = drive: BIOS drive number (must be 0) |
---|
193 | * |
---|
194 | * GRUB Legacy doesn't store the BIOS drive number at 0x20b, but at |
---|
195 | * another location. |
---|
196 | * |
---|
197 | * Partition numbers always start from zero. |
---|
198 | * Unused partition bytes must be set to 0xFF. |
---|
199 | * |
---|
200 | * We only care about top-level partition, so we only need to change |
---|
201 | * "part1" to the appropriate value: |
---|
202 | * -1: whole drive (default) (-1 = 0xFF) |
---|
203 | * 0-3: primary partitions |
---|
204 | * 4-*: logical partitions |
---|
205 | */ |
---|
206 | stage2->install_partition.part1 = iter->index - 1; |
---|
207 | |
---|
208 | /* |
---|
209 | * Grub Legacy reserves 89 bytes (from 0x8217 to 0x826f) for the |
---|
210 | * config filename. The filename passed via grubcfg= will overwrite |
---|
211 | * the default config filename "/boot/grub/menu.lst". |
---|
212 | */ |
---|
213 | if (opt.grubcfg) { |
---|
214 | if (strlen(opt.grubcfg) >= sizeof stage2->config_file) { |
---|
215 | error("The config filename length can't exceed 88 characters."); |
---|
216 | goto bail; |
---|
217 | } |
---|
218 | |
---|
219 | strcpy((char *)stage2->config_file, opt.grubcfg); |
---|
220 | } |
---|
221 | |
---|
222 | return 0; |
---|
223 | bail: |
---|
224 | return -1; |
---|
225 | } |
---|
226 | #if 0 |
---|
227 | /* |
---|
228 | * Dell's DRMK chainloading. |
---|
229 | */ |
---|
230 | int manglef_drmk(struct data_area *data) |
---|
231 | { |
---|
232 | /* |
---|
233 | * DRMK entry is different than MS-DOS/PC-DOS |
---|
234 | * A new size, aligned to 16 bytes to ease use of ds:[bp+28]. |
---|
235 | * We only really need 4 new, usable bytes at the end. |
---|
236 | */ |
---|
237 | |
---|
238 | if (!(opt.file && opt.drmk)) |
---|
239 | return 0; |
---|
240 | |
---|
241 | uint32_t tsize = (data->size + 19) & 0xfffffff0; |
---|
242 | const union syslinux_derivative_info *sdi; |
---|
243 | uint64_t fs_lba; |
---|
244 | |
---|
245 | sdi = syslinux_derivative_info(); |
---|
246 | /* We should lookup the Syslinux partition offset and use it */ |
---|
247 | fs_lba = *sdi->disk.partoffset; |
---|
248 | |
---|
249 | /* |
---|
250 | * fs_lba should be verified against the disk as some DRMK |
---|
251 | * variants will check and fail if it does not match |
---|
252 | */ |
---|
253 | dprintf(" fs_lba offset is %d\n", fs_lba); |
---|
254 | /* DRMK only uses a DWORD */ |
---|
255 | if (fs_lba > 0xffffffff) { |
---|
256 | error("LBA very large; Only using lower 32 bits; DRMK will probably fail."); |
---|
257 | } |
---|
258 | opt.regs.ss = opt.regs.fs = opt.regs.gs = 0; /* Used before initialized */ |
---|
259 | if (!realloc(data->data, tsize)) { |
---|
260 | error("Failed to realloc for DRMK."); |
---|
261 | goto bail; |
---|
262 | } |
---|
263 | data->size = tsize; |
---|
264 | /* ds:bp is assumed by DRMK to be the boot sector */ |
---|
265 | /* offset 28 is the FAT HiddenSectors value */ |
---|
266 | opt.regs.ds = (tsize >> 4) + (opt.fseg - 2); |
---|
267 | /* "Patch" into tail of the new space */ |
---|
268 | *(uint32_t *)((char*)data->data + tsize - 4) = fs_lba; |
---|
269 | |
---|
270 | return 0; |
---|
271 | bail: |
---|
272 | return -1; |
---|
273 | } |
---|
274 | #endif |
---|
275 | /* Adjust BPB common function */ |
---|
276 | static int mangle_bpb(const struct part_iter *iter, struct data_area *data, const char *tag) |
---|
277 | { |
---|
278 | int type = bpb_detect(data->data, tag); |
---|
279 | int off = drvoff_detect(type); |
---|
280 | |
---|
281 | /* BPB: hidden sectors 64bit - exFAT only for now */ |
---|
282 | if (type == bpbEXF) |
---|
283 | *(uint64_t *) ((char *)data->data + 0x40) = iter->abs_lba; |
---|
284 | /* BPB: hidden sectors 32bit*/ |
---|
285 | else if (bpbV34 <= type && type <= bpbV70) { |
---|
286 | if (iter->abs_lba < ~0u) |
---|
287 | *(uint32_t *) ((char *)data->data + 0x1c) = iter->abs_lba; |
---|
288 | else |
---|
289 | /* won't really help much, but ... */ |
---|
290 | *(uint32_t *) ((char *)data->data + 0x1c) = ~0u; |
---|
291 | /* BPB: hidden sectors 16bit*/ |
---|
292 | } else if (bpbV30 <= type && type <= bpbV32) { |
---|
293 | if (iter->abs_lba < 0xFFFF) |
---|
294 | *(uint16_t *) ((char *)data->data + 0x1c) = iter->abs_lba; |
---|
295 | else |
---|
296 | /* won't really help much, but ... */ |
---|
297 | *(uint16_t *) ((char *)data->data + 0x1c) = (uint16_t)~0u; |
---|
298 | } |
---|
299 | |
---|
300 | /* BPB: legacy geometry */ |
---|
301 | if (bpbV30 <= type && type <= bpbV70) { |
---|
302 | if (iter->di.cbios) |
---|
303 | *(uint32_t *)((char *)data->data + 0x18) = (iter->di.head << 16) | iter->di.spt; |
---|
304 | else { |
---|
305 | if (iter->di.disk & 0x80) |
---|
306 | *(uint32_t *)((char *)data->data + 0x18) = 0x00FF003F; |
---|
307 | else |
---|
308 | *(uint32_t *)((char *)data->data + 0x18) = 0x00020012; |
---|
309 | } |
---|
310 | } |
---|
311 | /* BPB: drive */ |
---|
312 | if (off >= 0) { |
---|
313 | *(uint8_t *)((char *)data->data + off) = (opt.swap ? iter->di.disk & 0x80 : iter->di.disk); |
---|
314 | } |
---|
315 | |
---|
316 | return 0; |
---|
317 | } |
---|
318 | |
---|
319 | /* |
---|
320 | * Adjust BPB of a BPB-compatible file |
---|
321 | */ |
---|
322 | int manglef_bpb(const struct part_iter *iter, struct data_area *data) |
---|
323 | { |
---|
324 | if (!(opt.file && opt.filebpb)) |
---|
325 | return 0; |
---|
326 | |
---|
327 | return mangle_bpb(iter, data, "file"); |
---|
328 | } |
---|
329 | |
---|
330 | /* |
---|
331 | * Adjust BPB of a sector |
---|
332 | */ |
---|
333 | int mangles_bpb(const struct part_iter *iter, struct data_area *data) |
---|
334 | { |
---|
335 | if (!(opt.sect && opt.setbpb)) |
---|
336 | return 0; |
---|
337 | |
---|
338 | return mangle_bpb(iter, data, "sect"); |
---|
339 | } |
---|
340 | |
---|
341 | /* |
---|
342 | * This function performs full BPB patching, analogously to syslinux's |
---|
343 | * native BSS. |
---|
344 | */ |
---|
345 | int manglesf_bss(struct data_area *sec, struct data_area *fil) |
---|
346 | { |
---|
347 | int type1, type2; |
---|
348 | size_t cnt = 0; |
---|
349 | |
---|
350 | if (!(opt.sect && opt.file && opt.bss)) |
---|
351 | return 0; |
---|
352 | |
---|
353 | type1 = bpb_detect(fil->data, "bss/file"); |
---|
354 | type2 = bpb_detect(sec->data, "bss/sect"); |
---|
355 | |
---|
356 | if (!type1 || !type2) { |
---|
357 | error("Couldn't determine the BPB type for option 'bss'."); |
---|
358 | goto bail; |
---|
359 | } |
---|
360 | if (type1 != type2) { |
---|
361 | error("Option 'bss' can't be used,\n" |
---|
362 | "when a sector and a file have incompatible BPBs."); |
---|
363 | goto bail; |
---|
364 | } |
---|
365 | |
---|
366 | /* Copy common 2.0 data */ |
---|
367 | memcpy((char *)fil->data + 0x0B, (char *)sec->data + 0x0B, 0x0D); |
---|
368 | |
---|
369 | /* Copy 3.0+ data */ |
---|
370 | if (type1 <= bpbV30) { |
---|
371 | cnt = 0x06; |
---|
372 | } else if (type1 <= bpbV32) { |
---|
373 | cnt = 0x08; |
---|
374 | } else if (type1 <= bpbV34) { |
---|
375 | cnt = 0x0C; |
---|
376 | } else if (type1 <= bpbV40) { |
---|
377 | cnt = 0x2E; |
---|
378 | } else if (type1 <= bpbVNT) { |
---|
379 | cnt = 0x3C; |
---|
380 | } else if (type1 <= bpbV70) { |
---|
381 | cnt = 0x42; |
---|
382 | } else if (type1 <= bpbEXF) { |
---|
383 | cnt = 0x60; |
---|
384 | } |
---|
385 | memcpy((char *)fil->data + 0x18, (char *)sec->data + 0x18, cnt); |
---|
386 | |
---|
387 | return 0; |
---|
388 | bail: |
---|
389 | return -1; |
---|
390 | } |
---|
391 | |
---|
392 | /* |
---|
393 | * Save sector. |
---|
394 | */ |
---|
395 | int mangles_save(const struct part_iter *iter, const struct data_area *data, void *org) |
---|
396 | { |
---|
397 | if (!(opt.sect && opt.save)) |
---|
398 | return 0; |
---|
399 | |
---|
400 | if (memcmp(org, data->data, data->size)) { |
---|
401 | if (disk_write_sectors(&iter->di, iter->abs_lba, data->data, 1)) { |
---|
402 | error("Cannot write the updated sector."); |
---|
403 | goto bail; |
---|
404 | } |
---|
405 | /* function can be called again */ |
---|
406 | memcpy(org, data->data, data->size); |
---|
407 | } |
---|
408 | |
---|
409 | return 0; |
---|
410 | bail: |
---|
411 | return -1; |
---|
412 | } |
---|
413 | |
---|
414 | /* |
---|
415 | * To boot the Recovery Console of Windows NT/2K/XP we need to write |
---|
416 | * the string "cmdcons\0" to memory location 0000:7C03. |
---|
417 | * Memory location 0000:7C00 contains the bootsector of the partition. |
---|
418 | */ |
---|
419 | int mangles_cmldr(struct data_area *data) |
---|
420 | { |
---|
421 | if (!(opt.sect && opt.cmldr)) |
---|
422 | return 0; |
---|
423 | |
---|
424 | memcpy((char *)data->data + 3, cmldr_signature, sizeof cmldr_signature); |
---|
425 | return 0; |
---|
426 | } |
---|
427 | |
---|
428 | /* Set common registers */ |
---|
429 | int mangler_init(const struct part_iter *iter) |
---|
430 | { |
---|
431 | /* Set initial registry values */ |
---|
432 | if (opt.file) { |
---|
433 | opt.regs.cs = opt.regs.ds = opt.regs.ss = opt.fseg; |
---|
434 | opt.regs.ip = opt.fip; |
---|
435 | } else { |
---|
436 | opt.regs.cs = opt.regs.ds = opt.regs.ss = opt.sseg; |
---|
437 | opt.regs.ip = opt.sip; |
---|
438 | } |
---|
439 | |
---|
440 | if (opt.regs.ip == 0x7C00 && !opt.regs.cs) |
---|
441 | opt.regs.esp.l = 0x7C00; |
---|
442 | |
---|
443 | /* DOS kernels want the drive number in BL instead of DL. Indulge them. */ |
---|
444 | opt.regs.ebx.b[0] = opt.regs.edx.b[0] = iter->di.disk; |
---|
445 | |
---|
446 | return 0; |
---|
447 | } |
---|
448 | |
---|
449 | /* ds:si & ds:bp */ |
---|
450 | int mangler_handover(const struct part_iter *iter, const struct data_area *data) |
---|
451 | { |
---|
452 | if (opt.file && opt.maps && !opt.hptr) { |
---|
453 | opt.regs.esi.l = opt.regs.ebp.l = opt.soff; |
---|
454 | opt.regs.ds = opt.sseg; |
---|
455 | opt.regs.eax.l = 0; |
---|
456 | } else if (opt.hand) { |
---|
457 | /* base is really 0x7be */ |
---|
458 | opt.regs.esi.l = opt.regs.ebp.l = data->base; |
---|
459 | opt.regs.ds = 0; |
---|
460 | if (iter->index && iter->type == typegpt) /* must be iterated and GPT */ |
---|
461 | opt.regs.eax.l = 0x54504721; /* '!GPT' */ |
---|
462 | else |
---|
463 | opt.regs.eax.l = 0; |
---|
464 | } |
---|
465 | |
---|
466 | return 0; |
---|
467 | } |
---|
468 | |
---|
469 | /* |
---|
470 | * GRLDR of GRUB4DOS wants the partition number in DH: |
---|
471 | * -1: whole drive (default) |
---|
472 | * 0-3: primary partitions |
---|
473 | * 4-*: logical partitions |
---|
474 | */ |
---|
475 | int mangler_grldr(const struct part_iter *iter) |
---|
476 | { |
---|
477 | if (opt.grldr) |
---|
478 | opt.regs.edx.b[1] = iter->index - 1; |
---|
479 | |
---|
480 | return 0; |
---|
481 | } |
---|
482 | |
---|
483 | /* |
---|
484 | * try to copy values from temporary iterator, if positions match |
---|
485 | */ |
---|
486 | static void mbrcpy(struct part_iter *diter, struct part_iter *siter) |
---|
487 | { |
---|
488 | if (diter->dos.cebr_lba == siter->dos.cebr_lba && |
---|
489 | diter->di.disk == siter->di.disk) { |
---|
490 | memcpy(diter->data, siter->data, sizeof(struct disk_dos_mbr)); |
---|
491 | } |
---|
492 | } |
---|
493 | |
---|
494 | static int fliphide(struct part_iter *iter, struct part_iter *miter) |
---|
495 | { |
---|
496 | struct disk_dos_part_entry *dp; |
---|
497 | static const uint16_t mask = |
---|
498 | (1 << 0x01) | (1 << 0x04) | (1 << 0x06) | |
---|
499 | (1 << 0x07) | (1 << 0x0b) | (1 << 0x0c) | (1 << 0x0e); |
---|
500 | uint8_t t; |
---|
501 | |
---|
502 | dp = (struct disk_dos_part_entry *)iter->record; |
---|
503 | t = dp->ostype; |
---|
504 | |
---|
505 | if ((t <= 0x1f) && ((mask >> (t & ~0x10u)) & 1)) { |
---|
506 | /* It's a hideable partition type */ |
---|
507 | if (miter->index == iter->index || opt.hide & HIDE_REV) |
---|
508 | t &= ~0x10u; /* unhide */ |
---|
509 | else |
---|
510 | t |= 0x10u; /* hide */ |
---|
511 | } |
---|
512 | if (dp->ostype != t) { |
---|
513 | dp->ostype = t; |
---|
514 | return -1; |
---|
515 | } |
---|
516 | return 0; |
---|
517 | } |
---|
518 | |
---|
519 | /* |
---|
520 | * miter - iterator we match against |
---|
521 | * hide bits meaning: |
---|
522 | * ..| - enable (1) / disable (0) |
---|
523 | * .|. - all (1) / pri (0) |
---|
524 | * |.. - unhide (1) / hide (0) |
---|
525 | */ |
---|
526 | int manglepe_hide(struct part_iter *miter) |
---|
527 | { |
---|
528 | int wb = 0, werr = 0; |
---|
529 | struct part_iter *iter = NULL; |
---|
530 | int ridx; |
---|
531 | |
---|
532 | if (!(opt.hide & HIDE_ON)) |
---|
533 | return 0; |
---|
534 | |
---|
535 | if (miter->type != typedos) { |
---|
536 | error("Option '[un]hide[all]' works only for legacy (DOS) partition scheme."); |
---|
537 | return -1; |
---|
538 | } |
---|
539 | |
---|
540 | if (miter->index > 4 && !(opt.hide & HIDE_EXT)) |
---|
541 | warn("Specified partition is logical, so it can't be unhidden without 'unhideall'."); |
---|
542 | |
---|
543 | if (!(iter = pi_begin(&miter->di, PIF_STEPALL | opt.piflags))) |
---|
544 | return -1; |
---|
545 | |
---|
546 | while (!pi_next(iter) && !werr) { |
---|
547 | ridx = iter->index0; |
---|
548 | if (!(opt.hide & HIDE_EXT) && ridx > 3) |
---|
549 | break; /* skip when we're constrained to pri only */ |
---|
550 | |
---|
551 | if (iter->index != -1) |
---|
552 | wb |= fliphide(iter, miter); |
---|
553 | |
---|
554 | /* |
---|
555 | * we have to update mbr and each extended partition, but only if |
---|
556 | * changes (wb) were detected and there was no prior write error (werr) |
---|
557 | */ |
---|
558 | if (ridx >= 3 && wb && !werr) { |
---|
559 | mbrcpy(miter, iter); |
---|
560 | werr |= disk_write_sectors(&iter->di, iter->dos.cebr_lba, iter->data, 1); |
---|
561 | wb = 0; |
---|
562 | } |
---|
563 | } |
---|
564 | |
---|
565 | if (iter->status < 0) |
---|
566 | goto bail; |
---|
567 | |
---|
568 | /* last update */ |
---|
569 | if (wb && !werr) { |
---|
570 | mbrcpy(miter, iter); |
---|
571 | werr |= disk_write_sectors(&iter->di, iter->dos.cebr_lba, iter->data, 1); |
---|
572 | } |
---|
573 | if (werr) |
---|
574 | warn("Failed to write E/MBR during '[un]hide[all]'."); |
---|
575 | |
---|
576 | bail: |
---|
577 | pi_del(&iter); |
---|
578 | return 0; |
---|
579 | } |
---|
580 | |
---|
581 | static int updchs(struct part_iter *iter, int ext) |
---|
582 | { |
---|
583 | struct disk_dos_part_entry *dp; |
---|
584 | uint32_t ochs1, ochs2, lba; |
---|
585 | |
---|
586 | dp = (struct disk_dos_part_entry *)iter->record; |
---|
587 | if (!ext) { |
---|
588 | /* primary or logical */ |
---|
589 | lba = (uint32_t)iter->abs_lba; |
---|
590 | } else { |
---|
591 | /* extended */ |
---|
592 | dp += 1; |
---|
593 | lba = iter->dos.nebr_lba; |
---|
594 | } |
---|
595 | ochs1 = *(uint32_t *)dp->start; |
---|
596 | ochs2 = *(uint32_t *)dp->end; |
---|
597 | |
---|
598 | /* |
---|
599 | * We have to be a bit more careful here in case of 0 start and/or length; |
---|
600 | * start = 0 would be converted to the beginning of the disk (C/H/S = |
---|
601 | * 0/0/1) or the [B]EBR, length = 0 would actually set the end CHS to be |
---|
602 | * lower than the start CHS. |
---|
603 | * |
---|
604 | * Both are harmless in case of a hole (and in non-hole case will make |
---|
605 | * partiter complain about corrupt layout if PIF_STRICT is set), but it |
---|
606 | * makes everything look silly and not really correct. |
---|
607 | * |
---|
608 | * Thus the approach as seen below. |
---|
609 | */ |
---|
610 | |
---|
611 | if (dp->start_lba || iter->index != -1) { |
---|
612 | lba2chs(&dp->start, &iter->di, lba, L2C_CADD); |
---|
613 | } else { |
---|
614 | memset(&dp->start, 0, sizeof dp->start); |
---|
615 | } |
---|
616 | |
---|
617 | if ((dp->start_lba || iter->index != -1) && dp->length) { |
---|
618 | lba2chs(&dp->end, &iter->di, lba + dp->length - 1, L2C_CADD); |
---|
619 | } else { |
---|
620 | memset(&dp->end, 0, sizeof dp->end); |
---|
621 | } |
---|
622 | |
---|
623 | return |
---|
624 | *(uint32_t *)dp->start != ochs1 || |
---|
625 | *(uint32_t *)dp->end != ochs2; |
---|
626 | } |
---|
627 | |
---|
628 | /* |
---|
629 | * miter - iterator we match against |
---|
630 | */ |
---|
631 | int manglepe_fixchs(struct part_iter *miter) |
---|
632 | { |
---|
633 | int wb = 0, werr = 0; |
---|
634 | struct part_iter *iter = NULL; |
---|
635 | int ridx; |
---|
636 | |
---|
637 | if (!opt.fixchs) |
---|
638 | return 0; |
---|
639 | |
---|
640 | if (miter->type != typedos) { |
---|
641 | error("Option 'fixchs' works only for legacy (DOS) partition scheme."); |
---|
642 | return -1; |
---|
643 | } |
---|
644 | |
---|
645 | if (!(iter = pi_begin(&miter->di, PIF_STEPALL | opt.piflags))) |
---|
646 | return -1; |
---|
647 | |
---|
648 | while (!pi_next(iter) && !werr) { |
---|
649 | ridx = iter->index0; |
---|
650 | |
---|
651 | wb |= updchs(iter, 0); |
---|
652 | if (ridx > 3) |
---|
653 | wb |= updchs(iter, 1); |
---|
654 | |
---|
655 | /* |
---|
656 | * we have to update mbr and each extended partition, but only if |
---|
657 | * changes (wb) were detected and there was no prior write error (werr) |
---|
658 | */ |
---|
659 | if (ridx >= 3 && wb && !werr) { |
---|
660 | mbrcpy(miter, iter); |
---|
661 | werr |= disk_write_sectors(&iter->di, iter->dos.cebr_lba, iter->data, 1); |
---|
662 | wb = 0; |
---|
663 | } |
---|
664 | } |
---|
665 | |
---|
666 | if (iter->status < 0) |
---|
667 | goto bail; |
---|
668 | |
---|
669 | /* last update */ |
---|
670 | if (wb && !werr) { |
---|
671 | mbrcpy(miter, iter); |
---|
672 | werr |= disk_write_sectors(&iter->di, iter->dos.cebr_lba, iter->data, 1); |
---|
673 | } |
---|
674 | if (werr) |
---|
675 | warn("Failed to write E/MBR during 'fixchs'."); |
---|
676 | |
---|
677 | bail: |
---|
678 | pi_del(&iter); |
---|
679 | return 0; |
---|
680 | } |
---|
681 | |
---|
682 | /* vim: set ts=8 sts=4 sw=4 noet: */ |
---|