… | |
… | |
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 | |
22 | use 5.016; # numerous features need 5.14, __SUB__ needs 5.16 |
22 | use 5.016; # numerous features need 5.14, __SUB__ needs 5.16 |
23 | |
23 | |
24 | our $VERSION = '1.2'; |
24 | our $VERSION = '1.3'; |
25 | our $JSON_VERSION = 2; # the version of the json objects generated by this program |
25 | our $JSON_VERSION = 3; # the version of the json objects generated by this program |
26 | |
26 | |
27 | our $CHANGELOG = <<EOF; |
27 | our $CHANGELOG = <<EOF; |
|
|
28 | |
|
|
29 | 1.3 Sat Aug 17 07:04:15 CEST 2019 |
|
|
30 | - output of pbcdedit elements --json has changed, as it didn't |
|
|
31 | take the reorganisation by classes fully into account. |
|
|
32 | - json schema bumped to 3. |
|
|
33 | - new "bcd-device" and "bcd-legacy-device" subcommands. |
|
|
34 | - implement --json option for lsblk. |
|
|
35 | |
28 | 1.2 Fri Aug 16 00:20:41 CEST 2019 |
36 | 1.2 Fri Aug 16 00:20:41 CEST 2019 |
29 | - bcde element names now depend on the bcd object type they are in, |
37 | - bcd element names now depend on the bcd object type they are in, |
30 | also affects "elements" output. |
38 | also affects "elements" output. |
31 | - json schema bumped to 2. |
39 | - json schema bumped to 2. |
32 | - new version command. |
40 | - new version command. |
33 | - numerous minor bugfixes. |
41 | - numerous minor bugfixes. |
34 | |
42 | |
… | |
… | |
136 | =item C<parse> F<path> I<instructions...> |
144 | =item C<parse> F<path> I<instructions...> |
137 | |
145 | |
138 | Same as C<edit>, above, except it doesn't save the data store again. Can |
146 | Same as C<edit>, above, except it doesn't save the data store again. Can |
139 | be useful to extract some data from it. |
147 | be useful to extract some data from it. |
140 | |
148 | |
141 | =item C<lsblk> |
149 | =item C<lsblk> [C<--json>] |
142 | |
150 | |
143 | On a GNU/Linux system, you can get a list of partition device descriptors |
151 | On a GNU/Linux system, you can get a list of partition device descriptors |
144 | using this command - the external C<lsblk> command is required, as well as |
152 | using this command - the external C<lsblk> command is required, as well as |
145 | a mounted C</sys> file system. |
153 | a mounted C</sys> file system. |
146 | |
154 | |
147 | The output will be a list of all partitions in the system and C<partition> |
155 | The output will be a list of all partitions in the system and C<partition> |
148 | descriptors for GPT and both C<legacypartition> and C<partition> |
156 | descriptors for GPT and both C<legacypartition> and C<partition> |
149 | descriptors for MBR partitions. |
157 | descriptors for MBR partitions. |
|
|
158 | |
|
|
159 | With C<--json> it will print similar informationm as C<lsblk --json>, but |
|
|
160 | with extra C<bcd_device> and C<bcd_legacy_device> attributes. |
|
|
161 | |
|
|
162 | =item C<bcd-device> F<path> |
|
|
163 | |
|
|
164 | Tries to find the BCD device element for the given device, which currently |
|
|
165 | must be a a partition of some kind. Prints the C<partition=> descriptor as |
|
|
166 | a result, or nothing. Exit status will be true on success, and false on |
|
|
167 | failure. |
|
|
168 | |
|
|
169 | Like C<lsblk>, above, this likely only works on GNU/Linux systems. |
|
|
170 | |
|
|
171 | Example: print the partition descriptor of tghe partition with label DATA. |
|
|
172 | |
|
|
173 | $ pbcdedit bcd-device /dev/disk/by-label/DATA |
|
|
174 | partition=<null>,harddisk,mbr,47cbc08a,213579202560 |
|
|
175 | |
|
|
176 | =item C<bcd-legacy-device> F<path> |
|
|
177 | |
|
|
178 | Like above, but uses a C<legacypartition> descriptor instead. |
150 | |
179 | |
151 | =item C<objects> [C<--json>] |
180 | =item C<objects> [C<--json>] |
152 | |
181 | |
153 | Outputs two tables: a table listing all type aliases with their hex BCD |
182 | Outputs two tables: a table listing all type aliases with their hex BCD |
154 | element ID, and all object name aliases with their GUID and default type |
183 | element ID, and all object name aliases with their GUID and default type |
… | |
… | |
352 | |
381 | |
353 | "displaybootmenu" : 0, |
382 | "displaybootmenu" : 0, |
354 | |
383 | |
355 | =item integer |
384 | =item integer |
356 | |
385 | |
357 | Again, very simple, this is a 64 bit integer. IT can be either specified |
386 | Again, very simple, this is a 64 bit integer. It can be either specified |
358 | as a decimal number, as a hex number (by prefixing it with C<0x>) or as a |
387 | as a decimal number, as a hex number (by prefixing it with C<0x>) or as a |
359 | binary number (prefix C<0b>). |
388 | binary number (prefix C<0b>). |
360 | |
389 | |
361 | For example, the boot C<timeout> is an integer, specifying the automatic |
390 | For example, the boot C<timeout> is an integer, specifying the automatic |
362 | boot delay in seconds: |
391 | boot delay in seconds: |
… | |
… | |
475 | the leading GUID, which it can always decode). In such cases, it will |
504 | the leading GUID, which it can always decode). In such cases, it will |
476 | convert the device into this type with a hexdump of the element data. |
505 | convert the device into this type with a hexdump of the element data. |
477 | |
506 | |
478 | =item C<null> |
507 | =item C<null> |
479 | |
508 | |
480 | This is another special type - sometimes, a device all zero-filled, which |
509 | This is another special type - sometimes, a device is all zero-filled, |
481 | is not valid. This can mark the absence of a device or something PBCDEDIT |
510 | which is not valid. This can mark the absence of a device or something |
482 | does not understand, so it decodes it into this special "all zero" type |
511 | PBCDEDIT does not understand, so it decodes it into this special "all |
483 | called C<null>. |
512 | zero" type called C<null>. |
484 | |
513 | |
485 | It's most commonly found in devices that can use an optional parent |
514 | It's most commonly found in devices that can use an optional parent |
486 | device, when no parent device is used. |
515 | device, when no parent device is used. |
487 | |
516 | |
488 | =item C<boot> |
517 | =item C<boot> |
… | |
… | |
599 | |
628 | |
600 | Last not least, the most complex type, C<block>, which... specifies block |
629 | Last not least, the most complex type, C<block>, which... specifies block |
601 | devices (which could be inside a F<vhdx> file for example). |
630 | devices (which could be inside a F<vhdx> file for example). |
602 | |
631 | |
603 | I<devicetypes> is one of C<harddisk>, C<floppy>, C<cdrom>, C<ramdisk>, |
632 | I<devicetypes> is one of C<harddisk>, C<floppy>, C<cdrom>, C<ramdisk>, |
604 | C<file> or C<vhd> - the same as for C<partiion=>. |
633 | C<file> or C<vhd> - the same as for C<partition=>. |
605 | |
634 | |
606 | The remaining arguments change depending on the I<devicetype>: |
635 | The remaining arguments change depending on the I<devicetype>: |
607 | |
636 | |
608 | =over |
637 | =over |
609 | |
638 | |
… | |
… | |
2390 | } |
2419 | } |
2391 | |
2420 | |
2392 | } |
2421 | } |
2393 | |
2422 | |
2394 | ############################################################################# |
2423 | ############################################################################# |
2395 | # command line parser |
2424 | # other utilities |
2396 | |
2425 | |
2397 | # json to stdout |
2426 | # json to stdout |
2398 | sub prjson($) { |
2427 | sub prjson($) { |
2399 | print $json_coder->encode ($_[0]); |
2428 | print $json_coder->encode ($_[0]); |
2400 | } |
2429 | } |
… | |
… | |
2404 | my $json; |
2433 | my $json; |
2405 | 1 while read STDIN, $json, 65536, length $json; |
2434 | 1 while read STDIN, $json, 65536, length $json; |
2406 | $json_coder->decode ($json) |
2435 | $json_coder->decode ($json) |
2407 | } |
2436 | } |
2408 | |
2437 | |
2409 | # all subcommands |
2438 | sub lsblk() { |
|
|
2439 | my $lsblk = $json_coder->decode (scalar qx<lsblk --json -o PATH,KNAME,MAJ:MIN,TYPE,PTTYPE,PTUUID,PARTUUID,LABEL,FSTYPE>); |
|
|
2440 | |
|
|
2441 | for my $dev (@{ $lsblk->{blockdevices} }) { |
|
|
2442 | if ($dev->{type} eq "part") { |
|
|
2443 | if ($dev->{pttype} eq "gpt") { |
|
|
2444 | $dev->{bcd_device} = "partition=<null>,harddisk,gpt,$dev->{ptuuid},$dev->{partuuid}"; |
|
|
2445 | } elsif ($dev->{pttype} eq "dos") { # why not "mbr" :( |
|
|
2446 | if ($dev->{partuuid} =~ /^([0-9a-f]{8})-([0-9a-f]{2})\z/i) { |
|
|
2447 | my ($diskid, $partno) = ($1, hex $2); |
|
|
2448 | $dev->{bcd_legacy_device} = "legacypartition=<null>,harddisk,mbr,$diskid,$partno"; |
|
|
2449 | if (open my $fh, "/sys/class/block/$dev->{kname}/start") { |
|
|
2450 | my $start = 512 * readline $fh; |
|
|
2451 | $dev->{bcd_device} = "partition=<null>,harddisk,mbr,$diskid,$start"; |
|
|
2452 | } |
|
|
2453 | } |
|
|
2454 | } |
|
|
2455 | } |
|
|
2456 | } |
|
|
2457 | |
|
|
2458 | $lsblk->{blockdevices} |
|
|
2459 | } |
|
|
2460 | |
|
|
2461 | sub prdev($$) { |
|
|
2462 | my ($path, $attribute) = @_; |
|
|
2463 | |
|
|
2464 | # rather than stat'ing and guessing how devices are encoded, we use lsblk for this |
|
|
2465 | # unfortunately, there doesn't seem to be a way to restrict lsblk to just oned evice, |
|
|
2466 | # so we always assume the first one is it. |
|
|
2467 | my $mm = $json_coder->decode (scalar qx<lsblk -o MAJ:MIN -J \Q$path\E>)->{blockdevices}[0]{"maj:min"}; |
|
|
2468 | |
|
|
2469 | my $lsblk = lsblk; |
|
|
2470 | |
|
|
2471 | for my $dev (@$lsblk) { |
|
|
2472 | if ($dev->{"maj:min"} eq $mm && $dev->{$attribute}) { |
|
|
2473 | say $dev->{$attribute}; |
|
|
2474 | exit 0; |
|
|
2475 | } |
|
|
2476 | } |
|
|
2477 | |
|
|
2478 | exit 1; |
|
|
2479 | } |
|
|
2480 | |
|
|
2481 | ############################################################################# |
|
|
2482 | # command line parser |
|
|
2483 | |
2410 | our %CMD = ( |
2484 | our %CMD = ( |
2411 | help => sub { |
2485 | help => sub { |
2412 | require Pod::Usage; |
2486 | require Pod::Usage; |
2413 | Pod::Usage::pod2usage (-verbose => 2); |
2487 | Pod::Usage::pod2usage (-verbose => 2); |
2414 | }, |
2488 | }, |
… | |
… | |
2465 | BCDE_FORMAT_INTEGER , "integer", |
2539 | BCDE_FORMAT_INTEGER , "integer", |
2466 | BCDE_FORMAT_BOOLEAN , "boolean", |
2540 | BCDE_FORMAT_BOOLEAN , "boolean", |
2467 | BCDE_FORMAT_INTEGER_LIST, "integer list", |
2541 | BCDE_FORMAT_INTEGER_LIST, "integer list", |
2468 | ); |
2542 | ); |
2469 | |
2543 | |
2470 | my %element; |
2544 | my @element; |
2471 | |
2545 | |
2472 | for my $class (sort keys %rbcde_byclass) { |
2546 | for my $class (sort keys %rbcde_byclass) { |
2473 | my $rbcde = $rbcde_byclass{$class}; |
2547 | my $rbcde = $rbcde_byclass{$class}; |
2474 | |
2548 | |
2475 | unless ($json) { |
2549 | unless ($json) { |
… | |
… | |
2478 | printf "%-9s %-12s %s\n", "Element", "Format", "Name Alias"; |
2552 | printf "%-9s %-12s %s\n", "Element", "Format", "Name Alias"; |
2479 | } |
2553 | } |
2480 | for my $name (sort keys %$rbcde) { |
2554 | for my $name (sort keys %$rbcde) { |
2481 | my $id = $rbcde->{$name}; |
2555 | my $id = $rbcde->{$name}; |
2482 | my $format = $format_name{$id & BCDE_FORMAT}; |
2556 | my $format = $format_name{$id & BCDE_FORMAT}; |
2483 | $id = sprintf "%08x", $id; |
|
|
2484 | |
2557 | |
2485 | if ($json) { |
2558 | if ($json) { |
2486 | $element{$id} = [$class, $format, $name]; |
2559 | push @element, [$class, $id * 1, $format, $name]; |
2487 | } else { |
2560 | } else { |
|
|
2561 | $id = sprintf "%08x", $id; |
2488 | printf "%-9s %-12s %s\n", $id, $format, $name; |
2562 | printf "%-9s %-12s %s\n", $id, $format, $name; |
2489 | } |
2563 | } |
2490 | } |
2564 | } |
2491 | } |
2565 | } |
2492 | print "\n" unless $json; |
2566 | print "\n" unless $json; |
2493 | |
2567 | |
2494 | prjson { |
2568 | prjson { |
2495 | version => $JSON_VERSION, |
2569 | version => $JSON_VERSION, |
2496 | element => \%element, |
2570 | element => \@element, |
2497 | class => \@bcde_typeclass, |
2571 | class => \@bcde_typeclass, |
2498 | } if $json; |
2572 | } if $json; |
2499 | |
2573 | |
2500 | }, |
2574 | }, |
2501 | |
2575 | |
… | |
… | |
2528 | "import-regf" => sub { |
2602 | "import-regf" => sub { |
2529 | regf_save shift, rdjson; |
2603 | regf_save shift, rdjson; |
2530 | }, |
2604 | }, |
2531 | |
2605 | |
2532 | lsblk => sub { |
2606 | lsblk => sub { |
|
|
2607 | my $json = $_[0] eq "--json"; |
|
|
2608 | |
|
|
2609 | my $lsblk = lsblk; |
|
|
2610 | |
|
|
2611 | if ($json) { |
|
|
2612 | prjson $lsblk; |
|
|
2613 | } else { |
2533 | printf "%-10s %-8.8s %-6.6s %-3s %s\n", "DEVICE", "LABEL", "FSTYPE", "PT", "DEVICE DESCRIPTOR"; |
2614 | printf "%-10s %-8.8s %-6.6s %-3s %s\n", "DEVICE", "LABEL", "FSTYPE", "PT", "DEVICE DESCRIPTOR"; |
2534 | |
2615 | for my $dev (@$lsblk) { |
2535 | my $lsblk = $json_coder->decode (scalar qx<lsblk --json -o PATH,KNAME,TYPE,PTTYPE,PTUUID,PARTUUID,LABEL,FSTYPE>); |
2616 | 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", |
2617 | printf "%-10s %-8.8s %-6.6s %-3s %s\n", |
2540 | $dev->{path}, $dev->{label}, $dev->{fstype}, $dev->{pttype}, $_[0]; |
2618 | $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 | } |
2619 | if $bcd; |
2554 | } |
|
|
2555 | } |
2620 | } |
2556 | } |
2621 | } |
2557 | } |
2622 | } |
|
|
2623 | }, |
|
|
2624 | |
|
|
2625 | "bcd-device" => sub { |
|
|
2626 | prdev shift, "bcd_device"; |
|
|
2627 | }, |
|
|
2628 | |
|
|
2629 | "bcd-legacy-device" => sub { |
|
|
2630 | prdev shift, "bcd_legacy_device"; |
2558 | }, |
2631 | }, |
2559 | |
2632 | |
2560 | version => sub { |
2633 | version => sub { |
2561 | print "\n", |
2634 | print "\n", |
2562 | "PBCDEDIT version $VERSION, copyright 2019 Marc A. Lehmann <pbcdedit\@schmorp.de>.\n", |
2635 | "PBCDEDIT version $VERSION, copyright 2019 Marc A. Lehmann <pbcdedit\@schmorp.de>.\n", |