mirror of
https://github.com/webmin/webmin.git
synced 2026-06-04 20:30:22 +01:00
Add GRUB 2 boot loader module
Adds a Webmin GRUB 2 module for inspecting boot entries, editing defaults, custom entries, themes, password protection, BLS-aware kernel options, safe menu regeneration, boot loader installation, manual config editing, status reporting, ACLs, backups, logging, and tests.
This commit is contained in:
48
grub2/acl_security.pl
Normal file
48
grub2/acl_security.pl
Normal file
@@ -0,0 +1,48 @@
|
||||
use strict;
|
||||
use warnings;
|
||||
no warnings 'redefine';
|
||||
no warnings 'uninitialized';
|
||||
|
||||
do 'grub2-lib.pl';
|
||||
|
||||
our (%in, %text);
|
||||
|
||||
# acl_security_form(&options)
|
||||
# Outputs HTML for editing security options for the GRUB 2 module.
|
||||
sub acl_security_form
|
||||
{
|
||||
my ($o) = @_;
|
||||
print &ui_table_span(&ui_tag('b', &html_escape($text{'acl_section_view'})));
|
||||
# View is separated because it controls whether the module can be entered.
|
||||
foreach my $a (qw(view)) {
|
||||
print &ui_table_row($text{'acl_'.$a},
|
||||
&ui_yesno_radio($a, &grub2_check_acl($a, $o)), 3);
|
||||
}
|
||||
print &ui_table_hr();
|
||||
print &ui_table_span(&ui_tag('b', &html_escape($text{'acl_section_change'})));
|
||||
# Change permissions modify GRUB configuration without granting install rights.
|
||||
foreach my $a (qw(edit security apply runtime)) {
|
||||
print &ui_table_row($text{'acl_'.$a},
|
||||
&ui_yesno_radio($a, &grub2_check_acl($a, $o)), 3);
|
||||
}
|
||||
print &ui_table_hr();
|
||||
print &ui_table_span(&ui_tag('b', &html_escape($text{'acl_section_admin'})));
|
||||
# Admin permissions expose direct file editing, backup, and boot-loader install.
|
||||
foreach my $a (qw(manual install backup)) {
|
||||
print &ui_table_row($text{'acl_'.$a},
|
||||
&ui_yesno_radio($a, &grub2_check_acl($a, $o)), 3);
|
||||
}
|
||||
}
|
||||
|
||||
# acl_security_save(&options)
|
||||
# Parses the form for security options for the GRUB 2 module.
|
||||
sub acl_security_save
|
||||
{
|
||||
my ($o) = @_;
|
||||
foreach my $a (&grub2_acl_keys()) {
|
||||
# Missing checkbox/radio values fall back to denied.
|
||||
$o->{$a} = $in{$a} || 0;
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
13
grub2/backup_config.pl
Normal file
13
grub2/backup_config.pl
Normal file
@@ -0,0 +1,13 @@
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
do 'grub2-lib.pl';
|
||||
|
||||
# backup_config_files()
|
||||
# Returns GRUB 2 files and directories that can be backed up.
|
||||
sub backup_config_files
|
||||
{
|
||||
return &grub2_config_files();
|
||||
}
|
||||
|
||||
1;
|
||||
19
grub2/config
Normal file
19
grub2/config
Normal file
@@ -0,0 +1,19 @@
|
||||
default_file=/etc/default/grub
|
||||
grub_cfg=/boot/grub/grub.cfg
|
||||
grub_dir=/etc/grub.d
|
||||
custom_file=/etc/grub.d/40_custom
|
||||
password_file=/etc/grub.d/01_webmin_password
|
||||
color_file=/etc/grub.d/06_webmin_colors
|
||||
theme_dir=/boot/grub/themes
|
||||
background_dir=/boot/grub/backgrounds
|
||||
grubenv_file=/boot/grub/grubenv
|
||||
bls_dir=/boot/loader/entries
|
||||
mkconfig_cmd=/usr/sbin/grub-mkconfig
|
||||
install_cmd=/usr/sbin/grub-install
|
||||
set_default_cmd=/usr/sbin/grub-set-default
|
||||
reboot_once_cmd=/usr/sbin/grub-reboot
|
||||
editenv_cmd=/usr/bin/grub-editenv
|
||||
script_check_cmd=/usr/bin/grub-script-check
|
||||
mkpasswd_cmd=/usr/bin/grub-mkpasswd-pbkdf2
|
||||
grubby_cmd=/usr/sbin/grubby
|
||||
shell_cmd=/bin/sh
|
||||
19
grub2/config-debian-linux
Normal file
19
grub2/config-debian-linux
Normal file
@@ -0,0 +1,19 @@
|
||||
default_file=/etc/default/grub
|
||||
grub_cfg=/boot/grub/grub.cfg
|
||||
grub_dir=/etc/grub.d
|
||||
custom_file=/etc/grub.d/40_custom
|
||||
password_file=/etc/grub.d/01_webmin_password
|
||||
color_file=/etc/grub.d/06_webmin_colors
|
||||
theme_dir=/boot/grub/themes
|
||||
background_dir=/boot/grub/backgrounds
|
||||
grubenv_file=/boot/grub/grubenv
|
||||
bls_dir=/boot/loader/entries
|
||||
mkconfig_cmd=/usr/sbin/grub-mkconfig
|
||||
install_cmd=/usr/sbin/grub-install
|
||||
set_default_cmd=/usr/sbin/grub-set-default
|
||||
reboot_once_cmd=/usr/sbin/grub-reboot
|
||||
editenv_cmd=/usr/bin/grub-editenv
|
||||
script_check_cmd=/usr/bin/grub-script-check
|
||||
mkpasswd_cmd=/usr/bin/grub-mkpasswd-pbkdf2
|
||||
grubby_cmd=/usr/sbin/grubby
|
||||
shell_cmd=/bin/sh
|
||||
19
grub2/config-openSUSE-Linux-15.0-ALL
Normal file
19
grub2/config-openSUSE-Linux-15.0-ALL
Normal file
@@ -0,0 +1,19 @@
|
||||
default_file=/etc/default/grub
|
||||
grub_cfg=/boot/grub2/grub.cfg
|
||||
grub_dir=/etc/grub.d
|
||||
custom_file=/etc/grub.d/40_custom
|
||||
password_file=/etc/grub.d/01_webmin_password
|
||||
color_file=/etc/grub.d/06_webmin_colors
|
||||
theme_dir=/boot/grub2/themes
|
||||
background_dir=/boot/grub2/backgrounds
|
||||
grubenv_file=/boot/grub2/grubenv
|
||||
bls_dir=/boot/loader/entries
|
||||
mkconfig_cmd=/usr/sbin/grub2-mkconfig
|
||||
install_cmd=/usr/sbin/grub2-install
|
||||
set_default_cmd=/usr/sbin/grub2-set-default
|
||||
reboot_once_cmd=/usr/sbin/grub2-reboot
|
||||
editenv_cmd=/usr/bin/grub2-editenv
|
||||
script_check_cmd=/usr/bin/grub2-script-check
|
||||
mkpasswd_cmd=/usr/bin/grub2-mkpasswd-pbkdf2
|
||||
grubby_cmd=/usr/sbin/grubby
|
||||
shell_cmd=/bin/sh
|
||||
19
grub2/config-redhat-linux
Normal file
19
grub2/config-redhat-linux
Normal file
@@ -0,0 +1,19 @@
|
||||
default_file=/etc/default/grub
|
||||
grub_cfg=/boot/grub2/grub.cfg
|
||||
grub_dir=/etc/grub.d
|
||||
custom_file=/etc/grub.d/40_custom
|
||||
password_file=/etc/grub.d/01_webmin_password
|
||||
color_file=/etc/grub.d/06_webmin_colors
|
||||
theme_dir=/boot/grub2/themes
|
||||
background_dir=/boot/grub2/backgrounds
|
||||
grubenv_file=/boot/grub2/grubenv
|
||||
bls_dir=/boot/loader/entries
|
||||
mkconfig_cmd=/usr/sbin/grub2-mkconfig
|
||||
install_cmd=/usr/sbin/grub2-install
|
||||
set_default_cmd=/usr/sbin/grub2-set-default
|
||||
reboot_once_cmd=/usr/sbin/grub2-reboot
|
||||
editenv_cmd=/usr/bin/grub2-editenv
|
||||
script_check_cmd=/usr/bin/grub2-script-check
|
||||
mkpasswd_cmd=/usr/bin/grub2-mkpasswd-pbkdf2
|
||||
grubby_cmd=/usr/sbin/grubby
|
||||
shell_cmd=/bin/sh
|
||||
19
grub2/config-suse-linux
Normal file
19
grub2/config-suse-linux
Normal file
@@ -0,0 +1,19 @@
|
||||
default_file=/etc/default/grub
|
||||
grub_cfg=/boot/grub2/grub.cfg
|
||||
grub_dir=/etc/grub.d
|
||||
custom_file=/etc/grub.d/40_custom
|
||||
password_file=/etc/grub.d/01_webmin_password
|
||||
color_file=/etc/grub.d/06_webmin_colors
|
||||
theme_dir=/boot/grub2/themes
|
||||
background_dir=/boot/grub2/backgrounds
|
||||
grubenv_file=/boot/grub2/grubenv
|
||||
bls_dir=/boot/loader/entries
|
||||
mkconfig_cmd=/usr/sbin/grub2-mkconfig
|
||||
install_cmd=/usr/sbin/grub2-install
|
||||
set_default_cmd=/usr/sbin/grub2-set-default
|
||||
reboot_once_cmd=/usr/sbin/grub2-reboot
|
||||
editenv_cmd=/usr/bin/grub2-editenv
|
||||
script_check_cmd=/usr/bin/grub2-script-check
|
||||
mkpasswd_cmd=/usr/bin/grub2-mkpasswd-pbkdf2
|
||||
grubby_cmd=/usr/sbin/grubby
|
||||
shell_cmd=/bin/sh
|
||||
21
grub2/config.info
Normal file
21
grub2/config.info
Normal file
@@ -0,0 +1,21 @@
|
||||
line1=Configuration files,11
|
||||
default_file=GRUB default settings file,0
|
||||
grub_cfg=Generated GRUB menu file,0
|
||||
grub_dir=GRUB script directory,0
|
||||
custom_file=Custom GRUB menu entries file,3,None
|
||||
password_file=Webmin-managed GRUB password script,3,None
|
||||
color_file=Webmin-managed GRUB color script,3,None
|
||||
theme_dir=GRUB theme installation directory,3,None
|
||||
background_dir=GRUB background image installation directory,3,None
|
||||
grubenv_file=GRUB environment file,3,None
|
||||
bls_dir=Boot Loader Specification entries directory,3,None
|
||||
line2=Executables,11
|
||||
mkconfig_cmd=Command to generate the GRUB menu file,0
|
||||
install_cmd=Command to install the GRUB boot loader,3,None
|
||||
set_default_cmd=Command to set the saved default entry,3,None
|
||||
reboot_once_cmd=Command to set the next boot entry,3,None
|
||||
editenv_cmd=Command to inspect the GRUB environment,3,None
|
||||
script_check_cmd=Command to validate GRUB scripts,3,None
|
||||
mkpasswd_cmd=Command to generate GRUB PBKDF2 password hashes,3,None
|
||||
grubby_cmd=Command to update BLS kernel options,3,None
|
||||
shell_cmd=Shell used to validate the default settings file,0
|
||||
54
grub2/custom_action.cgi
Executable file
54
grub2/custom_action.cgi
Executable file
@@ -0,0 +1,54 @@
|
||||
#!/usr/local/bin/perl
|
||||
# Apply an action to selected custom GRUB 2 entries.
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
require './grub2-lib.pl'; ## no critic
|
||||
|
||||
our (%in, %text);
|
||||
|
||||
&ReadParse();
|
||||
&error_setup($text{'custom_err'});
|
||||
&grub2_assert_acl('manual');
|
||||
|
||||
# Per-row up/down links post an index and direction directly.
|
||||
if (defined($in{'idx'}) || defined($in{'dir'})) {
|
||||
defined($in{'idx'}) && $in{'idx'} =~ /^\d+\z/ ||
|
||||
&error($text{'custom_eentry'});
|
||||
# Keep movement inside one submenu by leaving it to the library helper.
|
||||
defined($in{'dir'}) && $in{'dir'} =~ /^(up|down)\z/ ||
|
||||
&error($text{'custom_emove'});
|
||||
my $err = &grub2_move_custom_entry($in{'idx'}, $in{'dir'});
|
||||
&error($err) if ($err);
|
||||
&grub2_mark_regenerate_needed();
|
||||
&webmin_log("custom_move", undef, $in{'idx'});
|
||||
&redirect("index.cgi?mode=custom");
|
||||
}
|
||||
|
||||
# Checked-table actions can receive duplicate browser values; collapse them.
|
||||
my @selected = split(/\0/, defined($in{'d'}) ? $in{'d'} : "");
|
||||
my %seen;
|
||||
@selected = grep { defined($_) && $_ ne '' && !$seen{$_}++ } @selected;
|
||||
|
||||
my $err;
|
||||
# Delete accepts multiple selected entries and removes them in one rewrite.
|
||||
if ($in{'delete'}) {
|
||||
@selected || &error($text{'delete_enone'});
|
||||
$err = &grub2_delete_custom_entry_indexes(@selected);
|
||||
&error($err) if ($err);
|
||||
&grub2_mark_regenerate_needed();
|
||||
&webmin_log("custom_delete", undef, scalar(@selected));
|
||||
}
|
||||
elsif ($in{'move_up'} || $in{'move_down'}) {
|
||||
# Bulk move buttons are only safe for one entry at a time.
|
||||
@selected == 1 || &error($text{'custom_eone'});
|
||||
$err = &grub2_move_custom_entry($selected[0],
|
||||
$in{'move_up'} ? "up" : "down");
|
||||
&error($err) if ($err);
|
||||
&grub2_mark_regenerate_needed();
|
||||
&webmin_log("custom_move", undef, $selected[0]);
|
||||
}
|
||||
else {
|
||||
&error($text{'runtime_eaction'});
|
||||
}
|
||||
&redirect("index.cgi?mode=custom");
|
||||
8
grub2/defaultacl
Normal file
8
grub2/defaultacl
Normal file
@@ -0,0 +1,8 @@
|
||||
view=1
|
||||
edit=1
|
||||
security=1
|
||||
apply=1
|
||||
runtime=1
|
||||
manual=1
|
||||
install=1
|
||||
backup=1
|
||||
45
grub2/edit_custom.cgi
Executable file
45
grub2/edit_custom.cgi
Executable file
@@ -0,0 +1,45 @@
|
||||
#!/usr/local/bin/perl
|
||||
# Show a form for adding or editing a custom GRUB 2 menu entry.
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
require './grub2-lib.pl'; ## no critic
|
||||
|
||||
our (%in, %text);
|
||||
|
||||
&ReadParse();
|
||||
&error_setup($text{'custom_err'});
|
||||
&grub2_assert_acl('manual');
|
||||
|
||||
my $is_new = !defined($in{'idx'}) || $in{'idx'} eq '';
|
||||
my ($title, $id, $body) =
|
||||
("", "", "echo 'Custom entry not configured'\ntrue\n");
|
||||
# Existing entries are looked up by parsed custom-entry index, not line number.
|
||||
if (!$is_new) {
|
||||
$in{'idx'} =~ /^\d+\z/ || &error($text{'custom_eentry'});
|
||||
my $entry = &grub2_custom_entry_by_index($in{'idx'});
|
||||
&error($text{'custom_eentry'}) if (!$entry);
|
||||
$title = $entry->{'title'} || "";
|
||||
$id = $entry->{'id'} || "";
|
||||
$body = &grub2_custom_entry_body($entry);
|
||||
}
|
||||
|
||||
&ui_print_header(undef, $is_new ? $text{'custom_title_new'} :
|
||||
$text{'custom_title_edit'}, "");
|
||||
|
||||
print &ui_form_start("save_custom.cgi", "post");
|
||||
print &ui_hidden("idx", $in{'idx'}) if (!$is_new);
|
||||
print &ui_table_start($text{'custom_header'}, "width=100%", 2);
|
||||
print &ui_table_row(&hlink($text{'custom_entry_title'}, "custom_title"),
|
||||
&ui_textbox("title", $title, 60));
|
||||
print &ui_table_row(&hlink($text{'custom_entry_id'}, "custom_id"),
|
||||
&ui_textbox("id", $id, 60).
|
||||
&ui_tag('div', &ui_note($text{'custom_id_note'}, 0)));
|
||||
print &ui_table_hr();
|
||||
# The body is stored as GRUB script text inside a generated menuentry wrapper.
|
||||
print &ui_table_row(&hlink($text{'custom_entry_body'}, "custom_body"),
|
||||
&ui_textarea("body", $body, 16, 100), 2);
|
||||
print &ui_table_end();
|
||||
print &ui_form_end([ [ undef, $text{'save'} ] ]);
|
||||
|
||||
&ui_print_footer("index.cgi?mode=custom", $text{'index_return'});
|
||||
155
grub2/edit_defaults.cgi
Executable file
155
grub2/edit_defaults.cgi
Executable file
@@ -0,0 +1,155 @@
|
||||
#!/usr/local/bin/perl
|
||||
# Show a form for editing common GRUB 2 defaults.
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
require './grub2-lib.pl'; ## no critic
|
||||
|
||||
our (%text);
|
||||
|
||||
&ReadParse();
|
||||
&error_setup($text{'defaults_err'});
|
||||
&grub2_assert_acl('edit');
|
||||
|
||||
my $parsed = &read_grub_defaults();
|
||||
my $values = $parsed->{'values'};
|
||||
my @entries = &grub2_boot_entries();
|
||||
|
||||
&ui_print_header(undef, $text{'defaults_title'}, "");
|
||||
|
||||
# BLS warnings explain when edits also need grubby or existing entry updates.
|
||||
foreach my $warning (&grub2_bls_kernel_option_warnings(\@entries)) {
|
||||
print &ui_alert($warning, 'warning');
|
||||
}
|
||||
|
||||
print &ui_form_start("save_defaults.cgi", "post");
|
||||
print &ui_table_start($text{'defaults_header'}, "width=100%", 2);
|
||||
print &ui_table_row(
|
||||
&hlink($text{'defaults_default'}, "default"),
|
||||
&default_entry_input(&field_value($values->{'GRUB_DEFAULT'}, "0"),
|
||||
\@entries),
|
||||
2, undef, undef, 1);
|
||||
print &ui_table_hr();
|
||||
print &ui_table_row(
|
||||
&hlink($text{'defaults_timeout_style'}, "timeout_style"),
|
||||
&ui_select("timeout_style", &field_value($values->{'GRUB_TIMEOUT_STYLE'}),
|
||||
[
|
||||
[ "", $text{'defaults_keep'} ],
|
||||
[ "menu", $text{'defaults_menu'} ],
|
||||
[ "hidden", $text{'defaults_hidden'} ],
|
||||
[ "countdown", $text{'defaults_countdown'} ],
|
||||
])
|
||||
);
|
||||
print &ui_table_row(
|
||||
&hlink($text{'defaults_timeout'}, "timeout"),
|
||||
&ui_textbox("timeout", &field_value($values->{'GRUB_TIMEOUT'}), 8)
|
||||
);
|
||||
print &ui_table_row(
|
||||
&hlink($text{'defaults_kernelopts_source'}, "kernelopts_source"),
|
||||
&html_escape(&grub2_kernel_options_source_text(\@entries))
|
||||
);
|
||||
# Recovery is special on BLS systems because rescue entries are separate files.
|
||||
print &ui_table_row(
|
||||
&hlink($text{'defaults_disable_recovery'}, "disable_recovery"),
|
||||
&bool_select("disable_recovery", $values->{'GRUB_DISABLE_RECOVERY'}).
|
||||
(&grub2_has_bls_rescue_entries() ?
|
||||
&ui_tag('div', &ui_note($text{'defaults_disable_recovery_bls'}, 0)) :
|
||||
"")
|
||||
);
|
||||
print &ui_table_row(
|
||||
&hlink($text{'defaults_disable_os_prober'}, "disable_os_prober"),
|
||||
&bool_select("disable_os_prober", $values->{'GRUB_DISABLE_OS_PROBER'})
|
||||
);
|
||||
print &ui_table_hr();
|
||||
print &ui_table_row(
|
||||
&hlink($text{'defaults_cmdline_default'}, "cmdline_default"),
|
||||
&ui_textbox("cmdline_default",
|
||||
&field_value($values->{'GRUB_CMDLINE_LINUX_DEFAULT'}), 30,
|
||||
undef, undef, undef, "w-100")
|
||||
);
|
||||
print &ui_table_row(
|
||||
&hlink($text{'defaults_cmdline'}, "cmdline"),
|
||||
&ui_textbox("cmdline", &field_value($values->{'GRUB_CMDLINE_LINUX'}), 70,
|
||||
undef, undef, undef, "w-100")
|
||||
);
|
||||
print &ui_table_end();
|
||||
print &ui_form_end([ [ undef, $text{'save'} ] ]);
|
||||
|
||||
&ui_print_footer("index.cgi", $text{'index_return'});
|
||||
|
||||
# default_entry_input(value, &entries)
|
||||
# Returns a selector for known boot entries.
|
||||
sub default_entry_input
|
||||
{
|
||||
my ($value, $entries) = @_;
|
||||
my ($select_value, $options) = &default_entry_options($value, $entries);
|
||||
return &ui_select("default", $select_value, $options, undef, undef, undef,
|
||||
undef, 'style="field-sizing: content; max-width: 100%;"');
|
||||
}
|
||||
|
||||
# default_entry_options(value, &entries)
|
||||
# Returns select value and options for the default entry field.
|
||||
sub default_entry_options
|
||||
{
|
||||
my ($current, $entries) = @_;
|
||||
$current = '0' if (!defined($current) || $current eq '');
|
||||
my @options;
|
||||
my %seen;
|
||||
my $add = sub {
|
||||
my ($value, $label) = @_;
|
||||
# Avoid duplicate selectors when GRUB_DEFAULT already names an entry.
|
||||
return if (!defined($value) || $value eq '' || $seen{$value}++);
|
||||
push(@options, [ $value, $label ]);
|
||||
};
|
||||
$add->('saved', $text{'defaults_default_saved'});
|
||||
if ($current =~ /^\d+\z/ && $entries->[$current]) {
|
||||
# Keep numeric defaults meaningful by showing the currently indexed entry.
|
||||
$add->($current, &text('defaults_default_current_entry', $current,
|
||||
&default_entry_label($entries->[$current])));
|
||||
}
|
||||
foreach my $entry (@$entries) {
|
||||
my $selector = &grub2_entry_selector($entry);
|
||||
next if (!defined($selector) || $selector eq '');
|
||||
$add->($selector, &default_entry_label($entry));
|
||||
}
|
||||
if ($current ne '' && !$seen{$current}) {
|
||||
# Preserve unusual existing values without allowing arbitrary new input.
|
||||
$add->($current, &text('defaults_default_current', $current));
|
||||
}
|
||||
my $select_value = $seen{$current} ? $current : $options[0]->[0];
|
||||
return ($select_value, \@options);
|
||||
}
|
||||
|
||||
# default_entry_label(&entry)
|
||||
# Returns a concise label for one parsed generated boot entry.
|
||||
sub default_entry_label
|
||||
{
|
||||
my ($entry) = @_;
|
||||
my @path = @{$entry->{'path'} || []};
|
||||
my $label = join(' > ', (@path, $entry->{'title'} || ''));
|
||||
return &text('defaults_default_entry_id', $label, $entry->{'id'})
|
||||
if (defined($entry->{'id'}) && $entry->{'id'} ne '');
|
||||
return $label;
|
||||
}
|
||||
|
||||
# bool_select(name, value)
|
||||
# Returns a tri-state selector for GRUB true/false settings.
|
||||
sub bool_select
|
||||
{
|
||||
my ($name, $value) = @_;
|
||||
$value = '' if (!defined($value) || $value !~ /^(true|false)\z/);
|
||||
return &ui_select($name, $value,
|
||||
[
|
||||
[ "", $text{'defaults_keep'} ],
|
||||
[ "true", $text{'defaults_true'} ],
|
||||
[ "false", $text{'defaults_false'} ],
|
||||
]);
|
||||
}
|
||||
|
||||
# field_value(value, [default])
|
||||
# Returns a form value without treating the string 0 as empty.
|
||||
sub field_value
|
||||
{
|
||||
my ($value, $default) = @_;
|
||||
return defined($value) ? $value : ($default || '');
|
||||
}
|
||||
103
grub2/edit_install.cgi
Executable file
103
grub2/edit_install.cgi
Executable file
@@ -0,0 +1,103 @@
|
||||
#!/usr/local/bin/perl
|
||||
# Show a form for installing the GRUB 2 boot loader.
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
require './grub2-lib.pl'; ## no critic
|
||||
|
||||
our (%text);
|
||||
|
||||
&ReadParse();
|
||||
&error_setup($text{'install_err'});
|
||||
&grub2_assert_acl('install');
|
||||
|
||||
my $cmd = &grub2_command('install_cmd');
|
||||
my $platform = &grub2_default_platform_target();
|
||||
my $module_dir = $platform ? &grub2_platform_module_dir($platform) : '';
|
||||
my $efi_dir = &grub2_default_efi_directory();
|
||||
my $bootloader_id = &grub2_default_bootloader_id($efi_dir);
|
||||
|
||||
&ui_print_header(undef, $text{'install_title'}, "", "install_target");
|
||||
|
||||
# Installation is unavailable unless the configured grub-install is runnable.
|
||||
if (!$cmd) {
|
||||
print &ui_alert($text{'install_ecmd'}, 'warning');
|
||||
&ui_print_footer("index.cgi", $text{'index_return'});
|
||||
exit;
|
||||
}
|
||||
if ($platform && !$module_dir) {
|
||||
# Missing module directories usually mean the platform package is absent.
|
||||
print &ui_alert(&text('install_warn_modules', $platform), 'warning');
|
||||
}
|
||||
|
||||
print &ui_form_start("install.cgi", "post");
|
||||
print &ui_table_start($text{'install_header'}, "width=100%", 2);
|
||||
print &ui_table_row($text{'install_command'},
|
||||
&ui_tag('tt', &html_escape($cmd)));
|
||||
print &ui_table_row($text{'index_boot_mode'}, &install_boot_mode_cell());
|
||||
print &ui_table_row($text{'index_secure_boot'}, &install_secure_boot_cell());
|
||||
print &ui_table_row(
|
||||
&hlink($text{'install_target'}, "install_target"),
|
||||
&ui_filebox("target", "", 45)
|
||||
);
|
||||
print &ui_table_row(
|
||||
&hlink($text{'install_efi_dir'}, "install_efi_dir"),
|
||||
&ui_filebox("efi_dir", $efi_dir, 45, 0, undef, undef, 1)
|
||||
);
|
||||
print &ui_table_row(
|
||||
&hlink($text{'install_platform'}, "install_platform"),
|
||||
&ui_textbox("platform", $platform, 25)
|
||||
);
|
||||
print &ui_table_row(
|
||||
&hlink($text{'install_directory'}, "install_directory"),
|
||||
&ui_filebox("directory", $module_dir, 45, 0, undef, undef, 1)
|
||||
);
|
||||
# Keep --boot-directory opt-in because it changes install layout.
|
||||
print &ui_table_row(
|
||||
&hlink($text{'install_boot_directory'}, "install_boot_directory"),
|
||||
&ui_filebox("boot_directory", "/boot", 45, 0, undef, undef, 1).
|
||||
&ui_tag('div',
|
||||
&ui_checkbox("use_boot_directory", 1,
|
||||
$text{'install_boot_directory_enable'}, 0),
|
||||
{ 'style' => 'margin-left: 2px' })
|
||||
);
|
||||
print &ui_table_row(
|
||||
&hlink($text{'install_bootloader_id'}, "install_bootloader_id"),
|
||||
&ui_textbox("bootloader_id", $bootloader_id, 30)
|
||||
);
|
||||
print &ui_table_hr();
|
||||
print &ui_table_row(
|
||||
$text{'install_options'},
|
||||
&ui_div(&ui_checkbox("recheck", 1, $text{'install_recheck'}, 0)).
|
||||
&ui_div(&ui_checkbox("removable", 1, $text{'install_removable'}, 0)).
|
||||
&ui_div(&ui_checkbox("no_nvram", 1, $text{'install_no_nvram'}, 0)).
|
||||
&ui_div(&ui_checkbox("force", 1,
|
||||
&hlink($text{'install_force'}, "install_force"),
|
||||
0))
|
||||
);
|
||||
print &ui_table_hr();
|
||||
print &ui_table_row(
|
||||
&hlink($text{'install_confirm'}, "install_confirm"),
|
||||
&ui_checkbox("confirm", 1, $text{'install_confirm_label'}, 0)
|
||||
);
|
||||
print &ui_table_end();
|
||||
print &ui_form_end([ [ undef, $text{'install_submit'} ] ]);
|
||||
|
||||
&ui_print_footer("index.cgi", $text{'index_return'});
|
||||
|
||||
# install_boot_mode_cell()
|
||||
# Returns the detected firmware boot mode for display.
|
||||
sub install_boot_mode_cell
|
||||
{
|
||||
my $mode = &grub2_boot_mode();
|
||||
return $text{'index_boot_mode_uefi'} if ($mode eq 'uefi');
|
||||
return $text{'index_boot_mode_bios'};
|
||||
}
|
||||
|
||||
# install_secure_boot_cell()
|
||||
# Returns the detected Secure Boot state for display.
|
||||
sub install_secure_boot_cell
|
||||
{
|
||||
my $state = &grub2_secure_boot_status();
|
||||
return $text{'index_secure_boot_'.$state} || $text{'index_secure_boot_unknown'};
|
||||
}
|
||||
44
grub2/edit_manual.cgi
Executable file
44
grub2/edit_manual.cgi
Executable file
@@ -0,0 +1,44 @@
|
||||
#!/usr/local/bin/perl
|
||||
# Show a page for manually editing allowed GRUB 2 files.
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
require './grub2-lib.pl'; ## no critic
|
||||
|
||||
our (%in, %text);
|
||||
|
||||
&ReadParse();
|
||||
&error_setup($text{'manual_err'});
|
||||
&grub2_assert_acl('manual');
|
||||
|
||||
# The manual editor is restricted to discovered GRUB-related files only.
|
||||
my @files = &grub2_manual_files();
|
||||
@files || &error($text{'manual_enofile'});
|
||||
my @paths = map { $_->{'file'} } @files;
|
||||
my $file = $in{'file'} || $paths[0];
|
||||
&grub2_manual_file($file) || &error($text{'manual_efile'});
|
||||
|
||||
&ui_print_header(undef, $text{'manual_title'}, "");
|
||||
|
||||
print &ui_form_start("edit_manual.cgi");
|
||||
print &ui_tag('b', &html_escape($text{'manual_select'})),"\n";
|
||||
print &ui_select("file", $file, \@paths),"\n";
|
||||
print &ui_submit($text{'manual_ok'});
|
||||
print &ui_form_end();
|
||||
|
||||
# Lock while reading so the text shown matches the file validation target.
|
||||
my $data = "";
|
||||
if (-r $file) {
|
||||
&lock_file($file);
|
||||
$data = &read_file_contents($file);
|
||||
&unlock_file($file);
|
||||
}
|
||||
|
||||
print &ui_form_start("save_manual.cgi", "form-data");
|
||||
print &ui_hidden("file", $file);
|
||||
print &ui_table_start(undef, undef, 2);
|
||||
print &ui_table_row(undef, &ui_textarea("data", $data, 24, 100), 2);
|
||||
print &ui_table_end();
|
||||
print &ui_form_end([ [ undef, $text{'save'} ] ]);
|
||||
|
||||
&ui_print_footer("index.cgi", $text{'index_return'});
|
||||
75
grub2/edit_security.cgi
Executable file
75
grub2/edit_security.cgi
Executable file
@@ -0,0 +1,75 @@
|
||||
#!/usr/local/bin/perl
|
||||
# Show a form for editing GRUB 2 password protection.
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
require './grub2-lib.pl'; ## no critic
|
||||
|
||||
our (%text);
|
||||
|
||||
&ReadParse();
|
||||
&error_setup($text{'security_err'});
|
||||
&grub2_assert_acl('security');
|
||||
|
||||
my $state = &grub2_read_security_config();
|
||||
|
||||
&ui_print_header(undef, $text{'security_title'}, "", "security_current");
|
||||
|
||||
# Refuse to edit administrator-owned password scripts we cannot safely merge.
|
||||
if ($state->{'exists'} && !$state->{'managed'}) {
|
||||
print &ui_alert($text{'security_unmanaged'}, 'warning');
|
||||
&ui_print_footer("index.cgi", $text{'index_return'});
|
||||
exit;
|
||||
}
|
||||
|
||||
print &ui_form_start("save_security.cgi", "post");
|
||||
print &ui_table_start($text{'security_header'}, "width=100%", 2);
|
||||
print &ui_table_row(
|
||||
$text{'security_current_state'},
|
||||
$state->{'enabled'} ?
|
||||
&text('security_current_enabled',
|
||||
&html_escape($state->{'user'} || 'root')) :
|
||||
$text{'security_current_disabled'}
|
||||
);
|
||||
print &ui_table_row(
|
||||
$text{'security_current_hash'},
|
||||
$state->{'hash'} ? $text{'security_current_hash_set'} :
|
||||
$text{'security_current_hash_missing'}
|
||||
);
|
||||
print &ui_table_hr();
|
||||
print &ui_table_row(
|
||||
&hlink($text{'security_enable'}, "security_enable"),
|
||||
&ui_yesno_radio("enabled", $state->{'enabled'} ? 1 : 0)
|
||||
);
|
||||
print &ui_table_row(
|
||||
&hlink($text{'security_user'}, "security_user"),
|
||||
&ui_textbox("user", $state->{'user'} || "root", 30)
|
||||
);
|
||||
print &ui_table_hr();
|
||||
print &ui_table_row(
|
||||
$text{'security_password_status'},
|
||||
$state->{'enabled'} && $state->{'hash'} ?
|
||||
$text{'security_password_keep'} :
|
||||
$text{'security_password_required'}
|
||||
);
|
||||
# Password fields are optional when keeping the existing PBKDF2 hash.
|
||||
print &ui_table_row(
|
||||
&hlink($text{'security_newpass'}, "security_password"),
|
||||
&ui_password("password", "", 30)
|
||||
);
|
||||
print &ui_table_row(
|
||||
&hlink($text{'security_newpass2'}, "security_password"),
|
||||
&ui_password("password2", "", 30)
|
||||
);
|
||||
print &ui_table_hr();
|
||||
# Existing hashes are shown because GRUB stores hashes, not clear text.
|
||||
print &ui_table_row(
|
||||
&hlink($text{'security_hash'}, "security_hash"),
|
||||
&ui_textbox("hash", $state->{'hash'} || "", 30, undef, undef, undef,
|
||||
"w-100").
|
||||
&ui_tag('div', &ui_note($text{'security_hash_note'}, 0)),
|
||||
2, undef, undef, 1);
|
||||
print &ui_table_end();
|
||||
print &ui_form_end([ [ undef, $text{'save'} ] ]);
|
||||
|
||||
&ui_print_footer("index.cgi", $text{'index_return'});
|
||||
208
grub2/edit_theme.cgi
Executable file
208
grub2/edit_theme.cgi
Executable file
@@ -0,0 +1,208 @@
|
||||
#!/usr/local/bin/perl
|
||||
# Show a form for editing GRUB 2 theme and appearance settings.
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
require './grub2-lib.pl'; ## no critic
|
||||
|
||||
our (%text);
|
||||
|
||||
&ReadParse();
|
||||
&error_setup($text{'theme_err'});
|
||||
&grub2_assert_acl('edit');
|
||||
|
||||
my $parsed = &read_grub_defaults();
|
||||
my $values = $parsed->{'values'};
|
||||
my $current_theme = &field_value($values->{'GRUB_THEME'});
|
||||
my $theme_action = $current_theme ne '' ? 'keep' : 'clear';
|
||||
|
||||
&ui_print_header(undef, $text{'theme_title'}, "", "theme_mode");
|
||||
|
||||
# Theme source is only used when the action selector requests installation.
|
||||
print &ui_form_start("save_theme.cgi", "post");
|
||||
print &ui_table_start($text{'defaults_theme_header'}, "width=100%", 2);
|
||||
print &ui_table_row(
|
||||
&hlink($text{'defaults_theme_current'}, "theme"),
|
||||
$current_theme ne '' ?
|
||||
&ui_tag('tt', &html_escape($current_theme)) :
|
||||
$text{'defaults_theme_none'}
|
||||
);
|
||||
print &ui_table_row(
|
||||
&hlink($text{'defaults_theme_action'}, "theme_mode"),
|
||||
&ui_select("theme_mode", $theme_action,
|
||||
[
|
||||
[ "keep", $text{'defaults_theme_keep'} ],
|
||||
[ "install", $text{'defaults_theme_install'} ],
|
||||
[ "clear", $text{'defaults_theme_clear'} ],
|
||||
])
|
||||
);
|
||||
print &ui_table_row(
|
||||
&hlink($text{'defaults_theme_source'}, "theme_source"),
|
||||
&ui_textbox("theme_source", "", 60).
|
||||
" ".&file_chooser_button("theme_source").
|
||||
&ui_tag('div', &ui_note($text{'defaults_theme_note'}, 0))
|
||||
);
|
||||
print &ui_table_row(
|
||||
&hlink($text{'defaults_terminal_output'}, "terminal_output"),
|
||||
&ui_select("terminal_output",
|
||||
&field_value($values->{'GRUB_TERMINAL_OUTPUT'}),
|
||||
[
|
||||
[ "", $text{'defaults_keep'} ],
|
||||
[ "console", $text{'defaults_terminal_console'} ],
|
||||
[ "gfxterm", $text{'defaults_terminal_gfxterm'} ],
|
||||
[ "gfxterm console",
|
||||
$text{'defaults_terminal_gfxterm_console'} ],
|
||||
[ "serial", $text{'defaults_terminal_serial'} ],
|
||||
])
|
||||
);
|
||||
print &ui_table_row(
|
||||
&hlink($text{'defaults_gfxmode'}, "gfxmode"),
|
||||
&gfxmode_select(&field_value($values->{'GRUB_GFXMODE'}))
|
||||
);
|
||||
print &ui_table_row(
|
||||
&hlink($text{'defaults_background'}, "background"),
|
||||
&ui_textbox("background", &field_value($values->{'GRUB_BACKGROUND'}), 60).
|
||||
" ".&file_chooser_button("background").
|
||||
&ui_tag('div', &ui_note($text{'defaults_background_note'}, 0))
|
||||
);
|
||||
print &ui_table_row(
|
||||
&hlink($text{'defaults_color_normal'}, "color_normal"),
|
||||
&color_pair_select("color_normal", $values->{'GRUB_COLOR_NORMAL'},
|
||||
"white", "black")
|
||||
);
|
||||
print &ui_table_row(
|
||||
&hlink($text{'defaults_color_highlight'}, "color_highlight"),
|
||||
&color_pair_select("color_highlight",
|
||||
$values->{'GRUB_COLOR_HIGHLIGHT'},
|
||||
"black", "light-gray")
|
||||
);
|
||||
print &ui_table_end();
|
||||
print &ui_form_end([ [ undef, $text{'save'} ] ]);
|
||||
print &color_mode_script();
|
||||
|
||||
&ui_print_footer("index.cgi", $text{'index_return'});
|
||||
|
||||
# color_pair_select(name, value, default-foreground, default-background)
|
||||
# Returns foreground/background selectors for GRUB menu colors.
|
||||
sub color_pair_select
|
||||
{
|
||||
my ($name, $value, $default_fg, $default_bg) = @_;
|
||||
my ($fg, $bg) = ($default_fg, $default_bg);
|
||||
my $mode = "default";
|
||||
if (defined($value) && $value =~ /^([^\/]+)\/([^\/]+)\z/) {
|
||||
# Existing GRUB colors are stored as foreground/background pairs.
|
||||
($fg, $bg) = ($1, $2);
|
||||
$mode = "set";
|
||||
}
|
||||
return &ui_select($name."_mode", $mode, [
|
||||
[ "default", $text{'defaults_color_default'} ],
|
||||
[ "set", $text{'defaults_color_custom'} ],
|
||||
]).
|
||||
&ui_tag('span',
|
||||
" ".&html_escape($text{'defaults_color_text'})." ".
|
||||
&ui_select($name."_fg", $fg, &color_options())." ".
|
||||
" ".&html_escape($text{'defaults_color_background'}).
|
||||
" ".&ui_select($name."_bg", $bg, &color_options()),
|
||||
{
|
||||
'id' => $name."_custom_colors",
|
||||
'style' => 'white-space: nowrap; visibility: '.
|
||||
($mode eq 'set' ? 'visible' : 'hidden').';',
|
||||
});
|
||||
}
|
||||
|
||||
# color_mode_script()
|
||||
# Shows foreground/background selectors only for custom color pairs.
|
||||
sub color_mode_script
|
||||
{
|
||||
return &ui_tag('script', <<'EOF', { 'type' => 'application/javascript' });
|
||||
function grub2_color_mode_select(name) {
|
||||
// Theme reloads may replace IDs; fall back to the stable field name.
|
||||
return document.getElementById(name + '_mode') ||
|
||||
document.querySelector('select[name="' + name + '_mode"]');
|
||||
}
|
||||
function grub2_color_mode_changed(name) {
|
||||
const mode = grub2_color_mode_select(name);
|
||||
const custom = document.getElementById(name + '_custom_colors');
|
||||
if (!mode || !custom) {
|
||||
return;
|
||||
}
|
||||
// Visibility avoids layout jumps when a custom color pair is enabled.
|
||||
custom.style.visibility = mode.value === 'set' ? 'visible' : 'hidden';
|
||||
}
|
||||
function grub2_color_modes_refresh() {
|
||||
grub2_color_mode_changed('color_normal');
|
||||
grub2_color_mode_changed('color_highlight');
|
||||
}
|
||||
document.addEventListener('change', function(event) {
|
||||
const target = event.target;
|
||||
if (!target || !target.name) {
|
||||
return;
|
||||
}
|
||||
if (target.name === 'color_normal_mode') {
|
||||
grub2_color_mode_changed('color_normal');
|
||||
}
|
||||
else if (target.name === 'color_highlight_mode') {
|
||||
grub2_color_mode_changed('color_highlight');
|
||||
}
|
||||
});
|
||||
grub2_color_modes_refresh();
|
||||
document.addEventListener('DOMContentLoaded', grub2_color_modes_refresh);
|
||||
if (window.MutationObserver && document.body) {
|
||||
// Re-apply after theme JavaScript re-renders form controls.
|
||||
new MutationObserver(grub2_color_modes_refresh).observe(document.body, {
|
||||
childList: true,
|
||||
subtree: true
|
||||
});
|
||||
}
|
||||
EOF
|
||||
}
|
||||
|
||||
# gfxmode_select(value)
|
||||
# Returns a dropdown of common GRUB graphical resolutions.
|
||||
sub gfxmode_select
|
||||
{
|
||||
my ($value) = @_;
|
||||
return &ui_select("gfxmode", $value, &gfxmode_options(), undef, undef, 1);
|
||||
}
|
||||
|
||||
# gfxmode_options()
|
||||
# Returns common GRUB graphical resolution choices.
|
||||
sub gfxmode_options
|
||||
{
|
||||
return [
|
||||
[ "", $text{'defaults_gfxmode_default'} ],
|
||||
[ "auto", $text{'defaults_gfxmode_auto'} ],
|
||||
map { [ $_, $_ ] } qw(
|
||||
640x480
|
||||
800x600
|
||||
1024x768
|
||||
1280x720
|
||||
1280x800
|
||||
1366x768
|
||||
1440x900
|
||||
1600x900
|
||||
1680x1050
|
||||
1920x1080
|
||||
1920x1200
|
||||
2560x1440
|
||||
3840x2160
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
# color_options()
|
||||
# Returns GRUB color choices.
|
||||
sub color_options
|
||||
{
|
||||
return [
|
||||
map { [ $_, $text{'color_'.$_} || $_ ] } &grub2_color_names()
|
||||
];
|
||||
}
|
||||
|
||||
# field_value(value, [default])
|
||||
# Returns a form value without treating the string 0 as empty.
|
||||
sub field_value
|
||||
{
|
||||
my ($value, $default) = @_;
|
||||
return defined($value) ? $value : ($default || '');
|
||||
}
|
||||
143
grub2/generate.cgi
Executable file
143
grub2/generate.cgi
Executable file
@@ -0,0 +1,143 @@
|
||||
#!/usr/local/bin/perl
|
||||
# Generate the GRUB 2 menu file after a successful test generation.
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
require './grub2-lib.pl'; ## no critic
|
||||
|
||||
our (%in, %text);
|
||||
|
||||
&ReadParse();
|
||||
&error_setup($text{'generate_err'});
|
||||
&grub2_assert_acl('apply');
|
||||
|
||||
my $return_url = $in{'redir'} || "index.cgi";
|
||||
my ($current_step, $failed_printed, $failure_output_shown, $command_output) =
|
||||
('', 0, 0, '');
|
||||
|
||||
&ui_print_unbuffered_header(undef, $text{'generate_title'}, "");
|
||||
|
||||
# The generator emits coarse events so failures can show the right phase.
|
||||
my $callback = sub {
|
||||
my ($event, $value) = @_;
|
||||
if ($event eq 'command') {
|
||||
# Capture the command text and all output for a single disclosure block.
|
||||
$current_step = 'command';
|
||||
$command_output = $value."\n";
|
||||
&print_step_start($text{'generate_regenerating'});
|
||||
return;
|
||||
}
|
||||
if ($event eq 'output') {
|
||||
$command_output .= $value;
|
||||
return;
|
||||
}
|
||||
if ($event eq 'command_done') {
|
||||
# Successful generation keeps noisy mkconfig output collapsed.
|
||||
&print_step_output($text{'generate_done'}, $command_output);
|
||||
$current_step = '';
|
||||
return;
|
||||
}
|
||||
if ($event eq 'command_failed') {
|
||||
# On command failure the captured output is the most useful detail.
|
||||
&print_step_output($text{'generate_failed_status'},
|
||||
$command_output);
|
||||
$current_step = '';
|
||||
$failed_printed = 1;
|
||||
$failure_output_shown = 1;
|
||||
return;
|
||||
}
|
||||
if ($event eq 'check') {
|
||||
# The generated temporary grub.cfg is syntax-checked before replace.
|
||||
$current_step = 'check';
|
||||
&print_step_start($text{'generate_check'});
|
||||
return;
|
||||
}
|
||||
if ($event eq 'check_done') {
|
||||
&print_step_done(\$current_step);
|
||||
return;
|
||||
}
|
||||
if ($event eq 'check_failed') {
|
||||
&print_step_failed(\$current_step, \$failed_printed);
|
||||
return;
|
||||
}
|
||||
if ($event eq 'replace') {
|
||||
# Replacement only happens after a successful generation and check.
|
||||
$current_step = 'replace';
|
||||
&print_step_start($text{'generate_replace'});
|
||||
return;
|
||||
}
|
||||
if ($event eq 'replace_done') {
|
||||
&print_step_done(\$current_step);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
my $err = &grub2_generate_config($callback);
|
||||
if ($err) {
|
||||
# If the command output was not already shown, print the returned error.
|
||||
&print_step_failed(\$current_step, \$failed_printed)
|
||||
if ($current_step);
|
||||
&print_step_output($text{'generate_failed_status'}, $err)
|
||||
if (!$failure_output_shown);
|
||||
}
|
||||
else {
|
||||
&grub2_mark_generated();
|
||||
&webmin_log("generate", undef, &grub2_config_value('grub_cfg'));
|
||||
}
|
||||
|
||||
&ui_print_footer($return_url, $text{'generate_return'});
|
||||
|
||||
# print_step_start(text)
|
||||
# Prints the first progress line for one generation step.
|
||||
sub print_step_start
|
||||
{
|
||||
my ($msg) = @_;
|
||||
print &ui_tag('span', &html_escape($msg." .."),
|
||||
{ 'data-first-print' => undef });
|
||||
print "<br>\n";
|
||||
return;
|
||||
}
|
||||
|
||||
# print_step_output(status, output)
|
||||
# Prints command output inside an inline details disclosure.
|
||||
sub print_step_output
|
||||
{
|
||||
my ($status, $output) = @_;
|
||||
$output = '' if (!defined($output));
|
||||
print &ui_details({
|
||||
'html' => 1,
|
||||
'title' => &ui_tag('span', &html_escape(".. ".$status),
|
||||
{ 'data-second-print' => undef }),
|
||||
'content' => &ui_tag('pre', &html_escape($output),
|
||||
{ 'style' => 'margin-left: 10px;' }),
|
||||
'class' => 'inline inlined',
|
||||
});
|
||||
print "<div data-x-br=\"\"></div>\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{'generate_done'}),
|
||||
{ 'data-second-print' => undef });
|
||||
print "<br><div data-x-br=\"\"></div>\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{'generate_failed_status'}),
|
||||
{ 'data-second-print' => undef });
|
||||
print "<br><div data-x-br=\"\"></div>\n";
|
||||
$$current = '';
|
||||
$$printed = 1;
|
||||
return;
|
||||
}
|
||||
3347
grub2/grub2-lib.pl
Normal file
3347
grub2/grub2-lib.pl
Normal file
File diff suppressed because it is too large
Load Diff
4
grub2/help/background.html
Normal file
4
grub2/help/background.html
Normal file
@@ -0,0 +1,4 @@
|
||||
<header>Background image</header>
|
||||
<p>Sets the image used as the GRUB menu background. Select a PNG, JPEG, or TGA
|
||||
file. Webmin copies it under the configured GRUB background directory in
|
||||
<tt>/boot</tt> so GRUB can read it at boot time.</p>
|
||||
6
grub2/help/bls_dir.html
Normal file
6
grub2/help/bls_dir.html
Normal file
@@ -0,0 +1,6 @@
|
||||
<header>BLS entries directory</header>
|
||||
<p>Directory containing Boot Loader Specification entry files, usually
|
||||
<tt>/boot/loader/entries</tt> on Enterprise Linux style systems.</p>
|
||||
<p>Each <tt>.conf</tt> file describes one boot entry. Kernel options may be
|
||||
stored directly in these files or read from <tt>kernelopts</tt> in the GRUB
|
||||
environment.</p>
|
||||
6
grub2/help/boot_mode.html
Normal file
6
grub2/help/boot_mode.html
Normal file
@@ -0,0 +1,6 @@
|
||||
<header>Boot mode</header>
|
||||
<p>Shows whether the running system appears to have booted through UEFI
|
||||
firmware or legacy BIOS firmware.</p>
|
||||
<p>This matters because GRUB is installed differently in each mode. UEFI
|
||||
systems normally use an EFI system partition and a boot loader ID, while BIOS
|
||||
systems normally install GRUB boot code to a disk device.</p>
|
||||
12
grub2/help/cmdline.html
Normal file
12
grub2/help/cmdline.html
Normal file
@@ -0,0 +1,12 @@
|
||||
<header>Kernel options for all Linux entries</header>
|
||||
<p>Edits <tt>GRUB_CMDLINE_LINUX</tt>. GRUB menu generators normally add this
|
||||
value to every generated Linux menu entry, including recovery or rescue
|
||||
entries.</p>
|
||||
<p>Use this for options that must be present whenever Linux boots, such as
|
||||
storage, root filesystem, LVM, filesystem flag, security, mitigation, or
|
||||
<tt>crashkernel</tt> options.</p>
|
||||
<p>On BLS-based systems, existing boot entries may store options directly in
|
||||
BLS entry files, or reference <tt>$kernelopts</tt>, a GRUB environment value
|
||||
stored in <tt>grubenv</tt>. Webmin does not edit <tt>grubenv</tt> directly;
|
||||
when <tt>grubby</tt> is available, Webmin asks it to apply changes here to all
|
||||
existing BLS entries.</p>
|
||||
12
grub2/help/cmdline_default.html
Normal file
12
grub2/help/cmdline_default.html
Normal file
@@ -0,0 +1,12 @@
|
||||
<header>Kernel options for regular Linux entries</header>
|
||||
<p>Edits <tt>GRUB_CMDLINE_LINUX_DEFAULT</tt>. GRUB menu generators normally add
|
||||
this value to regular Linux menu entries, but not to generated recovery or
|
||||
rescue entries.</p>
|
||||
<p>Use this for options that make normal boots quieter or more convenient, such
|
||||
as <tt>quiet</tt>, <tt>splash</tt>, or console and graphics workarounds that
|
||||
are not needed for recovery boots.</p>
|
||||
<p>On BLS-based systems, existing boot entries may store options directly in
|
||||
BLS entry files, or reference <tt>$kernelopts</tt>, a GRUB environment value
|
||||
stored in <tt>grubenv</tt>. Webmin does not edit <tt>grubenv</tt> directly;
|
||||
when <tt>grubby</tt> is available, Webmin asks it to apply changes here to
|
||||
existing non-rescue BLS entries.</p>
|
||||
3
grub2/help/color_highlight.html
Normal file
3
grub2/help/color_highlight.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<header>Selected menu colors</header>
|
||||
<p>Sets the foreground and background colors for the currently selected GRUB
|
||||
menu entry. Leave both values unset to remove this setting.</p>
|
||||
3
grub2/help/color_normal.html
Normal file
3
grub2/help/color_normal.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<header>Normal menu colors</header>
|
||||
<p>Sets the foreground and background colors for normal GRUB menu entries.
|
||||
Leave both values unset to remove this setting.</p>
|
||||
3
grub2/help/custom_body.html
Normal file
3
grub2/help/custom_body.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<header>GRUB commands</header>
|
||||
<p>Commands to run inside the custom menu entry. Do not include the outer
|
||||
menuentry line; Webmin writes that from the title and ID fields.</p>
|
||||
4
grub2/help/custom_id.html
Normal file
4
grub2/help/custom_id.html
Normal file
@@ -0,0 +1,4 @@
|
||||
<header>Entry ID</header>
|
||||
<p>An optional stable identifier used by GRUB commands such as
|
||||
grub-set-default and grub-reboot. Leave this blank if the entry does not need a
|
||||
stable ID.</p>
|
||||
2
grub2/help/custom_title.html
Normal file
2
grub2/help/custom_title.html
Normal file
@@ -0,0 +1,2 @@
|
||||
<header>Menu title</header>
|
||||
<p>The title shown in the GRUB boot menu for this custom entry.</p>
|
||||
5
grub2/help/default.html
Normal file
5
grub2/help/default.html
Normal file
@@ -0,0 +1,5 @@
|
||||
<header>Default menu entry</header>
|
||||
<p>Edits <tt>GRUB_DEFAULT</tt>, the GRUB menu entry booted automatically.
|
||||
Choose a detected entry, or choose <tt>Saved environment entry</tt> to use the
|
||||
entry stored in the GRUB environment. Webmin's Set as default action updates
|
||||
that saved environment entry.</p>
|
||||
7
grub2/help/default_file.html
Normal file
7
grub2/help/default_file.html
Normal file
@@ -0,0 +1,7 @@
|
||||
<header>Default settings file</header>
|
||||
<p>Path to the GRUB defaults file, usually <tt>/etc/default/grub</tt>. This
|
||||
file contains shell-style assignments such as <tt>GRUB_DEFAULT</tt>,
|
||||
<tt>GRUB_TIMEOUT</tt>, and kernel command-line settings.</p>
|
||||
<p>Changes here normally affect the generated menu after the GRUB menu is
|
||||
regenerated. On BLS-based systems, some existing entries may also be updated
|
||||
with <tt>grubby</tt>.</p>
|
||||
3
grub2/help/disable_os_prober.html
Normal file
3
grub2/help/disable_os_prober.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<header>Disable OS prober</header>
|
||||
<p>When enabled, GRUB does not run OS prober while generating the menu. This
|
||||
prevents automatic entries for other installed operating systems.</p>
|
||||
9
grub2/help/disable_recovery.html
Normal file
9
grub2/help/disable_recovery.html
Normal file
@@ -0,0 +1,9 @@
|
||||
<header>Disable recovery and rescue entries</header>
|
||||
<p>When enabled, Webmin sets <tt>GRUB_DISABLE_RECOVERY=true</tt>, which tells
|
||||
GRUB generator scripts to omit recovery-mode entries on distributions that
|
||||
support this option.</p>
|
||||
<p>On BLS-based systems such as Rocky, AlmaLinux, and RHEL, rescue entries are
|
||||
separate files under <tt>/boot/loader/entries</tt>. Webmin hides existing BLS
|
||||
rescue entries by renaming their entry files, and restores only entries hidden
|
||||
by Webmin when this option is disabled again. Future kernel or rescue-image
|
||||
updates may create new BLS rescue entries.</p>
|
||||
5
grub2/help/entries.html
Normal file
5
grub2/help/entries.html
Normal file
@@ -0,0 +1,5 @@
|
||||
<header>Boot menu entries</header>
|
||||
<p>Number of boot entries detected from the generated GRUB menu and, when
|
||||
present, from BLS entry files referenced by that menu.</p>
|
||||
<p>This count is read-only status. Use the generated menu tab to inspect the
|
||||
entries and use the custom entries tab for entries managed by this module.</p>
|
||||
9
grub2/help/gfxmode.html
Normal file
9
grub2/help/gfxmode.html
Normal file
@@ -0,0 +1,9 @@
|
||||
<header>Graphics mode</header>
|
||||
<p>Sets the GRUB graphical screen mode used by themes and the graphical
|
||||
terminal. The theme provides layout and images, but this setting chooses the
|
||||
resolution GRUB renders them at.</p>
|
||||
|
||||
<p>Use <tt>auto</tt> to let GRUB choose, or enter one or more modes such as
|
||||
<tt>1024x768</tt> or <tt>1280x1024x32</tt>, separated by commas. If a theme is
|
||||
cropped or shifted, try a resolution closer to the one the theme was designed
|
||||
for.</p>
|
||||
6
grub2/help/grub_cfg.html
Normal file
6
grub2/help/grub_cfg.html
Normal file
@@ -0,0 +1,6 @@
|
||||
<header>Generated menu file</header>
|
||||
<p>Path to the generated GRUB menu file, commonly <tt>/boot/grub2/grub.cfg</tt>
|
||||
or <tt>/boot/grub/grub.cfg</tt>. GRUB reads this file at boot to build the boot
|
||||
menu and run boot commands.</p>
|
||||
<p>On BLS-based systems this file may contain loader code that reads separate
|
||||
BLS entry files instead of listing every kernel entry directly.</p>
|
||||
6
grub2/help/grub_dir.html
Normal file
6
grub2/help/grub_dir.html
Normal file
@@ -0,0 +1,6 @@
|
||||
<header>Script directory</header>
|
||||
<p>Directory containing GRUB menu generator scripts, usually
|
||||
<tt>/etc/grub.d</tt>. These scripts are run by <tt>grub-mkconfig</tt> or
|
||||
<tt>grub2-mkconfig</tt> to build the generated menu file.</p>
|
||||
<p>Distribution scripts should usually be left alone. Custom menu entries are
|
||||
normally placed in the configured custom script instead.</p>
|
||||
7
grub2/help/grubenv.html
Normal file
7
grub2/help/grubenv.html
Normal file
@@ -0,0 +1,7 @@
|
||||
<header>Environment file</header>
|
||||
<p>Path to the GRUB environment file, commonly <tt>/boot/grub2/grubenv</tt> or
|
||||
<tt>/boot/grub/grubenv</tt>. GRUB uses this file for persistent runtime state
|
||||
such as <tt>saved_entry</tt>, <tt>next_entry</tt>, and sometimes
|
||||
<tt>kernelopts</tt>.</p>
|
||||
<p>This module reads the file for status and uses GRUB tools for runtime boot
|
||||
selection changes.</p>
|
||||
6
grub2/help/install_boot_directory.html
Normal file
6
grub2/help/install_boot_directory.html
Normal file
@@ -0,0 +1,6 @@
|
||||
<header>Boot directory</header>
|
||||
<p>When enabled, this path is passed to <tt>grub-install</tt> as
|
||||
<tt>--boot-directory</tt>. Leave it disabled for normal installs, where GRUB
|
||||
uses its default boot directory, usually <tt>/boot</tt>.</p>
|
||||
<p>Use this only for custom layouts, chroots, rescue installs, or systems where
|
||||
the GRUB boot files must be installed under a non-default boot directory.</p>
|
||||
3
grub2/help/install_bootloader_id.html
Normal file
3
grub2/help/install_bootloader_id.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<header>Boot loader ID</header>
|
||||
|
||||
<p>Optional name for the EFI boot loader entry, such as <tt>GRUB</tt> or a distribution name. Leave it blank to let grub-install use its default.</p>
|
||||
6
grub2/help/install_cmd.html
Normal file
6
grub2/help/install_cmd.html
Normal file
@@ -0,0 +1,6 @@
|
||||
<header>Boot loader install command</header>
|
||||
<p>Command used to install GRUB boot loader files to a disk or EFI system
|
||||
partition, usually <tt>grub2-install</tt> or <tt>grub-install</tt>.</p>
|
||||
<p>This is separate from regenerating the menu. Installing GRUB changes boot
|
||||
loader data on disk or in firmware and should be done only when the target is
|
||||
known to be correct.</p>
|
||||
3
grub2/help/install_confirm.html
Normal file
3
grub2/help/install_confirm.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<header>Confirmation</header>
|
||||
|
||||
<p>Installing GRUB changes boot loader data on disk or in EFI firmware. Confirm this only after checking that the target and EFI directory match the system you intend to boot.</p>
|
||||
3
grub2/help/install_directory.html
Normal file
3
grub2/help/install_directory.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<header>GRUB module directory</header>
|
||||
|
||||
<p>Optional directory containing GRUB platform files and <tt>modinfo.sh</tt>. This is normally detected automatically from the platform target, but can be set when the distribution keeps GRUB modules in a non-standard location.</p>
|
||||
3
grub2/help/install_efi_dir.html
Normal file
3
grub2/help/install_efi_dir.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<header>EFI system directory</header>
|
||||
|
||||
<p>For UEFI systems, enter the mounted EFI system partition directory, usually <tt>/boot/efi</tt>. Webmin passes this to grub-install as the EFI directory.</p>
|
||||
3
grub2/help/install_force.html
Normal file
3
grub2/help/install_force.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<header>Force EFI install</header>
|
||||
|
||||
<p>Some distributions refuse to run <tt>grub-install</tt> for EFI platforms because the result may not support UEFI Secure Boot. Enable this only when Secure Boot is disabled or when you intentionally need grub-install to proceed anyway.</p>
|
||||
3
grub2/help/install_platform.html
Normal file
3
grub2/help/install_platform.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<header>Platform target</header>
|
||||
|
||||
<p>The GRUB platform to install, such as <tt>x86_64-efi</tt>, <tt>arm64-efi</tt>, or <tt>i386-pc</tt>. Webmin detects this from the current boot mode and CPU architecture when possible.</p>
|
||||
3
grub2/help/install_target.html
Normal file
3
grub2/help/install_target.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<header>Install target</header>
|
||||
|
||||
<p>Enter the device that GRUB should install to, such as <tt>/dev/sda</tt>, <tt>/dev/nvme0n1</tt>, or a stable path below <tt>/dev/disk/by-id</tt>. For EFI-only installs this may be left blank when an EFI system directory is supplied.</p>
|
||||
11
grub2/help/kernelopts_source.html
Normal file
11
grub2/help/kernelopts_source.html
Normal file
@@ -0,0 +1,11 @@
|
||||
<header>Detected kernel options source</header>
|
||||
<p>Shows where the currently detected Linux boot entries get their kernel
|
||||
command-line options.</p>
|
||||
<p>Generated menu entries usually come from the GRUB defaults file when the
|
||||
menu is regenerated. BLS entries may instead store options in
|
||||
<tt>/boot/loader/entries</tt> files, or reference <tt>$kernelopts</tt>.</p>
|
||||
<p><tt>kernelopts</tt> is not a setting in <tt>/etc/default/grub</tt>. It is a
|
||||
GRUB environment value stored in <tt>grubenv</tt> and commonly managed with
|
||||
<tt>grubby</tt>. Webmin does not edit <tt>grubenv</tt> directly; when
|
||||
<tt>grubby</tt> is available, Webmin asks it to apply changed kernel options to
|
||||
existing BLS entries.</p>
|
||||
5
grub2/help/mkconfig.html
Normal file
5
grub2/help/mkconfig.html
Normal file
@@ -0,0 +1,5 @@
|
||||
<header>Menu generation command</header>
|
||||
<p>Command used to rebuild the generated GRUB menu file, such as
|
||||
<tt>grub2-mkconfig</tt> or <tt>grub-mkconfig</tt>.</p>
|
||||
<p>When regenerating the menu, Webmin writes to a temporary file first, checks
|
||||
that generated file, and replaces the live menu only after the checks pass.</p>
|
||||
5
grub2/help/next_entry.html
Normal file
5
grub2/help/next_entry.html
Normal file
@@ -0,0 +1,5 @@
|
||||
<header>Next boot entry</header>
|
||||
<p>Shows the <tt>next_entry</tt> value from the GRUB environment file. When set,
|
||||
GRUB uses this entry for the next boot only and then clears it.</p>
|
||||
<p>The Boot Once action sets this value with the configured GRUB runtime
|
||||
command.</p>
|
||||
6
grub2/help/saved_entry.html
Normal file
6
grub2/help/saved_entry.html
Normal file
@@ -0,0 +1,6 @@
|
||||
<header>Environment default entry</header>
|
||||
<p>Shows the <tt>saved_entry</tt> value from the GRUB environment file. When
|
||||
<tt>GRUB_DEFAULT=saved</tt>, GRUB uses this saved value as the default boot
|
||||
entry.</p>
|
||||
<p>The Set as default action updates this value with the configured GRUB
|
||||
runtime command.</p>
|
||||
6
grub2/help/secure_boot.html
Normal file
6
grub2/help/secure_boot.html
Normal file
@@ -0,0 +1,6 @@
|
||||
<header>Secure Boot</header>
|
||||
<p>Shows the detected UEFI Secure Boot state. Secure Boot is only meaningful on
|
||||
UEFI systems; on legacy BIOS systems it is not applicable.</p>
|
||||
<p>Some distributions restrict or discourage direct <tt>grub-install</tt> use
|
||||
when Secure Boot is enabled because an incorrectly installed boot loader may no
|
||||
longer satisfy firmware signature checks.</p>
|
||||
15
grub2/help/security_current.html
Normal file
15
grub2/help/security_current.html
Normal file
@@ -0,0 +1,15 @@
|
||||
<header>Current protection</header>
|
||||
<p>GRUB password protection adds a GRUB superuser account to the generated boot
|
||||
menu. GRUB asks for this password when someone tries to use the GRUB command
|
||||
line or edit boot menu entries. Depending on how menu entries are generated, it
|
||||
may also be required to boot entries that are not marked as unrestricted.</p>
|
||||
|
||||
<p>This is useful on kiosks, lab systems, shared consoles, and other systems
|
||||
where an untrusted person may reach the boot menu. It helps stop simple boot
|
||||
menu attacks such as editing kernel parameters, starting a GRUB shell, or
|
||||
booting an unrestricted recovery entry.</p>
|
||||
|
||||
<p>It does not protect against someone who can change firmware boot settings,
|
||||
boot from other media, remove the disk, modify an unencrypted boot partition, or
|
||||
log in as root. Use it with firmware security, Secure Boot, encrypted storage,
|
||||
and normal operating system access controls when those threats matter.</p>
|
||||
3
grub2/help/security_enable.html
Normal file
3
grub2/help/security_enable.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<header>Enable password protection</header>
|
||||
<p>Controls whether Webmin writes GRUB superuser password commands into the
|
||||
generated boot menu. Regenerate the GRUB menu after saving.</p>
|
||||
6
grub2/help/security_file.html
Normal file
6
grub2/help/security_file.html
Normal file
@@ -0,0 +1,6 @@
|
||||
<header>Password script</header>
|
||||
<p>Path to the GRUB generator script that defines the Webmin-managed GRUB
|
||||
superuser and password hash.</p>
|
||||
<p>The script is included when the generated menu is rebuilt. If the file
|
||||
exists but is not recognized as managed by this module, the password status is
|
||||
shown as unmanaged.</p>
|
||||
4
grub2/help/security_hash.html
Normal file
4
grub2/help/security_hash.html
Normal file
@@ -0,0 +1,4 @@
|
||||
<header>PBKDF2 hash</header>
|
||||
<p>This is the stored GRUB password hash, not the original password. Leave it
|
||||
unchanged to keep the current password, or replace it with a hash produced by
|
||||
GRUB's password hash command.</p>
|
||||
5
grub2/help/security_mkpasswd.html
Normal file
5
grub2/help/security_mkpasswd.html
Normal file
@@ -0,0 +1,5 @@
|
||||
<header>Password hash command</header>
|
||||
<p>Command used to generate GRUB PBKDF2 password hashes, usually
|
||||
<tt>grub2-mkpasswd-pbkdf2</tt> or <tt>grub-mkpasswd-pbkdf2</tt>.</p>
|
||||
<p>GRUB stores the hash, not the original password. This command is needed when
|
||||
setting or replacing password protection from this module.</p>
|
||||
4
grub2/help/security_password.html
Normal file
4
grub2/help/security_password.html
Normal file
@@ -0,0 +1,4 @@
|
||||
<header>New password</header>
|
||||
<p>Enter and confirm a new password to replace the stored GRUB PBKDF2 hash.
|
||||
GRUB does not store the original password, so existing passwords cannot be
|
||||
displayed.</p>
|
||||
3
grub2/help/security_user.html
Normal file
3
grub2/help/security_user.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<header>Superuser name</header>
|
||||
<p>The GRUB user allowed to unlock protected boot menu editing and command-line
|
||||
access.</p>
|
||||
4
grub2/help/terminal_output.html
Normal file
4
grub2/help/terminal_output.html
Normal file
@@ -0,0 +1,4 @@
|
||||
<header>Terminal output</header>
|
||||
<p>Controls the GRUB terminal used for the boot menu. Console output shows the
|
||||
plain text menu. Graphical terminal output is required for GRUB themes and
|
||||
background images to appear.</p>
|
||||
5
grub2/help/theme.html
Normal file
5
grub2/help/theme.html
Normal file
@@ -0,0 +1,5 @@
|
||||
<header>Theme file</header>
|
||||
<p>Shows the extracted GRUB theme definition file currently saved in the GRUB
|
||||
defaults file. Webmin installs new themes under the configured GRUB theme
|
||||
directory in <tt>/boot</tt> and saves the installed theme.txt path here.</p>
|
||||
<p>The boot menu must use graphical terminal output for themes to appear.</p>
|
||||
6
grub2/help/theme_mode.html
Normal file
6
grub2/help/theme_mode.html
Normal file
@@ -0,0 +1,6 @@
|
||||
<header>Theme action</header>
|
||||
<p>Choose whether to keep the current theme setting, remove the theme setting,
|
||||
or install a new theme from the source below.</p>
|
||||
<p>Installing a theme copies or extracts it into the configured GRUB theme
|
||||
directory below <tt>/boot</tt>, then saves the installed theme.txt path in the GRUB
|
||||
defaults file.</p>
|
||||
7
grub2/help/theme_source.html
Normal file
7
grub2/help/theme_source.html
Normal file
@@ -0,0 +1,7 @@
|
||||
<header>Theme source</header>
|
||||
<p>Enter a local theme.txt file, a local directory containing theme.txt, a local
|
||||
<tt>.tar.gz</tt>, <tt>.tar</tt>, or <tt>.zip</tt> theme archive, or an HTTP,
|
||||
HTTPS, or FTP URL to one of those files.</p>
|
||||
<p>Archives are validated before extraction and installed under the configured
|
||||
GRUB theme directory in <tt>/boot</tt> so the boot loader can read the theme
|
||||
before the root filesystem is mounted.</p>
|
||||
4
grub2/help/timeout.html
Normal file
4
grub2/help/timeout.html
Normal file
@@ -0,0 +1,4 @@
|
||||
<header>Timeout</header>
|
||||
<p>Number of seconds GRUB waits before booting the default entry. Use 0 for
|
||||
immediate boot or -1 to wait indefinitely when supported by the local GRUB
|
||||
version.</p>
|
||||
4
grub2/help/timeout_style.html
Normal file
4
grub2/help/timeout_style.html
Normal file
@@ -0,0 +1,4 @@
|
||||
<header>Timeout style</header>
|
||||
<p>Controls how GRUB behaves while waiting for the timeout. Menu shows the boot
|
||||
menu, hidden suppresses it unless interrupted, and countdown displays a compact
|
||||
countdown when supported.</p>
|
||||
4
grub2/images/defaults.svg
Normal file
4
grub2/images/defaults.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48">
|
||||
<rect x="9" y="6" width="30" height="36" rx="3" fill="#eef4ff" stroke="#2563eb" stroke-width="2"/>
|
||||
<path d="M16 16h16M16 24h16M16 32h10" stroke="#1e3a8a" stroke-width="3" stroke-linecap="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 291 B |
5
grub2/images/install.svg
Normal file
5
grub2/images/install.svg
Normal file
@@ -0,0 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48">
|
||||
<rect x="8" y="28" width="32" height="11" rx="3" fill="#ecfdf5" stroke="#059669" stroke-width="2"/>
|
||||
<path d="M24 8v18M16 18l8 8 8-8" fill="none" stroke="#047857" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle cx="34" cy="34" r="2" fill="#059669"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 372 B |
5
grub2/images/manual.svg
Normal file
5
grub2/images/manual.svg
Normal file
@@ -0,0 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48">
|
||||
<rect x="7" y="10" width="34" height="26" rx="3" fill="#f8fafc" stroke="#475569" stroke-width="2"/>
|
||||
<path d="M12 17h6M12 23h10M12 29h7" stroke="#334155" stroke-width="3" stroke-linecap="round"/>
|
||||
<path d="M29 14l6 5-6 5M34 29h7" fill="none" stroke="#0f766e" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 420 B |
5
grub2/images/security.svg
Normal file
5
grub2/images/security.svg
Normal file
@@ -0,0 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48">
|
||||
<rect x="12" y="22" width="24" height="18" rx="3" fill="#fff7ed" stroke="#ea580c" stroke-width="2"/>
|
||||
<path d="M17 22v-6a7 7 0 0114 0v6" fill="none" stroke="#9a3412" stroke-width="3" stroke-linecap="round"/>
|
||||
<circle cx="24" cy="31" r="3" fill="#ea580c"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 351 B |
5
grub2/images/theme.svg
Normal file
5
grub2/images/theme.svg
Normal file
@@ -0,0 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48">
|
||||
<rect x="7" y="9" width="34" height="30" rx="4" fill="#f0fdf4" stroke="#16a34a" stroke-width="2"/>
|
||||
<circle cx="17" cy="20" r="4" fill="#facc15"/>
|
||||
<path d="M10 35l10-10 7 6 5-5 9 9" fill="none" stroke="#15803d" stroke-width="3" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 350 B |
405
grub2/index.cgi
Executable file
405
grub2/index.cgi
Executable file
@@ -0,0 +1,405 @@
|
||||
#!/usr/local/bin/perl
|
||||
# Display GRUB 2 boot menu and configuration status.
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
require './grub2-lib.pl'; ## no critic
|
||||
|
||||
our (%in, %text);
|
||||
our $module_name;
|
||||
our $grub2_formno = 0;
|
||||
|
||||
&ReadParse();
|
||||
&error_setup($text{'acl_ecannot'});
|
||||
my %access = &grub2_effective_acl();
|
||||
&error("$text{'eacl_np'} $text{'eacl_pview'}")
|
||||
if (!&grub2_can_enter_module(\%access));
|
||||
|
||||
# Show configuration/install guidance before rendering module actions.
|
||||
if (!&grub2_any_installed()) {
|
||||
&ui_print_header(&grub2_version_text() || "", $text{'index_title'},
|
||||
"", undef, 1, 1);
|
||||
print &ui_alert($text{'index_missing'}, 'warning');
|
||||
foreach my $issue (&grub2_install_issues()) {
|
||||
print &ui_div(&text('index_missing_detail',
|
||||
&ui_tag('tt', &html_escape($issue))));
|
||||
}
|
||||
print &ui_p(&ui_link("@{[&get_webprefix()]}/config.cgi?$module_name",
|
||||
$text{'index_config_link'}));
|
||||
if ($access{'install'} && &foreign_available("software")) {
|
||||
# Offer package installation only to users allowed to install GRUB.
|
||||
&foreign_require("software", "software-lib.pl");
|
||||
my $lnk = &software::missing_install_link(
|
||||
"grub2-common", $text{'index_install_pkg'},
|
||||
"../$module_name/", $text{'index_title'});
|
||||
print &ui_p($lnk) if ($lnk);
|
||||
}
|
||||
&ui_print_footer("/", $text{'index_return'});
|
||||
exit;
|
||||
}
|
||||
|
||||
&ui_print_header(&grub2_version_text() || "", $text{'index_title'}, "",
|
||||
undef, 1, 1, undef, &grub2_action_links(\%access));
|
||||
|
||||
foreach my $warning (&grub2_status_warnings()) {
|
||||
print &ui_alert($warning, 'warning');
|
||||
}
|
||||
|
||||
# Only the two entry lists are tabs; global settings live in separate pages.
|
||||
my @tabs = (
|
||||
[ 'entries', $text{'index_entries_tab'} ],
|
||||
[ 'custom', $text{'index_custom_tab'} ],
|
||||
);
|
||||
my %valid = map { $_->[0] => 1 } @tabs;
|
||||
my $requested = defined($in{'mode'}) ? $in{'mode'} : '';
|
||||
my $mode = $requested && $valid{$requested} ? $requested : 'entries';
|
||||
print &ui_tabs_start(\@tabs, "mode", $mode, 1);
|
||||
|
||||
print &ui_tabs_start_tab("mode", "entries");
|
||||
&print_entries_tab(\%access);
|
||||
print &ui_tabs_end_tab("mode", "entries");
|
||||
|
||||
print &ui_tabs_start_tab("mode", "custom");
|
||||
&print_custom_tab(\%access);
|
||||
print &ui_tabs_end_tab("mode", "custom");
|
||||
|
||||
print &ui_tabs_end();
|
||||
|
||||
&print_action_buttons(\%access);
|
||||
&ui_print_footer("/", $text{'index_return'});
|
||||
|
||||
# print_entries_tab(&access)
|
||||
# Outputs generated boot menu entries and selected-entry runtime actions.
|
||||
sub print_entries_tab
|
||||
{
|
||||
my ($access) = @_;
|
||||
my @entries = &grub2_boot_entries();
|
||||
my $parsed = &read_grub_defaults();
|
||||
my %env = &grub2_read_env();
|
||||
# Selection roles are derived from both defaults and grubenv state.
|
||||
my %selection = &grub2_entry_selection_roles(\@entries, $parsed, \%env);
|
||||
my $can_default = $access->{'runtime'} && &grub2_command('set_default_cmd');
|
||||
my $can_once = $access->{'runtime'} && &grub2_command('reboot_once_cmd');
|
||||
my $show_actions = $can_default || $can_once;
|
||||
print &ui_div($text{'index_entries_desc'});
|
||||
if (!@entries) {
|
||||
print &ui_alert($text{'index_no_entries'}, 'info');
|
||||
return;
|
||||
}
|
||||
my @heads = (
|
||||
$text{'index_col_title'},
|
||||
$text{'index_col_group'},
|
||||
$text{'index_col_selection'},
|
||||
($show_actions ? ( $text{'index_col_actions'} ) : ( )),
|
||||
);
|
||||
my @tds = (
|
||||
"",
|
||||
"",
|
||||
"width=10% nowrap",
|
||||
($show_actions ? ( "width=10% nowrap" ) : ( )),
|
||||
);
|
||||
print &ui_columns_start(\@heads, 100, 0, \@tds);
|
||||
foreach my $entry (@entries) {
|
||||
# Path displays submenu nesting; BLS top-level entries have no submenu path.
|
||||
my @cols = (
|
||||
&entry_title_cell($entry),
|
||||
@{$entry->{'path'} || []}
|
||||
? &html_escape(join(' > ', @{$entry->{'path'}}))
|
||||
: $text{'index_top'},
|
||||
&selection_cell($selection{$entry->{'index'}}),
|
||||
($show_actions ? ( &entry_actions_cell(
|
||||
$entry, $can_default, $can_once) ) : ( )),
|
||||
);
|
||||
print &ui_columns_row(\@cols, \@tds);
|
||||
}
|
||||
print &ui_columns_end();
|
||||
}
|
||||
|
||||
# print_custom_tab(&access)
|
||||
# Outputs editable custom menu entries from the configured custom file.
|
||||
sub print_custom_tab
|
||||
{
|
||||
my ($access) = @_;
|
||||
my $file = &grub2_config_value('custom_file') || '';
|
||||
my @entries = &grub2_custom_entries($file);
|
||||
my $can_edit = $access->{'manual'} && $file ne '';
|
||||
print &ui_div($text{'index_custom_desc'});
|
||||
if ($file eq '') {
|
||||
# A blank custom file path means the module cannot safely offer editing.
|
||||
print &ui_alert($text{'custom_enofile'}, 'info');
|
||||
return;
|
||||
}
|
||||
if ($can_edit && @entries) {
|
||||
# Checked-table actions need a stable form number for select-all links.
|
||||
my $formno = $grub2_formno;
|
||||
print &ui_form_start("custom_action.cgi", "post", undef,
|
||||
"id='grub2_custom_form'");
|
||||
$grub2_formno++;
|
||||
&print_custom_links($can_edit, scalar(@entries), $formno);
|
||||
}
|
||||
elsif (@entries) {
|
||||
&print_custom_links($can_edit, scalar(@entries), $grub2_formno);
|
||||
}
|
||||
if (!@entries) {
|
||||
print &ui_br();
|
||||
print &ui_p($text{'custom_empty'});
|
||||
if ($can_edit) {
|
||||
# Empty state uses a compact link, matching other Webmin list pages.
|
||||
print &ui_link("edit_custom.cgi", $text{'custom_add'},
|
||||
"plus");
|
||||
print &ui_br();
|
||||
}
|
||||
return;
|
||||
}
|
||||
# A single editable entry can be deleted, but cannot be reordered.
|
||||
my $show_order = $can_edit && @entries > 1;
|
||||
my @tds = $can_edit ? (
|
||||
"width=5",
|
||||
"",
|
||||
"",
|
||||
($show_order ? ( "width=40 style='white-space: nowrap; text-align: center'" ) : ( )),
|
||||
) : ( );
|
||||
print &ui_columns_start([
|
||||
($can_edit ? ( "" ) : ( )),
|
||||
$text{'index_col_title'},
|
||||
$text{'index_col_group'},
|
||||
($show_order ? ( $text{'index_col_order'} ) : ( )),
|
||||
], 100, 0, \@tds);
|
||||
foreach my $entry (@entries) {
|
||||
# Custom indexes refer to parsed menuentry blocks in the custom file.
|
||||
my $idx = $entry->{'custom_index'};
|
||||
my $title = &entry_title_cell($entry, "edit_custom.cgi?idx=$idx");
|
||||
my @cols = (
|
||||
$title,
|
||||
@{$entry->{'path'} || []}
|
||||
? &html_escape(join(' > ', @{$entry->{'path'}}))
|
||||
: $text{'index_top'},
|
||||
($show_order ? ( &custom_order_cell($idx, \@entries) ) : ( )),
|
||||
);
|
||||
if ($can_edit) {
|
||||
print &ui_checked_columns_row(\@cols, \@tds, "d", $idx);
|
||||
}
|
||||
else {
|
||||
print &ui_columns_row(\@cols);
|
||||
}
|
||||
}
|
||||
print &ui_columns_end();
|
||||
if ($can_edit) {
|
||||
my @left_buttons;
|
||||
my @right_buttons = (
|
||||
[ "delete", $text{'index_delete_entry'}, undef, undef,
|
||||
"form='grub2_custom_form'" ],
|
||||
);
|
||||
print &ui_form_end_side_by_side("grub2_custom_form",
|
||||
\@left_buttons, \@right_buttons);
|
||||
}
|
||||
}
|
||||
|
||||
# print_action_buttons(&access)
|
||||
# Outputs the main module actions allowed by ACLs.
|
||||
sub print_action_buttons
|
||||
{
|
||||
my ($access) = @_;
|
||||
my (@links, @titles, @icons);
|
||||
my $can_status = $access->{'view'};
|
||||
my $can_generate = $access->{'apply'} && &grub2_command('mkconfig_cmd');
|
||||
if ($access->{'install'}) {
|
||||
# Primary action tiles are ACL-filtered so unavailable pages stay hidden.
|
||||
push(@links, "edit_install.cgi");
|
||||
push(@titles, $text{'index_install'});
|
||||
push(@icons, "images/install.svg");
|
||||
}
|
||||
if ($access->{'edit'}) {
|
||||
push(@links, "edit_defaults.cgi");
|
||||
push(@titles, $text{'index_edit_defaults'});
|
||||
push(@icons, "images/defaults.svg");
|
||||
}
|
||||
if ($access->{'security'}) {
|
||||
push(@links, "edit_security.cgi");
|
||||
push(@titles, $text{'index_edit_security'});
|
||||
push(@icons, "images/security.svg");
|
||||
}
|
||||
if ($access->{'edit'}) {
|
||||
push(@links, "edit_theme.cgi");
|
||||
push(@titles, $text{'index_edit_theme'});
|
||||
push(@icons, "images/theme.svg");
|
||||
}
|
||||
if ($access->{'manual'}) {
|
||||
push(@links, "edit_manual.cgi");
|
||||
push(@titles, $text{'index_manual'});
|
||||
push(@icons, "images/manual.svg");
|
||||
}
|
||||
return if (!@links && !$can_status && !$can_generate);
|
||||
print &ui_hr();
|
||||
if (@links) {
|
||||
print &ui_subheading($text{'index_global'});
|
||||
&icons_table(\@links, \@titles, \@icons, scalar(@links) > 5 ? 5 :
|
||||
scalar(@links));
|
||||
}
|
||||
if ($can_status || $can_generate) {
|
||||
print &ui_hr() if (@links);
|
||||
print &ui_buttons_start();
|
||||
print &ui_buttons_row("status.cgi", $text{'index_view_status'},
|
||||
$text{'index_view_status_msg'}, undef, undef,
|
||||
undef, "get") if ($can_status);
|
||||
print &ui_buttons_row("generate.cgi", $text{'index_generate'},
|
||||
$text{'index_generate_msg'},
|
||||
[ [ "redir", &grub2_this_url() ] ])
|
||||
if ($can_generate);
|
||||
print &ui_buttons_end();
|
||||
}
|
||||
}
|
||||
|
||||
# print_custom_links(can-edit?, entry-count, form-number)
|
||||
# Outputs checked-table links for custom entries.
|
||||
sub print_custom_links
|
||||
{
|
||||
my ($can_edit, $count, $formno) = @_;
|
||||
return if (!$can_edit);
|
||||
my @left;
|
||||
if ($count) {
|
||||
push(@left, &select_all_link("d", $formno),
|
||||
&select_invert_link("d", $formno));
|
||||
}
|
||||
push(@left, &ui_link("edit_custom.cgi", $text{'custom_add'}));
|
||||
print &ui_links_row(\@left);
|
||||
}
|
||||
|
||||
# selection_cell(&roles)
|
||||
# Returns display text for default and next-boot entry roles.
|
||||
sub selection_cell
|
||||
{
|
||||
my ($roles) = @_;
|
||||
return '' if (!$roles || !@$roles);
|
||||
my @labels = map { $text{'index_selection_'.$_} || $_ } @$roles;
|
||||
return join(', ', @labels);
|
||||
}
|
||||
|
||||
# entry_title_cell(&entry, [link])
|
||||
# Returns a title cell with useful GRUB entry metadata in inline details.
|
||||
sub entry_title_cell
|
||||
{
|
||||
my ($entry, $link) = @_;
|
||||
my $title = &html_escape($entry->{'title'} || '');
|
||||
my $summary = $link ?
|
||||
&ui_tag('a', $title, { href => $link, style => 'padding: 0;' }) :
|
||||
$title;
|
||||
return &ui_details({
|
||||
'html' => 1,
|
||||
'title' => $summary,
|
||||
'content' => &entry_details_content($entry),
|
||||
'class' => 'inline inlined',
|
||||
});
|
||||
}
|
||||
|
||||
# entry_details_content(&entry)
|
||||
# Returns compact metadata for a boot entry details disclosure.
|
||||
sub entry_details_content
|
||||
{
|
||||
my ($entry) = @_;
|
||||
my @rows;
|
||||
my $index = defined($entry->{'index'}) ? $entry->{'index'} :
|
||||
$entry->{'custom_index'};
|
||||
# Only include rows that help identify or troubleshoot the selected entry.
|
||||
push(@rows, &entry_detail_line($text{'index_col_index'}, $index))
|
||||
if (defined($index));
|
||||
push(@rows, &entry_detail_line($text{'index_col_id'}, $entry->{'id'}))
|
||||
if ($entry->{'id'});
|
||||
push(@rows, &entry_source_detail_line($entry))
|
||||
if ($entry->{'source_file'});
|
||||
push(@rows, &entry_detail_line($text{'index_col_version'},
|
||||
$entry->{'version'}));
|
||||
push(@rows, &entry_detail_line($text{'index_col_kernel'},
|
||||
$entry->{'linux'}));
|
||||
push(@rows, &entry_detail_line($text{'index_col_initrd'},
|
||||
$entry->{'initrd'}));
|
||||
push(@rows, &entry_detail_line($text{'index_col_machine_id'},
|
||||
$entry->{'machine-id'}));
|
||||
push(@rows, &entry_detail_line($text{'index_col_options'},
|
||||
$entry->{'options'}));
|
||||
return join('', @rows);
|
||||
}
|
||||
|
||||
# entry_source_detail_line(&entry)
|
||||
# Returns source details without implying generator scripts are entry files.
|
||||
sub entry_source_detail_line
|
||||
{
|
||||
my ($entry) = @_;
|
||||
my $file = $entry->{'source_file'} || '';
|
||||
return '' if (!defined($file) || $file eq '');
|
||||
my $custom_file = &grub2_config_value('custom_file') || '';
|
||||
my $direct_file = (($entry->{'source'} || '') eq 'bls') ||
|
||||
($custom_file ne '' && $file eq $custom_file);
|
||||
# Direct entry files are shortened for readability; generator scripts are not.
|
||||
my $label = $direct_file ? $text{'index_col_file'} :
|
||||
$text{'index_col_generator'};
|
||||
my $html;
|
||||
if ($direct_file) {
|
||||
my $display = &entry_file_display_name($file);
|
||||
$html = &ui_tag('tt', &html_escape($display), { 'title' => $file });
|
||||
}
|
||||
else {
|
||||
$html = &ui_tag('tt', &html_escape($file));
|
||||
}
|
||||
if (&grub2_check_acl('manual') && &grub2_manual_file($file)) {
|
||||
# The manual editor repeats its allowlist check on entry.
|
||||
$html = &ui_tag('a', $html, {
|
||||
'href' => "edit_manual.cgi?file=".&urlize($file),
|
||||
});
|
||||
}
|
||||
return &entry_detail_line($label, $html, 1);
|
||||
}
|
||||
|
||||
# entry_file_display_name(file)
|
||||
# Returns a short display name for a linked entry file.
|
||||
sub entry_file_display_name
|
||||
{
|
||||
my ($file) = @_;
|
||||
$file = '' if (!defined($file));
|
||||
$file =~ s{.*/}{};
|
||||
return $file;
|
||||
}
|
||||
|
||||
# entry_detail_line(label, value, [html-value?])
|
||||
# Returns one escaped metadata line for a boot entry details disclosure.
|
||||
sub entry_detail_line
|
||||
{
|
||||
my ($label, $value, $html) = @_;
|
||||
return '' if (!defined($value) || $value eq '');
|
||||
my $display = $html ? $value : &ui_tag('tt', &html_escape($value));
|
||||
return &ui_tag('div',
|
||||
&ui_tag('span', &html_escape($label).':',
|
||||
{ 'style' => 'white-space: nowrap;' }).
|
||||
&ui_tag('span', $display,
|
||||
{ 'style' => 'min-width: 0; white-space: pre-wrap; overflow-wrap: anywhere;' }),
|
||||
{ 'style' => 'display: grid; grid-template-columns: max-content minmax(0, 1fr); column-gap: 0.35em; align-items: start;' });
|
||||
}
|
||||
|
||||
# entry_actions_cell(&entry, can-default?, can-once?)
|
||||
# Returns runtime action links for one generated boot entry.
|
||||
sub entry_actions_cell
|
||||
{
|
||||
my ($entry, $can_default, $can_once) = @_;
|
||||
my $idx = $entry->{'index'};
|
||||
my @actions;
|
||||
push(@actions, &ui_link("set_default.cgi?idx=$idx",
|
||||
$text{'index_set_default'})) if ($can_default);
|
||||
push(@actions, &ui_link("reboot_once.cgi?idx=$idx",
|
||||
$text{'index_reboot_once'})) if ($can_once);
|
||||
return join(' | ', @actions);
|
||||
}
|
||||
|
||||
# custom_order_cell(index, &entries)
|
||||
# Returns up/down ordering controls for one custom entry row.
|
||||
sub custom_order_cell
|
||||
{
|
||||
my ($idx, $entries) = @_;
|
||||
my $up = $idx > 0 &&
|
||||
&grub2_paths_equal($entries->[$idx], $entries->[$idx - 1]);
|
||||
my $down = $idx < @$entries - 1 &&
|
||||
&grub2_paths_equal($entries->[$idx], $entries->[$idx + 1]);
|
||||
# Disable movement across submenu boundaries so nesting remains intact.
|
||||
return &ui_up_down_arrows("custom_action.cgi?idx=$idx&dir=up",
|
||||
"custom_action.cgi?idx=$idx&dir=down",
|
||||
$up, $down);
|
||||
}
|
||||
146
grub2/install.cgi
Executable file
146
grub2/install.cgi
Executable file
@@ -0,0 +1,146 @@
|
||||
#!/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'});
|
||||
&grub2_assert_acl('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 "<br>\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 "<br><div data-x-br=\"\"></div>\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 "<br><div data-x-br=\"\"></div>\n";
|
||||
$$current = '';
|
||||
$$printed = 1;
|
||||
return;
|
||||
}
|
||||
18
grub2/install_check.pl
Normal file
18
grub2/install_check.pl
Normal file
@@ -0,0 +1,18 @@
|
||||
# install_check.pl
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
do 'grub2-lib.pl';
|
||||
|
||||
# is_installed(mode)
|
||||
# For mode 1, returns 2 if GRUB 2 is installed and configured for Webmin,
|
||||
# 1 if installed but not configured, or 0 otherwise.
|
||||
# For mode 0, returns 1 if installed, 0 if not.
|
||||
sub is_installed
|
||||
{
|
||||
my ($mode) = @_;
|
||||
return 0 if (!&grub2_any_installed());
|
||||
return $mode ? (&grub2_configured() ? 2 : 1) : 1;
|
||||
}
|
||||
|
||||
1;
|
||||
349
grub2/lang/en
Normal file
349
grub2/lang/en
Normal file
@@ -0,0 +1,349 @@
|
||||
index_title=GRUB 2 Boot Loader
|
||||
index_version=GRUB version $1
|
||||
index_return=GRUB 2 module
|
||||
status_title=GRUB status
|
||||
index_missing=GRUB 2 does not appear to be installed or configured. Install GRUB 2 packages or update this module's configuration paths.
|
||||
index_missing_detail=Missing or unusable item: $1
|
||||
index_config_link=Module configuration
|
||||
index_install_pkg=GRUB 2 packages
|
||||
index_summary=Configuration summary
|
||||
index_boot_mode=Boot mode
|
||||
index_boot_mode_uefi=UEFI
|
||||
index_boot_mode_bios=Legacy BIOS
|
||||
index_secure_boot=Secure Boot
|
||||
index_secure_boot_enabled=Enabled
|
||||
index_secure_boot_disabled=Disabled
|
||||
index_secure_boot_unknown=Unknown
|
||||
index_secure_boot_not_applicable=Not applicable for BIOS boot
|
||||
index_default_file=Default settings file
|
||||
index_grub_cfg=Generated menu file
|
||||
index_grub_dir=Script directory
|
||||
index_bls_dir=BLS entries directory
|
||||
index_mkconfig=Menu generation command
|
||||
index_install_cmd=Boot loader install command
|
||||
index_env=Environment file
|
||||
index_entries=Boot menu entries
|
||||
index_entry_count=$1 entries
|
||||
index_kernel_options_source=Kernel options source
|
||||
index_kernel_options_source_kernelopts=GRUB environment kernelopts
|
||||
index_kernel_options_source_bls=BLS entry files
|
||||
index_kernel_options_source_defaults=Generated menu entries
|
||||
index_no_entries=No boot entries were found in the generated GRUB menu file.
|
||||
index_entries_tab=Generated menu
|
||||
index_custom_tab=Custom entries
|
||||
index_entries_desc=Review entries from the generated GRUB menu and choose one entry for runtime actions; generated kernel, BLS, and distribution entries are not editable from this page.
|
||||
index_custom_desc=Add, edit, reorder, or delete entries from the configured custom menu file. These entries appear in the generated menu after regeneration.
|
||||
index_status_desc=Review discovered GRUB paths, common defaults, theme appearance, saved boot selection, and password protection managed by Webmin.
|
||||
index_security_state=Current protection
|
||||
index_security_enabled=Enabled
|
||||
index_security_disabled=Disabled
|
||||
index_security_unmanaged=Unmanaged file
|
||||
index_security_user=Superuser
|
||||
index_security_hash=Password hash
|
||||
index_security_hash_set=Configured
|
||||
index_security_hash_missing=Missing
|
||||
index_security_file=Password script
|
||||
index_security_mkpasswd=Password hash command
|
||||
index_boot_selection=Boot selection
|
||||
index_col_index=Index
|
||||
index_col_selection=Selection
|
||||
index_col_order=Order
|
||||
index_col_title=Title
|
||||
index_col_id=Entry ID
|
||||
index_col_group=Submenu
|
||||
index_col_actions=Actions
|
||||
index_col_file=File
|
||||
index_col_generator=Generator script
|
||||
index_col_version=Version
|
||||
index_col_kernel=Kernel
|
||||
index_col_initrd=Initial ramdisk
|
||||
index_col_machine_id=Machine ID
|
||||
index_col_options=Kernel options
|
||||
index_selection_default=Default
|
||||
index_selection_saved=Saved default
|
||||
index_selection_next=Boot once
|
||||
index_top=Top level
|
||||
index_bls=Boot Loader Specification
|
||||
index_saved_entry=Environment default entry
|
||||
index_next_entry=Next boot entry
|
||||
index_not_set=Not set
|
||||
index_not_readable=Not readable
|
||||
index_missing_file=Missing file
|
||||
index_delete_entry=Delete entry
|
||||
index_global=Global Options
|
||||
index_edit_defaults=Edit GRUB Defaults
|
||||
index_edit_theme=Edit Theme and Appearance
|
||||
index_edit_security=Edit GRUB Password
|
||||
index_manual=Edit Config Files Manually
|
||||
index_view_status=View GRUB status
|
||||
index_view_status_msg=Review detected paths, defaults, boot selection, theme, and password protection.
|
||||
index_generate=Regenerate GRUB menu
|
||||
index_generate_msg=Run GRUB's menu generator and replace the generated menu only after a successful test run.
|
||||
index_install=Install GRUB Boot Loader
|
||||
index_set_default=Make Default
|
||||
index_reboot_once=Boot Once
|
||||
index_warn_missing_cfg=The generated menu file does not exist. Generate the menu before relying on these settings at boot.
|
||||
index_warn_missing_default=The default settings file does not exist. Create it or update the module configuration.
|
||||
index_warn_mkconfig=The menu generation command is not available, so Webmin cannot regenerate the boot menu.
|
||||
index_warn_saved=The default is set to saved, but the GRUB environment file could not be read.
|
||||
index_warn_theme_invalid=The configured GRUB theme cannot be used: $1
|
||||
index_warn_theme_console=A GRUB theme is configured, but terminal output is set to console. Use graphical terminal output for the theme to appear.
|
||||
index_warn_bls_options=Detected BLS boot entries store kernel options in BLS entry files. Install grubby or configure its path to update existing BLS entries automatically.
|
||||
index_warn_kernelopts_source=Detected BLS boot entries read kernel options from grubenv kernelopts. Install grubby or configure its path if existing BLS entries do not change after saving kernel options.
|
||||
index_warn_kernelopts_missing=BLS boot entries refer to grubenv kernelopts, but no kernelopts value was found in the GRUB environment file.
|
||||
defaults_title=GRUB default settings
|
||||
defaults_header=Common default settings
|
||||
defaults_theme_header=Theme and menu appearance
|
||||
defaults_default=Default menu entry
|
||||
defaults_default_saved=Saved environment entry
|
||||
defaults_default_current=Current value: $1
|
||||
defaults_default_current_entry=Current index $1: $2
|
||||
defaults_default_entry_id=$1 [$2]
|
||||
defaults_timeout_style=Timeout style
|
||||
defaults_timeout=Timeout
|
||||
defaults_terminal_output=Terminal output
|
||||
defaults_terminal_console=Console
|
||||
defaults_terminal_gfxterm=Graphical terminal
|
||||
defaults_terminal_gfxterm_console=Graphical terminal, then console
|
||||
defaults_terminal_serial=Serial
|
||||
defaults_cmdline_default=Kernel options for regular Linux entries
|
||||
defaults_cmdline=Kernel options for all Linux entries
|
||||
defaults_kernelopts_source=Detected kernel options source
|
||||
defaults_disable_recovery=Disable recovery and rescue entries
|
||||
defaults_disable_recovery_bls=Existing BLS rescue entries are hidden by renaming their entry files.
|
||||
defaults_disable_os_prober=Disable OS prober
|
||||
defaults_theme=Theme file
|
||||
defaults_theme_current=Current theme file
|
||||
defaults_theme_none=Not set
|
||||
defaults_theme_action=Theme action
|
||||
defaults_theme_keep=Keep current theme
|
||||
defaults_theme_install=Install or select theme source
|
||||
defaults_theme_clear=Use no theme
|
||||
defaults_theme_source=Theme source
|
||||
defaults_gfxmode=Graphics mode
|
||||
defaults_gfxmode_default=Use default resolution
|
||||
defaults_gfxmode_auto=Automatic resolution
|
||||
defaults_background=Background image
|
||||
defaults_color_normal=Normal menu colors
|
||||
defaults_color_highlight=Selected menu colors
|
||||
defaults_color_default=Use default colors
|
||||
defaults_color_custom=Set custom colors
|
||||
defaults_color_text=Text
|
||||
defaults_color_background=Background
|
||||
defaults_keep=Use GRUB default
|
||||
defaults_menu=Menu
|
||||
defaults_hidden=Hidden
|
||||
defaults_countdown=Countdown
|
||||
defaults_true=Yes
|
||||
defaults_false=No
|
||||
defaults_format_note=Saving these settings rewrites the managed assignments in normalized shell format while preserving other lines and comments.
|
||||
defaults_err=Failed to save GRUB defaults
|
||||
defaults_edefault=The default menu entry cannot contain line breaks or null bytes.
|
||||
defaults_edefault_choice=The selected default menu entry is not one of the detected entries.
|
||||
defaults_etimeout=The timeout must be -1 or a non-negative number of seconds.
|
||||
defaults_etimeout_style=Invalid timeout style.
|
||||
defaults_eterminal_output=Invalid terminal output.
|
||||
defaults_egfxmode=Invalid graphics mode. Use auto or modes like 1024x768 or 1024x768x32, separated by commas.
|
||||
defaults_ebool=Invalid boolean value for $1.
|
||||
defaults_ecmdline=$1 cannot contain line breaks or null bytes.
|
||||
defaults_egrubby=The grubby command is not available, so existing BLS entries were not updated.
|
||||
defaults_egrubby_failed=The grubby command failed without output.
|
||||
defaults_ebls_rescue_exists=Cannot disable BLS rescue entry $1 because $2 already exists.
|
||||
defaults_ebls_rescue_move=Failed to move BLS rescue entry from $1 to $2: $3
|
||||
defaults_edir=Directory $1 does not exist or is not accessible.
|
||||
defaults_epath=$1 cannot contain line breaks or null bytes.
|
||||
defaults_eabspath=$1 must be an absolute path.
|
||||
defaults_econfigpath=Configured file path $1 must be absolute.
|
||||
defaults_epathchars=$1 contains characters that are not allowed in GRUB file paths.
|
||||
defaults_ecolor=Invalid color selection for $1.
|
||||
defaults_ecolorfile=The configured GRUB color script already exists but is not managed by Webmin. Edit it manually or choose another path in module configuration.
|
||||
defaults_etheme_archive=$1 is a theme archive, not a GRUB theme file. Extract the theme and select its theme.txt file.
|
||||
defaults_etheme_file=The GRUB theme file $1 does not exist or cannot be read.
|
||||
defaults_etheme_source=Enter a local theme file, local theme archive, local theme directory, or HTTP, HTTPS, or FTP URL.
|
||||
defaults_etheme_url=Enter a valid HTTP, HTTPS, or FTP URL for the theme source.
|
||||
defaults_etheme_download=Failed to download the theme source: $1
|
||||
defaults_etheme_mode=Invalid theme action.
|
||||
defaults_etheme_nottheme=$1 is not a theme.txt file or a supported theme archive.
|
||||
defaults_etheme_notfound=No theme.txt file was found in the selected theme source.
|
||||
defaults_etheme_archive_list=Failed to list the theme archive.
|
||||
defaults_etheme_extract=Failed to extract the theme archive.
|
||||
defaults_etheme_type=Unsupported theme archive type.
|
||||
defaults_etheme_cmd=The command $1 is required to install this theme source.
|
||||
defaults_etheme_member=The theme archive contains an unsafe or unsupported member: $1
|
||||
defaults_etheme_terminal=GRUB themes require graphical terminal output. Change Terminal output to Graphical terminal before saving this theme.
|
||||
defaults_ebackground_file=The GRUB background image $1 does not exist or cannot be read.
|
||||
defaults_ebackground_type=The GRUB background image $1 must be a PNG, JPEG, or TGA file.
|
||||
defaults_theme_note=Enter an existing theme.txt, a theme directory, a local .tar.gz or .zip archive, or an HTTP, HTTPS, or FTP URL. Webmin installs the theme under the configured GRUB theme directory in <tt>/boot</tt>. Use graphical terminal output for themes.
|
||||
defaults_background_note=Webmin copies this image under the configured GRUB background directory in <tt>/boot</tt> before saving it.
|
||||
theme_title=GRUB theme and appearance
|
||||
theme_err=Failed to save GRUB theme and appearance
|
||||
security_title=GRUB password protection
|
||||
security_header=Password protection
|
||||
security_current_state=Current protection
|
||||
security_current_enabled=Enabled for superuser $1
|
||||
security_current_disabled=Disabled
|
||||
security_current_hash=Current password
|
||||
security_current_hash_set=Set, not shown
|
||||
security_current_hash_missing=Not set
|
||||
security_enable=Enable password protection
|
||||
security_user=Superuser name
|
||||
security_password_status=Password update
|
||||
security_password_keep=Leave blank to keep the current password, or enter a new one to replace it.
|
||||
security_password_required=No password is currently set. Enter and confirm a password before enabling protection.
|
||||
security_newpass=New password
|
||||
security_newpass2=Confirm password
|
||||
security_hash=PBKDF2 hash
|
||||
security_hash_note=This is the stored GRUB password hash, not the original password. Leave it unchanged to keep the current password, or replace it with a pre-generated grub.pbkdf2 hash.
|
||||
security_unmanaged=The configured password script already exists but is not managed by Webmin. Edit it manually or choose another path in module configuration.
|
||||
security_err=Failed to save GRUB password protection
|
||||
security_euser=The GRUB superuser name is required and can only contain letters, numbers, dots, underscores, plus signs, at signs, and hyphens.
|
||||
security_epass=Enter a password or PBKDF2 hash before enabling password protection.
|
||||
security_epassmatch=The password and confirmation do not match.
|
||||
security_epasschars=The password cannot contain line breaks or null bytes.
|
||||
security_epassmode=Enter either a password or a PBKDF2 hash, not both.
|
||||
security_ehash=The PBKDF2 hash is invalid.
|
||||
security_ehashgen=The password hash command did not return a GRUB PBKDF2 hash.
|
||||
security_emkpasswd=The GRUB password hash command is not available. Install GRUB tools or paste a PBKDF2 hash.
|
||||
security_eunmanaged=The configured GRUB password script is not managed by Webmin and will not be overwritten.
|
||||
color_black=Black
|
||||
color_blue=Blue
|
||||
color_green=Green
|
||||
color_cyan=Cyan
|
||||
color_red=Red
|
||||
color_magenta=Magenta
|
||||
color_brown=Brown
|
||||
color_light-gray=Light gray
|
||||
color_dark-gray=Dark gray
|
||||
color_light-blue=Light blue
|
||||
color_light-green=Light green
|
||||
color_light-cyan=Light cyan
|
||||
color_light-red=Light red
|
||||
color_light-magenta=Light magenta
|
||||
color_yellow=Yellow
|
||||
color_white=White
|
||||
manual_title=Manual GRUB configuration
|
||||
manual_select=Edit config file:
|
||||
manual_ok=Edit
|
||||
manual_err=Failed to save GRUB file
|
||||
manual_efile=The selected file is not allowed for manual editing.
|
||||
manual_enofile=No GRUB files are configured for manual editing.
|
||||
manual_evalidate=The file failed validation: $1
|
||||
manual_ebls=The BLS entry must contain key/value lines and may contain comments or blank lines.
|
||||
manual_eblsline=Line $1 is not valid BLS key/value syntax.
|
||||
custom_title_new=Add Custom GRUB Entry
|
||||
custom_title_edit=Edit Custom GRUB Entry
|
||||
custom_header=Custom boot entry
|
||||
custom_add=Add new custom boot entry
|
||||
custom_entry_title=Menu title
|
||||
custom_entry_id=Entry ID
|
||||
custom_entry_body=GRUB commands
|
||||
custom_id_note=Optional. Use letters, numbers, dots, underscores, colons, plus signs, equals signs, commas, at signs, and hyphens only.
|
||||
custom_empty=No custom boot entries were found.
|
||||
custom_err=Failed to save custom GRUB entry
|
||||
custom_efile=No custom GRUB menu file is configured.
|
||||
custom_enofile=No custom GRUB menu file is configured.
|
||||
custom_eentry=Invalid custom boot entry.
|
||||
custom_eone=Select exactly one custom boot entry.
|
||||
custom_etitle=The menu title is required and cannot contain line breaks or null bytes.
|
||||
custom_eid=The entry ID contains invalid characters.
|
||||
custom_ebody=The GRUB commands contain invalid data.
|
||||
custom_evalidate=The GRUB script failed validation.
|
||||
custom_ebraces=The GRUB commands have unbalanced braces.
|
||||
custom_emove=The selected custom entry cannot be moved in that direction.
|
||||
generate_title=Regenerating GRUB menu
|
||||
generate_err=Failed to generate the GRUB menu
|
||||
generate_missing=The GRUB menu generation command is not available.
|
||||
generate_empty=The generated test menu was empty.
|
||||
generate_failed=The GRUB menu generation command failed without output.
|
||||
generate_evalidate=The generated test menu failed validation: $1
|
||||
generate_regenerating=Regenerating GRUB menu
|
||||
generate_check=Checking generated test menu
|
||||
generate_replace=Replacing generated menu
|
||||
generate_done=done
|
||||
generate_failed_status=failed
|
||||
generate_return=GRUB 2 module
|
||||
install_title=Install GRUB boot loader
|
||||
install_progress_title=Installing GRUB boot loader
|
||||
install_header=Boot loader installation
|
||||
install_command=Install command
|
||||
install_target=Install target
|
||||
install_efi_dir=EFI system directory
|
||||
install_platform=Platform target
|
||||
install_directory=GRUB module directory
|
||||
install_boot_directory=Boot directory
|
||||
install_bootloader_id=Boot loader ID
|
||||
install_options=Options
|
||||
install_boot_directory_enable=Pass boot directory to grub-install
|
||||
install_recheck=Probe devices again before installing
|
||||
install_removable=Install as removable EFI media
|
||||
install_no_nvram=Do not update EFI firmware boot variables
|
||||
install_force=Force EFI install even though it may not support Secure Boot
|
||||
install_confirm=Confirmation
|
||||
install_confirm_label=I understand that installing GRUB to the wrong target can make this system unbootable.
|
||||
install_submit=Install GRUB
|
||||
install_installing=Installing GRUB boot loader
|
||||
install_done=done
|
||||
install_failed_status=failed
|
||||
install_return=GRUB 2 module
|
||||
install_warn_modules=GRUB platform files for $1 were not found. Install the matching GRUB EFI/module package before installing the boot loader, or enter the module directory manually.
|
||||
install_err=Failed to install the GRUB boot loader
|
||||
install_ecmd=The GRUB boot loader install command is not available.
|
||||
install_etarget=Enter an absolute device path under /dev such as /dev/sda, or an EFI system directory.
|
||||
install_etarget_missing=Install target $1 does not exist.
|
||||
install_eefi=The EFI system directory must be an absolute path with safe characters.
|
||||
install_eefi_missing=EFI system directory $1 does not exist.
|
||||
install_eplatform=The platform target can only contain letters, numbers, underscores, and hyphens.
|
||||
install_eplatform_modules=GRUB platform files for $1 were not found. Install the matching GRUB EFI/module package or enter the module directory manually. Checked: $2
|
||||
install_edirectory=The GRUB module directory must be an absolute path with safe characters.
|
||||
install_edirectory_missing=GRUB module directory $1 does not exist.
|
||||
install_edirectory_modinfo=GRUB module directory $1 does not contain modinfo.sh.
|
||||
install_eboot_directory=The boot directory must be an absolute path with safe characters.
|
||||
install_eboot_directory_missing=Boot directory $1 does not exist.
|
||||
install_eboot_directory_required=Enter a boot directory, or clear the boot directory option.
|
||||
install_ebootloader=The boot loader ID can only contain letters, numbers, dots, underscores, plus signs, and hyphens.
|
||||
install_eoption=Invalid install option.
|
||||
install_econfirm=Confirm that you understand the risk before installing GRUB.
|
||||
install_failed=The GRUB boot loader install command failed without output.
|
||||
install_log_efi=EFI directory $1
|
||||
runtime_err=Failed to update GRUB boot selection
|
||||
runtime_eentry=Invalid boot entry.
|
||||
runtime_ecmd=The required GRUB command is not available.
|
||||
runtime_eselector=Unsafe or invalid GRUB boot entry selector.
|
||||
runtime_eaction=No GRUB boot action was selected.
|
||||
delete_enone=Select one or more boot menu entries to delete.
|
||||
delete_ecustom=Only custom menu entries from the configured custom file can be deleted here.
|
||||
acl_section_view=View permissions
|
||||
acl_section_change=Change permissions
|
||||
acl_section_admin=Administrative permissions
|
||||
acl_view=View GRUB configuration and boot entries
|
||||
acl_edit=Edit common GRUB defaults
|
||||
acl_security=Edit GRUB password protection
|
||||
acl_apply=Generate the GRUB menu
|
||||
acl_runtime=Set saved or one-time boot entries
|
||||
acl_manual=Manually edit allowed GRUB files
|
||||
acl_install=Install GRUB boot loader
|
||||
acl_backup=Include GRUB files in backups
|
||||
acl_ecannot=You are not allowed to perform this GRUB 2 action.
|
||||
eacl_np=Access denied:
|
||||
eacl_pview=view GRUB configuration
|
||||
eacl_pedit=edit GRUB defaults
|
||||
eacl_psecurity=edit GRUB password protection
|
||||
eacl_papply=generate the GRUB menu
|
||||
eacl_pruntime=change GRUB boot selection
|
||||
eacl_pmanual=manually edit GRUB files
|
||||
eacl_pinstall=install GRUB boot loader
|
||||
eacl_pbackup=backup GRUB files
|
||||
log_defaults=Modified GRUB default settings
|
||||
log_bls_args=Updated existing BLS kernel options
|
||||
log_theme=Modified GRUB theme and appearance
|
||||
log_security=Modified GRUB password protection
|
||||
log_manual=Modified GRUB file $1
|
||||
log_custom_create=Created custom GRUB entry $1
|
||||
log_custom_modify=Modified custom GRUB entry $1
|
||||
log_custom_move=Moved custom GRUB entry $1
|
||||
log_generate=Generated GRUB menu $1
|
||||
log_install=Installed GRUB boot loader to $1
|
||||
log_default=Set saved GRUB default to $1
|
||||
log_once=Set next GRUB boot to $1
|
||||
log_custom_delete=Deleted $1 custom GRUB menu entries
|
||||
__norefs=1
|
||||
68
grub2/log_parser.pl
Normal file
68
grub2/log_parser.pl
Normal file
@@ -0,0 +1,68 @@
|
||||
# log_parser.pl
|
||||
# Functions for parsing this module's logs.
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
do 'grub2-lib.pl';
|
||||
|
||||
our %text;
|
||||
|
||||
# parse_webmin_log(user, script, action, type, object, ¶ms, [long])
|
||||
# Converts logged information from this module into human-readable form.
|
||||
sub parse_webmin_log
|
||||
{
|
||||
my ($user, $script, $action, $type, $object, $p, $long) = @_;
|
||||
# Simple module-wide actions do not need an object value.
|
||||
if ($action eq 'defaults') {
|
||||
return $text{'log_defaults'};
|
||||
}
|
||||
if ($action eq 'bls_args') {
|
||||
return $text{'log_bls_args'};
|
||||
}
|
||||
if ($action eq 'theme') {
|
||||
return $text{'log_theme'};
|
||||
}
|
||||
if ($action eq 'security') {
|
||||
return $text{'log_security'};
|
||||
}
|
||||
# Object-bearing actions display paths, selectors, or titles as literals.
|
||||
if ($action eq 'manual') {
|
||||
return &text('log_manual', &log_value($object));
|
||||
}
|
||||
if ($action eq 'custom_create') {
|
||||
return &text('log_custom_create', &log_value($object));
|
||||
}
|
||||
if ($action eq 'custom_modify') {
|
||||
return &text('log_custom_modify', &log_value($object));
|
||||
}
|
||||
if ($action eq 'custom_move') {
|
||||
return &text('log_custom_move', &log_value($object));
|
||||
}
|
||||
if ($action eq 'generate') {
|
||||
return &text('log_generate', &log_value($object));
|
||||
}
|
||||
if ($action eq 'install') {
|
||||
return &text('log_install', &log_value($object));
|
||||
}
|
||||
if ($action eq 'default') {
|
||||
return &text('log_default', &log_value($object));
|
||||
}
|
||||
if ($action eq 'once') {
|
||||
return &text('log_once', &log_value($object));
|
||||
}
|
||||
if ($action eq 'custom_delete') {
|
||||
return &text('log_custom_delete', $object || 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
# log_value(value)
|
||||
# Returns a styled inline value for log descriptions.
|
||||
sub log_value
|
||||
{
|
||||
my ($value) = @_;
|
||||
$value = '' if (!defined($value));
|
||||
return &ui_tag('tt', &html_escape($value));
|
||||
}
|
||||
|
||||
1;
|
||||
7
grub2/module.info
Normal file
7
grub2/module.info
Normal file
@@ -0,0 +1,7 @@
|
||||
name=GRUB 2
|
||||
desc=GRUB 2 Boot Loader
|
||||
category=hardware
|
||||
os_support=*-linux
|
||||
longdesc=Configure GRUB 2 boot loader defaults, inspect generated menu entries, and update boot loader configuration safely.
|
||||
rpm_recommends=grub2-tools
|
||||
deb_recommends=grub2-common
|
||||
22
grub2/reboot_once.cgi
Executable file
22
grub2/reboot_once.cgi
Executable file
@@ -0,0 +1,22 @@
|
||||
#!/usr/local/bin/perl
|
||||
# Set the one-time next GRUB 2 boot entry.
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
require './grub2-lib.pl'; ## no critic
|
||||
|
||||
our (%in, %text);
|
||||
|
||||
&ReadParse();
|
||||
&error_setup($text{'runtime_err'});
|
||||
&grub2_assert_acl('runtime');
|
||||
|
||||
# Runtime commands operate on the parsed generated menu index shown on index.cgi.
|
||||
my $entry = &grub2_entry_by_index($in{'idx'});
|
||||
&error($text{'runtime_eentry'}) if (!$entry);
|
||||
# The helper validates the selector before invoking grub-reboot.
|
||||
my $err = &grub2_run_entry_command('reboot_once_cmd', $entry);
|
||||
&error($err) if ($err);
|
||||
my $selector = &grub2_entry_selector($entry);
|
||||
&webmin_log("once", undef, $selector);
|
||||
&redirect("");
|
||||
31
grub2/save_custom.cgi
Executable file
31
grub2/save_custom.cgi
Executable file
@@ -0,0 +1,31 @@
|
||||
#!/usr/local/bin/perl
|
||||
# Save a custom GRUB 2 menu entry.
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
require './grub2-lib.pl'; ## no critic
|
||||
|
||||
our (%in, %text);
|
||||
|
||||
&ReadParse();
|
||||
&error_setup($text{'custom_err'});
|
||||
&grub2_assert_acl('manual');
|
||||
|
||||
# A missing index means create; a present one must address a parsed entry.
|
||||
my $idx = defined($in{'idx'}) && $in{'idx'} ne '' ? $in{'idx'} : undef;
|
||||
if (defined($idx) && $idx !~ /^\d+\z/) {
|
||||
&error($text{'custom_eentry'});
|
||||
}
|
||||
# Normalize absent fields before validation so empty strings mean intentional.
|
||||
foreach my $field (qw(title id body)) {
|
||||
$in{$field} = "" if (!defined($in{$field}));
|
||||
}
|
||||
$in{'body'} =~ s/\r//g;
|
||||
# The library validates GRUB script balance before rewriting the custom file.
|
||||
my $err = &grub2_save_custom_entry($idx, $in{'title'}, $in{'id'},
|
||||
$in{'body'});
|
||||
&error($err) if ($err);
|
||||
&grub2_mark_regenerate_needed();
|
||||
&webmin_log(defined($idx) ? "custom_modify" : "custom_create",
|
||||
undef, $in{'title'});
|
||||
&redirect("index.cgi?mode=custom");
|
||||
215
grub2/save_defaults.cgi
Executable file
215
grub2/save_defaults.cgi
Executable file
@@ -0,0 +1,215 @@
|
||||
#!/usr/local/bin/perl
|
||||
# Save common GRUB 2 defaults.
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
require './grub2-lib.pl'; ## no critic
|
||||
|
||||
our (%in, %text);
|
||||
|
||||
&ReadParse();
|
||||
&error_setup($text{'defaults_err'});
|
||||
&grub2_assert_acl('edit');
|
||||
|
||||
# Capture both the current defaults file and generated entries for validation.
|
||||
my $current = &read_grub_defaults();
|
||||
my $current_values = $current->{'values'};
|
||||
my @entries = &grub2_boot_entries();
|
||||
my %updates;
|
||||
# Default entries must come from the selector, except for the preserved value.
|
||||
$in{'default'} = '' if (!defined($in{'default'}));
|
||||
$in{'default'} =~ /[\r\n\0]/ && &error($text{'defaults_edefault'});
|
||||
&error($text{'defaults_edefault_choice'})
|
||||
if (!&valid_default_entry_value(
|
||||
$in{'default'}, $current_values->{'GRUB_DEFAULT'}, \@entries));
|
||||
$updates{'GRUB_DEFAULT'} = $in{'default'} if ($in{'default'} ne '');
|
||||
|
||||
my %styles = map { $_ => 1 } ('', qw(menu hidden countdown));
|
||||
&error($text{'defaults_etimeout_style'})
|
||||
if (!defined($in{'timeout_style'}) || !$styles{$in{'timeout_style'}});
|
||||
$updates{'GRUB_TIMEOUT_STYLE'} =
|
||||
$in{'timeout_style'} eq '' ? undef : $in{'timeout_style'};
|
||||
|
||||
# Empty timeout removes the local override; otherwise GRUB accepts -1 or more.
|
||||
if (defined($in{'timeout'}) && $in{'timeout'} ne '') {
|
||||
$in{'timeout'} =~ /^-?\d+\z/ && $in{'timeout'} >= -1
|
||||
|| &error($text{'defaults_etimeout'});
|
||||
$updates{'GRUB_TIMEOUT'} = $in{'timeout'};
|
||||
}
|
||||
else {
|
||||
$updates{'GRUB_TIMEOUT'} = undef;
|
||||
}
|
||||
|
||||
# Kernel command-line values are single-line shell assignment values.
|
||||
foreach my $field (
|
||||
[ 'cmdline_default', 'GRUB_CMDLINE_LINUX_DEFAULT',
|
||||
$text{'defaults_cmdline_default'} ],
|
||||
[ 'cmdline', 'GRUB_CMDLINE_LINUX', $text{'defaults_cmdline'} ],
|
||||
)
|
||||
{
|
||||
my ($input, $key, $label) = @$field;
|
||||
$in{$input} = '' if (!defined($in{$input}));
|
||||
$in{$input} =~ /[\r\n\0]/ && &error(&text('defaults_ecmdline', $label));
|
||||
$updates{$key} = $in{$input} eq '' ? undef : $in{$input};
|
||||
}
|
||||
|
||||
# Boolean GRUB defaults keep their tri-state UI: inherit, true, or false.
|
||||
foreach my $field (
|
||||
[ 'disable_recovery', 'GRUB_DISABLE_RECOVERY',
|
||||
$text{'defaults_disable_recovery'} ],
|
||||
[ 'disable_os_prober', 'GRUB_DISABLE_OS_PROBER',
|
||||
$text{'defaults_disable_os_prober'} ],
|
||||
)
|
||||
{
|
||||
my ($input, $key, $label) = @$field;
|
||||
$in{$input} = '' if (!defined($in{$input}));
|
||||
if ($in{$input} eq '') {
|
||||
$updates{$key} = undef;
|
||||
}
|
||||
elsif ($in{$input} =~ /^(true|false)\z/) {
|
||||
$updates{$key} = $in{$input};
|
||||
}
|
||||
else {
|
||||
&error(&text('defaults_ebool', $label));
|
||||
}
|
||||
}
|
||||
|
||||
my $err = &save_grub_defaults_values(\%updates);
|
||||
&error(&text('manual_evalidate', $err)) if ($err);
|
||||
|
||||
# BLS rescue entries are real files, so restore them before changing BLS args.
|
||||
my $disable_bls_rescue =
|
||||
(($updates{'GRUB_DISABLE_RECOVERY'} || '') eq 'true') ? 1 : 0;
|
||||
my $can_handle_bls_rescue =
|
||||
&grub2_has_bls_rescue_entries(\@entries) ||
|
||||
&grub2_disabled_bls_rescue_files();
|
||||
my $bls_rescue_err;
|
||||
if (!$disable_bls_rescue) {
|
||||
$bls_rescue_err = &grub2_set_bls_rescue_disabled(0);
|
||||
# Refresh entry data after restores so grubby sees current BLS files.
|
||||
@entries = &grub2_boot_entries() if (!$bls_rescue_err);
|
||||
}
|
||||
|
||||
# On BLS systems, grubby applies kernel arg deltas to existing boot entries.
|
||||
my %bls_args_updated;
|
||||
my $bls_err;
|
||||
if (&grub2_bls_update_available(\@entries)) {
|
||||
my @locked_bls_files = &lock_bls_update_files(
|
||||
$current_values, \%updates, \@entries);
|
||||
($bls_err, %bls_args_updated) = &update_bls_kernel_args(
|
||||
$current_values, \%updates, \@entries);
|
||||
&unlock_bls_update_files(@locked_bls_files);
|
||||
}
|
||||
if (!$bls_err && !$bls_rescue_err && $disable_bls_rescue) {
|
||||
# Hide rescue files after grubby has had a chance to update normal entries.
|
||||
$bls_rescue_err = &grub2_set_bls_rescue_disabled(1, \@entries);
|
||||
}
|
||||
$bls_args_updated{'GRUB_DISABLE_RECOVERY'} = 1
|
||||
if (!$bls_rescue_err && $can_handle_bls_rescue &&
|
||||
!&grub2_has_non_bls_recovery_entries(\@entries));
|
||||
&grub2_mark_regenerate_needed()
|
||||
if (&grub2_defaults_updates_need_generate(
|
||||
$current_values, \%updates, \%bls_args_updated));
|
||||
&webmin_log("defaults");
|
||||
&error($bls_err) if ($bls_err);
|
||||
&error($bls_rescue_err) if ($bls_rescue_err);
|
||||
&redirect("index.cgi");
|
||||
|
||||
# valid_default_entry_value(value, current-value, &entries)
|
||||
# Returns true if a posted default entry came from the detected selector.
|
||||
sub valid_default_entry_value
|
||||
{
|
||||
my ($value, $current, $entries) = @_;
|
||||
return 1 if (!defined($value) || $value eq '');
|
||||
$current = '0' if (!defined($current) || $current eq '');
|
||||
return 1 if ($value eq 'saved');
|
||||
return 1 if ($value eq $current);
|
||||
foreach my $entry (@$entries) {
|
||||
my $selector = &grub2_entry_selector($entry);
|
||||
return 1 if (defined($selector) && $selector eq $value);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
# update_bls_kernel_args(&old-values, &updates, &entries)
|
||||
# Applies changed kernel option defaults to existing BLS entries.
|
||||
sub update_bls_kernel_args
|
||||
{
|
||||
my ($old_values, $updates, $entries) = @_;
|
||||
my %updated;
|
||||
foreach my $field (
|
||||
[ 'GRUB_CMDLINE_LINUX', undef ],
|
||||
[ 'GRUB_CMDLINE_LINUX_DEFAULT',
|
||||
[ &grub2_bls_kernel_arg_targets($entries, 0) ] ],
|
||||
)
|
||||
{
|
||||
my ($key, $targets) = @$field;
|
||||
my ($remove, $add) =
|
||||
&grub2_kernel_args_delta($old_values->{$key}, $updates->{$key});
|
||||
# No delta means this defaults field can be ignored for BLS updates.
|
||||
next if (!@$remove && !@$add);
|
||||
next if (defined($targets) && !@$targets);
|
||||
my $err = &grub2_update_bls_kernel_args(
|
||||
$old_values->{$key}, $updates->{$key}, $targets);
|
||||
if ($err) {
|
||||
# A partial grubby failure falls back to regeneration when needed.
|
||||
&grub2_mark_regenerate_needed()
|
||||
if (&grub2_defaults_updates_need_generate(
|
||||
$old_values, $updates, \%updated));
|
||||
return ($err, %updated);
|
||||
}
|
||||
$updated{$key} = 1;
|
||||
}
|
||||
return (undef, %updated);
|
||||
}
|
||||
|
||||
# lock_bls_update_files(&old-values, &updates, &entries)
|
||||
# Locks files that grubby may change so Webmin can diff them.
|
||||
sub lock_bls_update_files
|
||||
{
|
||||
my ($old_values, $updates, $entries) = @_;
|
||||
my %lock_all = &kernel_args_changed(
|
||||
$old_values->{'GRUB_CMDLINE_LINUX'}, $updates->{'GRUB_CMDLINE_LINUX'}) ?
|
||||
( all => 1 ) : ();
|
||||
my %lock_default = &kernel_args_changed(
|
||||
$old_values->{'GRUB_CMDLINE_LINUX_DEFAULT'},
|
||||
$updates->{'GRUB_CMDLINE_LINUX_DEFAULT'}) ? ( default => 1 ) : ();
|
||||
return () if (!%lock_all && !%lock_default);
|
||||
my (@locked, %seen);
|
||||
# kernelopts-based entries may be updated through grubenv instead of .conf files.
|
||||
if (grep { &grub2_entry_uses_kernelopts($_) } @$entries) {
|
||||
my $file = &grub2_config_value('grubenv_file') || '';
|
||||
if ($file ne '' && -e $file && !$seen{$file}++) {
|
||||
&lock_file($file);
|
||||
push(@locked, $file);
|
||||
}
|
||||
}
|
||||
foreach my $entry (@$entries) {
|
||||
next if (($entry->{'source'} || '') ne 'bls');
|
||||
# Default-only changes skip rescue entries, matching the edit form wording.
|
||||
next if (!%lock_all && &grub2_entry_is_bls_rescue($entry));
|
||||
my $file = $entry->{'file'};
|
||||
next if (!defined($file) || $file eq '' || $seen{$file}++);
|
||||
&lock_file($file);
|
||||
push(@locked, $file);
|
||||
}
|
||||
return @locked;
|
||||
}
|
||||
|
||||
# unlock_bls_update_files(files...)
|
||||
# Unlocks files after grubby has run.
|
||||
sub unlock_bls_update_files
|
||||
{
|
||||
foreach my $file (reverse @_) {
|
||||
&unlock_file($file);
|
||||
}
|
||||
}
|
||||
|
||||
# kernel_args_changed(old-args, new-args)
|
||||
# Returns true when a kernel-args delta would be applied.
|
||||
sub kernel_args_changed
|
||||
{
|
||||
my ($old_args, $new_args) = @_;
|
||||
my ($remove, $add) = &grub2_kernel_args_delta($old_args, $new_args);
|
||||
return @$remove || @$add;
|
||||
}
|
||||
25
grub2/save_manual.cgi
Executable file
25
grub2/save_manual.cgi
Executable file
@@ -0,0 +1,25 @@
|
||||
#!/usr/local/bin/perl
|
||||
# Save a manually edited allowlisted GRUB 2 file.
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
require './grub2-lib.pl'; ## no critic
|
||||
|
||||
our (%in, %text);
|
||||
|
||||
&ReadParseMime();
|
||||
&error_setup($text{'manual_err'});
|
||||
&grub2_assert_acl('manual');
|
||||
|
||||
# Re-check the allowlist on save; the form value is not trusted.
|
||||
my $file = $in{'file'} || '';
|
||||
&grub2_manual_file($file) || &error($text{'manual_efile'});
|
||||
$in{'data'} = '' if (!defined($in{'data'}));
|
||||
$in{'data'} =~ s/\r//g;
|
||||
|
||||
# Each file type gets its own validator before the locked write happens.
|
||||
my $err = &save_manual_grub_file($file, $in{'data'});
|
||||
&error(&text('manual_evalidate', $err)) if ($err);
|
||||
&grub2_mark_regenerate_needed();
|
||||
&webmin_log("manual", undef, $file);
|
||||
&redirect("");
|
||||
36
grub2/save_security.cgi
Executable file
36
grub2/save_security.cgi
Executable file
@@ -0,0 +1,36 @@
|
||||
#!/usr/local/bin/perl
|
||||
# Save GRUB 2 password protection settings.
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
require './grub2-lib.pl'; ## no critic
|
||||
|
||||
our (%in, %text);
|
||||
|
||||
&ReadParse();
|
||||
&error_setup($text{'security_err'});
|
||||
&grub2_assert_acl('security');
|
||||
|
||||
# The enable flag is deliberately boolean; all other fields normalize below.
|
||||
defined($in{'enabled'}) && $in{'enabled'} =~ /^[01]\z/ ||
|
||||
&error($text{'security_err'});
|
||||
foreach my $field (qw(user password password2 hash)) {
|
||||
$in{$field} = "" if (!defined($in{$field}));
|
||||
}
|
||||
$in{'hash'} =~ s/^\s+|\s+\z//g;
|
||||
|
||||
# Read current state so disabling an existing script still triggers regenerate.
|
||||
my $current = &grub2_read_security_config();
|
||||
my $err = &grub2_save_security_config({
|
||||
'enabled' => $in{'enabled'},
|
||||
'user' => $in{'user'},
|
||||
'password' => $in{'password'},
|
||||
'password2' => $in{'password2'},
|
||||
'hash' => $in{'hash'},
|
||||
});
|
||||
&error($err) if ($err);
|
||||
# A changed password script is included by grub-mkconfig, so refresh the menu.
|
||||
&grub2_mark_regenerate_needed()
|
||||
if ($in{'enabled'} || $current->{'exists'});
|
||||
&webmin_log("security", undef, $in{'enabled'} ? "enabled" : "disabled");
|
||||
&redirect("index.cgi");
|
||||
119
grub2/save_theme.cgi
Executable file
119
grub2/save_theme.cgi
Executable file
@@ -0,0 +1,119 @@
|
||||
#!/usr/local/bin/perl
|
||||
# Save GRUB 2 theme and appearance settings.
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
require './grub2-lib.pl'; ## no critic
|
||||
|
||||
our (%in, %text);
|
||||
|
||||
&ReadParse();
|
||||
&error_setup($text{'theme_err'});
|
||||
&grub2_assert_acl('edit');
|
||||
|
||||
my $parsed = &read_grub_defaults();
|
||||
my $current_values = $parsed->{'values'};
|
||||
my %updates;
|
||||
|
||||
# Terminal output is constrained because themes require graphical output.
|
||||
my %terminal_outputs = map { $_ => 1 }
|
||||
('', 'console', 'gfxterm', 'gfxterm console', 'serial');
|
||||
$in{'terminal_output'} = '' if (!defined($in{'terminal_output'}));
|
||||
&error($text{'defaults_eterminal_output'})
|
||||
if (!$terminal_outputs{$in{'terminal_output'}});
|
||||
$updates{'GRUB_TERMINAL_OUTPUT'} =
|
||||
$in{'terminal_output'} eq '' ? undef : $in{'terminal_output'};
|
||||
|
||||
# Graphics mode is a small GRUB grammar, not a general shell value.
|
||||
$in{'gfxmode'} = '' if (!defined($in{'gfxmode'}));
|
||||
my $gerr = &grub2_validate_gfxmode($in{'gfxmode'});
|
||||
&error($gerr) if ($gerr);
|
||||
$updates{'GRUB_GFXMODE'} = $in{'gfxmode'} eq '' ? undef : $in{'gfxmode'};
|
||||
|
||||
# Theme mode decides whether a source is installed, kept, or explicitly unset.
|
||||
my %theme_modes = map { $_ => 1 } qw(keep install clear);
|
||||
$in{'theme_mode'} = 'keep' if (!defined($in{'theme_mode'}));
|
||||
&error($text{'defaults_etheme_mode'}) if (!$theme_modes{$in{'theme_mode'}});
|
||||
if ($in{'theme_mode'} eq 'install') {
|
||||
# Refuse a graphical theme if the pending terminal output is console-only.
|
||||
my $requested_terminal_output =
|
||||
defined($updates{'GRUB_TERMINAL_OUTPUT'}) ?
|
||||
$updates{'GRUB_TERMINAL_OUTPUT'} :
|
||||
$current_values->{'GRUB_TERMINAL_OUTPUT'};
|
||||
if (defined($requested_terminal_output) &&
|
||||
$requested_terminal_output eq 'console') {
|
||||
&error($text{'defaults_etheme_terminal'});
|
||||
}
|
||||
my ($theme, $terr) = &grub2_install_theme_source($in{'theme_source'});
|
||||
&error($terr) if ($terr);
|
||||
$updates{'GRUB_THEME'} = $theme;
|
||||
}
|
||||
elsif ($in{'theme_mode'} eq 'clear') {
|
||||
$updates{'GRUB_THEME'} = undef;
|
||||
}
|
||||
|
||||
# Background images are copied below the configured GRUB boot tree.
|
||||
$in{'background'} = '' if (!defined($in{'background'}));
|
||||
if ($in{'background'} eq '') {
|
||||
$updates{'GRUB_BACKGROUND'} = undef;
|
||||
}
|
||||
else {
|
||||
my ($background, $berr) =
|
||||
&grub2_install_background_source($in{'background'});
|
||||
&error($berr) if ($berr);
|
||||
$updates{'GRUB_BACKGROUND'} = $background;
|
||||
}
|
||||
|
||||
# Color fields use a mode selector so the default/unset state stays explicit.
|
||||
foreach my $field (
|
||||
[ 'color_normal', 'GRUB_COLOR_NORMAL',
|
||||
$text{'defaults_color_normal'} ],
|
||||
[ 'color_highlight', 'GRUB_COLOR_HIGHLIGHT',
|
||||
$text{'defaults_color_highlight'} ],
|
||||
)
|
||||
{
|
||||
my ($input, $key, $label) = @$field;
|
||||
my $mode = $in{$input.'_mode'} || 'default';
|
||||
my $fg = $in{$input.'_fg'} || '';
|
||||
my $bg = $in{$input.'_bg'} || '';
|
||||
my %colors = map { $_ => 1 } &grub2_color_names();
|
||||
if ($mode eq 'default') {
|
||||
$updates{$key} = undef;
|
||||
}
|
||||
elsif ($mode eq 'set' && $colors{$fg} && $colors{$bg}) {
|
||||
$updates{$key} = $fg.'/'.$bg;
|
||||
}
|
||||
else {
|
||||
&error(&text('defaults_ecolor', $label));
|
||||
}
|
||||
}
|
||||
|
||||
my $theme = exists($updates{'GRUB_THEME'}) ?
|
||||
$updates{'GRUB_THEME'} : $current_values->{'GRUB_THEME'};
|
||||
my $terminal_output = exists($updates{'GRUB_TERMINAL_OUTPUT'}) ?
|
||||
$updates{'GRUB_TERMINAL_OUTPUT'} :
|
||||
$current_values->{'GRUB_TERMINAL_OUTPUT'};
|
||||
# Check the final combined state too, because either field may be unchanged.
|
||||
if (defined($theme) && $theme ne '' &&
|
||||
defined($terminal_output) && $terminal_output eq 'console') {
|
||||
&error($text{'defaults_etheme_terminal'});
|
||||
}
|
||||
|
||||
# Keep the generator script while any color override exists or used to exist.
|
||||
my $need_color_script =
|
||||
(defined($updates{'GRUB_COLOR_NORMAL'}) &&
|
||||
$updates{'GRUB_COLOR_NORMAL'} ne '') ||
|
||||
(defined($updates{'GRUB_COLOR_HIGHLIGHT'}) &&
|
||||
$updates{'GRUB_COLOR_HIGHLIGHT'} ne '') ||
|
||||
-e &grub2_color_file();
|
||||
|
||||
my $err = &save_grub_defaults_values(\%updates);
|
||||
&error(&text('manual_evalidate', $err)) if ($err);
|
||||
if ($need_color_script) {
|
||||
# The color script reads /etc/default/grub at generation time.
|
||||
$err = &grub2_save_color_script();
|
||||
&error(&text('manual_evalidate', $err)) if ($err);
|
||||
}
|
||||
&grub2_mark_regenerate_needed();
|
||||
&webmin_log("theme");
|
||||
&redirect("index.cgi");
|
||||
22
grub2/set_default.cgi
Executable file
22
grub2/set_default.cgi
Executable file
@@ -0,0 +1,22 @@
|
||||
#!/usr/local/bin/perl
|
||||
# Set the saved GRUB 2 default boot entry.
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
require './grub2-lib.pl'; ## no critic
|
||||
|
||||
our (%in, %text);
|
||||
|
||||
&ReadParse();
|
||||
&error_setup($text{'runtime_err'});
|
||||
&grub2_assert_acl('runtime');
|
||||
|
||||
# Runtime commands operate on the parsed generated menu index shown on index.cgi.
|
||||
my $entry = &grub2_entry_by_index($in{'idx'});
|
||||
&error($text{'runtime_eentry'}) if (!$entry);
|
||||
# The helper validates the selector before invoking grub-set-default.
|
||||
my $err = &grub2_run_entry_command('set_default_cmd', $entry);
|
||||
&error($err) if ($err);
|
||||
my $selector = &grub2_entry_selector($entry);
|
||||
&webmin_log("default", undef, $selector);
|
||||
&redirect("");
|
||||
252
grub2/status.cgi
Executable file
252
grub2/status.cgi
Executable file
@@ -0,0 +1,252 @@
|
||||
#!/usr/local/bin/perl
|
||||
# Display GRUB 2 configuration and runtime status.
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
require './grub2-lib.pl'; ## no critic
|
||||
|
||||
our (%text);
|
||||
|
||||
&error_setup($text{'acl_ecannot'});
|
||||
&grub2_assert_acl('view');
|
||||
|
||||
my %access = &grub2_effective_acl();
|
||||
&ui_print_header(undef, $text{'status_title'}, "");
|
||||
|
||||
# Missing-install output mirrors index.cgi but keeps this page read-only.
|
||||
if (!&grub2_any_installed()) {
|
||||
print &ui_alert($text{'index_missing'}, 'warning');
|
||||
foreach my $issue (&grub2_install_issues()) {
|
||||
print &ui_div(&text('index_missing_detail',
|
||||
&ui_tag('tt', &html_escape($issue))));
|
||||
}
|
||||
&ui_print_footer("index.cgi", $text{'index_return'});
|
||||
exit;
|
||||
}
|
||||
|
||||
foreach my $warning (&grub2_status_warnings()) {
|
||||
print &ui_alert($warning, 'warning');
|
||||
}
|
||||
|
||||
print &ui_div($text{'index_status_desc'});
|
||||
|
||||
# The summary uses defaults plus grubenv because GRUB stores both persistently.
|
||||
my $parsed = &read_grub_defaults();
|
||||
my %env = &grub2_read_env();
|
||||
|
||||
&print_summary($parsed);
|
||||
&print_boot_selection($parsed, \%env);
|
||||
&print_security_status();
|
||||
&print_theme_status($parsed);
|
||||
|
||||
&ui_print_footer("index.cgi", $text{'index_return'});
|
||||
|
||||
# print_summary(&parsed-defaults)
|
||||
# Outputs a compact summary of important GRUB paths, commands, and defaults.
|
||||
sub print_summary
|
||||
{
|
||||
my ($parsed) = @_;
|
||||
my $values = $parsed->{'values'};
|
||||
my @entries = &grub2_boot_entries();
|
||||
print &ui_table_start($text{'index_summary'}, "width=100%", 2);
|
||||
# Start with path and command discovery so support issues are visible first.
|
||||
print &status_table_row($text{'index_boot_mode'}, "boot_mode",
|
||||
&boot_mode_cell());
|
||||
print &status_table_row($text{'index_secure_boot'}, "secure_boot",
|
||||
&secure_boot_cell());
|
||||
print &status_table_row($text{'index_default_file'}, "default_file",
|
||||
&path_cell(&grub2_config_value('default_file')));
|
||||
print &status_table_row($text{'index_grub_cfg'}, "grub_cfg",
|
||||
&path_cell(&grub2_config_value('grub_cfg')));
|
||||
print &status_table_row($text{'index_grub_dir'}, "grub_dir",
|
||||
&path_cell(&grub2_config_value('grub_dir')));
|
||||
print &status_table_row($text{'index_bls_dir'}, "bls_dir",
|
||||
&path_cell(&grub2_config_value('bls_dir')));
|
||||
print &status_table_row($text{'index_mkconfig'}, "mkconfig",
|
||||
&command_cell('mkconfig_cmd'));
|
||||
print &status_table_row($text{'index_install_cmd'}, "install_cmd",
|
||||
&command_cell('install_cmd'));
|
||||
print &ui_table_hr();
|
||||
# Defaults below the separator mirror the editable defaults page.
|
||||
print &status_table_row($text{'index_entries'}, "entries",
|
||||
&text('index_entry_count', scalar(@entries)));
|
||||
print &status_table_row($text{'index_kernel_options_source'},
|
||||
"kernelopts_source",
|
||||
&value_cell(&grub2_kernel_options_source_text(\@entries)));
|
||||
foreach my $pair (
|
||||
[ 'GRUB_TIMEOUT_STYLE', $text{'defaults_timeout_style'}, "timeout_style" ],
|
||||
[ 'GRUB_TIMEOUT', $text{'defaults_timeout'}, "timeout" ],
|
||||
[ 'GRUB_CMDLINE_LINUX_DEFAULT', $text{'defaults_cmdline_default'},
|
||||
"cmdline_default" ],
|
||||
[ 'GRUB_CMDLINE_LINUX', $text{'defaults_cmdline'}, "cmdline" ],
|
||||
[ 'GRUB_DISABLE_RECOVERY', $text{'defaults_disable_recovery'},
|
||||
"disable_recovery" ],
|
||||
[ 'GRUB_DISABLE_OS_PROBER', $text{'defaults_disable_os_prober'},
|
||||
"disable_os_prober" ],
|
||||
)
|
||||
{
|
||||
my ($key, $label, $help) = @$pair;
|
||||
print &status_table_row($label, $help, &literal_cell($values->{$key}));
|
||||
}
|
||||
print &ui_table_end();
|
||||
}
|
||||
|
||||
# print_theme_status(&parsed-defaults)
|
||||
# Outputs theme and graphical menu appearance settings.
|
||||
sub print_theme_status
|
||||
{
|
||||
my ($parsed) = @_;
|
||||
my $values = $parsed->{'values'};
|
||||
print &ui_hidden_table_start($text{'defaults_theme_header'}, "width=100%", 2,
|
||||
"theme", 0);
|
||||
foreach my $pair (
|
||||
[ 'GRUB_TERMINAL_OUTPUT', $text{'defaults_terminal_output'},
|
||||
"terminal_output" ],
|
||||
[ 'GRUB_GFXMODE', $text{'defaults_gfxmode'}, "gfxmode" ],
|
||||
[ 'GRUB_THEME', $text{'defaults_theme'}, "theme" ],
|
||||
[ 'GRUB_BACKGROUND', $text{'defaults_background'}, "background" ],
|
||||
[ 'GRUB_COLOR_NORMAL', $text{'defaults_color_normal'}, "color_normal" ],
|
||||
[ 'GRUB_COLOR_HIGHLIGHT', $text{'defaults_color_highlight'},
|
||||
"color_highlight" ],
|
||||
)
|
||||
{
|
||||
my ($key, $label, $help) = @$pair;
|
||||
print &status_table_row($label, $help, &literal_cell($values->{$key}));
|
||||
}
|
||||
print &ui_hidden_table_end("theme");
|
||||
}
|
||||
|
||||
# print_boot_selection(&parsed-defaults, &env)
|
||||
# Outputs saved and one-time boot selection state.
|
||||
sub print_boot_selection
|
||||
{
|
||||
my ($parsed, $env) = @_;
|
||||
print &ui_hidden_table_start($text{'index_boot_selection'}, "width=100%", 2,
|
||||
"boot_selection", 0);
|
||||
print &status_table_row($text{'defaults_default'}, "default",
|
||||
&literal_cell($parsed->{'values'}->{'GRUB_DEFAULT'}));
|
||||
print &status_table_row($text{'index_saved_entry'}, "saved_entry",
|
||||
&literal_cell($env->{'saved_entry'}));
|
||||
print &status_table_row($text{'index_next_entry'}, "next_entry",
|
||||
&literal_cell($env->{'next_entry'}));
|
||||
print &status_table_row($text{'index_env'}, "grubenv",
|
||||
&path_cell(&grub2_config_value('grubenv_file')));
|
||||
print &ui_hidden_table_end("boot_selection");
|
||||
}
|
||||
|
||||
# print_security_status()
|
||||
# Outputs Webmin-managed GRUB password protection state.
|
||||
sub print_security_status
|
||||
{
|
||||
my $state = &grub2_read_security_config();
|
||||
print &ui_alert($text{'security_unmanaged'}, 'warning')
|
||||
if ($state->{'exists'} && !$state->{'managed'});
|
||||
print &ui_hidden_table_start($text{'security_header'}, "width=100%", 2,
|
||||
"security", 0);
|
||||
# Password hash contents are never displayed, only whether one is configured.
|
||||
print &status_table_row($text{'index_security_state'}, "security_current",
|
||||
&security_state_cell($state));
|
||||
print &status_table_row($text{'index_security_user'}, "security_user",
|
||||
$state->{'enabled'} ? &html_escape($state->{'user'}) :
|
||||
$text{'index_not_set'});
|
||||
print &status_table_row($text{'index_security_hash'}, "security_hash",
|
||||
$state->{'hash'} ? $text{'index_security_hash_set'} :
|
||||
$text{'index_security_hash_missing'});
|
||||
print &status_table_row($text{'index_security_file'}, "security_file",
|
||||
&path_cell($state->{'file'}));
|
||||
print &status_table_row($text{'index_security_mkpasswd'}, "security_mkpasswd",
|
||||
&command_cell('mkpasswd_cmd'));
|
||||
print &ui_hidden_table_end("security");
|
||||
}
|
||||
|
||||
# status_table_row(label, help, value)
|
||||
# Returns a standard status table row with contextual help on the label.
|
||||
sub status_table_row
|
||||
{
|
||||
my ($label, $help, $value) = @_;
|
||||
return &ui_table_row(&hlink($label, $help), $value);
|
||||
}
|
||||
|
||||
# path_cell(path)
|
||||
# Returns escaped path display HTML with missing-state text.
|
||||
sub path_cell
|
||||
{
|
||||
my ($path) = @_;
|
||||
return $text{'index_not_set'} if (!defined($path) || $path eq '');
|
||||
my $html = &manual_path_link($path, &ui_tag('tt', &html_escape($path)));
|
||||
return -e $path ? $html : $html.' '.$text{'index_missing_file'};
|
||||
}
|
||||
|
||||
# command_cell(config-key)
|
||||
# Returns escaped command display HTML with availability state.
|
||||
sub command_cell
|
||||
{
|
||||
my ($key) = @_;
|
||||
my $cmd = &grub2_command($key);
|
||||
return &ui_tag('tt', &html_escape($cmd)) if ($cmd);
|
||||
my $raw = &grub2_config_value($key);
|
||||
return $text{'index_not_set'} if (!defined($raw) || $raw eq '');
|
||||
return &ui_tag('tt', &html_escape($raw)).' '.$text{'index_not_readable'};
|
||||
}
|
||||
|
||||
# manual_path_link(path, html)
|
||||
# Links editable GRUB files to the manual editor when permitted.
|
||||
sub manual_path_link
|
||||
{
|
||||
my ($path, $html) = @_;
|
||||
return $html if (!&grub2_check_acl('manual') || !&grub2_manual_file($path));
|
||||
# Link only allowlisted paths; generated grub.cfg remains informational.
|
||||
return &ui_tag('a', $html, {
|
||||
'href' => "edit_manual.cgi?file=".&urlize($path),
|
||||
});
|
||||
}
|
||||
|
||||
# security_state_cell(&state)
|
||||
# Returns text for the password protection status.
|
||||
sub security_state_cell
|
||||
{
|
||||
my ($state) = @_;
|
||||
return $text{'index_security_unmanaged'}
|
||||
if ($state->{'exists'} && !$state->{'managed'});
|
||||
return $state->{'enabled'} ? $text{'index_security_enabled'} :
|
||||
$text{'index_security_disabled'};
|
||||
}
|
||||
|
||||
# boot_mode_cell()
|
||||
# Returns the detected firmware boot mode for display.
|
||||
sub boot_mode_cell
|
||||
{
|
||||
my $mode = &grub2_boot_mode();
|
||||
return $text{'index_boot_mode_uefi'} if ($mode eq 'uefi');
|
||||
return $text{'index_boot_mode_bios'};
|
||||
}
|
||||
|
||||
# secure_boot_cell()
|
||||
# Returns the detected Secure Boot state for display.
|
||||
sub secure_boot_cell
|
||||
{
|
||||
my $state = &grub2_secure_boot_status();
|
||||
return $text{'index_secure_boot_'.$state} || $text{'index_secure_boot_unknown'};
|
||||
}
|
||||
|
||||
# value_cell(value)
|
||||
# Returns escaped value display HTML with unset-state text.
|
||||
sub value_cell
|
||||
{
|
||||
my ($value) = @_;
|
||||
return $text{'index_not_set'} if (!defined($value) || $value eq '');
|
||||
return $text{'defaults_true'} if ($value eq 'true');
|
||||
return $text{'defaults_false'} if ($value eq 'false');
|
||||
return &html_escape($value);
|
||||
}
|
||||
|
||||
# literal_cell(value)
|
||||
# Returns an escaped literal GRUB value with unset and boolean mapping.
|
||||
sub literal_cell
|
||||
{
|
||||
my ($value) = @_;
|
||||
return $text{'index_not_set'} if (!defined($value) || $value eq '');
|
||||
return $text{'defaults_true'} if ($value eq 'true');
|
||||
return $text{'defaults_false'} if ($value eq 'false');
|
||||
return &ui_tag('tt', &html_escape($value));
|
||||
}
|
||||
68
grub2/t/perlcritic.t
Normal file
68
grub2/t/perlcritic.t
Normal file
@@ -0,0 +1,68 @@
|
||||
#!/usr/bin/perl
|
||||
use strict;
|
||||
use warnings;
|
||||
use Test::More;
|
||||
|
||||
BEGIN {
|
||||
eval { require Perl::Critic; 1 }
|
||||
or plan skip_all => 'Perl::Critic not installed';
|
||||
}
|
||||
|
||||
use File::Find;
|
||||
|
||||
# script_dir()
|
||||
# Returns the directory containing this test file, without relying on Cwd.
|
||||
sub script_dir
|
||||
{
|
||||
my $path = $0;
|
||||
if ($path =~ m{^/}) {
|
||||
$path =~ s{/[^/]+$}{};
|
||||
return $path;
|
||||
}
|
||||
my $cwd = `pwd`;
|
||||
chomp($cwd);
|
||||
if ($path =~ m{/}) {
|
||||
$path =~ s{/[^/]+$}{};
|
||||
return $cwd.'/'.$path;
|
||||
}
|
||||
return $cwd;
|
||||
}
|
||||
|
||||
my $bindir = script_dir();
|
||||
my $module_dir = "$bindir/..";
|
||||
my $profile = "$bindir/../../.perlcriticrc";
|
||||
if (!-r $profile) {
|
||||
plan skip_all => 'Perl::Critic profile not installed';
|
||||
}
|
||||
chdir($module_dir) or die "chdir: $!";
|
||||
|
||||
my @files;
|
||||
find(
|
||||
sub {
|
||||
return if -d;
|
||||
return if -l;
|
||||
return unless /\.(pl|cgi)\z/;
|
||||
return if /\.info\.pl\z/;
|
||||
push(@files, $File::Find::name);
|
||||
},
|
||||
'.'
|
||||
);
|
||||
|
||||
@files = sort @files;
|
||||
if (!@files) {
|
||||
plan skip_all => 'no perl files to check';
|
||||
}
|
||||
|
||||
my $critic = Perl::Critic->new(
|
||||
-profile => $profile,
|
||||
);
|
||||
|
||||
foreach my $file (@files) {
|
||||
my @violations = $critic->critique($file);
|
||||
is(scalar @violations, 0, "$file perlcritic");
|
||||
if (@violations) {
|
||||
diag join("", @violations);
|
||||
}
|
||||
}
|
||||
|
||||
done_testing();
|
||||
1422
grub2/t/run-tests.t
Normal file
1422
grub2/t/run-tests.t
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user