2 # Functions for installing packages from debian APT
4 $apt_get_command = $config{'apt_mode'} ? "aptitude" : "apt-get";
5 $apt_search_command = $config{'apt_mode'} ? "aptitude" : "apt-cache";
7 sub list_update_system_commands
9 return ($apt_get_command, $apt_search_command);
12 # update_system_install([package], [&in], [no-force])
13 # Install some package with apt
14 sub update_system_install
16 local $update = $_[0] || $in{'update'};
17 local $force = !$_[2];
18 local (@rv, @newpacks);
20 # Build the command to run
21 $ENV{'DEBIAN_FRONTEND'} = 'noninteractive';
22 local $cmd = $apt_get_command eq "apt-get" ?
23 "$apt_get_command -y ".($force ? " --force-yes -f" : "")." install $update" :
24 "$apt_get_command -y".($force ? " -f" : "")." install $update";
25 $update = join(" ", map { quotemeta($_) } split(/\s+/, $update));
26 print "<b>",&text('apt_install', "<tt>$cmd</tt>"),"</b><p>\n";
28 &additional_log('exec', undef, $cmd);
30 # Run dpkg --configure -a to clear any un-configured packages
31 $SIG{'TERM'} = 'ignore'; # This may cause a Webmin re-config!
32 local $out = &backquote_logged("dpkg --configure -a 2>&1 </dev/null");
33 print &html_escape($out);
35 # Create an input file of 'yes'
36 local $yesfile = &transname();
37 &open_tempfile(YESFILE, ">$yesfile", 0, 1);
39 &print_tempfile(YESFILE, "Yes\n");
41 &close_tempfile(YESFILE);
44 &open_execute_command(CMD, "$cmd <$yesfile", 2);
46 if (/setting\s+up\s+(\S+)/i && !/as\s+MDA/i) {
49 elsif (/packages\s+will\s+be\s+upgraded/i ||
50 /new\s+packages\s+will\s+be\s+installed/i) {
53 $line =~ s/^\s+//; $line =~ s/\s+$//;
54 push(@newpacks, split(/\s+/, $line));
56 print &html_escape("$_");
59 if (!@rv && $config{'package_system'} ne 'debian' && !$?) {
60 # Other systems don't list the packages installed!
64 if ($?) { print "<b>$text{'apt_failed'}</b><p>\n"; }
65 else { print "<b>$text{'apt_ok'}</b><p>\n"; }
69 # update_system_operations(packages)
70 # Given a list of packages, returns a list containing packages that will
71 # actually get installed, each of which is a hash ref with name and version.
72 sub update_system_operations
75 $ENV{'DEBIAN_FRONTEND'} = 'noninteractive';
76 my $cmd = "apt-get -s install ".
77 join(" ", map { quotemeta($_) } split(/\s+/, $packages)).
79 my $out = &backquote_command($cmd);
81 foreach my $l (split(/\r?\n/, $out)) {
82 if ($l =~ /Inst\s+(\S+)\s+\[(\S+)\]\s+\(([^ \)]+)/ ||
83 $l =~ /Inst\s+(\S+)\s+\[(\S+)\]/) {
84 my $pkg = { 'name' => $1,
85 'version' => $3 || $2 };
86 if ($pkg->{'version'} =~ s/^(\S+)://) {
95 # update_system_form()
96 # Shows a form for updating all packages on the system
97 sub update_system_form
99 print &ui_subheading($text{'apt_form'});
100 print &ui_form_start("apt_upgrade.cgi");
101 print &ui_table_start($text{'apt_header'}, undef, 2);
103 print &ui_table_row($text{'apt_update'},
104 &ui_yesno_radio("update", 1));
106 print &ui_table_row($text{'apt_mode'},
107 &ui_radio("mode", 0, [ [ 2, $text{'apt_mode2'} ],
108 [ 1, $text{'apt_mode1'} ],
109 [ 0, $text{'apt_mode0'} ] ]));
111 print &ui_table_row($text{'apt_sim'},
112 &ui_yesno_radio("sim", 0));
114 print &ui_table_end();
115 print &ui_form_end([ [ undef, $text{'apt_apply'} ] ]);
118 # update_system_resolve(name)
119 # Converts a standard package name like apache, sendmail or squid into
120 # the name used by APT.
121 sub update_system_resolve
124 return $name eq "dhcpd" ? "dhcp3-server" :
125 $name eq "bind" ? "bind9" :
126 $name eq "mysql" ? "mysql-client mysql-server mysql-admin" :
127 $name eq "apache" ? "apache2" :
128 $name eq "postgresql" ? "postgresql postgresql-client" :
129 $name eq "openssh" ? "ssh" :
130 $name eq "openldap" ? "slapd" :
131 $name eq "dovecot" ? "dovecot-common dovecot-imapd dovecot-pop3d" :
135 # update_system_available()
136 # Returns a list of package names and versions that are available from APT
137 sub update_system_available
139 local (@rv, $pkg, %done);
141 # Use dump to get versions
142 &execute_command("$apt_get_command update");
144 &open_execute_command(DUMP, "apt-cache dump 2>/dev/null", 1, 1);
146 if (/^\s*Package:\s*(\S+)/) {
147 $pkg = { 'name' => $1 };
151 elsif (/^\s*Version:\s*(\S+)/ && $pkg && !$pkg->{'version'}) {
152 $pkg->{'version'} = $1;
153 if ($pkg->{'version'} =~ /^(\d+):(.*)$/) {
154 $pkg->{'epoch'} = $1;
155 $pkg->{'version'} = $2;
158 elsif (/^\s*File:\s*(\S+)/ && $pkg) {
159 $pkg->{'file'} ||= $1;
163 &reset_environment();
165 # Use search to get descriptions
166 foreach my $s (&update_system_search('.*')) {
167 my $pkg = $done{$s->{'name'}};
169 $pkg->{'desc'} = $s->{'desc'};
173 &set_pinned_versions(\@rv);
177 # update_system_search(text)
178 # Returns a list of packages matching some search
179 sub update_system_search
183 &open_execute_command(DUMP, "$apt_search_command search ".
184 quotemeta($_[0])." 2>/dev/null", 1, 1);
186 if (/^(\S+)\s*-\s*(.*)/) {
187 push(@rv, { 'name' => $1, 'desc' => $2 });
189 elsif (/^(\S)\s+(\S+)\s+-\s*(.*)/) {
190 push(@rv, { 'name' => $2, 'desc' => $3 });
194 &reset_environment();
198 # update_system_updates()
199 # Returns a list of available package updates
200 sub update_system_updates
202 &execute_command("$apt_get_command update");
204 # Find held packages by dpkg
206 if ($config{'package_system'} eq 'debian') {
208 &open_execute_command(HOLDS, "dpkg --get-selections", 1, 1);
210 if (/^(\S+)\s+hold/) {
215 &reset_environment();
218 if (&has_command("apt-show-versions")) {
219 # This awesome command can give us all updates in one hit, and takes
220 # pinned versions and backports into account
223 &open_execute_command(PKGS, "apt-show-versions 2>/dev/null", 1, 1);
225 if (/^(\S+)\/(\S+)\s+upgradeable\s+from\s+(\S+)\s+to\s+(\S+)/ &&
227 local $pkg = { 'name' => $1,
230 if ($pkg->{'version'} =~ s/^(\S+)://) {
231 $pkg->{'epoch'} = $1;
237 &reset_environment();
241 # Need to manually compose by calling dpkg and apt-cache showpkg
243 local $n = &list_packages();
245 for(my $i=0; $i<$n; $i++) {
246 local $pkg = { 'name' => $packages{$i,'name'},
247 'oldversion' => $packages{$i,'version'},
248 'desc' => $packages{$i,'desc'},
249 'oldepoch' => $packages{$i,'epoch'} };
250 $currentmap{$pkg->{'name'}} ||= $pkg;
253 local @names = grep { !$holds{$_} } keys %currentmap;
254 while(scalar(@names)) {
256 if (scalar(@names) > 100) {
258 @somenames = @names[0..99];
259 @names = @names[100..$#names];
267 &open_execute_command(PKGS, "apt-cache showpkg ".
268 join(" ", @somenames)." 2>/dev/null", 1, 1);
272 if (/^\s*Package:\s*(\S+)/) {
273 $pkg = $currentmap{$1};
275 elsif (/^Versions:\s*$/ && $pkg && !$pkg->{'version'}) {
276 # Newest version is on next line
278 $ver =~ s/\s.*\r?\n//;
280 if ($ver =~ s/^(\d+)://) {
283 $pkg->{'version'} = $ver;
284 $pkg->{'epoch'} = $epoch;
286 $pkg->{'epoch'} <=> $pkg->{'oldepoch'} ||
287 &compare_versions($pkg->{'version'},
288 $pkg->{'oldversion'});
295 &reset_environment();
297 &set_pinned_versions(\@rv);
302 # set_pinned_versions(&package-list)
303 # Updates the version and epoch fields in a list of available packages based
305 sub set_pinned_versions
308 local %pkgmap = map { $_->{'name'}, $_ } @$pkgs;
310 &open_execute_command(PKGS, "apt-cache policy 2>/dev/null", 1, 1);
313 if (/\s+(\S+)\s+\-\>\s+(\S+)/) {
314 my ($name, $pin) = ($1, $2);
315 my $pkg = $pkgmap{$name};
317 $pkg->{'version'} = $pin;
318 $pkg->{'epoch'} = undef;
319 if ($pkg->{'version'} =~ s/^(\S+)://) {
320 $pkg->{'epoch'} = $1;
326 &reset_environment();