#!/usr/local/bin/perl # Install the GRUB 2 boot loader with progress output. use strict; use warnings; require './grub2-lib.pl'; ## no critic our (%in, %text); &ReadParse(); &error_setup($text{'install_err'}); my %access = &get_module_acl(); &error("$text{'eacl_np'} $text{'eacl_pinstall'}") if (!$access{'install'}); # Trim text fields before validation so shell arguments are deterministic. foreach my $field (qw(target efi_dir platform directory boot_directory bootloader_id)) { $in{$field} = "" if (!defined($in{$field})); $in{$field} =~ s/^\s+|\s+\z//g; } &error($text{'install_eboot_directory_required'}) if ($in{'use_boot_directory'} && $in{'boot_directory'} eq ''); my %opts = ( 'target' => $in{'target'}, 'efi_dir' => $in{'efi_dir'}, 'platform' => $in{'platform'} || &grub2_default_platform_target(), 'directory' => $in{'directory'}, 'boot_directory' => $in{'use_boot_directory'} ? $in{'boot_directory'} : '', 'bootloader_id' => $in{'bootloader_id'}, 'recheck' => $in{'recheck'} ? 1 : 0, 'removable' => $in{'removable'} ? 1 : 0, 'no_nvram' => $in{'no_nvram'} ? 1 : 0, 'force' => $in{'force'} ? 1 : 0, ); $in{'confirm'} || &error($text{'install_econfirm'}); &grub2_command('install_cmd') || &error($text{'install_ecmd'}); # Validate all paths and identifiers before any progress output is started. my $precheck = &grub2_validate_install_options(\%opts); &error($precheck) if ($precheck); my ($pre_open, $current_step, $failed_printed, $captured_output) = (0, '', 0, ''); &ui_print_unbuffered_header(undef, $text{'install_progress_title'}, ""); my $callback = sub { my ($event, $value) = @_; if ($event eq 'command') { # The first event opens the visible command transcript. $current_step = 'command'; &print_step_start($text{'install_installing'}); print &ui_tag_start('pre', { 'style' => 'margin-left: 10px;' }); $pre_open = 1; print &html_escape($value)."\n"; return; } if ($event eq 'output') { # Some commands emit output before command_done; keep one pre open. if (!$pre_open) { print &ui_tag_start('pre', { 'style' => 'margin-left: 10px;' }); $pre_open = 1; } $captured_output .= $value; print &html_escape($value); return; } if ($event eq 'command_done') { # Close the transcript before printing the final status marker. &close_output(\$pre_open); &print_step_done(\$current_step); return; } if ($event eq 'command_failed') { # Print only one failure line even if the caller also returns an error. &close_output(\$pre_open); &print_step_failed(\$current_step, \$failed_printed); return; } }; my $err = &grub2_install_bootloader(\%opts, $callback); &close_output(\$pre_open); if ($err) { # Avoid duplicating the same error when it was already in command output. &print_step_failed(\$current_step, \$failed_printed) if ($current_step); my $shown = $captured_output || ''; $shown =~ s/^\s+|\s+\z//g; print &ui_tag('pre', &html_escape($err), { 'style' => 'margin-left: 10px;' }) if ($err ne $shown); } else { &webmin_log("install", undef, &grub2_install_log_target(\%opts)); } &ui_print_footer("index.cgi", $text{'install_return'}); # close_output(&open-flag) # Closes the command output block when it is currently being printed. sub close_output { my ($open) = @_; if ($$open) { print &ui_tag_end('pre'); $$open = 0; } return; } # print_step_start(text) # Prints the first progress line for the installation step. sub print_step_start { my ($msg) = @_; print &ui_tag('span', &html_escape($msg." .."), { 'data-first-print' => undef }); print "
\n"; return; } # print_step_done(¤t-step) # Prints a successful progress line and clears the active step. sub print_step_done { my ($current) = @_; print &ui_tag('span', &html_escape(".. ".$text{'install_done'}), { 'data-second-print' => undef }); print "
\n"; $$current = ''; return; } # print_step_failed(¤t-step, &printed-flag) # Prints a failed progress line once and clears the active step. sub print_step_failed { my ($current, $printed) = @_; return if ($$printed); print &ui_tag('span', &html_escape(".. ".$text{'install_failed_status'}), { 'data-second-print' => undef }); print "
\n"; $$current = ''; $$printed = 1; return; }