3 # Download usermin and upgrade all managed servers of compatible types
5 require './cluster-usermin-lib.pl';
6 &foreign_require("proc", "proc-lib.pl");
7 &foreign_require("webmin", "webmin-lib.pl");
8 &foreign_require("webmin", "gnupg-lib.pl");
11 &ui_print_unbuffered_header(undef, $text{'upgrade_title'}, "");
13 # Save this CGI from being killed by the upgrade
14 $SIG{'TERM'} = 'IGNORE';
16 if ($in{'source'} == 0) {
18 &error_setup(&usermin::text('upgrade_err1', $in{'file'}));
20 if (!(-r $file)) { &inst_error($usermin::text{'upgrade_efile'}); }
22 elsif ($in{'source'} == 1) {
24 &error_setup($usermin::text{'upgrade_err2'});
28 &inst_error($usermin::text{'upgrade_ebrowser'});
31 print MOD $in{'upload'};
34 elsif ($in{'source'} == 2) {
35 # find latest version at www.usermin.com by looking at index page
36 &error_setup($usermin::text{'upgrade_err3'});
38 &http_download($usermin::update_host, $usermin::update_port, '/index6.html', $file, \$error);
39 $error && &inst_error($error);
42 if (/usermin-([0-9\.]+)\.tar\.gz/) {
49 if ($in{'mode'} eq 'rpm') {
50 $progress_callback_url = "http://$usermin::update_host/download/rpm/usermin-$site_version-1.noarch.rpm";
51 &http_download($usermin::update_host, $usermin::update_port,
52 "/download/rpm/usermin-$site_version-1.noarch.rpm", $file,
53 \$error, \&progress_callback);
55 elsif ($in{'mode'} eq 'deb') {
56 $progress_callback_url = "http://$usermin::update_host/download/deb/usermin_$site_version.deb";
57 &http_download($usermin::update_host, $usermin::update_port,
58 "/download/deb/usermin_$site_version.deb", $file,
59 \$error, \&progress_callback);
62 $progress_callback_url = "http://$usermin::update_host/download/usermin-$site_version.tar.gz";
63 &http_download($usermin::update_host, $usermin::update_port,
64 "/download/usermin-$site_version.tar.gz", $file,
65 \$error, \&progress_callback);
67 $error && &inst_error($error);
70 elsif ($in{'source'} == 5) {
71 # Download from some URL
72 &error_setup(&usermin::text('upgrade_err5', $in{'url'}));
74 $progress_callback_url = $in{'url'};
75 if ($in{'url'} =~ /^(http|https):\/\/([^\/]+)(\/.*)$/) {
77 $host = $2; $page = $3; $port = $ssl ? 443 : 80;
78 if ($host =~ /^(.*):(\d+)$/) { $host = $1; $port = $2; }
79 &http_download($host, $port, $page, $file, \$error,
80 \&progress_callback, $ssl);
82 elsif ($in{'url'} =~ /^ftp:\/\/([^\/]+)(:21)?\/(.*)$/) {
83 $host = $1; $ffile = $3;
84 &ftp_download($host, $ffile, $file,
85 \$error, \&progress_callback);
87 else { &inst_error($usermin::text{'upgrade_eurl'}); }
89 $error && &inst_error($error);
92 # Work out what kind of file we have (RPM or tar.gz)
93 if (`rpm -qp $file 2>&1` =~ /(^|\n)usermin-(\d+\.\d+)/) {
94 # Looks like a usermin RPM
98 elsif (`dpkg --info $file 2>&1` =~ /Package:\s+usermin-(\d+\.\d+)/) {
99 # Looks like a Usermin Debian package
104 # Check if it is a usermin tar.gz file
105 open(TAR, "gunzip -c $file | tar tf - 2>&1 |");
108 if (/^usermin-([0-9\.]+)\//) {
111 if (/^webmin-([0-9\.]+)\//) {
112 $webmin_version = $1;
114 if (/^[^\/]+\/(\S+)$/) {
117 if (/^(usermin-([0-9\.]+)\/[^\/]+)$/) {
120 elsif (/^usermin-[0-9\.]+\/([^\/]+)\//) {
125 if ($webmin_version) {
126 &inst_error(&usermin::text('upgrade_ewebmin',
130 if ($hasfile{'module.info'}) {
131 &inst_error(&usermin::text('upgrade_emod', 'index.cgi'));
134 &inst_error($usermin::text{'upgrade_etar'});
140 # gunzip the file if needed
144 if ($two eq "\037\213") {
145 if (!&has_command("gunzip")) {
146 &inst_error($usermin::text{'upgrade_egunzip'});
148 $newfile = &tempname();
149 $out = `gunzip -c $file 2>&1 >$newfile`;
152 &inst_error(&usermin::text('upgrade_egzip', "<tt>$out</tt>"));
154 unlink($file) if ($need_unlink);
159 # Setup error handler for down hosts
162 $inst_error_msg = join("", @_);
164 &remote_error_setup(\&inst_error);
166 # Build list of selected hosts
167 @hosts = &list_usermin_hosts();
168 @servers = &list_servers();
169 if ($in{'server'} == -2) {
170 # Upgrade servers know to run older versions?
171 @hosts = grep { $_->{'version'} < $version } @hosts;
172 print "<b>",&text('upgrade_header3', $version),"</b><p>\n";
174 elsif ($in{'server'} =~ /^group_(.*)/) {
175 # Upgrade members of some group
176 local ($group) = grep { $_->{'name'} eq $1 }
177 &servers::list_all_groups(\@servers);
178 @hosts = grep { local $hid = $_->{'id'};
179 local ($s) = grep { $_->{'id'} == $hid } @servers;
180 &indexof($s->{'host'}, @{$group->{'members'}}) >= 0 }
182 print "<b>",&text('upgrade_header4', $group->{'name'}),"</b><p>\n";
184 elsif ($in{'server'} != -1) {
186 @hosts = grep { $_->{'id'} == $in{'server'} } @hosts;
187 local ($s) = grep { $_->{'id'} == $hosts[0]->{'id'} } @servers;
188 print "<b>",&text('upgrade_header2', &server_name($s)),"</b><p>\n";
191 # Upgrading every host
192 print "<p><b>",&text('upgrade_header'),"</b><p>\n";
197 foreach $h (@hosts) {
198 local ($s) = grep { $_->{'id'} == $h->{'id'} } @servers;
200 local ($rh = "READ$p", $wh = "WRITE$p");
202 select($wh); $| = 1; select(STDOUT);
204 # Do the install in a subprocess
207 if (!$s->{'fast'} && $s->{'id'} != 0) {
208 print $wh &serialise_variable($text{'upgrade_efast'});
211 &remote_foreign_require($s->{'host'}, "usermin",
213 if ($inst_error_msg) {
214 # Failed to contact host ..
215 print $wh &serialise_variable($inst_error_msg);
219 # Check the remote host's version
220 local $rver = &remote_foreign_call($s->{'host'}, "usermin",
221 "get_usermin_version");
222 if ($version == $rver) {
223 print $wh &serialise_variable(
224 &usermin::text('upgrade_elatest', $version));
227 elsif ($version <= $rver) {
228 print $wh &serialise_variable(
229 &usermin::text('upgrade_eversion', $version));
233 # Check the install type on the remote host
234 local $rmode = &remote_eval($s->{'host'}, "usermin",
235 "&get_usermin_miniserv_config(\\\%miniserv); chop(\$m = `cat \$miniserv{'root'}/install-type`); \$m");
236 if ($rmode ne $mode) {
237 print $wh &serialise_variable(
238 &text('upgrade_emode',
239 $text{'upgrade_mode_'.$rmode},
240 $text{'upgrade_mode_'.$mode}));
244 # Get the file to the server somehow
246 local $host_need_unlink = 1;
248 # This host, so we already have the file
250 $host_need_unlink = 0;
252 elsif ($in{'source'} == 0) {
253 # Is the file the same on remote? (like if we have NFS)
254 local @st = stat($file);
255 local $rst = &remote_eval($s->{'host'}, "usermin",
256 "[ stat('$file') ]");
258 if (@st && @rst && $st[7] == $rst[7] &&
260 # File is the same! No need to download
262 $host_need_unlink = 0;
265 # Need to copy the file across :(
266 $rfile = &remote_write(
267 $s->{'host'}, $file);
271 # Need to copy the file across :(
272 $rfile = &remote_write($s->{'host'}, $file);
276 if ($mode eq "rpm") {
277 # Can just run RPM command
278 # XXX doesn't actually check output!
279 &remote_eval($s->{'host'}, "usermin", "system(\"rpm --import \$root_directory/webmin/jcameron-key.asc >/dev/null 2>&1\")");
280 ($out, $ex) = &remote_eval($s->{'host'}, "usermin", "\$out = `rpm -U --ignoreos --ignorearch '$rfile' >/dev/null 2>&1 </dev/null`; (\$out, \$?)");
281 &remote_eval($s->{'host'}, "usermin",
283 if ($host_need_unlink);
285 print $wh &serialise_variable(
290 elsif ($mode eq "deb") {
291 # Can just run dpkg command
292 ($out, $ex) = &remote_eval($s->{'host'}, "usermin", "\$out = `dpkg --install '$rfile' >/dev/null 2>&1 </dev/null`; (\$out, \$?)");
293 &remote_eval($s->{'host'}, "usermin","unlink('$rfile')")
294 if ($host_need_unlink);
296 print $wh &serialise_variable(
302 # Get the original install directory
303 local $rdir = &remote_eval($s->{'host'}, "usermin",
304 "chop(\$m = `cat \$config{'usermin_dir'}/install-dir`); \$m");
306 # Extract tar.gz in temporary location first
307 $extract = &remote_foreign_call($s->{'host'}, "usermin", "tempname");
308 &remote_eval($s->{'host'}, "usermin", "mkdir('$extract', 0755)");
311 # Extract next to original dir
312 $oldroot = &remote_eval($s->{'host'}, "usermin", "\$root_directory");
313 $extract = "$oldroot/..";
316 # Actually unpack the tar file
317 local ($out, $ex) = &remote_eval($s->{'host'}, "usermin", "\$out = `cd '$extract' ; tar xf '$rfile' 2>&1 >/dev/null`; (\$out, \$?)");
319 print $wh &serialise_variable(
324 # Delete the original tar.gz
325 &remote_eval($s->{'host'}, "usermin", "unlink('$rfile')")
326 if ($host_need_unlink);
328 # Run setup.sh in the extracted directory
329 $setup = $rdir ? "./setup.sh '$rdir'" : "./setup.sh";
330 ($out, $ex) = &remote_eval($s->{'host'}, "usermin",
331 "\$SIG{'TERM'} = 'IGNORE';
332 \$ENV{'config_dir'} = \$config{'usermin_dir'};
333 \$ENV{'webmin_upgrade'} = 1;
334 \$ENV{'autothird'} = 1;
335 \$out = `(cd $extract/usermin-$version && $setup) </dev/null 2>&1 | tee /tmp/.webmin/usermin-setup.out`;
337 if ($out !~ /success/i) {
338 print $wh &serialise_variable(
343 # Can delete the temporary source directory
344 &remote_eval($s->{'host'}, "usermin",
345 "system(\"rm -rf \'$extract\'\")");
347 elsif ($in{'delete'}) {
348 # Can delete the old root directory
349 &remote_eval($s->{'host'}, "usermin",
350 "system(\"rm -rf \'$oldroot\'\")");
354 # Force an RPC re-connect to new version
356 &remote_foreign_require($s->{'host'}, "usermin",
358 if ($inst_error_msg) {
359 # Failed to contact host ..
360 print $wh &serialise_variable(
361 &text('upgrade_ereconn', $inst_error_msg));
364 &remote_foreign_require($s->{'host'}, "acl", "acl-lib.pl");
366 # Update local version number and module lists
367 $h->{'version'} = $version;
368 local @mods = &remote_foreign_call($s->{'host'},
369 "usermin", "list_modules");
370 @mods = grep { !$_->{'clone'} } @mods;
371 $h->{'modules'} = \@mods;
372 local @themes = &remote_foreign_call($s->{'host'},
373 "usermin", "list_themes");
374 $h->{'themes'} = \@themes;
375 &save_usermin_host($h);
377 print $wh &serialise_variable("");
385 # Get back all the results
387 foreach $h (@hosts) {
388 local $rh = "READ$p";
391 local $rv = &unserialise_variable($line);
393 local ($s) = grep { $_->{'id'} == $h->{'id'} } @servers;
394 local $d = &server_name($s);
397 print &text('upgrade_failed', $d, "Unknown reason"),"<br>\n";
400 print &text('upgrade_failed', $d, $rv),"<br>\n";
403 print &text('upgrade_ok',
404 $text{'upgrade_mode_'.$mode}, $d),"<br>\n";
408 unlink($file) if ($need_unlink);
409 print "<p><b>$text{'upgrade_done'}</b><p>\n";
412 &ui_print_footer("", $text{'index_return'});
416 unlink($file) if ($need_unlink);
417 print "<br><b>$whatfailed : $_[0]</b> <p>\n";
418 &ui_print_footer("", $text{'index_return'});