ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/pbcdedit/pbcdedit
(Generate patch)

Comparing pbcdedit/pbcdedit (file contents):
Revision 1.39 by root, Thu Aug 15 23:49:22 2019 UTC vs.
Revision 1.62 by root, Mon Aug 26 06:58:57 2019 UTC

19# along with this program. If not, see <https://www.gnu.org/licenses/>. 19# along with this program. If not, see <https://www.gnu.org/licenses/>.
20# 20#
21 21
22use 5.016; # numerous features need 5.14, __SUB__ needs 5.16 22use 5.016; # numerous features need 5.14, __SUB__ needs 5.16
23 23
24our $VERSION = '1.2'; 24our $VERSION = '1.4';
25our $JSON_VERSION = 2; # the version of the json objects generated by this program 25our $JSON_VERSION = 3; # the version of the json objects generated by this program
26 26
27our $CHANGELOG = <<EOF; 27our $CHANGELOG = <<EOF;
28
29 - work around lsblk bug sometimes giving dos pttype for gpt partitions.
30 - bootmenupolicy in synopsis must be set to 0 for text menu.
31
321.4 Thu Aug 22 10:48:22 CEST 2019
33 - new "create" subcommand.
34 - "create" and "edit" try to save and restore ownership/permissions
35 of bcd hives when writing the new file.
36 - editorial fixes to the documentation.
37 - add mininmal hive creation example.
38
391.3 Sat Aug 17 07:04:15 CEST 2019
40 - output of pbcdedit elements --json has changed, as it didn't
41 take the reorganisation by classes fully into account.
42 - json schema bumped to 3.
43 - new "bcd-device" and "bcd-legacy-device" subcommands.
44 - implement --json option for lsblk.
45
281.2 Fri Aug 16 00:20:41 CEST 2019 461.2 Fri Aug 16 00:20:41 CEST 2019
29 - bcde element names now depend on the bcd object type they are in, 47 - bcd element names now depend on the bcd object type they are in,
30 also affects "elements" output. 48 also affects "elements" output.
31 - json schema bumped to 2. 49 - json schema bumped to 2.
32 - new version command. 50 - new version command.
33 - numerous minor bugfixes. 51 - numerous minor bugfixes.
34 52
48 pbcdedit edit path/to/BCD edit-instructions... 66 pbcdedit edit path/to/BCD edit-instructions...
49 67
50 pbcdedit objects # list all supported object aliases and types 68 pbcdedit objects # list all supported object aliases and types
51 pbcdedit elements # list all supported bcd element aliases 69 pbcdedit elements # list all supported bcd element aliases
52 70
71 # Example: enable text-based boot menu.
72 pbcdedit edit /my/BCD set '{default}' bootmenupolicy 0
73
74 # Example change system device to first partition containing winload.
75 pbcdedit edit /my/BCD \
76 set '{default}' device 'locate=<null>,element,path' \
77 set '{default}' osdevice 'locate=<null>,element,path'
78
79
53=head1 DESCRIPTION 80=head1 DESCRIPTION
54 81
55This program allows you to create, read and modify Boot Configuration Data 82This program allows you to create, read and modify Boot Configuration Data
56(BCD) stores used by Windows Vista and newer versions of Windows. 83(BCD) stores used by Windows Vista and newer versions of Windows.
57 84
136=item C<parse> F<path> I<instructions...> 163=item C<parse> F<path> I<instructions...>
137 164
138Same as C<edit>, above, except it doesn't save the data store again. Can 165Same as C<edit>, above, except it doesn't save the data store again. Can
139be useful to extract some data from it. 166be useful to extract some data from it.
140 167
141=item C<lsblk> 168=item C<create> F<path> I<instructions...>
169
170Same as C<edit>, above, except it creates a new data store from scratch if
171needed. An existing store will be emptied completely.
172
173=item C<lsblk> [C<--json>]
142 174
143On a GNU/Linux system, you can get a list of partition device descriptors 175On a GNU/Linux system, you can get a list of partition device descriptors
144using this command - the external C<lsblk> command is required, as well as 176using this command - the external C<lsblk> command is required, as well as
145a mounted C</sys> file system. 177a mounted C</sys> file system.
146 178
147The output will be a list of all partitions in the system and C<partition> 179The output will be a list of all partitions in the system and C<partition>
148descriptors for GPT and both C<legacypartition> and C<partition> 180descriptors for GPT and both C<legacypartition> and C<partition>
149descriptors for MBR partitions. 181descriptors for MBR partitions.
182
183With C<--json> it will print similar information as C<lsblk --json>, but
184with extra C<bcd_device> and C<bcd_legacy_device> attributes.
185
186=item C<bcd-device> F<path>
187
188Tries to find the BCD device element for the given device, which currently
189must be a a partition of some kind. Prints the C<partition=> descriptor as
190a result, or nothing. Exit status will be true on success, and false on
191failure.
192
193Like C<lsblk>, above, this likely only works on GNU/Linux systems.
194
195Example: print the partition descriptor of tghe partition with label DATA.
196
197 $ pbcdedit bcd-device /dev/disk/by-label/DATA
198 partition=<null>,harddisk,mbr,47cbc08a,213579202560
199
200=item C<bcd-legacy-device> F<path>
201
202Like above, but uses a C<legacypartition> descriptor instead.
150 203
151=item C<objects> [C<--json>] 204=item C<objects> [C<--json>]
152 205
153Outputs two tables: a table listing all type aliases with their hex BCD 206Outputs two tables: a table listing all type aliases with their hex BCD
154element ID, and all object name aliases with their GUID and default type 207element ID, and all object name aliases with their GUID and default type
256 309
257Note that minimal doesn't mean recommended - Windows itself will add stuff 310Note that minimal doesn't mean recommended - Windows itself will add stuff
258to this during or after boot, and you might or might not run into issues 311to this during or after boot, and you might or might not run into issues
259when installing updates as it might not be able to find the F<bootmgr>. 312when installing updates as it might not be able to find the F<bootmgr>.
260 313
314This is how you would create a minimal hive with PBCDEDIT from within
315GNU/Linux, assuming F</dev/sdc3> is the windows partition, using
316a random GUID for the osloader and using C<partition> instead of
317C<legacypartition>:
318
319 osldr="{$(uuidgen)}"
320 part=$(pbcdedit bcd-device /dev/sdc3)
321 pbcdedit create minimal.bcd \
322 set '{bootmgr}' default "$osldr" \
323 set "$osldr" type application::osloader \
324 set "$osldr" description 'Windows Boot' \
325 set "$osldr" device "$part" \
326 set "$osldr" osdevice "$part" \
327 set "$osldr" path '\Windows\system32\winload.exe' \
328 set "$osldr" systemroot '\Windows'
329
261=head2 The C<meta> key 330=head2 The C<meta> key
262 331
263The C<meta> key is not stored in the BCD data store but is used only 332The C<meta> key is not stored in the BCD data store but is used only
264by PBCDEDIT. It is always generated when exporting, and importing will 333by PBCDEDIT. It is always generated when exporting, and importing will
265be refused when it exists and the version stored inside doesn't store 334be refused when it exists and the version stored inside doesn't store
352 421
353 "displaybootmenu" : 0, 422 "displaybootmenu" : 0,
354 423
355=item integer 424=item integer
356 425
357Again, very simple, this is a 64 bit integer. IT can be either specified 426Again, very simple, this is a 64 bit integer. It can be either specified
358as a decimal number, as a hex number (by prefixing it with C<0x>) or as a 427as a decimal number, as a hex number (by prefixing it with C<0x>) or as a
359binary number (prefix C<0b>). 428binary number (prefix C<0b>).
360 429
361For example, the boot C<timeout> is an integer, specifying the automatic 430For example, the boot C<timeout> is an integer, specifying the automatic
362boot delay in seconds: 431boot delay in seconds:
364 "timeout" : 30, 433 "timeout" : 30,
365 434
366=item integer list 435=item integer list
367 436
368This is a list of 64 bit integers separated by whitespace. It is not used 437This is a list of 64 bit integers separated by whitespace. It is not used
369much, so here is a somewhat artificial an untested example of using 438much, so here is a somewhat artificial and untested example of using
370C<customactions> to specify a certain custom, eh, action to be executed 439C<customactions> to specify a certain custom, eh, action to be executed
371when pressing C<F10> at boot: 440when pressing C<F10> at boot:
372 441
373 "customactions" : "0x1000044000001 0x54000001", 442 "customactions" : "0x1000044000001 0x54000001",
374 443
402This type is why I write I<most> are easy to explain earlier: This type 471This type is why I write I<most> are easy to explain earlier: This type
403is the pinnacle of Microsoft-typical hacks layered on top of other 472is the pinnacle of Microsoft-typical hacks layered on top of other
404hacks. Understanding this type took more time than writing all the rest of 473hacks. Understanding this type took more time than writing all the rest of
405PBCDEDIT, and because it is so complex, this type has its own subsection 474PBCDEDIT, and because it is so complex, this type has its own subsection
406below. 475below.
476
407=back 477=back
408 478
409=head4 The BCD "device" element type 479=head3 The BCD "device" element type
410 480
411Device elements specify, well, devices. They are used for such diverse 481Device elements specify, well, devices. They are used for such diverse
412purposes such as finding a TFTP network boot image, serial ports or VMBUS 482purposes such as finding a TFTP network boot image, serial ports or VMBUS
413devices, but most commonly they are used to specify the disk (harddisk, 483devices, but most commonly they are used to specify the disk (harddisk,
414cdrom, ramdisk, vhd...) to boot from. 484cdrom, ramdisk, vhd...) to boot from.
422element, so almost everything known about it had to be researched first 492element, so almost everything known about it had to be researched first
423in the process of writing this script, and consequently, support for BCD 493in the process of writing this script, and consequently, support for BCD
424device elements is partial only. 494device elements is partial only.
425 495
426On the other hand, the expressive power of PBCDEDIT in specifying devices 496On the other hand, the expressive power of PBCDEDIT in specifying devices
427is much bigger than BCDEDIT and therefore more can be done with it. The 497is much greater than BCDEDIT and therefore more can be done with it. The
428downside is that BCD device elements are much more complicated than what 498downside is that BCD device elements are much more complicated than what
429you might think from reading the BCDEDIT documentation. 499you might think from reading the BCDEDIT documentation.
430 500
431In other words, simple things are complicated, and complicated things are 501In other words, simple things are complicated, and complicated things are
432possible. 502possible.
475the leading GUID, which it can always decode). In such cases, it will 545the leading GUID, which it can always decode). In such cases, it will
476convert the device into this type with a hexdump of the element data. 546convert the device into this type with a hexdump of the element data.
477 547
478=item C<null> 548=item C<null>
479 549
480This is another special type - sometimes, a device all zero-filled, which 550This is another special type - sometimes, a device is all zero-filled,
481is not valid. This can mark the absence of a device or something PBCDEDIT 551which is not valid. This can mark the absence of a device or something
482does not understand, so it decodes it into this special "all zero" type 552PBCDEDIT does not understand, so it decodes it into this special "all
483called C<null>. 553zero" type called C<null>.
484 554
485It's most commonly found in devices that can use an optional parent 555It's most commonly found in devices that can use an optional parent
486device, when no parent device is used. 556device, when no parent device is used.
487 557
488=item C<boot> 558=item C<boot>
599 669
600Last not least, the most complex type, C<block>, which... specifies block 670Last not least, the most complex type, C<block>, which... specifies block
601devices (which could be inside a F<vhdx> file for example). 671devices (which could be inside a F<vhdx> file for example).
602 672
603I<devicetypes> is one of C<harddisk>, C<floppy>, C<cdrom>, C<ramdisk>, 673I<devicetypes> is one of C<harddisk>, C<floppy>, C<cdrom>, C<ramdisk>,
604C<file> or C<vhd> - the same as for C<partiion=>. 674C<file> or C<vhd> - the same as for C<partition=>.
605 675
606The remaining arguments change depending on the I<devicetype>: 676The remaining arguments change depending on the I<devicetype>:
607 677
608=over 678=over
609 679
639 709
640Probably not yet implemented. Tell me of your needs... 710Probably not yet implemented. Tell me of your needs...
641 711
642=back 712=back
643 713
644=back5 Examples 714=head4 Examples
645 715
646This concludes the syntax overview for device elements, but probably 716This concludes the syntax overview for device elements, but probably
647leaves many questions open. I can't help with most of them, as I also ave 717leaves many questions open. I can't help with most of them, as I also have
648many questions, but I can walk you through some actual examples using more 718many questions, but I can walk you through some actual examples using more
649complex aspects. 719complex aspects.
650 720
651=item C<< locate=<block=vhd,<block=file,<locate=<null>,path,\disk.vhdx>,\disk.vhdx>>,element,path >> 721=item C<< locate=<block=vhd,<block=file,<locate=<null>,path,\disk.vhdx>,\disk.vhdx>>,element,path >>
652 722
866sub xxd($$) { 936sub xxd($$) {
867 open my $xxd, "| xxd | sed -e 's/^/\Q$_[0]\E: /'"; 937 open my $xxd, "| xxd | sed -e 's/^/\Q$_[0]\E: /'";
868 syswrite $xxd, $_[1]; 938 syswrite $xxd, $_[1];
869} 939}
870 940
941# get some meta info on a file (uid, gid, perms)
942sub stat_get($) {
943 [(stat shift)[4, 5, 2]]
944}
945
946# set stat info on a file
947sub stat_set($$) {
948 my ($fh_or_path, $stat) = @_;
949
950 return unless $stat;
951 chown $stat->[0], $stat->[1], $fh_or_path;
952 chmod +($stat->[2] & 07777), $fh_or_path;
953}
954
871sub file_load($) { 955sub file_load($) {
872 my ($path) = @_; 956 my ($path) = @_;
873 957
874 open my $fh, "<:raw", $path 958 open my $fh, "<:raw", $path
875 or die "$path: $!\n"; 959 or die "$path: $!\n";
876 my $size = -s $fh; 960 my $size = -s $fh;
877 $size = read $fh, my $buf, $size 961 $size = read $fh, my $buf, $size
878 or die "$path: short read\n"; 962 or die "$path: short read\n";
879 963
880 $buf 964 $buf
965}
966
967sub file_save($$;$) {
968 my ($path, $data, $stat) = @_;
969
970 open my $fh, ">:raw", "$path~"
971 or die "$path~: $!\n";
972 print $fh $data
973 or die "$path~: short write\n";
974 stat_set $fh, $stat;
975 $fh->sync;
976 close $fh;
977
978 rename "$path~", $path;
881} 979}
882 980
883# sources and resources used for writing pbcdedit 981# sources and resources used for writing pbcdedit
884# 982#
885# registry: 983# registry:
1071 my ($rname, $root) = $decode_key->($rootcell); 1169 my ($rname, $root) = $decode_key->($rootcell);
1072 1170
1073 [$rname, $root] 1171 [$rname, $root]
1074} 1172}
1075 1173
1076# return a binary windows fILETIME struct 1174# return a binary windows FILETIME struct
1077sub filetime_now { 1175sub filetime_now {
1078 my ($s, $ms) = Time::HiRes::gettimeofday; 1176 my ($s, $ms) = Time::HiRes::gettimeofday;
1079 1177
1080 pack "Q<", $s = ($s * 1_000_000 + $ms) * 10 + 116_444_736_000_000_000 1178 pack "Q<", $s = ($s * 1_000_000 + $ms) * 10 + 116_444_736_000_000_000
1081} 1179}
1242 1340
1243 regf_decode file_load $path 1341 regf_decode file_load $path
1244} 1342}
1245 1343
1246# encode and save registry to file 1344# encode and save registry to file
1247sub regf_save { 1345sub regf_save($$;$) {
1248 my ($path, $hive) = @_; 1346 my ($path, $hive, $stat) = @_;
1249 1347
1250 $hive = regf_encode $hive; 1348 $hive = regf_encode $hive;
1251 1349
1252 open my $regf, ">:raw", "$path~" 1350 file_save $path, $hive, $stat;
1253 or die "$path~: $!\n";
1254 print $regf $hive
1255 or die "$path~: short write\n";
1256 $regf->sync;
1257 close $regf;
1258
1259 rename "$path~", $path;
1260} 1351}
1261 1352
1262############################################################################# 1353#############################################################################
1263# bcd stuff 1354# bcd stuff
1264 1355
2199 or die "$_: malformed or missing vmbus interface instance guid\n"; 2290 or die "$_: malformed or missing vmbus interface instance guid\n";
2200 my $instance = enc_guid $1; 2291 my $instance = enc_guid $1;
2201 2292
2202 $payload = pack "a16a16x24", $type, $instance; 2293 $payload = pack "a16a16x24", $type, $instance;
2203 2294
2295# } elsif ($type eq "udp") {
2296# $payload = pack "Va16", 1, "12345678";
2297
2204 } else { 2298 } else {
2205 die "$type: not a supported device type (binary, null, boot, legacypartition, partition, block, locate)\n"; 2299 die "$type: not a supported device type (binary, null, boot, legacypartition, partition, block, locate)\n";
2206 } 2300 }
2207 2301
2208 return ( 2302 return (
2390 } 2484 }
2391 2485
2392} 2486}
2393 2487
2394############################################################################# 2488#############################################################################
2395# command line parser 2489# other utilities
2396 2490
2397# json to stdout 2491# json to stdout
2398sub prjson($) { 2492sub prjson($) {
2399 print $json_coder->encode ($_[0]); 2493 print $json_coder->encode ($_[0]);
2400} 2494}
2404 my $json; 2498 my $json;
2405 1 while read STDIN, $json, 65536, length $json; 2499 1 while read STDIN, $json, 65536, length $json;
2406 $json_coder->decode ($json) 2500 $json_coder->decode ($json)
2407} 2501}
2408 2502
2409# all subcommands 2503sub lsblk() {
2504 my $lsblk = $json_coder->decode (scalar qx<lsblk --json -o PATH,KNAME,MAJ:MIN,TYPE,PTTYPE,PTUUID,PARTUUID,LABEL,FSTYPE>);
2505
2506 for my $dev (@{ $lsblk->{blockdevices} }) {
2507 if ($dev->{type} eq "part") {
2508
2509 # lsblk sometimes gives a bogus pttype, so we recreate it here
2510 $dev->{pttype} = $dev->{ptuuid} =~ /^$RE_GUID\z/
2511 ? "gpt" : "dos";
2512
2513 if ($dev->{pttype} eq "gpt") {
2514 $dev->{bcd_device} = "partition=<null>,harddisk,gpt,$dev->{ptuuid},$dev->{partuuid}";
2515 } elsif ($dev->{pttype} eq "dos") { # why not "mbr" :(
2516 if ($dev->{partuuid} =~ /^([0-9a-f]{8})-([0-9a-f]{2})\z/i) {
2517 my ($diskid, $partno) = ($1, hex $2);
2518 $dev->{bcd_legacy_device} = "legacypartition=<null>,harddisk,mbr,$diskid,$partno";
2519 if (open my $fh, "/sys/class/block/$dev->{kname}/start") {
2520 my $start = 512 * readline $fh;
2521 $dev->{bcd_device} = "partition=<null>,harddisk,mbr,$diskid,$start";
2522 }
2523 }
2524 }
2525 }
2526 }
2527
2528 $lsblk->{blockdevices}
2529}
2530
2531sub prdev($$) {
2532 my ($path, $attribute) = @_;
2533
2534 # rather than stat'ing and guessing how devices are encoded, we use lsblk for this
2535 my $mm = $json_coder->decode (scalar qx<lsblk -d -o MAJ:MIN -J \Q$path\E>)->{blockdevices}[0]{"maj:min"};
2536
2537 my $lsblk = lsblk;
2538
2539 for my $dev (@$lsblk) {
2540 if ($dev->{"maj:min"} eq $mm && $dev->{$attribute}) {
2541 say $dev->{$attribute};
2542 exit 0;
2543 }
2544 }
2545
2546 exit 1;
2547}
2548
2549#############################################################################
2550# command line parser
2551
2410our %CMD = ( 2552our %CMD = (
2411 help => sub { 2553 help => sub {
2412 require Pod::Usage; 2554 require Pod::Usage;
2413 Pod::Usage::pod2usage (-verbose => 2); 2555 Pod::Usage::pod2usage (-verbose => 2);
2414 }, 2556 },
2465 BCDE_FORMAT_INTEGER , "integer", 2607 BCDE_FORMAT_INTEGER , "integer",
2466 BCDE_FORMAT_BOOLEAN , "boolean", 2608 BCDE_FORMAT_BOOLEAN , "boolean",
2467 BCDE_FORMAT_INTEGER_LIST, "integer list", 2609 BCDE_FORMAT_INTEGER_LIST, "integer list",
2468 ); 2610 );
2469 2611
2470 my %element; 2612 my @element;
2471 2613
2472 for my $class (sort keys %rbcde_byclass) { 2614 for my $class (sort keys %rbcde_byclass) {
2473 my $rbcde = $rbcde_byclass{$class}; 2615 my $rbcde = $rbcde_byclass{$class};
2474 2616
2475 unless ($json) { 2617 unless ($json) {
2478 printf "%-9s %-12s %s\n", "Element", "Format", "Name Alias"; 2620 printf "%-9s %-12s %s\n", "Element", "Format", "Name Alias";
2479 } 2621 }
2480 for my $name (sort keys %$rbcde) { 2622 for my $name (sort keys %$rbcde) {
2481 my $id = $rbcde->{$name}; 2623 my $id = $rbcde->{$name};
2482 my $format = $format_name{$id & BCDE_FORMAT}; 2624 my $format = $format_name{$id & BCDE_FORMAT};
2483 $id = sprintf "%08x", $id;
2484 2625
2485 if ($json) { 2626 if ($json) {
2486 $element{$id} = [$class, $format, $name]; 2627 push @element, [$class, $id * 1, $format, $name];
2487 } else { 2628 } else {
2629 $id = sprintf "%08x", $id;
2488 printf "%-9s %-12s %s\n", $id, $format, $name; 2630 printf "%-9s %-12s %s\n", $id, $format, $name;
2489 } 2631 }
2490 } 2632 }
2491 } 2633 }
2492 print "\n" unless $json; 2634 print "\n" unless $json;
2493 2635
2494 prjson { 2636 prjson {
2495 version => $JSON_VERSION, 2637 version => $JSON_VERSION,
2496 element => \%element, 2638 element => \@element,
2497 class => \@bcde_typeclass, 2639 class => \@bcde_typeclass,
2498 } if $json; 2640 } if $json;
2499 2641
2500 }, 2642 },
2501 2643
2505 2647
2506 import => sub { 2648 import => sub {
2507 regf_save shift, bcd_encode rdjson; 2649 regf_save shift, bcd_encode rdjson;
2508 }, 2650 },
2509 2651
2652 create => sub {
2653 my $path = shift;
2654 my $stat = stat_get $path; # should actually be done at file load time
2655 my $bcd = { };
2656 bcd_edit $path, $bcd, @_;
2657 regf_save $path, bcd_encode $bcd;
2658 stat_set $path, $stat;
2659 },
2660
2510 edit => sub { 2661 edit => sub {
2511 my $path = shift; 2662 my $path = shift;
2663 my $stat = stat_get $path; # should actually be done at file load time
2512 my $bcd = bcd_decode regf_load $path; 2664 my $bcd = bcd_decode regf_load $path;
2513 bcd_edit $path, $bcd, @_; 2665 bcd_edit $path, $bcd, @_;
2514 regf_save $path, bcd_encode $bcd; 2666 regf_save $path, bcd_encode $bcd;
2667 stat_set $path, $stat;
2515 }, 2668 },
2516 2669
2517 parse => sub { 2670 parse => sub {
2518 my $path = shift; 2671 my $path = shift;
2519 my $bcd = bcd_decode regf_load $path; 2672 my $bcd = bcd_decode regf_load $path;
2528 "import-regf" => sub { 2681 "import-regf" => sub {
2529 regf_save shift, rdjson; 2682 regf_save shift, rdjson;
2530 }, 2683 },
2531 2684
2532 lsblk => sub { 2685 lsblk => sub {
2686 my $json = $_[0] eq "--json";
2687
2688 my $lsblk = lsblk;
2689
2690 if ($json) {
2691 prjson $lsblk;
2692 } else {
2533 printf "%-10s %-8.8s %-6.6s %-3s %s\n", "DEVICE", "LABEL", "FSTYPE", "PT", "DEVICE DESCRIPTOR"; 2693 printf "%-10s %-8.8s %-6.6s %-3s %s\n", "DEVICE", "LABEL", "FSTYPE", "PT", "DEVICE DESCRIPTOR";
2534 2694 for my $dev (@$lsblk) {
2535 my $lsblk = $json_coder->decode (scalar qx<lsblk --json -o PATH,KNAME,TYPE,PTTYPE,PTUUID,PARTUUID,LABEL,FSTYPE>); 2695 for my $bcd ($dev->{bcd_device}, $dev->{bcd_legacy_device}) {
2536
2537 for my $dev (@{ $lsblk->{blockdevices} }) {
2538 my $pr = sub {
2539 printf "%-10s %-8.8s %-6.6s %-3s %s\n", 2696 printf "%-10s %-8.8s %-6.6s %-3s %s\n",
2540 $dev->{path}, $dev->{label}, $dev->{fstype}, $dev->{pttype}, $_[0]; 2697 $dev->{path}, $dev->{label}, $dev->{fstype}, $dev->{pttype}, $bcd
2541 };
2542
2543 if ($dev->{type} eq "part") {
2544 if ($dev->{pttype} eq "gpt") {
2545 $pr->("partition=<null>,harddisk,gpt,$dev->{ptuuid},$dev->{partuuid}");
2546 } elsif ($dev->{pttype} eq "dos") { # why not "mbr" :(
2547 if ($dev->{partuuid} =~ /^([0-9a-f]{8})-([0-9a-f]{2})\z/i) {
2548 my ($diskid, $partno) = ($1, hex $2);
2549 $pr->("legacypartition=<null>,harddisk,mbr,$diskid,$partno");
2550 if (open my $fh, "/sys/class/block/$dev->{kname}/start") {
2551 my $start = 512 * readline $fh;
2552 $pr->("partition=<null>,harddisk,mbr,$diskid,$start");
2553 } 2698 if $bcd;
2554 }
2555 } 2699 }
2556 } 2700 }
2557 } 2701 }
2702 },
2703
2704 "bcd-device" => sub {
2705 prdev shift, "bcd_device";
2706 },
2707
2708 "bcd-legacy-device" => sub {
2709 prdev shift, "bcd_legacy_device";
2558 }, 2710 },
2559 2711
2560 version => sub { 2712 version => sub {
2561 print "\n", 2713 print "\n",
2562 "PBCDEDIT version $VERSION, copyright 2019 Marc A. Lehmann <pbcdedit\@schmorp.de>.\n", 2714 "PBCDEDIT version $VERSION, copyright 2019 Marc A. Lehmann <pbcdedit\@schmorp.de>.\n",

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines