winupd/pkgtool.pl
2017-11-12 07:29:03 +01:00

275 lines
7.9 KiB
Perl

#!perl -w
use strict;
my $DEFAULT_DOMAIN_NAME = 'karinthy.hu';
my $DEFAULT_CONFIG_FILE_NAME = 'pkgtool.cfg';
my $base_directory;
BEGIN {
$base_directory = $0;
if ($^O eq 'MSWin32') {
if ($base_directory =~ /^(.*[\/\\])[^\/\\]*$/o) {
$base_directory = $1;
}
else {
$base_directory = '.';
}
}
else {
if ($base_directory =~ /^(.*\/)[^\/]*$/o) {
$base_directory = $1;
}
else {
$base_directory = '.';
}
}
push @INC, $base_directory if -d $base_directory;
}
use logging;
use cmdline;
use cfgparser;
use pkgtool;
my $print_help;
my $config_file_name;
my $proxycmd = $base_directory.'\\install.cmd';
my $standalone = 0;
my $globals = {};
sub set_standalone_flag ($)
{
my ($param) = @_;
$standalone = $param;
}
sub set_global ($)
{
my ($param) = @_;
if ($param =~ /^([^=]+)=(.*)$/o) {
my $key = $1;
my $value = $2;
$$globals{$key} = $value;
}
}
my $CONFIG_OPTIONS = [{
General => 1,
Option => '<command>',
Description => 'Command: list, status, update'
}, {
Short => 'c',
Long => 'config',
Description => 'Config file name',
Type => 'string',
Default => $DEFAULT_CONFIG_FILE_NAME,
StoreInto => \$config_file_name
}, {
Short => 'd',
Long => 'debug',
Description => 'Debug log level (0=off)',
Type => 'integer',
Default => 0,
StoreFunc => \&set_log_level
}, {
Short => 'g',
Long => 'global',
Description => 'Set generic variable (key=value)',
Type => 'keyvalue',
StoreFunc => \&set_global
}, {
Short => 'h',
Long => 'help',
Description => 'Print usage',
Type => 'flag',
Default => 0,
StoreInto => \$print_help
}, {
Short => 's',
Long => 'standalone',
Description => 'Skip accessing install server',
Type => 'flag',
StoreFunc => \&set_standalone_flag
}, {
Short => 'v',
Long => 'verbose',
Description => 'Verbose logging',
Type => 'flag',
Default => 0,
StoreFunc => \&set_verbose_flag
}];
set_pkgtool_dir($base_directory);
my $commands = parse_cmdline($CONFIG_OPTIONS);
if (! defined $commands || scalar @$commands < 1 || $print_help) {
print_usage($CONFIG_OPTIONS);
exit(1);
}
my $cmd = $$commands[0];
if ($cmd ne 'list' && $cmd ne 'status' && $cmd ne 'update') {
print_log('global', ERROR, 'Unknown command: %s', $cmd);
print_usage($CONFIG_OPTIONS);
exit(1);
}
my $dns_domain = get_default_dnsdomain();
$dns_domain = $DEFAULT_DOMAIN_NAME unless defined $dns_domain;
my $install_host = 'install.'.$dns_domain;
my $config = parse_cfg_file(substitute_variables({}, $config_file_name,
1, $base_directory, 'global'), get_cfg_syntax());
exit(1) unless defined $config;
$$config{'generic-variables'} = [] unless defined $$config{'generic-variables'};
$$config{'proxy-command'} = $proxycmd;
$$config{'install-host'} = $install_host;
set_log_base_dir(substitute_variables(get_default_vars(),
$$config{'log-directory'}, 1, $base_directory, 'global'));
set_log_defs($$config{logging}) if defined $$config{logging};
if ($standalone) {
print_log('global', INFO, 'Skipping install server');
}
else {
print_log('global', INFO, 'Install server: %s', $install_host);
my $error = get_install_sets($config);
exit(1) if defined $error;
}
my $error = scan_package_dirs($config, $base_directory);
exit(1) if defined $error;
$$config{'package-def'} = {} unless defined $$config{'package-def'};
$$config{'global-variables'} = $globals;
my $db = {};
read_installed_packages($db);
read_installed_patches($db);
my $counters = {
RebootFlag => 0,
InstalledList => [],
InstalledCount => 0,
RemovedList => [],
RemovedCount => 0,
FailList => [],
FailCount => 0,
SkipList => [],
SkipCount => 0,
ToInstallList => [],
ToInstallCount => 0,
ToRemoveList => [],
ToRemoveCount => 0
};
my $stats;
my $results;
if ($cmd eq 'list') {
print_log('global', INFO, '== Listing packages');
my $pkgdefs = $$config{'package-def'};
foreach my $key (sort keys %$pkgdefs) {
my $def = $$pkgdefs{$key};
next unless defined $def;
print_log('global', INFO, 'Definition: %s "%s"', $key, $$def{description});
}
my $installed = $$db{Installed};
foreach my $instname (sort keys %$installed) {
my $inst = $$installed{$instname};
next unless defined $inst && defined $$inst{DisplayName} && defined $$inst{DisplayVersion};
print_log('global', INFO, 'Installed: %s "%s" "%s" "%s"',
$$inst{UserPackage} ? 'user' : 'global', $instname, $$inst{DisplayName}, $$inst{DisplayVersion});
}
$installed = $$db{InstalledSpec};
foreach my $instname (sort keys %$installed) {
my $inst = $$installed{$instname};
next unless defined $inst && defined $$inst{DisplayName} && defined $$inst{DisplayVersion};
print_log('global', INFO, 'Installed: %s "%s" "%s" "%s"',
$$inst{UserPackage} ? 'user' : 'global', $instname, $$inst{DisplayName}, $$inst{DisplayVersion});
}
print_log('global', INFO, '== Listing patches');
my $patches = $$db{Patches};
foreach my $kb (sort { ${$$patches{$a}}{Number} <=> ${$$patches{$b}}{Number} } keys %$patches) {
my $patch = $$patches{$kb};
next unless defined $patch;
print_log('global', INFO, 'Installed: %s %s %s %s',
$$patch{KB},
($$patch{Type} eq 'OS' ? 'OS' : 'Packages('.join(',', sort keys %{$$patch{Packages}}).')'),
($$patch{Original} ? 'original' : 'update'),
($$patch{Current} ? 'current' : 'obsoleted'));
}
}
elsif ($cmd eq 'status') {
print_log('global', INFO, '== Displaying package status');
my $pkgdefs = $$config{'package-def'};
my $pkgs = $$config{'packages'};
foreach my $pkg (@$pkgs) {
handle_pkg($config, $base_directory, $db, $pkg, $counters, 0);
}
$stats = '';
}
elsif ($cmd eq 'update') {
my $pkgname = $$commands[1];
print_log('global', INFO, '== Updating packages/patches: %s', defined $pkgname ? $pkgname : 'all');
my $pkgdefs = $$config{'package-def'};
my $pkgs = $$config{'packages'};
foreach my $pkg (@$pkgs) {
my $name = $$pkg{name};
next if defined $pkgname && $name ne $pkgname;
handle_pkg($config, $base_directory, $db, $pkg, $counters, 1);
}
$stats = '';
}
if (defined $stats) {
$results = '';
if ($$counters{SkipCount} > 0) {
$stats .= $stats eq '' ? 'S' : ', s';
$stats .= sprintf('kipping %d', $$counters{SkipCount});
$results .= $results eq '' ? 'S' : ', s';
$results .= 'kipping: '.join(',', @{$$counters{SkipList}});
}
if ($$counters{FailCount} > 0) {
$stats .= $stats eq '' ? 'F' : ', f';
$stats .= sprintf('ailed %d', $$counters{FailCount});
$results .= $results eq '' ? 'F' : ', f';
$results .= 'ailed: '.join(',', @{$$counters{FailList}});
}
if ($$counters{ToInstallCount} > 0) {
$stats .= $stats eq '' ? 'To ' : ', to ';
$stats .= sprintf('install %d', $$counters{ToInstallCount});
$results .= $results eq '' ? 'To ' : ', to ';
$results .= 'install: '.join(',', @{$$counters{ToInstallList}});
}
if ($$counters{ToRemoveCount} > 0) {
$stats .= $stats eq '' ? 'To ' : ', to ';
$stats .= sprintf('remove %d', $$counters{ToRemoveCount});
$results .= $results eq '' ? 'To ' : ', to ';
$results .= 'remove: '.join(',', @{$$counters{ToRemoveList}});
}
if ($cmd eq 'update') {
$stats .= $stats eq '' ? 'I' : ', i';
$stats .= sprintf('nstalled %d, removed %d', $$counters{InstalledCount}, $$counters{RemovedCount});
$results .= $results eq '' ? 'I' : ', i';
if (scalar @{$$counters{InstalledList}} > 0) {
$results .= 'nstalled: '.join(',', @{$$counters{InstalledList}});
}
else {
$results .= 'nstalled: -';
}
if (scalar @{$$counters{RemovedList}} > 0) {
$results .= ', removed: '.join(',', @{$$counters{RemovedList}});
}
else {
$results .= ', removed: -';
}
}
if ($$counters{RebootFlag}) {
$stats .= $stats eq '' ? 'R' : ', r';
$stats .= sprintf('eboot needed!');
}
}
print_log('global', WARNING, 'Package/patch statistics: %s', $stats) if defined $stats;
print_log('global', INFO, '%s', $results) if defined $results;
close_all_log_files(0);
exit(0);