mirror of
https://github.com/webmin/webmin.git
synced 2026-05-16 11:50:26 +01:00
243 lines
9.1 KiB
Perl
Executable File
243 lines
9.1 KiB
Perl
Executable File
# os-eol-lib.pl
|
|
# Functions for managing OS end-of-life data
|
|
|
|
use strict;
|
|
use warnings;
|
|
no warnings 'redefine';
|
|
no warnings 'uninitialized';
|
|
use Time::Local;
|
|
|
|
our (%gconfig, %text, $root_directory, $config_directory);
|
|
|
|
# eol_oses_list()
|
|
# Returns a list of OSes for which EOL data is available
|
|
sub eol_oses_list
|
|
{
|
|
return ('almalinux', 'amazon-linux', 'centos-stream', 'centos',
|
|
'debian', 'fedora', 'freebsd', 'openbsd', 'opensuse',
|
|
'oracle-linux', 'rhel', 'rocky-linux', 'ubuntu');
|
|
}
|
|
|
|
# eol_get_os()
|
|
# Returns the current OS or undef if the OS is not supported
|
|
sub eol_get_os
|
|
{
|
|
my $os_type = lc($gconfig{'real_os_type'});
|
|
my @eol_oses_list = &eol_oses_list();
|
|
my ($os_found) = grep {
|
|
my $__ = $_;
|
|
$__ =~ s/-?linux//;
|
|
$__ =~ s/-/ /;
|
|
$os_type =~ /$__/ } @eol_oses_list;
|
|
return $os_found if ($os_found);
|
|
return undef;
|
|
}
|
|
|
|
# eol_build_all_os_data()
|
|
# Fetches the latest EOL data for all supported
|
|
# OSes and writes it to given file.
|
|
sub eol_build_all_os_data
|
|
{
|
|
my $eol_cache_file = shift;
|
|
$eol_cache_file ||= "$root_directory/os_eol.json";
|
|
my @eol_oses = &eol_oses_list();
|
|
my @eol_oses_data;
|
|
foreach my $os (@eol_oses) {
|
|
my $fdata =
|
|
&backquote_command(
|
|
"curl -sS --request GET " .
|
|
"--url https://endoflife.date/api/$os.json ".
|
|
"--header 'Accept: application/json' ".
|
|
"2>&1 </dev/null");
|
|
if ($?) {
|
|
die("Could not fetch OS EOL data : $?");
|
|
}
|
|
my $fdata_json;
|
|
eval { $fdata_json = &convert_from_json($fdata); };
|
|
if ($@) {
|
|
die("Could not parse fetched OS EOL data: $@");
|
|
}
|
|
# Add OS
|
|
$fdata_json = [ map { $_->{'_os'} = $os; $_ } @$fdata_json ];
|
|
# Fix (blessed) LTS key
|
|
$fdata_json = [ map { $_->{'lts'} = $_->{'lts'} ? 1 : 0; $_ } @$fdata_json ];
|
|
push(@eol_oses_data, @$fdata_json);
|
|
}
|
|
my $eol_oses_data = &convert_to_json(\@eol_oses_data);
|
|
&backquote_command("echo -n '$eol_oses_data' > $eol_cache_file 2>&1 </dev/null");
|
|
if ($?) {
|
|
die("Could not write OS EOL data file : $?");
|
|
}
|
|
}
|
|
|
|
# eol_get_os_data()
|
|
# Returns EOL data for the current OS.
|
|
# Returns undef if OS is not supported.
|
|
sub eol_get_os_data
|
|
{
|
|
my $os = &eol_get_os();
|
|
return undef if (!$os);
|
|
my $eol_file = shift;
|
|
$eol_file ||= "$root_directory/os_eol.json";
|
|
if (!-r $eol_file) {
|
|
&error_stderr("Could not read OS EOL data file: $eol_file");
|
|
return undef;
|
|
}
|
|
my $eol_data = &read_file_contents($eol_file);
|
|
my $eol_json;
|
|
eval { $eol_json = &convert_from_json($eol_data); };
|
|
if ($@) {
|
|
&error_stderr("Could not parse OS EOL data: $@");
|
|
return undef;
|
|
}
|
|
if (ref($eol_json) eq 'ARRAY' && @$eol_json) {
|
|
my $os_version = $gconfig{'real_os_version'};
|
|
# Extract the major and minor versions
|
|
$os_version =~ m/^(?:stable\/)?(?<major>\d+)(?:\.(?<minor>\d+))?/;
|
|
$os_version = $+{minor} ? "$+{major}.$+{minor}" : $+{major};
|
|
return undef if (!$+{major});
|
|
# Minor versions in cycle are allowed only for Ubuntu
|
|
$os_version = $+{major} if ($os !~ /ubuntu/);
|
|
my ($eol_json_this_os) =
|
|
grep { $_->{'_os'} eq $os &&
|
|
$_->{'cycle'} eq $os_version } @$eol_json;
|
|
return undef if (!$eol_json_this_os);
|
|
$eol_json_this_os->{'_os_name'} = $gconfig{'real_os_type'};
|
|
$eol_json_this_os->{'_os_version'} = $os_version;
|
|
# Convert EOL date to a timestamp
|
|
my ($year, $month, $day) = split('-', $eol_json_this_os->{'eol'});
|
|
$eol_json_this_os->{'_eol_timestamp'} = timelocal(0, 0, 0, $day, $month - 1, $year);
|
|
# Convert EOL extendend date to a timestamp
|
|
if ($eol_json_this_os->{'extendedSupport'}) {
|
|
my ($year, $month, $day) = split('-', $eol_json_this_os->{'extendedSupport'});
|
|
$eol_json_this_os->{'_ext_eol_timestamp'} =
|
|
timelocal(0, 0, 0, $day, $month - 1, $year);
|
|
}
|
|
return $eol_json_this_os if ($eol_json_this_os);
|
|
}
|
|
return undef;
|
|
}
|
|
|
|
# eol_populate_dates(&eol_data)
|
|
# Updates given EOL hash reference with
|
|
# human readable date and the time ago
|
|
sub eol_populate_dates
|
|
{
|
|
my ($eol_data) = @_;
|
|
if (!$eol_data->{'_eol_timestamp'}) {
|
|
&error_stderr("The provided data is not a valid EOL data hash reference");
|
|
return undef;
|
|
}
|
|
my $eol_date = &make_date($eol_data->{'_eol_timestamp'}, { });
|
|
if (ref($eol_date)) {
|
|
my $eol_in = sub {
|
|
my $eol_date = shift;
|
|
my $ago = $eol_date->{'ago'};
|
|
my @ago_units = qw(year month week day hour minute second);
|
|
foreach my $unit (@ago_units) {
|
|
if ($ago->{"${unit}s"}) {
|
|
my $value = abs($ago->{"${unit}s"});
|
|
return $value == 1 ? "1 " . $text{"os_eol_${unit}"} :
|
|
"$value " . $text{"os_eol_${unit}s"};
|
|
}
|
|
}
|
|
};
|
|
$eol_data->{'_eol'} = $eol_date->{'short'};
|
|
$eol_data->{'_eol_in'} = $eol_in->($eol_date);
|
|
if ($eol_data->{'extendedSupport'}) {
|
|
my $eol_date = &make_date(
|
|
$eol_data->{'_ext_eol_timestamp'}, { '_' => 1 });
|
|
$eol_data->{'_ext_eol'} = $eol_date->{'short'};
|
|
$eol_data->{'_ext_eol_in'} = $eol_in->($eol_date);
|
|
}
|
|
}
|
|
else {
|
|
$eol_data->{'_eol'} =
|
|
&make_date($eol_data->{'_eol_timestamp'}, 1);
|
|
if ($eol_data->{'extendedSupport'}) {
|
|
$eol_data->{'_ext_eol'} =
|
|
&make_date($eol_data->{'_ext_eol_timestamp'}, 1);
|
|
}
|
|
}
|
|
|
|
# Is expired?
|
|
my $expired = ($eol_data->{'_ext_eol_timestamp'} ||
|
|
$eol_data->{'_eol_timestamp'}) < time();
|
|
$eol_data->{'_expired'} = $text{'os_eol_reached'} if ($expired);
|
|
|
|
# Is expiring (in 3 months by default, unless configured otherwise)
|
|
my $os_eol_before = $gconfig{'os_eol_before'} // 3;
|
|
if (!$expired && $os_eol_before) {
|
|
my $expiring = ($eol_data->{'_ext_eol_timestamp'} ||
|
|
$eol_data->{'_eol_timestamp'}) < time() +
|
|
60*60*24*30*$os_eol_before ? 1 : 0;
|
|
# Set the expiring message
|
|
if ($expiring) {
|
|
$eol_data->{'_expiring'} =
|
|
$eol_data->{'_eol_in'} ?
|
|
$text{'os_eol_reaching'} . " " .
|
|
$eol_data->{'_eol_in'} :
|
|
$text{'os_eol_reaching2'};
|
|
}
|
|
# Set extended support expiring message (if available)
|
|
if ($eol_data->{'extendedSupport'}) {
|
|
my $expiring = $eol_data->{'_ext_eol_timestamp'} < time() +
|
|
60*60*24*30*$os_eol_before ? 1 : 0;
|
|
if ($expiring) {
|
|
$eol_data->{'_ext_expiring'} =
|
|
$eol_data->{'_ext_eol_in'} ?
|
|
$text{'os_eol_reaching'} . " " .
|
|
$eol_data->{'_ext_eol_in'} :
|
|
$text{'os_eol_reaching2'};
|
|
}
|
|
}
|
|
}
|
|
return $eol_data;
|
|
}
|
|
|
|
# eol_update_cache()
|
|
# Caches the OS EOL data until the next Webmin update
|
|
sub eol_update_cache
|
|
{
|
|
my $webmin_version = &get_webmin_version();
|
|
if ($gconfig{'os_eol_db'} ne $webmin_version) {
|
|
# Invalidate EOL cache
|
|
foreach my $key ('os_eol_about', 'os_eol_expired',
|
|
'os_eol_expiring') {
|
|
delete($gconfig{$key});
|
|
}
|
|
# This is the first time we check
|
|
# EOL data or after Webmin update
|
|
my $eol_data = &eol_get_os_data();
|
|
&eol_populate_dates($eol_data);
|
|
if (ref($eol_data)) {
|
|
$gconfig{'os_eol_about'} = 0;
|
|
if ($eol_data->{'_expired'}) {
|
|
$gconfig{'os_eol_expired'} = $eol_data->{'_expired'};
|
|
$gconfig{'os_eol_about'} = 2;
|
|
}
|
|
elsif ($eol_data->{'_expiring'}) {
|
|
$gconfig{'os_eol_expiring'} =
|
|
$eol_data->{'_ext_expiring'} ||
|
|
$eol_data->{'_expiring'};
|
|
$gconfig{'os_eol_about'} = 1;
|
|
}
|
|
$gconfig{'os_eol'} = $eol_data->{'_eol'};
|
|
$gconfig{'os_eol_in'} = $eol_data->{'_eol_in'};
|
|
$gconfig{'os_ext_eol'} = $eol_data->{'_ext_eol'}
|
|
if ($eol_data->{'_ext_eol'});
|
|
$gconfig{'os_ext_eol_in'} = $eol_data->{'_ext_eol_in'}
|
|
if ($eol_data->{'_ext_eol_in'});
|
|
}
|
|
# Store EOL db version and don't check it until next Webmin upgrade
|
|
$gconfig{'os_eol_db'} = $webmin_version;
|
|
|
|
# Store the updated data
|
|
&lock_file("$config_directory/config");
|
|
&write_file("$config_directory/config", \%gconfig);
|
|
&unlock_file("$config_directory/config");
|
|
}
|
|
}
|
|
|
|
1;
|