Gro├čes Update:
[ipfire-2.x.git] / html / cgi-bin / backup.cgi
CommitLineData
ac1cfefa
MT
1#!/usr/bin/perl
2#
78331e30 3# IPFire CGI's - backup.cgi: manage import/export of configuration files
ac1cfefa
MT
4#
5# This code is distributed under the terms of the GPL
6#
78331e30 7# (c) The IPFire Team
ac1cfefa
MT
8# 2005 Franck Bourdonnec, major rewrite
9#
10# $Id: backup.cgi,v 1.2.2.15 2006/01/29 15:31:49 eoberlander Exp $
11#
12#
13
14
15# to fully troubleshot your code, uncomment diagnostics, Carp and cluck lines
16# use diagnostics; # need to add the file /usr/lib/perl5/5.8.x/pods/perldiag.pod before to work
17# next look at /var/log/httpd/error_log , http://www.perl.com/pub/a/2002/05/07/mod_perl.html may help
18#use warnings;
19use strict;
20#use Carp ();
21#local $SIG{__WARN__} = \&Carp::cluck;
22use File::Copy;
23use Sys::Hostname;
24
25require 'CONFIG_ROOT/general-functions.pl';
26require "${General::swroot}/lang.pl";
27require "${General::swroot}/header.pl";
28
29my $errormessage = '';
30my $warnmessage = '';
31my $setdir = '/home/httpd/html/backup'; # location where sets are stored and imported
32my $datafile = hostname() . '.dat'; # file containing data backup
33my $datefile = $datafile . '.time'; # and creation date
34
35# ask if backup crypting key exists
36my $tmpkeyfile = "$setdir/key"; # import the backup key
37
38# Get GUI values
39my %settings = ();
40&Header::getcgihash(\%settings, {'wantfile' => 1, 'filevar' => 'FH'});
41
42##
43## Backup key management
44##
45
46#
47# Export the key. root pw is required to avoid user 'noboby' uses the helper to read it and creates
48# fake backup.
49#
50if ($settings{'ACTION'} eq $Lang::tr{'backup export key'}) {
51
52 my $size = 0;
53 if ($settings{'PASSWORD1'} ne '' && $settings{'PASSWORD1'} ne $settings{'PASSWORD2'} ){
54 $errormessage = $Lang::tr{'passwords do not match'}
55 } else {
78331e30 56 my @lines = `/usr/local/bin/ipfirebackup -keycat $settings{'PASSWORD'}`;
ac1cfefa
MT
57 # If previous operation succeded and the key need to be crypted, redo operation with pipe to openssl
58 if (@lines && $settings{'PASSWORD1'}) {
78331e30 59 @lines = `/usr/local/bin/ipfirebackup -keycat $settings{'PASSWORD'}|openssl enc -a -e -aes256 -salt -pass pass:$settings{'PASSWORD1'} `;
ac1cfefa
MT
60 }
61 if (@lines) {
62 use bytes;
63 foreach (@lines) {$size += length($_)};
64 print "Pragma: no-cache\n";
65 print "Cache-control: no-cache\n";
66 print "Connection: close\n";
67 print "Content-type: application/octet-stream\n";
68 print "Content-Disposition: filename=backup.key\n";
69 print "Content-Length: $size\n\n";
70 print @lines;
71 exit (0);
72 } else {
73 $errormessage = $Lang::tr{'incorrect password'};
74 }
75 }
76}
77#
78# Import the key. Fail if key exists. This avoid creating fake backup.
79#
80if ($settings{'ACTION'} eq $Lang::tr{'backup import key'}) {
81 if (ref ($settings{'FH'}) ne 'Fh') {
82 $errormessage = $Lang::tr{'no cfg upload'};
83 } else {
84 if (copy ($settings{'FH'}, $tmpkeyfile) != 1) {
85 $errormessage = $Lang::tr{'save error'};
86 } else {
87 # if a password is given, decrypt the key received in $tmpkeyfile file with it.
88 # no error is produce if the password is wrong.
89 if ($settings{'PASSWORD1'}) {
90 my @lines = `openssl enc -a -d -aes256 -salt -pass pass:$settings{'PASSWORD1'} -in $tmpkeyfile`;
91 open(FILE,">$tmpkeyfile");
92 print FILE @lines;
93 close (FILE);
94 }
78331e30 95 $errormessage = &get_bk_error(system ('/usr/local/bin/ipfirebackup -key import')>>8);
ac1cfefa
MT
96 }
97 }
98}
99#
100# Import the key. Fail if key exists. Key is extracted from a non-encrypted backup (pre 1.4.10)
101#
102if ($settings{'ACTION'} eq $Lang::tr{'backup extract key'}) {
103 if (ref ($settings{'FH'}) ne 'Fh') {
104 $errormessage = $Lang::tr{'no cfg upload'};
105 } else {
106 if (copy ($settings{'FH'}, '/tmp/tmptarfile.tgz') != 1) {
107 $errormessage = $Lang::tr{'save error'};
108 } else {
109 system( "tar -C /tmp -xzf /tmp/tmptarfile.tgz */backup/backup.key;\
110 mv -f /tmp${General::swroot}/backup/backup.key $tmpkeyfile;\
111 rm -rf /tmp${General::swroot};\
112 rm /tmp/tmptarfile.tgz");
78331e30 113 $errormessage = &get_bk_error(system ('/usr/local/bin/ipfirebackup -key import')>>8);
ac1cfefa
MT
114 }
115 }
116}
117#
118# Create the key. Cannot overwrite existing key to avoid difference with exported (saved) key
119#
120if ($settings{'ACTION'} eq $Lang::tr{'backup generate key'}) {
78331e30 121 $errormessage = &get_bk_error(system('/usr/local/bin/ipfirebackup -key new')>>8);
ac1cfefa
MT
122}
123
78331e30 124my $cryptkeymissing = system ('/usr/local/bin/ipfirebackup -key exist')>>8;
ac1cfefa
MT
125
126&Header::showhttpheaders();
127if ($cryptkeymissing) { #If no key is present, force creation or import
128 &Header::openpage($Lang::tr{'backup configuration'}, 1, '');
129 &Header::openbigbox('100%', 'left', '', $errormessage);
130 if ($errormessage) {
131 &Header::openbox('100%', 'left', $Lang::tr{'error messages'});
132 print "<font class='base'>$errormessage&nbsp;</font>";
133 &Header::closebox();
134 }
135 &Header::openbox('100%', 'left', $Lang::tr{'backup key'});
136 print <<END
137 <form method = 'post' enctype = 'multipart/form-data'>
138 <table>
139 <tr>
140 <td colspan='2'>
141 $Lang::tr{'backup explain key'}:
142 <ul>
143 <li>$Lang::tr{'backup explain key li1'}
144 <li>$Lang::tr{'backup explain key li2'}
145 <li>$Lang::tr{'backup explain key li3'}
146 </ul>
147 </td>
148 </tr><tr>
149 <td width='15%'></td><td width='20%'></td><td>
150 <input type = 'submit' name = 'ACTION' value = '$Lang::tr{'backup generate key'}' />
151 </td>
152 </tr><tr>
153 <td align='right'>$Lang::tr{'backup key file'}:</td><td><input type = 'file' name = 'FH' size = '30' value='backup.key' />
154 </td><td>
155 <input type = 'submit' name = 'ACTION' value = '$Lang::tr{'backup import key'}' />
156 </tr><tr>
157 <td align='right'>$Lang::tr{'backup protect key password'}:<td><input type = 'password' name='PASSWORD1' size='10' />
158 </td>
159 </tr><tr>
78331e30 160 <td align='right'>$Lang::tr{'backup clear archive'}:</td><td><input type = 'file' name = 'FH' size = '30' value='your-ipfire.tar.gz' />
ac1cfefa
MT
161 </td><td>
162 <input type = 'submit' name = 'ACTION' value = '$Lang::tr{'backup extract key'}' />
163 </td>
164 </tr>
165 </table>
166 $Lang::tr{'notes'}:
167 <ul>
168 <li>$Lang::tr{'backup explain key no1'}
169 <li>$Lang::tr{'backup explain key no2'}
170 </ul>
171 </form>
172END
173;
174 &floppybox();
175 &Header::closebox();
176 &Header::closebigbox();
177 &Header::closepage();
178 exit (0);
179}
180
181##
182## Sets management (create/delete/import/restore)
183##
184
185erase_files ($setdir); #clean up
186
187#
188# create new archive set
189#
190if ($settings{'ACTION'} eq $Lang::tr{'create'}) {
78331e30 191 $errormessage = &get_bk_error(system('/usr/local/bin/ipfirebkcfg > /dev/null')>>8);
ac1cfefa
MT
192 &import_set (" ".&Header::cleanhtml ($settings{'COMMENT'})) if (!$errormessage);
193}
194#
195# delete a backup set
196#
197if ($settings{'ACTION'} eq $Lang::tr{'remove'}) {
198 erase_files (&Header::cleanhtml ($settings{'KEY'})); # remove files
199 rmdir($settings{'KEY'}); # remove directory
200}
201#
202# import an archive set
203#
204if ($settings{'ACTION'} eq $Lang::tr{'import'}) {
205 if (ref ($settings{'FH'}) ne 'Fh') {
206 $errormessage = $Lang::tr{'no cfg upload'};
207 } else {
208 if (!copy ($settings{'FH'}, "$setdir/$datafile")) {
209 $errormessage = $Lang::tr{'save error'};
210 } else {
211 &import_set ('&nbsp;(imported)');
212 }
213 }
214}
215#
216# restore an archive
217#
218if ($settings{'ACTION'} eq $Lang::tr{'restore'}) {
219 if ($settings{'AreYouSure'} eq 'yes') {
220 if (!$cryptkeymissing) { # if keyfile exists
221 if (-e "$settings{'KEY'}/$datafile"){ # encrypted dat is required
222 copy_files($settings{'KEY'}, $setdir); # to working dir
78331e30 223 $errormessage = get_rs_error(system("/usr/local/bin/ipfirerscfg"
ac1cfefa
MT
224 . ($settings{'RESTOREHW'} eq 'on' ? ' --hardware' : '')
225 . ' >/dev/null')>>8);
226 if (!$errormessage) {
227 # restored ok, recommend restarting system
228 $warnmessage = $Lang::tr{'cfg restart'};
229 }
230 erase_files ($setdir); #clean up
231 } else {
232 $errormessage = $Lang::tr{'missing dat'}."$settings{'KEY'}/$datafile";
233 }
234 } else { # if keyfile does not exist
235 $errormessage = $Lang::tr{'backup missing key'};
236 }
237
238 } else { # not AreYouSure=yes
239 &Header::openpage($Lang::tr{'backup configuration'}, 1, '');
240 &Header::openbigbox('100%', 'left');
241 &Header::openbox('100%', 'left', $Lang::tr{'are you sure'});
242 print <<END
243<form method = 'post'>
244 <input type = 'hidden' name = 'KEY' value ='$settings{'KEY'}' />
245 <input type = 'hidden' name = 'AreYouSure' value ='yes' />
246 <table align = 'center'>
247 <tr>
248 <td align = 'center'>
249 <input type = 'submit' name = 'ACTION' value = '$Lang::tr{'restore'}' />
250 </td><td>
251 <input type = 'submit' name = 'ACTION' value = '$Lang::tr{'cancel'}' />
252 </td>
253 </tr><tr>
254 <td>
255 $Lang::tr{'restore hardware settings'}: <input type = 'checkbox' name = 'RESTOREHW'>
256 </td>
257 </tr>
258</table>
259</form>
260END
261;
262 &Header::closebox();
263 &Header::closebigbox();
264 &Header::closepage();
265 exit (0);
266 }
267}
268##
269## Media management
270##
271#
272# now build the list of removable device
273#
274
275# Read partitions sizes registered with the system
276my %partitions;
78331e30 277foreach my $li (`/usr/local/bin/ipfirebackup -proc partitions`) { # use suid helper...
ac1cfefa
MT
278 # partitions{'sda1'} = 128M if /major minor blocks name/
279 $partitions{$4} = &kmgt($3*1024,4) if ($li =~ /(\d+) +(\d+) +(\d+) +(.*)/);
280}
281
282# Search usb-storage scsi device
283my %medias;
284
78331e30 285foreach (`/usr/local/bin/ipfirebackup -glob '/proc/scsi/usb-storage*/*'`) {# use suid helper...
ac1cfefa
MT
286 my $m;
287 foreach ( `cat $_` ) { # list each line of information for the device:
288# Host scsi0: usb-storage
289# Vendor: SWISSBIT
290# Product: Black Silver
291# Serial Number: D0ED423A4F84A31E
292# Protocol: Transparent SCSI
293# Transport: Bulk
294# GUID: 13706828d0ed423a4f84a31e
295# Attached: Yes
296
297 chomp;
298 my ($key,$val) = split(': ',$_,2);
299 $key =~ s/^ *//; # remove front space
300
301 # convert 'scsi?' key to sda, sdb,... and use it as a %medias keyhash
302 if ($key =~ /Host scsi(.)/) {
303 $val = $m = 'sd' . chr(97+$1);
304 $key = 'Host';
305 }
306 $medias{$m}{$key} = $val; # save data
307 }
308}
309
310#
311# Switch mounted media
312#
313if ($settings{'ACTION'} eq $Lang::tr{'mount'})
314{
315 # Find what is really mounted under backup. Can be local hard disk or any removable media
316 my $mounted = &findmounted();
317 #umount previous, even if same device already mouted.
78331e30
MT
318 system ("/usr/local/bin/ipfirebackup -U $mounted") if ($mounted ne $Lang::tr{'local hard disk'});
319 $errormessage = `/usr/local/bin/ipfirebackup -M $settings{'SELECT'}` if (grep (/$settings{'SELECT'}/,%partitions));
ac1cfefa
MT
320}
321#
322# Compute a full description of device
323#
324my $mounted = &findmounted();
325my $media_des = $mounted; # Description
326if ($mounted ne $Lang::tr{'local hard disk'}) {
327 $_ = $mounted; # sda1 => sda
328 tr/0-9//d;
329 $media_des = "$medias{$_}{'Product'} ($media_des, $partitions{$mounted})";
330}
331&Header::openpage($Lang::tr{'backup configuration'}, 1, '');
332&Header::openbigbox('100%', 'left', '', $errormessage);
333
334if ($errormessage) {
335 &Header::openbox('100%', 'left', $Lang::tr{'error messages'});
336 print "<font class='base'>$errormessage&nbsp;</font>";
337 &Header::closebox();
338}
339
340$warnmessage = "<font color=${Header::colourred}><b>$Lang::tr{'capswarning'}</b></font>: $warnmessage <p>" if ($warnmessage);
341
342&Header::openbox('100%', 'left', $Lang::tr{'backup configuration'});
343
344#Divide the window in two : left and right
345print <<END
346 <table width = '100%' >
347 <tr>
348 <th width = '50%'>$Lang::tr{'current media'}:<font color=${Header::colourred}><b>$media_des</b></font></th>
349 <th width = '3%'></th>
350 <th>$Lang::tr{'choose media'}</th>
351 </tr>
352END
353;
354
355# Left part of window
356print <<END
357 <tr><td>
358 <ul>
359 <li>$Lang::tr{'backup sets'}:
360 <table width = '80%' border='0'>
361 <tr>
362 <th class = 'boldbase' align = 'center'>$Lang::tr{'name'}</th>
363 <th class = 'boldbase' align = 'center' colspan = '3'>$Lang::tr{'action'}</th>
364 </tr>
365END
366;
367
368# get list of available sets by globbing directories under $setdir
369# External device (usk key) are mounted in $setdir. -R permits finding sets in hierarchy.
370my $i = 0;
371foreach my $set (`ls -Rt1 $setdir`) {
372 chop ($set); #remove ':' & newline from line
373 chop ($set);
374 if (-d $set && ($set =~ m!/.+/\d{8}_\d{6}! ) ) { # filter out things not sets !
375 if ($i++ % 2) {
376 print "<tr bgcolor = '$Header::table2colour'>";
377 } else {
378 print "<tr bgcolor = '$Header::table1colour'>";
379 }
380 my $settime = read_timefile( "$set/$datefile", "$set/$datafile" );
381 my $name = substr ($set,length($setdir)+1);
382 print<<EOF
383<td>
384 $settime
385</td>
386
387<td align = 'center'>
388<form method = 'post'>
389<input type = 'hidden' name = 'ACTION' value ='$Lang::tr{'restore'}' />
390<input type = 'image' name = '$Lang::tr{'restore'}' src = '/images/reload.gif' alt = '$Lang::tr{'restore'}' title = '$Lang::tr{'restore'}' />
391<input type = 'hidden' name = 'KEY' value = '$set' />
392</form>
393</td>
394
395<td align = 'center'>
396<a href = '/backup/$name/$datafile'><img src = '/images/floppy.gif' title = '$Lang::tr{'export'}'></a>
397</td>
398
399<td align = 'center'>
400<form method = 'post'>
401<input type = 'hidden' name = 'ACTION' value = '$Lang::tr{'remove'}' />
402<input type = 'image' name = '$Lang::tr{'remove'}' src = '/images/delete.gif' alt = '$Lang::tr{'remove'}' title = '$Lang::tr{'remove'}' border = '0' />
403<input type = 'hidden' name = 'KEY' value = '$set' />
404</form>
405</td>
406</tr>
407EOF
408;
409 }
410}
411print "</table>" . ($i ? "<br>" : "$Lang::tr{'empty'}!<hr /><br>");
412print <<EOF
413$warnmessage
414<form method = 'post'>
415 <li>$Lang::tr{'backup configuration'}<br>
416 $Lang::tr{'description'}:<input type = 'text' name = 'COMMENT' size='30' />
417 <input type = 'submit' name = 'ACTION' value = '$Lang::tr{'create'}' />
418</form><p>
419<form method = 'post' enctype = 'multipart/form-data'>
420 <li>$Lang::tr{'backup import dat file'}:<br>
421 <input type = 'file' name = 'FH' size = '20' />
422 <input type = 'submit' name = 'ACTION' value = '$Lang::tr{'import'}' />
423</form>
424</ul>
425EOF
426;
427
428print "</td><td></td><td valign='top'>"; # Start right part (devices selection)
429print $Lang::tr{'backup media info'};
430
431print "<form method = 'post'>";
432print "<table width = '100%'><tr><td>";
433my $nodev = 1; # nothing present
434foreach my $media (keys %medias) {
435 if ( $medias{$media}{'Attached'} eq 'Yes') { # device is attached to USB bus ?
436 $nodev = 0; # at least one device present
437 my $checked = $medias{$media}{'Host'} eq $mounted ? "checked='checked'" : '';
438 print "<input type='radio' name = 'SELECT' value = '$medias{$media}{'Host'}' $checked />";
439 print "<b>$medias{$media}{'Product'}</b><br>";
440 # list attached partitions to this media
441 foreach my $part (sort (keys (%partitions))) {
442 if ($part =~ /$medias{$media}{'Host'}./) {
443 my $checked = $part eq $mounted ? "checked='checked'" : '';
444 print "&nbsp;&nbsp;&nbsp;<input type='radio' name = 'SELECT' value = '$part' $checked />$part ($partitions{$part})<br>";
445 }
446 }
447 }
448}
449if ($nodev) {
450 print "<br>$Lang::tr{'insert removable device'}";
451 print "</td><td>";
452 print "<br><input type = 'submit' name = 'ACTION' value = '$Lang::tr{'done'}' />";
453} else {
454 #Add an entry for the local disk
455 my $checked = $Lang::tr{'local hard disk'} eq $mounted ? "checked='checked'" : '';
456 print "<input type = 'radio' name = 'SELECT' value = '$Lang::tr{'local hard disk'}' $checked />";
457 print "<b>$Lang::tr{'local hard disk'}</b>";
458 print "</td><td>";
459 print "<br><input type = 'submit' name = 'ACTION' value = '$Lang::tr{'mount'}' />";
460}
461print "</tr></table>";
462print "</form>";
463#
464#Backup key
465#
466print<<EOF
467 <hr />
468<form method='post'>
469 <b>$Lang::tr{'backup key'}</b><br>
470 $Lang::tr{'backup key info'}<br>
471 <table><tr>
472 <td align= 'right'>$Lang::tr{'root user password'}:
473 <td align='left'><input type = 'password' name='PASSWORD' />
474 <input type = 'submit' name = 'ACTION' value = '$Lang::tr{'backup export key'}' />
475 </tr><tr>
476 <td align='right'>$Lang::tr{'backup protect key password'}:
477 <td align='left'><input type = 'password' name='PASSWORD1' size='10' />
478 </tr><tr>
479 <td align='right'>$Lang::tr{'again'}
480 <td align='left'><input type = 'password' name='PASSWORD2' size='10'/>
481 </tr></table>
482</form>
483
484EOF
485;
486# End of right table
487print "</td></tr></table>";
488
489&floppybox();
490
491&Header::closebox();
492&Header::closebigbox();
493&Header::closepage();
494
495sub floppybox {
496 print <<END
497<hr />
498<form method = 'post'>
499<table width='100%'>
500<tr>
501 <td>
502 <b>$Lang::tr{'backup to floppy'}</b>
503 </td>
504</tr>
505<tr>
506 <td width='50%'>
507 $Lang::tr{'insert floppy'}
508 </td>
509 <td align='center'>
510 <input type='submit' name='ACTION' value='$Lang::tr{'backup to floppy'}' />
511 </td>
512</tr>
513</table>
514</form>
515END
516;
517 print "<b>$Lang::tr{'alt information'}</b><pre>" .
78331e30 518 `/usr/local/bin/ipfirebackup -savecfg floppy` .
ac1cfefa
MT
519 '&nbsp;</pre>' if ($settings{'ACTION'} eq $Lang::tr{'backup to floppy'} );
520}
521
522# Return device name of what is mounted under 'backup'
523sub findmounted() {
524 my $mounted = `mount|grep ' /home/httpd/html/backup '`;
525 if ($mounted) { # extract device name
526 $mounted =~ m!^/dev/(.*) on!; # device on mountmoint options
527 return $1;
528 } else { # it's the normal subdir
529 return $Lang::tr{'local hard disk'};
530 }
531}
532# read and return a date/time string from a time file
533sub read_timefile() {
534 my $fname = shift; # name of file to read from
535 my $fname2 = shift; # if first file doesn't exist, get date of this file
536
537 my $dt;
538 if (defined(open(FH, "<$fname"))) {
539 $dt = <FH>;
540 chomp $dt;
541 close(FH);
542 } else {
543 $dt = &get_fdate($fname2); # get file date/time
544 write_timefile($fname, $dt); # write to expected time file
545 }
546 return $dt;
547}
548# write a date/time string to a time file
549sub write_timefile() {
550 my $fname = shift; # name of file to write to
551 my $dt = shift; # date/time string to write
552
553 if (open(FH, ">$fname")) {
554 print FH "$dt\n";
555 close(FH);
556 }
557}
558# move a dat file without time stamp to subdir
559sub import_set() {
560 my $dt = get_fdate("$setdir/$datafile") . shift;
561 &write_timefile("$setdir/$datefile", $dt);
562
563 # create set directory
564 my $setname = "$setdir/" . get_ddate("$setdir/$datafile");
565 mkdir($setname);
566
567 # move files to the new set directory
568 copy_files($setdir, $setname);
569 erase_files ($setdir);
570}
571
572# get date/time string from file
573sub get_fdate() {
574 my $fname = shift;
575 open(DT, "/bin/date -r $fname|");
576 my $dt = <DT>;
577 close(DT);
578 chomp $dt;
579 $dt =~ s/\s+/ /g; # remove duplicate spaces
580 return $dt;
581}
582# get date/time string from file for use as directory name
583sub get_ddate() {
584 my $fname = shift;
585 open(DT, "/bin/date -r $fname +%Y%m%d_%H%M%S|");
586 my $dt = <DT>;
587 close(DT);
588 chomp $dt;
589 return $dt;
590}
591# copy archive files from source directory to destination directory
592sub copy_files() {
593 my $src_dir = shift;
594 my $dest_dir = shift;
595 map (copy ("$src_dir/$_", "$dest_dir/$_"), ($datafile, $datefile) );
596}
597# erase set files
598sub erase_files() {
599 my $src_dir = shift;
600 map (unlink ("$src_dir/$_"), ($datafile, $datefile));
601}
602# get backup error text
603sub get_bk_error() {
604 my $exit_code = shift || return '';
605 if ($exit_code == 0) {
606 return '';
607 } elsif ($exit_code == 2) {
608 return $Lang::tr{'err bk 2 key'};
609 } elsif ($exit_code == 3) {
610 return $Lang::tr{'err bk 3 tar'};
611 } elsif ($exit_code == 4) {
612 return $Lang::tr{'err bk 4 gz'};
613 } elsif ($exit_code == 5) {
614 return $Lang::tr{'err bk 5 encrypt'};
615 } else {
616 return $Lang::tr{'err bk 1'};
617 }
618}
619# show any restore errors
620sub get_rs_error() {
621
622 my $exit_code = shift || return '';
623 if ($exit_code == 0) {
624 return '';
625 } elsif ($exit_code == 6) {
626 return $Lang::tr{'err rs 6 decrypt'};
627 } elsif ($exit_code == 7) {
628 return $Lang::tr{'err rs 7 untartst'};
629 } elsif ($exit_code == 8) {
630 return $Lang::tr{'err rs 8 untar'};
631 } elsif ($exit_code == 9) {
632 return $Lang::tr{'missing dat'};
633 } else {
634 return $Lang::tr{'err rs 1'}."($exit_code)";
635 }
636}
637sub kmgt {
638 my ($value,$length,$opt_U) = @_;
639 if ( $value > 10**( $length + 8 ) or $opt_U eq 'T' ) {
640 return sprintf( "%d%s", int( ( $value / 1024**4 ) + .5 ), 'T' );
641 } elsif ( $value > 10**( $length + 5 ) or $opt_U eq 'G' ) {
642 return sprintf( "%d%s", int( ( $value / 1024**3 ) + .5 ), 'G' );
643 } elsif ( $value > 10**( $length + 2 ) or $opt_U eq 'M' ) {
644 return sprintf( "%d%s", int( ( $value / 1024**2 ) + .5 ), 'M' );
645 } elsif ( $value > 10**($length) or $opt_U eq 'K' ) {
646 return sprintf( "%d%s", int( ( $value / 1024 ) + .5 ), 'K' );
647 } else {
648 return $value;
649 }
650}
651
6521;