#!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 => '', 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; #$error = scan_driver_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); read_present_devices($db); read_installed_infs($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);