… | |
… | |
106 | The reverse of C<export>: Reads a JSON representation of a BCD data store |
106 | The reverse of C<export>: Reads a JSON representation of a BCD data store |
107 | from standard input, and creates or replaces the given BCD data store. |
107 | from standard input, and creates or replaces the given BCD data store. |
108 | |
108 | |
109 | =item edit F<path> instructions... |
109 | =item edit F<path> instructions... |
110 | |
110 | |
111 | #TODO |
111 | Load a BCD data store, apply some instructions to it, and save it again. |
|
|
112 | |
|
|
113 | See the section L<EDITING BCD DATA STORES>, below, for more info. |
|
|
114 | |
|
|
115 | =item parse F<path> instructions... |
|
|
116 | |
|
|
117 | Same as C<edit>, above, except it doesn't save the data store again. Can |
|
|
118 | be useful to extract some data from it. |
112 | |
119 | |
113 | =item lsblk |
120 | =item lsblk |
114 | |
121 | |
115 | On a GNU/Linux system, you can get a list of partition device descriptors |
122 | On a GNU/Linux system, you can get a list of partition device descriptors |
116 | using this command - the external C<lsblk> command is required, as well as |
123 | using this command - the external C<lsblk> command is required, as well as |
… | |
… | |
697 | seems to be always there on this kind of entry. |
704 | seems to be always there on this kind of entry. |
698 | |
705 | |
699 | If you have some good examples to add here, feel free to mail me. |
706 | If you have some good examples to add here, feel free to mail me. |
700 | |
707 | |
701 | |
708 | |
|
|
709 | =head1 EDITING BCD DATA STORES |
|
|
710 | |
|
|
711 | The C<edit> and C<parse> subcommands allow you to read a BCD data store |
|
|
712 | and modify it or extract data from it. This is done by exyecuting a series |
|
|
713 | of "editing instructions" which are explained here. |
|
|
714 | |
|
|
715 | =over |
|
|
716 | |
|
|
717 | =item get I<object> I<element> |
|
|
718 | |
|
|
719 | Reads the BCD element I<element> from the BCD object I<object> and writes |
|
|
720 | it to standard output, followed by a newline. The I<object> can be a GUID |
|
|
721 | or a human-readable alias, or the special string C<{default}>, which will |
|
|
722 | refer to the default BCD object. |
|
|
723 | |
|
|
724 | Example: find description of the default BCD object. |
|
|
725 | |
|
|
726 | pbcdedit parse BCD get "{default}" description |
|
|
727 | |
|
|
728 | =item set I<object> I<element> I<value> |
|
|
729 | |
|
|
730 | Similar to C<get>, but sets the element to the given I<value> instead. |
|
|
731 | |
|
|
732 | Example: change bootmgr default too |
|
|
733 | C<{b097d2ad-bc00-11e9-8a9a-525400123456}>: |
|
|
734 | |
|
|
735 | pbcdedit edit BCD set "{bootmgr}" resumeobject "{b097d2ad-bc00-11e9-8a9a-525400123456}" |
|
|
736 | |
|
|
737 | =item eval I<perlcode> |
|
|
738 | |
|
|
739 | This takes the next argument, interprets it as Perl code and |
|
|
740 | evaluates it. This allows you to do more complicated modifications or |
|
|
741 | extractions. |
|
|
742 | |
|
|
743 | The following variables are predefined for your use: |
|
|
744 | |
|
|
745 | =over |
|
|
746 | |
|
|
747 | =item C<$PATH> |
|
|
748 | |
|
|
749 | The path to the BCD data store, as given to C<edit> or C<parse>. |
|
|
750 | |
|
|
751 | =item C<$BCD> |
|
|
752 | |
|
|
753 | The decoded BCD data store. |
|
|
754 | |
|
|
755 | =item C<$DEFAULT> |
|
|
756 | |
|
|
757 | The default BCD object name. |
|
|
758 | |
|
|
759 | =back |
|
|
760 | |
|
|
761 | The example given for C<get>, above, could be expressed like this with |
|
|
762 | C<eval>: |
|
|
763 | |
|
|
764 | pbcdedit edit BCD eval 'say $BCD->{$DEFAULT}{description}' |
|
|
765 | |
|
|
766 | The example given for C<set> could be expresed like this: |
|
|
767 | |
|
|
768 | pbcdedit edit BCD eval '$BCD->{$DEFAULT}{resumeobject} = "{b097d2ad-bc00-11e9-8a9a-525400123456}"' |
|
|
769 | |
|
|
770 | =item do I<path> |
|
|
771 | |
|
|
772 | Similar to C<eval>, above, but instead of using the argument as perl code, |
|
|
773 | it loads the perl code from the given file and executes it. This makes it |
|
|
774 | easier to write more complicated or larger programs. |
|
|
775 | |
|
|
776 | =back |
|
|
777 | |
702 | =head1 SEE ALSO |
778 | =head1 SEE ALSO |
703 | |
779 | |
704 | For ideas on what you can do, and some introductory material, try |
780 | For ideas on what you can do, and some introductory material, try |
705 | L<http://www.mistyprojects.co.uk/documents/BCDEdit/index.html>. |
781 | L<http://www.mistyprojects.co.uk/documents/BCDEdit/index.html>. |
706 | |
782 | |
… | |
… | |
760 | |
836 | |
761 | # hack used for debugging |
837 | # hack used for debugging |
762 | sub xxd($$) { |
838 | sub xxd($$) { |
763 | open my $xxd, "| xxd | sed -e 's/^/\Q$_[0]\E: /'"; |
839 | open my $xxd, "| xxd | sed -e 's/^/\Q$_[0]\E: /'"; |
764 | syswrite $xxd, $_[1]; |
840 | syswrite $xxd, $_[1]; |
|
|
841 | } |
|
|
842 | |
|
|
843 | sub file_load($) { |
|
|
844 | my ($path) = @_; |
|
|
845 | |
|
|
846 | open my $fh, "<:raw", $path |
|
|
847 | or die "$path: $!\n"; |
|
|
848 | my $size = -s $fh; |
|
|
849 | $size = read $fh, my $buf, $size |
|
|
850 | or die "$path: short read\n"; |
|
|
851 | |
|
|
852 | $buf |
765 | } |
853 | } |
766 | |
854 | |
767 | # sources and resources used for this: |
855 | # sources and resources used for this: |
768 | # registry: |
856 | # registry: |
769 | # https://github.com/msuhanov/regf/blob/master/Windows%20registry%20file%20format%20specification.md |
857 | # https://github.com/msuhanov/regf/blob/master/Windows%20registry%20file%20format%20specification.md |
… | |
… | |
1120 | } |
1208 | } |
1121 | |
1209 | |
1122 | # load and parse registry from file |
1210 | # load and parse registry from file |
1123 | sub regf_load($) { |
1211 | sub regf_load($) { |
1124 | my ($path) = @_; |
1212 | my ($path) = @_; |
1125 | open my $regf, "<:raw", $path |
|
|
1126 | or die "$path: $!\n"; |
|
|
1127 | my $size = -s $regf; |
|
|
1128 | $size = read $regf, my $buf, $size |
|
|
1129 | or die "$path: short read\n"; |
|
|
1130 | |
1213 | |
1131 | regf_decode $buf |
1214 | regf_decode file_load $path |
1132 | } |
1215 | } |
1133 | |
1216 | |
1134 | # encode and save registry to file |
1217 | # encode and save registry to file |
1135 | sub regf_save { |
1218 | sub regf_save { |
1136 | my ($path, $hive) = @_; |
1219 | my ($path, $hive) = @_; |
… | |
… | |
2157 | }]] |
2240 | }]] |
2158 | } |
2241 | } |
2159 | |
2242 | |
2160 | ############################################################################# |
2243 | ############################################################################# |
2161 | |
2244 | |
|
|
2245 | sub bcd_edit_eval { |
|
|
2246 | package pbcdedit; |
|
|
2247 | |
|
|
2248 | our ($PATH, $BCD, $DEFAULT); |
|
|
2249 | |
|
|
2250 | eval shift; |
|
|
2251 | die "$@" if $@; |
|
|
2252 | } |
|
|
2253 | |
|
|
2254 | sub bcd_edit { |
|
|
2255 | my ($path, $bcd, @insns) = @_; |
|
|
2256 | |
|
|
2257 | my $default = $bcd->{"{bootmgr}"}{resumeobject}; |
|
|
2258 | |
|
|
2259 | # prepare "officially visible" variables |
|
|
2260 | local $pbcdedit::PATH = $path; |
|
|
2261 | local $pbcdedit::BCD = $bcd; |
|
|
2262 | local $pbcdedit::DEFAULT = $default; |
|
|
2263 | |
|
|
2264 | while (@insns) { |
|
|
2265 | my $insn = shift @insns; |
|
|
2266 | |
|
|
2267 | if ($insn eq "get") { |
|
|
2268 | my $object = shift @insns; |
|
|
2269 | my $elem = shift @insns; |
|
|
2270 | |
|
|
2271 | $object = $default if $object eq "{default}"; |
|
|
2272 | |
|
|
2273 | print $bcd->{$object}{$elem}, "\n"; |
|
|
2274 | |
|
|
2275 | } elsif ($insn eq "set") { |
|
|
2276 | my $object = shift @insns; |
|
|
2277 | my $elem = shift @insns; |
|
|
2278 | my $value = shift @insns; |
|
|
2279 | |
|
|
2280 | $object = $default if $object eq "{default}"; |
|
|
2281 | |
|
|
2282 | $bcd->{$object}{$elem} = $value; |
|
|
2283 | |
|
|
2284 | } elsif ($insn eq "eval") { |
|
|
2285 | bcd_edit_eval shift @insns; |
|
|
2286 | |
|
|
2287 | } elsif ($insn eq "do") { |
|
|
2288 | my $path = shift @insns; |
|
|
2289 | my $file = file_load $path; |
|
|
2290 | bcd_edit_eval "#line 1 '$path'\n$file"; |
|
|
2291 | |
|
|
2292 | } else { |
|
|
2293 | die "$insn: not a recognized instruction for edit/parse\n"; |
|
|
2294 | } |
|
|
2295 | } |
|
|
2296 | |
|
|
2297 | } |
|
|
2298 | |
|
|
2299 | ############################################################################# |
|
|
2300 | |
2162 | # json to stdout |
2301 | # json to stdout |
2163 | sub prjson($) { |
2302 | sub prjson($) { |
2164 | print $json_coder->encode ($_[0]); |
2303 | print $json_coder->encode ($_[0]); |
2165 | } |
2304 | } |
2166 | |
2305 | |
… | |
… | |
2263 | prjson bcd_decode regf_load shift; |
2402 | prjson bcd_decode regf_load shift; |
2264 | }, |
2403 | }, |
2265 | |
2404 | |
2266 | import => sub { |
2405 | import => sub { |
2267 | regf_save shift, bcd_encode rdjson; |
2406 | regf_save shift, bcd_encode rdjson; |
|
|
2407 | }, |
|
|
2408 | |
|
|
2409 | edit => sub { |
|
|
2410 | my $path = shift; |
|
|
2411 | my $bcd = bcd_decode regf_load $path; |
|
|
2412 | bcd_edit $path, $bcd, @_; |
|
|
2413 | regf_save $path, bcd_encode $bcd; |
|
|
2414 | }, |
|
|
2415 | |
|
|
2416 | parse => sub { |
|
|
2417 | my $path = shift; |
|
|
2418 | my $bcd = bcd_decode regf_load $path; |
|
|
2419 | bcd_edit $path, $bcd, @_; |
2268 | }, |
2420 | }, |
2269 | |
2421 | |
2270 | "export-regf" => sub { |
2422 | "export-regf" => sub { |
2271 | prjson regf_load shift; |
2423 | prjson regf_load shift; |
2272 | |
2424 | |