First checkin of Bacula module

This commit is contained in:
Jamie Cameron
2007-06-27 21:04:56 +00:00
parent bf1db966f9
commit 8a357076cf
182 changed files with 7440 additions and 0 deletions

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1 @@
../file/BorderPanel.java

2
bacula-backup/CHANGELOG Normal file
View File

@@ -0,0 +1,2 @@
---- Changes since 1.350 ----
First version of this module, which allows Bacula to be configured and both backups and restores to be executed.

Binary file not shown.

1
bacula-backup/CbButton.java Symbolic link
View File

@@ -0,0 +1 @@
../file/CbButton.java

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1 @@
../file/CbScrollbar.java

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1 @@
../file/ErrorWindow.java

Binary file not shown.

View File

@@ -0,0 +1 @@
../file/FixedFrame.java

Binary file not shown.

View File

@@ -0,0 +1 @@
../file/GrayPanel.java

Binary file not shown.

View File

@@ -0,0 +1 @@
../file/Hierarchy.java

Binary file not shown.

Binary file not shown.

2
bacula-backup/Makefile Normal file
View File

@@ -0,0 +1,2 @@
TreeChooser.class: TreeChooser.java
CLASSPATH=/usr/local/netscape7/plugins/java2/lib/javaplugin.jar:. javac -target 1.1 *.java

Binary file not shown.

View File

@@ -0,0 +1,295 @@
import java.awt.*;
import java.io.*;
import java.applet.*;
import java.net.*;
import java.util.*;
import netscape.javascript.JSObject;
public class TreeChooser extends Applet
implements CbButtonCallback, HierarchyCallback
{
CbButton add_b, remove_b, close_b;
Hierarchy tree;
BaculaNode root;
String volume;
String session;
String job;
Vector added = new Vector();
public void init()
{
// Create the root
String rpath = getParameter("root");
root = new BaculaNode(this, rpath, true, null);
volume = getParameter("volume");
session = getParameter("session");
job = getParameter("job");
// Build the UI
setLayout(new BorderLayout());
BorderPanel top = new BorderPanel(2);
top.setLayout(new FlowLayout(FlowLayout.LEFT));
top.add(add_b = new CbButton("Add", this));
top.add(remove_b = new CbButton("Remove", this));
top.add(close_b = new CbButton("Close", this));
add("North", top);
add("Center", tree = new Hierarchy(root, this));
}
Image get_image(String img)
{
return getImage(getDocumentBase(), "images/"+img);
}
String[] get_text(String url)
{
Cursor orig = getCursor();
try {
Cursor busy = Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR);
setCursor(busy);
long now = System.currentTimeMillis();
if (url.indexOf('?') > 0) url += "&rand="+now;
else url += "?rand="+now;
URL u = new URL(getDocumentBase(), url);
URLConnection uc = u.openConnection();
set_cookie(uc);
String charset = get_charset(uc.getContentType());
BufferedReader is = new BufferedReader(
(charset == null) ?
new InputStreamReader(uc.getInputStream()) :
new InputStreamReader(uc.getInputStream(), charset));
Vector lv = new Vector();
while(true) {
String l = is.readLine();
if (l == null) { break; }
lv.addElement(l);
}
is.close();
String rv[] = new String[lv.size()];
lv.copyInto(rv);
return rv;
}
catch(Exception e) {
e.printStackTrace();
//return null;
String err[] = { e.getMessage() };
return err;
}
finally {
setCursor(orig);
}
}
void set_cookie(URLConnection conn)
{
if (session != null)
conn.setRequestProperty("Cookie", session);
}
// Gets charset parameter from Content-Type: header
String get_charset(String ct)
{
if (ct == null)
return null;
StringTokenizer st = new StringTokenizer(ct, ";");
while (st.hasMoreTokens()) {
String l = st.nextToken().trim().toLowerCase();
if (l.startsWith("charset=")) {
// get the value of charset= param.
return l.substring(8);
}
}
return null;
}
public void openNode(Hierarchy h, HierarchyNode n)
{
// Get the files under this directory, and expand the tree
BaculaNode bn = (BaculaNode)n;
bn.fill();
}
public void closeNode(Hierarchy h, HierarchyNode n)
{
// No need to do anything
}
public void clickNode(Hierarchy h, HierarchyNode n)
{
// Also no need to do anything
}
public void doubleNode(Hierarchy h, HierarchyNode n)
{
// add or remove a file
BaculaNode sel = (BaculaNode)n;
if (sel.added) remove_node(sel);
else add_node(sel);
}
public void click(CbButton b)
{
BaculaNode sel = (BaculaNode)tree.selected();
if (b == close_b) {
// Close the window, and update the text box
try {
JSObject win = JSObject.getWindow(this);
String params1[] = { "" };
win.call("clear_files", params1);
for(int i=0; i<added.size(); i++) {
BaculaNode n = (BaculaNode)added.elementAt(i);
String params2[] = { n.path };
if (n.isdir && !n.path.equals("/"))
params2[0] = n.path+"/";
win.call("add_file", params2);
}
String params3[] = { "" };
win.call("finished", params3);
}
catch(Exception e) {
e.printStackTrace();
new ErrorWindow("Failed to set files : "+
e.getMessage());
}
}
else if (b == add_b) {
// Flag the selected file as added
if (sel != null) {
add_node(sel);
}
}
else if (b == remove_b) {
// Un-flag the selected file
if (sel != null) {
remove_node(sel);
}
}
}
void add_node(BaculaNode n)
{
if (!n.added) {
n.added = true;
n.set_all_icons();
tree.redraw();
added.addElement(n);
}
}
void remove_node(BaculaNode n)
{
if (n.added) {
n.added = false;
n.set_all_icons();
tree.redraw();
added.removeElement(n);
}
}
static String urlize(String s)
{
StringBuffer rv = new StringBuffer();
for(int i=0; i<s.length(); i++) {
char c = s.charAt(i);
if (c < 16)
rv.append("%0"+Integer.toString(c, 16));
else if (!Character.isLetterOrDigit(c) && c != '/' &&
c != '.' && c != '_' && c != '-')
rv.append("%"+Integer.toString(c, 16));
else
rv.append(c);
}
return rv.toString();
}
}
class BaculaNode extends HierarchyNode
{
TreeChooser parent;
String path;
boolean isdir;
boolean known = false;
boolean added = false;
BaculaNode dir;
BaculaNode(TreeChooser parent, String path, boolean isdir, BaculaNode dir)
{
this.parent = parent;
this.path = path;
this.isdir = isdir;
this.dir = dir;
open = false;
set_icon();
ch = isdir ? new Vector() : null;
if (path.equals("/"))
text = "/";
else {
String ns = path.endsWith("/") ?
path.substring(0, path.length() - 1) : path;
int slash = ns.lastIndexOf("/");
text = path.substring(slash+1);
}
}
void set_icon()
{
String imname = isdir ? "dir.gif" : "rfile.gif";
if (selected()) imname = "s"+imname;
im = parent.get_image(imname);
}
void set_all_icons()
{
set_icon();
if (ch != null) {
for(int i=0; i<ch.size(); i++) {
BaculaNode c = (BaculaNode)ch.elementAt(i);
c.set_all_icons();
}
}
}
void fill()
{
if (!known && isdir) {
ch.removeAllElements();
String l[] = parent.get_text("list.cgi?dir="+
parent.urlize(path)+
"&volume="+
parent.urlize(parent.volume)+
"&job="+
parent.urlize(parent.job));
if (l[0].length() > 0) {
new ErrorWindow("Failed to get files under "+path+
" : "+l[0]);
return;
}
for(int i=1; i<l.length; i++) {
if (l[i].endsWith("/")) {
ch.addElement(
new BaculaNode(
parent, l[i].substring(0, l[i].length()-1),
true, this));
}
else {
ch.addElement(
new BaculaNode(
parent, l[i], false, this));
}
}
parent.tree.redraw();
known = true;
}
}
boolean selected()
{
BaculaNode n = this;
while(n != null) {
if (n.added) return true;
n = n.dir;
}
return false;
}
}

BIN
bacula-backup/Util.class Normal file

Binary file not shown.

1
bacula-backup/Util.java Symbolic link
View File

@@ -0,0 +1 @@
../file/Util.java

11
bacula-backup/apply.cgi Executable file
View File

@@ -0,0 +1,11 @@
#!/usr/local/bin/perl
# Apply the Bacula configuration
require './bacula-backup-lib.pl';
&error_setup($text{'apply_err'});
$err = &apply_configuration();
&error($err) if ($err);
&webmin_log("restart");
&redirect("");

81
bacula-backup/backup.cgi Executable file
View File

@@ -0,0 +1,81 @@
#!/usr/local/bin/perl
# Actually execute a backup
require './bacula-backup-lib.pl';
&ui_print_unbuffered_header(undef, $text{'backup_title'}, "");
&ReadParse();
print "<b>",&text('backup_run', "<tt>$in{'job'}</tt>"),"</b>\n";
print "<pre>";
$h = &open_console();
# Clear messages
&console_cmd($h, "messages");
# Select the job to run
&sysprint($h->{'infh'}, "run\n");
&wait_for($h->{'outfh'}, 'run\\n');
$rv = &wait_for($h->{'outfh'}, 'Select Job.*:');
print $wait_for_input;
if ($rv == 0 && $wait_for_input =~ /(\d+):\s+\Q$in{'job'}\E/) {
&sysprint($h->{'infh'}, "$1\n");
}
else {
&job_error($text{'backup_ejob'});
}
# Say that it is OK
$rv = &wait_for($h->{'outfh'}, 'OK to run.*:');
print $wait_for_input;
if ($rv == 0) {
&sysprint($h->{'infh'}, "yes\n");
}
else {
&job_error($text{'backup_eok'});
}
print "</pre>";
if ($in{'wait'}) {
# Wait till we have a status
print "</pre>\n";
print "<b>",$text{'backup_running'},"</b>\n";
print "<pre>";
while(1) {
$out = &console_cmd($h, "messages");
if ($out !~ /You\s+have\s+no\s+messages/i) {
print $out;
}
if ($out =~ /Termination:\s+(.*)/) {
$status = $1;
last;
}
sleep(1);
}
print "</pre>\n";
if ($status =~ /Backup\s+OK/i && $status !~ /warning/i) {
print "<b>",$text{'backup_done'},"</b><p>\n";
}
else {
print "<b>",$text{'backup_failed'},"</b><p>\n";
}
}
else {
# Let it fly
print "<b>",$text{'backup_running2'},"</b><p>\n";
}
&close_console($h);
&webmin_log("backup", $in{'job'});
&ui_print_footer("backup_form.cgi", $text{'backup_return'});
sub job_error
{
&close_console($h);
print "</pre>\n";
print "<b>",@_,"</b><p>\n";
&ui_print_footer("backup_form.cgi", $text{'backup_return'});
exit;
}

24
bacula-backup/backup_form.cgi Executable file
View File

@@ -0,0 +1,24 @@
#!/usr/local/bin/perl
# Show a form for running one backup job
require './bacula-backup-lib.pl';
&ui_print_header(undef, $text{'backup_title'}, "", "backup");
print &ui_form_start("backup.cgi", "post");
print &ui_table_start($text{'backup_header'}, undef, 2);
# Job to run
@jobs = sort { lc($a->{'name'}) cmp lc($b->{'name'}) }
grep { !&is_oc_object($_) } &get_bacula_jobs();
print &ui_table_row($text{'backup_job'},
&ui_select("job", undef,
[ map { [ $_->{'name'}, &text('backup_jd', $_->{'name'}, $_->{'fileset'}, $_->{'client'}) ] } @jobs ]));
# Wait for completion?
print &ui_table_row($text{'backup_wait'},
&ui_yesno_radio("wait", $config{'wait'}));
print &ui_table_end();
print &ui_form_end([ [ "backup", $text{'backup_ok'} ] ]);
&ui_print_footer("", $text{'index_return'});

File diff suppressed because it is too large Load Diff

21
bacula-backup/bootup.cgi Executable file
View File

@@ -0,0 +1,21 @@
#!/usr/local/bin/perl
# Start or stop Bacula at boot
require './bacula-backup-lib.pl';
&ReadParse();
&foreign_require("init", "init-lib.pl");
if ($in{'boot'}) {
foreach $p (@bacula_inits) {
&init::enable_at_boot($p);
}
&webmin_log("bootup");
}
else {
foreach $p (@bacula_inits) {
&init::disable_at_boot($p);
}
&webmin_log("bootdown");
}
&redirect("");

32
bacula-backup/cancel_jobs.cgi Executable file
View File

@@ -0,0 +1,32 @@
#!/usr/local/bin/perl
# Cancel running jobs
require './bacula-backup-lib.pl';
&ReadParse();
if (!$in{'refresh'}) {
# Cancel jobs if not refreshing
&error_setup($text{'cancel_err'});
@d = split(/\0/, $in{'d'});
@d || &error($text{'cancel_enone'});
$h = &open_console();
foreach $d (@d) {
$out = &console_cmd($h, "cancel JobId=$d");
if ($out =~ /failed|error/i) {
&error(&text('dvolumes_ebacula', "<tt>$out</tt>"));
}
}
&close_console($h);
}
if ($in{'client'}) {
&redirect("clientstatus_form.cgi?client=$in{'client'}");
}
elsif ($in{'storage'}) {
&redirect("storagestatus_form.cgi?storage=$in{'storage'}");
}
else {
&redirect("dirstatus_form.cgi");
}

View File

@@ -0,0 +1,93 @@
#!/usr/local/bin/perl
# Show a form for displaying the status of one client
require './bacula-backup-lib.pl';
&ui_print_header(undef, $text{'clientstatus_title'}, "", "clientstatus");
&ReadParse();
# Client selector
@clients = sort { lc($a->{'name'}) cmp lc($b->{'name'}) }
grep { !&is_oc_object($_, 1) } &get_bacula_clients();
if (@clients == 1) {
$in{'client'} ||= $clients[0]->{'name'};
}
print &ui_form_start("clientstatus_form.cgi");
print "<b>$text{'clientstatus_show'}</b>\n";
print &ui_select("client", $in{'client'},
[ map { [ $_->{'name'},
&text('clientstatus_on', $_->{'name'}, $_->{'address'}) ] }
@clients ]);
print &ui_submit($text{'clientstatus_ok'}),"<br>\n";
print &ui_form_end();
if ($in{'client'}) {
# Show this client
($msg, $ok, $run, $done) = &get_client_status($in{'client'});
if ($ok) {
print &text('clientstatus_msg', $in{'client'}, $msg),"<p>\n";
# Running jobs
print &ui_subheading($text{'dirstatus_run'});
if (@$run) {
print &ui_form_start("cancel_jobs.cgi", "post");
print &ui_hidden("client", $in{'client'}),"\n";
@links = ( &select_all_link("d", 1),
&select_invert_link("d", 1) );
print &ui_links_row(\@links);
@tds = ( "width=5" );
print &ui_columns_start([ "", $text{'dirstatus_name'},
$text{'dirstatus_id'},
$text{'dirstatus_date2'} ],
"100%", 0, \@tds);
foreach $j (@$run) {
print &ui_checked_columns_row([
&joblink($j->{'name'}),
$j->{'id'},
$j->{'date'} ], \@tds, "d", $j->{'id'});
}
print &ui_columns_end();
print &ui_links_row(\@links);
print &ui_form_end([ [ "cancel", $text{'dirstatus_cancel'} ] ]);
}
else {
print "<b>$text{'dirstatus_runnone'}</b><p>\n";
}
# Completed jobs
print &ui_subheading($text{'dirstatus_done'});
if (@$done) {
print &ui_columns_start([ $text{'dirstatus_name'},
$text{'dirstatus_id'},
$text{'dirstatus_level'},
$text{'dirstatus_date'},
$text{'dirstatus_bytes'},
$text{'dirstatus_files'},
$text{'dirstatus_status2'} ],
"100%");
foreach $j (@$done) {
print &ui_columns_row([
&joblink($j->{'name'}),
$j->{'id'},
$j->{'level'},
$j->{'date'},
&nice_size($j->{'bytes'}),
$j->{'files'},
$j->{'status'} ]);
}
print &ui_columns_end();
}
else {
print "<b>$text{'dirstatus_donenone'}</b><p>\n";
}
}
else {
# Couldn't connect!
print "<b>",&text('clientstatus_err', $in{'client'}, $msg),
"</b><p>\n";
}
}
&ui_print_footer("", $text{'index_return'});

11
bacula-backup/config Normal file
View File

@@ -0,0 +1,11 @@
driver=Pg
user=bacula
pass=
db=bacula
bacula_dir=/etc/bacula
bextract=bextract
bls=bls
btape=btape
wait=1
apply=1
showdirs=0

View File

@@ -0,0 +1,11 @@
driver=Pg
user=bacula
pass=opencountry
db=bacula
bacula_dir=c:/bacula/bin
bextract=bextract
bls=bls
btape=btape
wait=1
apply=1
showdirs=0

15
bacula-backup/config.info Normal file
View File

@@ -0,0 +1,15 @@
line0=Configurable options,11
wait=Default backup wait mode,1,1-Wait for completion,0-Run in background
apply=Automatically apply director configuration?,1,1-Yes,0-No
groupmode=Get node group information from,1,webmin-Webmin Servers Index module,oc-OCM Manager database,-Nowhere
showdirs=Always show remote directors?,1,1-Yes,0-No
line1=Bacula database settings,11
driver=Database type,1,Pg-PostgreSQL,mysql-MySQL,SQLite-SQLite
user=User to login to database as,0
pass=Password to login with,0
db=Database or file containing Bacula information,0
line2=File settings,11
bacula_dir=Bacula configuration directory,0
bextract=Full path to <tt>bextract</tt> command,0
bls=Full path to <tt>bls</tt> command,0
btape=Full path to <tt>btape</tt> command,0

View File

@@ -0,0 +1,27 @@
#!/usr/local/bin/perl
# Delete multiple clients
require './bacula-backup-lib.pl';
&ReadParse();
$conf = &get_director_config();
$parent = &get_director_config_parent();
@clients = &find("Client", $conf);
&error_setup($text{'clients_derr'});
@d = split(/\0/, $in{'d'});
@d || &error($text{'filesets_ednone'});
&lock_file($parent->{'file'});
foreach $d (@d) {
$client = &find_by("Name", $d, \@clients);
if ($client) {
$child = &find_dependency("Client", $d, [ "Job", "JobDefs" ], $conf);
$child && &error(&text('client_echild', $child));
&save_directive($conf, $parent, $client, undef, 0);
}
}
&flush_file_lines($parent->{'file'});
&unlock_file($parent->{'file'});
&webmin_log("delete", "clients", scalar(@d));
&redirect("list_clients.cgi");

View File

@@ -0,0 +1,25 @@
#!/usr/local/bin/perl
# Delete multiple fdirector devices
require './bacula-backup-lib.pl';
&ReadParse();
$conf = &get_file_config();
$parent = &get_file_config_parent();
@fdirectors = &find("Director", $conf);
&error_setup($text{'fdirectors_derr'});
@d = split(/\0/, $in{'d'});
@d || &error($text{'filesets_ednone'});
&lock_file($parent->{'file'});
foreach $d (@d) {
$fdirector = &find_by("Name", $d, \@fdirectors);
if ($fdirector) {
&save_directive($conf, $parent, $fdirector, undef, 0);
}
}
&flush_file_lines($parent->{'file'});
&unlock_file($parent->{'file'});
&webmin_log("delete", "fdirectors", scalar(@d));
&redirect("list_fdirectors.cgi");

View File

@@ -0,0 +1,27 @@
#!/usr/local/bin/perl
# Delete multiple filesets
require './bacula-backup-lib.pl';
&ReadParse();
$conf = &get_director_config();
$parent = &get_director_config_parent();
@filesets = &find("FileSet", $conf);
&error_setup($text{'filesets_derr'});
@d = split(/\0/, $in{'d'});
@d || &error($text{'filesets_ednone'});
&lock_file($parent->{'file'});
foreach $d (@d) {
$fileset = &find_by("Name", $d, \@filesets);
if ($fileset) {
$child = &find_dependency("Client", $d, [ "Job", "JobDefs" ], $conf);
$child && &error(&text('fileset_echild', $child));
&save_directive($conf, $parent, $fileset, undef, 0);
}
}
&flush_file_lines($parent->{'file'});
&unlock_file($parent->{'file'});
&webmin_log("delete", "filesets", scalar(@d));
&redirect("list_filesets.cgi");

33
bacula-backup/delete_gjobs.cgi Executable file
View File

@@ -0,0 +1,33 @@
#!/usr/local/bin/perl
# Delete group backup jobs
require './bacula-backup-lib.pl';
&ReadParse();
$conf = &get_director_config();
$parent = &get_director_config_parent();
@jobs = &find("JobDefs", $conf);
@nodegroups = &list_node_groups();
&error_setup($text{'gjobs_derr'});
@d = split(/\0/, $in{'d'});
@d || &error($text{'filesets_ednone'});
&lock_file($parent->{'file'});
foreach $d (@d) {
$job = &find_by("Name", "ocjob_".$d, \@jobs);
if ($job) {
$client = &find_value("Client", $job->{'members'});
&save_directive($conf, $parent, $job, undef, 0);
($nodegroup) = grep { $_->{'name'} eq $client } @nodegroups;
if ($nodegroup) {
&sync_group_clients($nodegroup);
}
}
}
&flush_file_lines($parent->{'file'});
&unlock_file($parent->{'file'});
&webmin_log("delete", "gjobs", scalar(@d));
&redirect("list_gjobs.cgi");

34
bacula-backup/delete_groups.cgi Executable file
View File

@@ -0,0 +1,34 @@
#!/usr/local/bin/perl
# Delete multiple node groups
require './bacula-backup-lib.pl';
&ReadParse();
$conf = &get_director_config();
$parent = &get_director_config_parent();
@clients = &find("Client", $conf);
@nodegroups = &list_node_groups();
&error_setup($text{'groups_derr'});
@d = split(/\0/, $in{'d'});
@d || &error($text{'filesets_ednone'});
&lock_file($parent->{'file'});
foreach $d (@d) {
$client = &find_by("Name", "ocgroup_".$d, \@clients);
if ($client) {
$child = &find_dependency("Client", $d, [ "Job", "JobDefs" ], $conf);
$child && &error(&text('client_echild', $child));
&save_directive($conf, $parent, $client, undef, 0);
($nodegroup) = grep { $_->{'name'} eq $d } @nodegroups;
if ($nodegroup) {
&sync_group_clients($nodegroup);
}
}
}
&flush_file_lines($parent->{'file'});
&unlock_file($parent->{'file'});
&webmin_log("delete", "groups", scalar(@d));
&redirect("list_groups.cgi");

27
bacula-backup/delete_jobs.cgi Executable file
View File

@@ -0,0 +1,27 @@
#!/usr/local/bin/perl
# Delete multiple jobs
require './bacula-backup-lib.pl';
&ReadParse();
$conf = &get_director_config();
$parent = &get_director_config_parent();
@jobs = ( &find("JobDefs", $conf), &find("Job", $conf) );
&error_setup($text{'jobs_derr'});
@d = split(/\0/, $in{'d'});
@d || &error($text{'filesets_ednone'});
&lock_file($parent->{'file'});
foreach $d (@d) {
$job = &find_by("Name", $d, \@jobs);
if ($job) {
$child = &find_dependency("JobDefs", $d, [ "Job" ], $conf);
$child && &error(&text('job_echild', $child));
&save_directive($conf, $parent, $job, undef, 0);
}
}
&flush_file_lines($parent->{'file'});
&unlock_file($parent->{'file'});
&webmin_log("delete", "jobs", scalar(@d));
&redirect("list_jobs.cgi");

27
bacula-backup/delete_pools.cgi Executable file
View File

@@ -0,0 +1,27 @@
#!/usr/local/bin/perl
# Delete multiple pool devices
require './bacula-backup-lib.pl';
&ReadParse();
$conf = &get_director_config();
$parent = &get_director_config_parent();
@pools = &find("Pool", $conf);
&error_setup($text{'pools_derr'});
@d = split(/\0/, $in{'d'});
@d || &error($text{'filesets_ednone'});
&lock_file($parent->{'file'});
foreach $d (@d) {
$pool = &find_by("Name", $d, \@pools);
if ($pool) {
$child = &find_dependency("Pool", $d, [ "Job", "JobDefs" ], $conf);
$child && &error(&text('pool_echild', $child));
&save_directive($conf, $parent, $pool, undef, 0);
}
}
&flush_file_lines($parent->{'file'});
&unlock_file($parent->{'file'});
&webmin_log("delete", "pools", scalar(@d));
&redirect("list_pools.cgi");

View File

@@ -0,0 +1,27 @@
#!/usr/local/bin/perl
# Delete multiple schedules
require './bacula-backup-lib.pl';
&ReadParse();
$conf = &get_director_config();
$parent = &get_director_config_parent();
@schedules = &find("Schedule", $conf);
&error_setup($text{'schedules_derr'});
@d = split(/\0/, $in{'d'});
@d || &error($text{'filesets_ednone'});
&lock_file($parent->{'file'});
foreach $d (@d) {
$schedule = &find_by("Name", $d, \@schedules);
if ($schedule) {
$child = &find_dependency("Schedule", $d, [ "Job", "JobDefs" ], $conf);
$child && &error(&text('schedule_echild', $child));
&save_directive($conf, $parent, $schedule, undef, 0);
}
}
&flush_file_lines($parent->{'file'});
&unlock_file($parent->{'file'});
&webmin_log("delete", "schedules", scalar(@d));
&redirect("list_schedules.cgi");

View File

@@ -0,0 +1,25 @@
#!/usr/local/bin/perl
# Delete multiple storage daemon directors
require './bacula-backup-lib.pl';
&ReadParse();
$conf = &get_storage_config();
$parent = &get_storage_config_parent();
@sdirectors = &find("Director", $conf);
&error_setup($text{'sdirectors_derr'});
@d = split(/\0/, $in{'d'});
@d || &error($text{'filesets_ednone'});
&lock_file($parent->{'file'});
foreach $d (@d) {
$sdirector = &find_by("Name", $d, \@sdirectors);
if ($sdirector) {
&save_directive($conf, $parent, $sdirector, undef, 0);
}
}
&flush_file_lines($parent->{'file'});
&unlock_file($parent->{'file'});
&webmin_log("delete", "sdirectors", scalar(@d));
&redirect("list_sdirectors.cgi");

View File

@@ -0,0 +1,27 @@
#!/usr/local/bin/perl
# Delete multiple storage devices
require './bacula-backup-lib.pl';
&ReadParse();
$conf = &get_director_config();
$parent = &get_director_config_parent();
@storages = &find("Storage", $conf);
&error_setup($text{'storages_derr'});
@d = split(/\0/, $in{'d'});
@d || &error($text{'filesets_ednone'});
&lock_file($parent->{'file'});
foreach $d (@d) {
$storage = &find_by("Name", $d, \@storages);
if ($storage) {
$child = &find_dependency("Storage", $d, [ "Job", "JobDefs" ], $conf);
$child && &error(&text('storage_echild', $child));
&save_directive($conf, $parent, $storage, undef, 0);
}
}
&flush_file_lines($parent->{'file'});
&unlock_file($parent->{'file'});
&webmin_log("delete", "storages", scalar(@d));
&redirect("list_storages.cgi");

View File

@@ -0,0 +1,24 @@
#!/usr/local/bin/perl
# Delete a bunch of volumes from a pool
require './bacula-backup-lib.pl';
&ReadParse();
&error_setup($text{'dvolumes_err'});
@d = split(/\0/, $in{'d'});
@d || &error($text{'dvolumes_enone'});
$h = &open_console();
foreach $d (@d) {
&sysprint($h->{'infh'}, "delete media volume=$d\n");
$rv = &wait_for($h->{'outfh'}, "Are you sure.*:");
if ($rv == 0) {
&sysprint($h->{'infh'}, "yes\n");
}
else {
&error(&text('dvolumes_ebacula', "<tt>$wait_for_input</tt>"));
}
}
&close_console($h);
&redirect("poolstatus_form.cgi?pool=$in{'pool'}");

View File

@@ -0,0 +1,92 @@
#!/usr/local/bin/perl
# Show the status of the director, including recent jobs
require './bacula-backup-lib.pl';
&ui_print_header(undef, $text{'dirstatus_title'}, "", "dirstatus");
($sched, $run, $done) = &get_director_status();
# Running jobs
print &ui_subheading($text{'dirstatus_run'});
if (@$run) {
print &ui_form_start("cancel_jobs.cgi", "post");
@links = ( &select_all_link("d"),
&select_invert_link("d") );
print &ui_links_row(\@links);
@tds = ( "width=5" );
print &ui_columns_start([ "",
$text{'dirstatus_name'},
$text{'dirstatus_id'},
$text{'dirstatus_level'},
$text{'dirstatus_status'} ], "100%",
0, \@tds);
foreach $j (@$run) {
print &ui_checked_columns_row([
&joblink($j->{'name'}),
$j->{'id'},
$j->{'level'},
$j->{'status'} ], \@tds, "d", $j->{'id'});
}
print &ui_columns_end();
print &ui_links_row(\@links);
print &ui_form_end([ [ "cancel", $text{'dirstatus_cancel'} ],
[ "refresh", $text{'dirstatus_refresh'} ] ]);
}
else {
print "<b>$text{'dirstatus_runnone'}</b><p>\n";
print &ui_form_start("cancel_jobs.cgi");
print &ui_form_end([ [ "refresh", $text{'dirstatus_refresh'} ] ]);
}
# Completed jobs
print &ui_subheading($text{'dirstatus_done'});
if (@$done) {
print &ui_columns_start([ $text{'dirstatus_name'},
$text{'dirstatus_id'},
$text{'dirstatus_level'},
$text{'dirstatus_date'},
$text{'dirstatus_bytes'},
$text{'dirstatus_files'},
$text{'dirstatus_status2'} ], "100%");
foreach $j (@$done) {
print &ui_columns_row([
&joblink($j->{'name'}),
$j->{'id'},
$j->{'level'},
$j->{'date'},
&nice_size($j->{'bytes'}),
$j->{'files'},
$j->{'status'} ]);
}
print &ui_columns_end();
}
else {
print "<b>$text{'dirstatus_donenone'}</b><p>\n";
}
# Scheduled jobs
print &ui_subheading($text{'dirstatus_sched'});
if (@$sched) {
print &ui_columns_start([ $text{'dirstatus_name'},
$text{'dirstatus_level'},
$text{'dirstatus_type'},
$text{'dirstatus_date'},
$text{'dirstatus_volume'} ], "100%");
foreach $j (@$sched) {
print &ui_columns_row([
&joblink($j->{'name'}),
$j->{'level'},
$j->{'type'},
$j->{'date'},
$j->{'volume'} ]);
}
print &ui_columns_end();
}
else {
print "<b>$text{'dirstatus_schednone'}</b><p>\n";
}
&ui_print_footer("", $text{'index_return'});

84
bacula-backup/edit_client.cgi Executable file
View File

@@ -0,0 +1,84 @@
#!/usr/local/bin/perl
# Show the details of one client
require './bacula-backup-lib.pl';
&ReadParse();
$conf = &get_director_config();
@clients = &find("Client", $conf);
@catalogs = map { $n=&find_value("Name", $_->{'members'}) }
&find("Catalog", $conf);
if ($in{'new'}) {
&ui_print_header(undef, $text{'client_title1'}, "");
$mems = [ { 'name' => 'FDPort',
'value' => 9102 },
{ 'name' => 'Catalog',
'value' => $catalogs[0] },
{ 'name' => 'File Retention',
'value' => '30 days' },
{ 'name' => 'Job Retention',
'value' => '6 months' },
];
$client = { 'members' => $mems };
}
else {
&ui_print_header(undef, $text{'client_title2'}, "");
$client = &find_by("Name", $in{'name'}, \@clients);
$client || &error($text{'client_egone'});
$mems = $client->{'members'};
}
# Show details
print &ui_form_start("save_client.cgi", "post");
print &ui_hidden("new", $in{'new'}),"\n";
print &ui_hidden("old", $in{'name'}),"\n";
print &ui_table_start($text{'client_header'}, "width=100%", 4);
# Client name
print &ui_table_row($text{'client_name'},
&ui_textbox("name", $name=&find_value("Name", $mems), 40), 3);
# Password for remote
print &ui_table_row($text{'client_pass'},
&ui_textbox("pass", $pass=&find_value("Password", $mems), 60), 3);
# Connection details
print &ui_table_row($text{'client_address'},
&ui_textbox("address", $address=&find_value("Address", $mems), 20));
print &ui_table_row($text{'client_port'},
&ui_textbox("port", $port=&find_value("FDPort", $mems), 6));
# Catalog
print &ui_table_row($text{'client_catalog'},
&ui_select("catalog", $catalog=&find_value("Catalog", $mems),
[ map { [ $_ ] } @catalogs ], 1, 0, 1));
# Prune option
$prune = &find_value("AutoPrune", $mems);
print &ui_table_row($text{'client_prune'},
&ui_radio("prune", $prune,
[ [ "yes", $text{'yes'} ], [ "no", $text{'no'} ],
[ "", $text{'default'} ] ]));
# Retention options
$fileret = &find_value("File Retention", $mems);
print &ui_table_row($text{'client_fileret'},
&show_period_input("fileret", $fileret));
$jobret = &find_value("Job Retention", $mems);
print &ui_table_row($text{'client_jobret'},
&show_period_input("jobret", $jobret));
# SSL options
&show_tls_directives($client);
# All done
print &ui_table_end();
if ($in{'new'}) {
print &ui_form_end([ [ "create", $text{'create'} ] ]);
}
else {
print &ui_form_end([ [ "save", $text{'save'} ],
[ "status", $text{'client_status'} ],
[ "delete", $text{'delete'} ] ]);
}
&ui_print_footer("list_clients.cgi", $text{'clients_return'});

74
bacula-backup/edit_device.cgi Executable file
View File

@@ -0,0 +1,74 @@
#!/usr/local/bin/perl
# Show the details of one device device
require './bacula-backup-lib.pl';
&ReadParse();
$conf = &get_storage_config();
@devices = &find("Device", $conf);
if ($in{'new'}) {
&ui_print_header(undef, $text{'device_title1'}, "");
$mems = [ { 'name' => 'Media Type',
'value' => 'File' },
{ 'name' => 'LabelMedia',
'value' => 'yes' },
{ 'name' => 'Random Access',
'value' => 'yes' },
{ 'name' => 'AutomaticMount',
'value' => 'yes' },
{ 'name' => 'RemovableMedia',
'value' => 'no' },
{ 'name' => 'AlwaysOpen',
'value' => 'no' },
];
$device = { 'members' => $mems };
}
else {
&ui_print_header(undef, $text{'device_title2'}, "");
$device = &find_by("Name", $in{'name'}, \@devices);
$device || &error($text{'device_egone'});
$mems = $device->{'members'};
}
# Show details
print &ui_form_start("save_device.cgi", "post");
print &ui_hidden("new", $in{'new'}),"\n";
print &ui_hidden("old", $in{'name'}),"\n";
print &ui_table_start($text{'device_header'}, "width=100%", 4);
# Device name
print &ui_table_row($text{'device_name'},
&ui_textbox("name", $name=&find_value("Name", $mems), 40), 3);
# Archive device or file
print &ui_table_row($text{'device_device'},
&ui_textbox("device", $device=&find_value("Archive Device", $mems), 40)." ".
&file_chooser_button("device", 0), 3);
# Media type
print &ui_table_row($text{'device_media'},
&ui_textbox("media", $media=&find_value("Media Type", $mems), 20));
# Various yes/no options
print &ui_table_row($text{'device_label'},
&bacula_yesno("label", "LabelMedia", $mems));
print &ui_table_row($text{'device_random'},
&bacula_yesno("random", "Random Access", $mems));
print &ui_table_row($text{'device_auto'},
&bacula_yesno("auto", "AutomaticMount", $mems));
print &ui_table_row($text{'device_removable'},
&bacula_yesno("removable", "RemovableMedia", $mems));
print &ui_table_row($text{'device_always'},
&bacula_yesno("always", "AlwaysOpen", $mems));
# All done
print &ui_table_end();
if ($in{'new'}) {
print &ui_form_end([ [ "create", $text{'create'} ] ]);
}
else {
print &ui_form_end([ [ "save", $text{'save'} ],
[ "delete", $text{'delete'} ] ]);
}
&ui_print_footer("list_devices.cgi", $text{'devices_return'});

49
bacula-backup/edit_director.cgi Executable file
View File

@@ -0,0 +1,49 @@
#!/usr/local/bin/perl
# Show the global director configuration
require './bacula-backup-lib.pl';
&ReadParse();
$conf = &get_director_config();
$director = &find("Director", $conf);
$director || &error($text{'director_enone'});
$mems = $director->{'members'};
@messages = map { $n=&find_value("Name", $_->{'members'}) }
&find("Messages", $conf);
&ui_print_header(undef, $text{'director_title'}, "", "director");
print &ui_form_start("save_director.cgi", "post");
print &ui_table_start($text{'director_header'}, "width=100%", 4);
$name = &find_value("Name", $mems);
print &ui_table_row($text{'director_name'},
&ui_textbox("name", $name, 20));
$port = &find_value("DIRport", $mems);
print &ui_table_row($text{'director_port'},
&ui_textbox("port", $port, 6));
$jobs = &find_value("Maximum Concurrent Jobs", $mems);
print &ui_table_row($text{'director_jobs'},
&ui_opt_textbox("jobs", $jobs, 6, $text{'default'}));
$messages = &find_value("Messages", $mems);
print &ui_table_row($text{'director_messages'},
&ui_select("messages", $messages,
[ [ "", "&lt;$text{'default'}&gt;" ],
map { [ $_ ] } @messages ], 1, 0, 1));
$dir = &find_value("WorkingDirectory", $mems);
print &ui_table_row($text{'director_dir'},
&ui_textbox("dir", $dir, 60)." ".
&file_chooser_button("dir", 1), 3);
# SSL options
&show_tls_directives($director);
print &ui_table_end();
print &ui_form_end([ [ "save", $text{'save'} ] ]);
&ui_print_footer("", $text{'index_return'});

View File

@@ -0,0 +1,51 @@
#!/usr/local/bin/perl
# Show the details of one file fdirector daemon
require './bacula-backup-lib.pl';
&ReadParse();
$conf = &get_file_config();
@fdirectors = &find("Director", $conf);
if ($in{'new'}) {
&ui_print_header(undef, $text{'fdirector_title1'}, "");
$mems = [ ];
$fdirector = { 'members' => $mems };
}
else {
&ui_print_header(undef, $text{'fdirector_title2'}, "");
$fdirector = &find_by("Name", $in{'name'}, \@fdirectors);
$fdirector || &error($text{'fdirector_egone'});
$mems = $fdirector->{'members'};
}
# Show details
print &ui_form_start("save_fdirector.cgi", "post");
print &ui_hidden("new", $in{'new'}),"\n";
print &ui_hidden("old", $in{'name'}),"\n";
print &ui_table_start($text{'fdirector_header'}, "width=100%", 4);
# Director name
print &ui_table_row($text{'fdirector_name'},
&ui_textbox("name", $name=&find_value("Name", $mems), 40), 3);
# Password for remote
print &ui_table_row($text{'fdirector_pass'},
&ui_textbox("pass", $pass=&find_value("Password", $mems), 60), 3);
# Monitor mode
print &ui_table_row($text{'fdirector_monitor'},
&bacula_yesno("monitor", "Monitor", $mems));
&show_tls_directives($fdirector);
# All done
print &ui_table_end();
if ($in{'new'}) {
print &ui_form_end([ [ "create", $text{'create'} ] ]);
}
else {
print &ui_form_end([ [ "save", $text{'save'} ],
[ "delete", $text{'delete'} ] ]);
}
&ui_print_footer("list_fdirectors.cgi", $text{'fdirectors_return'});

40
bacula-backup/edit_file.cgi Executable file
View File

@@ -0,0 +1,40 @@
#!/usr/local/bin/perl
# Show the global file daemon configuration
require './bacula-backup-lib.pl';
&ReadParse();
$conf = &get_file_config();
$file = &find("FileDaemon", $conf);
$file || &error($text{'file_enone'});
$mems = $file->{'members'};
&ui_print_header(undef, $text{'file_title'}, "", "file");
print &ui_form_start("save_file.cgi", "post");
print &ui_table_start($text{'file_header'}, "width=100%", 4);
$name = &find_value("Name", $mems);
print &ui_table_row($text{'file_name'},
&ui_textbox("name", $name, 20));
$port = &find_value("FDport", $mems);
print &ui_table_row($text{'file_port'},
&ui_textbox("port", $port, 6));
$jobs = &find_value("Maximum Concurrent Jobs", $mems);
print &ui_table_row($text{'file_jobs'},
&ui_opt_textbox("jobs", $jobs, 6, $text{'default'}));
$dir = &find_value("WorkingDirectory", $mems);
print &ui_table_row($text{'file_dir'},
&ui_textbox("dir", $dir, 60)." ".
&file_chooser_button("dir", 1), 3);
# SSL options
&show_tls_directives($file);
print &ui_table_end();
print &ui_form_end([ [ "save", $text{'save'} ] ]);
&ui_print_footer("", $text{'index_return'});

62
bacula-backup/edit_fileset.cgi Executable file
View File

@@ -0,0 +1,62 @@
#!/usr/local/bin/perl
# Show the details of one fileset
require './bacula-backup-lib.pl';
&ReadParse();
$conf = &get_director_config();
@filesets = &find("FileSet", $conf);
if ($in{'new'}) {
&ui_print_header(undef, $text{'fileset_title1'}, "");
$mems = [ ];
$fileset = { };
}
else {
&ui_print_header(undef, $text{'fileset_title2'}, "");
$fileset = &find_by("Name", $in{'name'}, \@filesets);
$fileset || &error($text{'fileset_egone'});
$mems = $fileset->{'members'};
}
# Show details
print &ui_form_start("save_fileset.cgi", "post");
print &ui_hidden("new", $in{'new'}),"\n";
print &ui_hidden("old", $in{'name'}),"\n";
print &ui_table_start($text{'fileset_header'}, "width=100%", 4);
# File set name
print &ui_table_row($text{'fileset_name'},
&ui_textbox("name", $name=&find_value("Name", $mems), 40), 3);
# Included files
$inc = &find("Include", $mems);
@files = $inc ? &find_value("File", $inc->{'members'}) : ( );
print &ui_table_row($text{'fileset_include'},
&ui_textarea("include", join("\n", @files), 5, 60)."\n".
&file_chooser_button("include", 0, 0, undef, 1), 3);
# Options
$opts = $inc ? &find("Options", $inc->{'members'}) : undef;
$sig = $opts ? &find_value("signature", $opts->{'members'}) : undef;
print &ui_table_row($text{'fileset_sig'},
&ui_select("signature", $sig,
[ [ "", $text{'fileset_none'} ],
[ "MD5" ], [ "SHA1" ] ], 1, 0, 1));
# Excluded files
$exc = &find("Exclude", $mems);
@files = $exc ? &find_value("File", $exc->{'members'}) : ( );
print &ui_table_row($text{'fileset_exclude'},
&ui_textarea("exclude", join("\n", @files), 5, 60)."\n".
&file_chooser_button("exclude", 0, 0, undef, 1), 3);
# All done
print &ui_table_end();
if ($in{'new'}) {
print &ui_form_end([ [ "create", $text{'create'} ] ]);
}
else {
print &ui_form_end([ [ "save", $text{'save'} ],
[ "delete", $text{'delete'} ] ]);
}
&ui_print_footer("list_filesets.cgi", $text{'filesets_return'});

144
bacula-backup/edit_gjob.cgi Executable file
View File

@@ -0,0 +1,144 @@
#!/usr/local/bin/perl
# Show the details of one backup job
require './bacula-backup-lib.pl';
&ReadParse();
$conf = &get_director_config();
@jobs = &find("JobDefs", $conf);
@clients = map { $n=&find_value("Name", $_->{'members'}); }
grep { ($g, $c) = &is_oc_object($_); $g && !$c }
&find("Client", $conf);
@filesets = map { $n=&find_value("Name", $_->{'members'}) }
&find("FileSet", $conf);
@schedules = map { $n=&find_value("Name", $_->{'members'}) }
&find("Schedule", $conf);
@storages = map { $n=&find_value("Name", $_->{'members'}) }
&find("Storage", $conf);
@pools = map { $n=&find_value("Name", $_->{'members'}) }
&find("Pool", $conf);
@messages = map { $n=&find_value("Name", $_->{'members'}) }
&find("Messages", $conf);
if ($in{'new'}) {
&ui_print_header(undef, $text{'gjob_title1'}, "");
$mems = [ { 'name' => 'Type',
'value' => 'Backup' },
{ 'name' => 'Level',
'value' => 'Incremental' },
{ 'name' => 'Client',
'value' => $clients[0] },
{ 'name' => 'FileSet',
'value' => $filesets[0] },
{ 'name' => 'Schedule',
'value' => $schedules[0] },
{ 'name' => 'Storage',
'value' => $storages[0] },
{ 'name' => 'Messages',
'value' => $messages[0] },
{ 'name' => 'Pool',
'value' => $pools[0] },
];
$job = { 'name' => 'Job',
'members' => $mems };
}
else {
&ui_print_header(undef, $text{'gjob_title2'}, "");
$job = &find_by("Name", "ocjob_".$in{'name'}, \@jobs);
$job || &error($text{'job_egone'});
$mems = $job->{'members'};
}
# Show details
print &ui_form_start("save_gjob.cgi", "post");
print &ui_hidden("new", $in{'new'}),"\n";
print &ui_hidden("old", $in{'name'}),"\n";
print &ui_table_start($text{'gjob_header'}, "width=100%", 4);
# Job name
print &ui_table_row($text{'job_name'},
&ui_textbox("name", $in{'name'}, 40), 3);
# Job type
$type = &find_value("Type", $mems);
print &ui_table_row($text{'job_type'},
&ui_select("type", $type,
[ [ "Backup" ], [ "Restore" ], [ "Verify" ], [ "Admin" ] ],
1, 0, 1));
# Backup level
$level = &find_value("Level", $mems);
print &ui_table_row($text{'job_level'},
&ui_select("level", $level,
[ map { [ $_ ] } @backup_levels ],
1, 0, 1));
# Client being backed up
$client = &find_value("Client", $mems);
print &ui_table_row($text{'gjob_client'},
&ui_select("client", $client,
[ map { [ $_, &is_oc_object($_) ] } @clients ], 1, 0, 1));
# Files to be backed up
$fileset = &find_value("FileSet", $mems);
print &ui_table_row($text{'job_fileset'},
&ui_select("fileset", $fileset,
[ map { [ $_ ] } @filesets ], 1, 0, 1));
# Backup schedule
$schedule = &find_value("Schedule", $mems);
print &ui_table_row($text{'job_schedule'},
&ui_select("schedule", $schedule,
[ [ "", "&lt;$text{'default'}&gt;" ],
map { [ $_ ] } @schedules ], 1, 0, 1));
# Storage device
$storage = &find_value("Storage", $mems);
print &ui_table_row($text{'job_storage'},
&ui_select("storage", $storage,
[ map { [ $_ ] } @storages ], 1, 0, 1));
# Backup pool
$pool = &find_value("Pool", $mems);
print &ui_table_row($text{'job_pool'},
&ui_select("pool", $pool,
[ map { [ $_ ] } @pools ], 1, 0, 1));
# Backup messages
$messages = &find_value("Messages", $mems);
print &ui_table_row($text{'job_messages'},
&ui_select("messages", $messages,
[ map { [ $_ ] } @messages ], 1, 0, 1));
# Priority level
$prority = &find_value("Priority", $mems);
print &ui_table_row($text{'job_prority'},
&ui_opt_textbox("priority", $priority, 4, $text{'default'}));
# Before and after commands
print &ui_table_hr();
$before = &find_value("Run Before Job", $mems);
print &ui_table_row($text{'job_before'},
&ui_opt_textbox("before", $before, 60, $text{'default'}), 3);
$after = &find_value("Run After Job", $mems);
print &ui_table_row($text{'job_after'},
&ui_opt_textbox("after", $after, 60, $text{'default'}), 3);
$cbefore = &find_value("Client Run Before Job", $mems);
print &ui_table_row($text{'job_cbefore'},
&ui_opt_textbox("cbefore", $cbefore, 60, $text{'default'}), 3);
$cafter = &find_value("Client Run After Job", $mems);
print &ui_table_row($text{'job_cafter'},
&ui_opt_textbox("cafter", $cafter, 60, $text{'default'}), 3);
# All done
print &ui_table_end();
if ($in{'new'}) {
print &ui_form_end([ [ "create", $text{'create'} ] ]);
}
else {
print &ui_form_end([ [ "save", $text{'save'} ],
[ "run", $text{'job_run'} ],
[ "delete", $text{'delete'} ] ]);
}
&ui_print_footer("list_gjobs.cgi", $text{'jobs_return'});

87
bacula-backup/edit_group.cgi Executable file
View File

@@ -0,0 +1,87 @@
#!/usr/local/bin/perl
# Show the details of one node group, which is actually a special client
require './bacula-backup-lib.pl';
&ReadParse();
$conf = &get_director_config();
@groups = &find("Client", $conf);
@catalogs = map { $n=&find_value("Name", $_->{'members'}) }
&find("Catalog", $conf);
if ($in{'new'}) {
&ui_print_header(undef, $text{'group_title1'}, "");
$mems = [ { 'name' => 'FDPort',
'value' => 9102 },
{ 'name' => 'Catalog',
'value' => $catalogs[0] },
{ 'name' => 'File Retention',
'value' => '30 days' },
{ 'name' => 'Job Retention',
'value' => '6 months' },
];
$group = { 'members' => $mems };
}
else {
&ui_print_header(undef, $text{'group_title2'}, "");
$group = &find_by("Name", "ocgroup_".$in{'name'}, \@groups);
$group || &error($text{'group_egone'});
$mems = $group->{'members'};
}
# Get node group
@nodegroups = &list_node_groups();
$ngname = $in{'name'} || $in{'new'};
($nodegroup) = grep { $_->{'name'} eq $ngname } @nodegroups;
# Show details
print &ui_form_start("save_group.cgi", "post");
print &ui_hidden("new", $in{'new'}),"\n";
print &ui_hidden("old", $in{'name'}),"\n";
print &ui_table_start($text{'group_header'}, "width=100%", 4);
# Group name
print &ui_table_row($text{'group_name'},
$in{'new'} || $in{'name'});
# Password for remote
print &ui_table_row($text{'client_pass'},
&ui_textbox("pass", $pass=&find_value("Password", $mems), 60), 3);
# FD port
print &ui_table_row($text{'client_port'},
&ui_textbox("port", $port=&find_value("FDPort", $mems), 6), 3);
# Catalog
print &ui_table_row($text{'client_catalog'},
&ui_select("catalog", $catalog=&find_value("Catalog", $mems),
[ map { [ $_ ] } @catalogs ], 1, 0, 1));
# Prune option
$prune = &find_value("AutoPrune", $mems);
print &ui_table_row($text{'client_prune'},
&ui_radio("prune", $prune,
[ [ "yes", $text{'yes'} ], [ "no", $text{'no'} ],
[ "", $text{'default'} ] ]));
# Retention options
$fileret = &find_value("File Retention", $mems);
print &ui_table_row($text{'client_fileret'},
&show_period_input("fileret", $fileret));
$jobret = &find_value("Job Retention", $mems);
print &ui_table_row($text{'client_jobret'},
&show_period_input("jobret", $jobret));
# Members
print &ui_table_row($text{'group_members'},
join(", ", @{$nodegroup->{'members'}}), 3);
# All done
print &ui_table_end();
if ($in{'new'}) {
print &ui_form_end([ [ "create", $text{'create'} ] ]);
}
else {
print &ui_form_end([ [ "save", $text{'save'} ],
[ "delete", $text{'delete'} ] ]);
}
&ui_print_footer("list_groups.cgi", $text{'groups_return'});

164
bacula-backup/edit_job.cgi Executable file
View File

@@ -0,0 +1,164 @@
#!/usr/local/bin/perl
# Show the details of one backup job
require './bacula-backup-lib.pl';
&ReadParse();
$conf = &get_director_config();
@jobs = ( &find("JobDefs", $conf), &find("Job", $conf) );
@clients = map { $n=&find_value("Name", $_->{'members'}) }
grep { !&is_oc_object($_) } &find("Client", $conf);
@filesets = map { $n=&find_value("Name", $_->{'members'}) }
&find("FileSet", $conf);
@schedules = map { $n=&find_value("Name", $_->{'members'}) }
&find("Schedule", $conf);
@storages = map { $n=&find_value("Name", $_->{'members'}) }
&find("Storage", $conf);
@pools = map { $n=&find_value("Name", $_->{'members'}) }
&find("Pool", $conf);
@messages = map { $n=&find_value("Name", $_->{'members'}) }
&find("Messages", $conf);
@defs = map { $n=&find_value("Name", $_->{'members'}) }
&find("JobDefs", $conf);
if ($in{'new'}) {
&ui_print_header(undef, $text{'job_title1'}, "");
$mems = [ { 'name' => 'Type',
'value' => 'Backup' },
{ 'name' => 'Level',
'value' => 'Incremental' },
{ 'name' => 'Client',
'value' => $clients[0] },
{ 'name' => 'FileSet',
'value' => $filesets[0] },
{ 'name' => 'Schedule',
'value' => $schedules[0] },
{ 'name' => 'Storage',
'value' => $storages[0] },
{ 'name' => 'Messages',
'value' => $messages[0] },
{ 'name' => 'Pool',
'value' => $pools[0] },
];
$job = { 'name' => 'Job',
'members' => $mems };
}
else {
&ui_print_header(undef, $text{'job_title2'}, "");
$job = &find_by("Name", $in{'name'}, \@jobs);
$job || &error($text{'job_egone'});
$mems = $job->{'members'};
}
# Show details
print &ui_form_start("save_job.cgi", "post");
print &ui_hidden("new", $in{'new'}),"\n";
print &ui_hidden("old", $in{'name'}),"\n";
print &ui_table_start($text{'job_header'}, "width=100%", 4);
# Job name
print &ui_table_row($text{'job_name'},
&ui_textbox("name", $name=&find_value("Name", $mems), 40), 3);
# Default or source
$defs = &find_value("JobDefs", $mems);
$dmode = $defs ? 2 : $job->{'name'} eq 'Job' ? 1 : 0;
print &ui_table_row($text{'job_def'},
&ui_radio("dmode", $dmode,
[ [ 0, $text{'job_def0'} ],
[ 1, $text{'job_def1'} ],
[ 2, &text('job_def2',
&ui_select("defs", $defs, [ map { [ $_ ] } @defs ])) ] ]), 3);
# Job type
$type = &find_value("Type", $mems);
print &ui_table_row($text{'job_type'},
&ui_select("type", $type,
[ [ "", "&lt;$text{'default'}&gt;" ],
[ "Backup" ], [ "Restore" ], [ "Verify" ], [ "Admin" ] ],
1, 0, 1));
# Backup level
$level = &find_value("Level", $mems);
print &ui_table_row($text{'job_level'},
&ui_select("level", $level,
[ [ "", "&lt;$text{'default'}&gt;" ],
map { [ $_ ] } @backup_levels ],
1, 0, 1));
# Client being backed up
$client = &find_value("Client", $mems);
print &ui_table_row($text{'job_client'},
&ui_select("client", $client,
[ [ "", "&lt;$text{'default'}&gt;" ],
map { [ $_ ] } @clients ], 1, 0, 1));
# Files to be backed up
$fileset = &find_value("FileSet", $mems);
print &ui_table_row($text{'job_fileset'},
&ui_select("fileset", $fileset,
[ [ "", "&lt;$text{'default'}&gt;" ],
map { [ $_ ] } @filesets ], 1, 0, 1));
# Backup schedule
$schedule = &find_value("Schedule", $mems);
print &ui_table_row($text{'job_schedule'},
&ui_select("schedule", $schedule,
[ [ "", "&lt;$text{'default'}&gt;" ],
map { [ $_ ] } @schedules ], 1, 0, 1));
# Storage device
$storage = &find_value("Storage", $mems);
print &ui_table_row($text{'job_storage'},
&ui_select("storage", $storage,
[ [ "", "&lt;$text{'default'}&gt;" ],
map { [ $_ ] } @storages ], 1, 0, 1));
# Backup pool
$pool = &find_value("Pool", $mems);
print &ui_table_row($text{'job_pool'},
&ui_select("pool", $pool,
[ [ "", "&lt;$text{'default'}&gt;" ],
map { [ $_ ] } @pools ], 1, 0, 1));
# Backup messages
$messages = &find_value("Messages", $mems);
print &ui_table_row($text{'job_messages'},
&ui_select("messages", $messages,
[ [ "", "&lt;$text{'default'}&gt;" ],
map { [ $_ ] } @messages ], 1, 0, 1));
# Priority level
$prority = &find_value("Priority", $mems);
print &ui_table_row($text{'job_prority'},
&ui_opt_textbox("priority", $priority, 4, $text{'default'}));
# Before and after commands
print &ui_table_hr();
$before = &find_value("Run Before Job", $mems);
print &ui_table_row($text{'job_before'},
&ui_opt_textbox("before", $before, 60, $text{'default'}), 3);
$after = &find_value("Run After Job", $mems);
print &ui_table_row($text{'job_after'},
&ui_opt_textbox("after", $after, 60, $text{'default'}), 3);
$cbefore = &find_value("Client Run Before Job", $mems);
print &ui_table_row($text{'job_cbefore'},
&ui_opt_textbox("cbefore", $cbefore, 60, $text{'default'}), 3);
$cafter = &find_value("Client Run After Job", $mems);
print &ui_table_row($text{'job_cafter'},
&ui_opt_textbox("cafter", $cafter, 60, $text{'default'}), 3);
# All done
print &ui_table_end();
if ($in{'new'}) {
print &ui_form_end([ [ "create", $text{'create'} ] ]);
}
else {
($bjob) = grep { $_->{'name'} eq $in{'name'} } &get_bacula_jobs();
print &ui_form_end([ [ "save", $text{'save'} ],
( $job->{'name'} eq 'Job' && $bjob ?
( [ "run", $text{'job_run'} ] ) : ( ) ),
[ "delete", $text{'delete'} ] ]);
}
&ui_print_footer("list_jobs.cgi", $text{'jobs_return'});

78
bacula-backup/edit_pool.cgi Executable file
View File

@@ -0,0 +1,78 @@
#!/usr/local/bin/perl
# Show the details of one file pool daemon
require './bacula-backup-lib.pl';
&ReadParse();
$conf = &get_director_config();
@pools = &find("Pool", $conf);
if ($in{'new'}) {
&ui_print_header(undef, $text{'pool_title1'}, "");
$mems = [ { 'name' => 'Pool Type',
'value' => 'Backup' },
{ 'name' => 'Recycle',
'value' => 'yes' },
{ 'name' => 'AutoPrune',
'value' => 'yes' },
{ 'name' => 'Accept Any Volume',
'value' => 'yes' },
{ 'name' => 'Volume Retention',
'value' => '365 days' },
];
$pool = { 'members' => $mems };
}
else {
&ui_print_header(undef, $text{'pool_title2'}, "");
$pool = &find_by("Name", $in{'name'}, \@pools);
$pool || &error($text{'pool_egone'});
$mems = $pool->{'members'};
}
# Show details
print &ui_form_start("save_pool.cgi", "post");
print &ui_hidden("new", $in{'new'}),"\n";
print &ui_hidden("old", $in{'name'}),"\n";
print &ui_table_start($text{'pool_header'}, "width=100%", 4);
# Pool name
print &ui_table_row($text{'pool_name'},
&ui_textbox("name", $name=&find_value("Name", $mems), 40), 3);
# Pool type
print &ui_table_row($text{'pool_type'},
&ui_select("type", $type=&find_value("Pool Type", $mems),
[ map { [ $_, $_ =~ /^\*(.*)$/ ? $1 : $_ ] }
@pool_types ], 1, 0, 1));
# Maximum Volume Jobs
$max = &find_value("Maximum Volume Jobs", $mems);
print &ui_table_row($text{'pool_max'},
&ui_radio("maxmode", $max == 0 ? 0 : 1,
[ [ 0, $text{'pool_unlimited'} ],
[ 1, &ui_textbox('max', $max == 0 ? "" : $max, 6) ] ]));
# Retention period
$reten = &find_value("Volume Retention", $mems);
print &ui_table_row($text{'pool_reten'},
&show_period_input("reten", $reten));
# Various yes/no options
print &ui_table_row($text{'pool_recycle'},
&bacula_yesno("recycle", "Recycle", $mems));
print &ui_table_row($text{'pool_auto'},
&bacula_yesno("auto", "AutoPrune", $mems));
print &ui_table_row($text{'pool_any'},
&bacula_yesno("any", "Accept Any Volume", $mems));
# All done
print &ui_table_end();
if ($in{'new'}) {
print &ui_form_end([ [ "create", $text{'create'} ] ]);
}
else {
print &ui_form_end([ [ "save", $text{'save'} ],
[ "status", $text{'pool_status'} ],
[ "delete", $text{'delete'} ] ]);
}
&ui_print_footer("list_pools.cgi", $text{'pools_return'});

62
bacula-backup/edit_schedule.cgi Executable file
View File

@@ -0,0 +1,62 @@
#!/usr/local/bin/perl
# Show the details of one schedule
require './bacula-backup-lib.pl';
&ReadParse();
$conf = &get_director_config();
@schedules = &find("Schedule", $conf);
if ($in{'new'}) {
&ui_print_header(undef, $text{'schedule_title1'}, "");
$mems = [ ];
$schedule = { };
}
else {
&ui_print_header(undef, $text{'schedule_title2'}, "");
$schedule = &find_by("Name", $in{'name'}, \@schedules);
$schedule || &error($text{'schedule_egone'});
$mems = $schedule->{'members'};
}
# Show details
print &ui_form_start("save_schedule.cgi", "post");
print &ui_hidden("new", $in{'new'}),"\n";
print &ui_hidden("old", $in{'name'}),"\n";
print &ui_table_start($text{'schedule_header'}, "width=100%", 4);
# Schedule
print &ui_table_row($text{'schedule_name'},
&ui_textbox("name", $name=&find_value("Name", $mems), 40), 3);
# Run files
@runs = &find_value("Run", $schedule->{'members'});
$rtable = &ui_columns_start([ $text{'schedule_level'},
$text{'schedule_times'} ], "width=100%");
$i = 0;
foreach $r (@runs, undef, undef, undef) {
($level, $times) = split(/\s+/, $r, 2);
$level =~ s/^Level\s*=\s*//;
$sched = &parse_schedule($times);
$rtable .= &ui_columns_row([
&ui_select("level_$i", $level,
[ [ "", "&nbsp;" ], [ "Full" ],
[ "Incremental" ], [ "Differential" ] ],
1, 0, 1),
&ui_textbox("times_$i", $times,
$sched || !$r ? "40 readonly" : 40)." ".
&schedule_chooser_button("times_$i") ]);
$i++;
}
$rtable .= &ui_columns_end();
print &ui_table_row($text{'schedule_runs'}, $rtable);
# All done
print &ui_table_end();
if ($in{'new'}) {
print &ui_form_end([ [ "create", $text{'create'} ] ]);
}
else {
print &ui_form_end([ [ "save", $text{'save'} ],
[ "delete", $text{'delete'} ] ]);
}
&ui_print_footer("list_schedules.cgi", $text{'schedules_return'});

View File

@@ -0,0 +1,51 @@
#!/usr/local/bin/perl
# Show the details of one file daemon director
require './bacula-backup-lib.pl';
&ReadParse();
$conf = &get_storage_config();
@sdirectors = &find("Director", $conf);
if ($in{'new'}) {
&ui_print_header(undef, $text{'sdirector_title1'}, "");
$mems = [ ];
$sdirector = { 'members' => $mems };
}
else {
&ui_print_header(undef, $text{'sdirector_title2'}, "");
$sdirector = &find_by("Name", $in{'name'}, \@sdirectors);
$sdirector || &error($text{'sdirector_egone'});
$mems = $sdirector->{'members'};
}
# Show details
print &ui_form_start("save_sdirector.cgi", "post");
print &ui_hidden("new", $in{'new'}),"\n";
print &ui_hidden("old", $in{'name'}),"\n";
print &ui_table_start($text{'sdirector_header'}, "width=100%", 4);
# Director name
print &ui_table_row($text{'sdirector_name'},
&ui_textbox("name", $name=&find_value("Name", $mems), 40), 3);
# Password for remote
print &ui_table_row($text{'sdirector_pass'},
&ui_textbox("pass", $pass=&find_value("Password", $mems), 60), 3);
# Monitor mode
print &ui_table_row($text{'sdirector_monitor'},
&bacula_yesno("monitor", "Monitor", $mems));
&show_tls_directives($sdirector);
# All done
print &ui_table_end();
if ($in{'new'}) {
print &ui_form_end([ [ "create", $text{'create'} ] ]);
}
else {
print &ui_form_end([ [ "save", $text{'save'} ],
[ "delete", $text{'delete'} ] ]);
}
&ui_print_footer("list_sdirectors.cgi", $text{'sdirectors_return'});

94
bacula-backup/edit_storage.cgi Executable file
View File

@@ -0,0 +1,94 @@
#!/usr/local/bin/perl
# Show the details of one file storage daemon
require './bacula-backup-lib.pl';
&ReadParse();
$conf = &get_director_config();
@storages = &find("Storage", $conf);
$sconf = &get_storage_config();
if ($sconf) {
@devices = map { $n=&find_value("Name", $_->{'members'}) }
&find("Device", $sconf);
}
if ($in{'new'}) {
&ui_print_header(undef, $text{'storage_title1'}, "");
$mems = [ { 'name' => 'SDPort',
'value' => 9103 },
{ 'name' => 'Address',
'value' => &get_system_hostname() },
{ 'name' => 'Media Type',
'value' => 'File' },
{ 'name' => 'Device',
'value' => $devices[0] },
];
if (@storages) {
push(@$mems,
{ 'name' => 'Password',
'value' => &find_value("Password",
$storages[0]->{'members'})
});
}
$storage = { 'members' => $mems };
}
else {
&ui_print_header(undef, $text{'storage_title2'}, "");
$storage = &find_by("Name", $in{'name'}, \@storages);
$storage || &error($text{'storage_egone'});
$mems = $storage->{'members'};
}
# Show details
print &ui_form_start("save_storage.cgi", "post");
print &ui_hidden("new", $in{'new'}),"\n";
print &ui_hidden("old", $in{'name'}),"\n";
print &ui_table_start($text{'storage_header'}, "width=100%", 4);
# Storage name
print &ui_table_row($text{'storage_name'},
&ui_textbox("name", $name=&find_value("Name", $mems), 40), 3);
# Password for remote
print &ui_table_row($text{'storage_pass'},
&ui_textbox("pass", $pass=&find_value("Password", $mems), 60), 3);
# Connection details
print &ui_table_row($text{'storage_address'},
&ui_textbox("address", $address=&find_value("Address", $mems), 20));
print &ui_table_row($text{'storage_port'},
&ui_textbox("port", $port=&find_value("SDPort", $mems), 6));
# Device name
if (@devices) {
$device=&find_value("Device", $mems);
$found = &indexof($device, @devices) >= 0;
print &ui_table_row($text{'storage_device'},
&ui_select("device", $found ? $device : "",
[ (map { [ $_ ] } @devices),
[ "", $text{'storage_other'} ] ])."\n".
&ui_textbox("other", $found ? "" : $device, 10));
}
else {
print &ui_table_row($text{'storage_device'},
&ui_textbox("device", $device=&find_value("Device",$mems), 20));
}
# Media type
print &ui_table_row($text{'storage_media'},
&ui_textbox("media", $media=&find_value("Media Type", $mems), 20));
# SSL options
&show_tls_directives($storage);
# All done
print &ui_table_end();
if ($in{'new'}) {
print &ui_form_end([ [ "create", $text{'create'} ] ]);
}
else {
print &ui_form_end([ [ "save", $text{'save'} ],
[ "status", $text{'storage_status'} ],
[ "delete", $text{'delete'} ] ]);
}
&ui_print_footer("list_storages.cgi", $text{'storages_return'});

43
bacula-backup/edit_storagec.cgi Executable file
View File

@@ -0,0 +1,43 @@
#!/usr/local/bin/perl
# Show the global storage daemon configuration
require './bacula-backup-lib.pl';
&ReadParse();
$conf = &get_storage_config();
$storagec = &find("Storage", $conf);
$storagec || &error($text{'storagec_enone'});
$mems = $storagec->{'members'};
@messages = map { $n=&find_value("Name", $_->{'members'}) }
&find("Messages", $conf);
&ui_print_header(undef, $text{'storagec_title'}, "", "storagec");
print &ui_form_start("save_storagec.cgi", "post");
print &ui_table_start($text{'storagec_header'}, "width=100%", 4);
$name = &find_value("Name", $mems);
print &ui_table_row($text{'storagec_name'},
&ui_textbox("name", $name, 20));
$port = &find_value("SDport", $mems);
print &ui_table_row($text{'storagec_port'},
&ui_textbox("port", $port, 6));
$jobs = &find_value("Maximum Concurrent Jobs", $mems);
print &ui_table_row($text{'storagec_jobs'},
&ui_opt_textbox("jobs", $jobs, 6, $text{'default'}));
$dir = &find_value("WorkingDirectory", $mems);
print &ui_table_row($text{'storagec_dir'},
&ui_textbox("dir", $dir, 60)." ".
&file_chooser_button("dir", 1), 3);
# SSL options
&show_tls_directives($storagec);
print &ui_table_end();
print &ui_form_end([ [ "save", $text{'save'} ] ]);
&ui_print_footer("", $text{'index_return'});

19
bacula-backup/fixaddr.cgi Executable file
View File

@@ -0,0 +1,19 @@
#!/usr/local/bin/perl
# Update the host in bconsole.conf to match this system
require './bacula-backup-lib.pl';
&lock_file($bconsole_conf_file);
$conconf = &get_bconsole_config();
$condir = &find("Director", $conconf);
$addr = &get_system_hostname();
if (!gethostbyname($addr)) {
$addr = "localhost";
}
&save_directive($conconf, $condir, "Address", $addr, 1);
&flush_file_lines();
&unlock_file($bconsole_conf_file);
&webmin_log("fixaddr");
&redirect("");

18
bacula-backup/fixpass.cgi Executable file
View File

@@ -0,0 +1,18 @@
#!/usr/local/bin/perl
# Update the password in bconsole.conf to match bacula-dir.conf
require './bacula-backup-lib.pl';
&lock_file($bconsole_conf_file);
$dirconf = &get_director_config();
$dirdir = &find("Director", $dirconf);
$conconf = &get_bconsole_config();
$condir = &find("Director", $conconf);
$dirpass = &find_value("Password", $dirdir->{'members'});
&save_directive($conconf, $condir, "Password", $dirpass, 1);
&flush_file_lines();
&unlock_file($bconsole_conf_file);
&webmin_log("fixpass");
&redirect("");

71
bacula-backup/gbackup.cgi Executable file
View File

@@ -0,0 +1,71 @@
#!/usr/local/bin/perl
# Execute multiple backup jobs, one for each client
require './bacula-backup-lib.pl';
&ui_print_unbuffered_header(undef, $text{'gbackup_title'}, "");
&ReadParse();
# Get the backup job def and real jobs
$conf = &get_director_config();
@jobdefs = &find("JobDefs", $conf);
$jobdef = &find_by("Name", "ocjob_".$in{'job'}, \@jobdefs);
foreach $job (&get_bacula_jobs()) {
($j, $c) = &is_oc_object($job);
if ($j eq $in{'job'} && $c) {
push(@jobs, $job);
}
}
print "<b>",&text('gbackup_run', "<tt>$in{'job'}</tt>",
scalar(@jobs)),"</b>\n";
# Clear messages
$h = &open_console();
&console_cmd($h, "messages");
# Run the real jobs
print "<dl>\n";
foreach $job (@jobs) {
($j, $c) = &is_oc_object($job);
print "<dt>",&text('gbackup_on', "<tt>$c</tt>"),"\n";
print "<dd><pre>";
# Select the job to run
&sysprint($h->{'infh'}, "run\n");
&wait_for($h->{'outfh'}, 'run\\n');
$rv = &wait_for($h->{'outfh'}, 'Select Job.*:');
print $wait_for_input;
if ($rv == 0 && $wait_for_input =~ /(\d+):\s+\Q$job->{'name'}\E/) {
&sysprint($h->{'infh'}, "$1\n");
}
else {
&job_error($text{'backup_ejob'});
}
# Say that it is OK
$rv = &wait_for($h->{'outfh'}, 'OK to run.*:');
print $wait_for_input;
if ($rv == 0) {
&sysprint($h->{'infh'}, "yes\n");
}
else {
&job_error($text{'backup_eok'});
}
print "</pre>";
}
print "</dl>\n";
&close_console($h);
&webmin_log("gbackup", $in{'job'});
&ui_print_footer("", $text{'index_return'});
sub job_error
{
print "</pre>\n";
print "<b>",@_,"</b><p>\n";
&close_console($h);
&ui_print_footer("backup_form.cgi", $text{'backup_return'});
exit;
}

View File

@@ -0,0 +1,8 @@
<header>Run Backup Job</header>
This form can be used to start the immediate execution of a Bacula backup
job. To run a job, you only need to select it from the list, and select whether
or not Webmin should wait for its final status to be displayed. <p>
<footer>

View File

@@ -0,0 +1,18 @@
<header>Backup Clients</header>
A Bacula client is a system whose files can be backed up. All the clients
that you wish to backup files on must be listed on this page, and each must
have the Bacula file daemon running on it. In a typical single-system setup,
on this server needs to be listed. <p>
When adding remote clients, in addition to the hostname you also need to know
the name of it's Bacula file daemon, and the daemon's password. These are set
in the <tt>/etc/bacula/bacula-fd.conf</tt> file on the client system. <p>
If shown, the TLS options on the client page determine if encryption is used
when this director communicates with the client. Before TLS can be enabled,
you must generate an SSL certificate and key, and enter their paths into the
appropriate fields on this form. <p>
<footer>

View File

@@ -0,0 +1,8 @@
<header>Client Status</header>
This page displays backup jobs that are currently running and the 10 most
recently run, on a selected Bacula client system. Those running or run on
different clients will not be displayed. <p>
<footer>

View File

@@ -0,0 +1,19 @@
<header>Storage Devices</header>
Unlike all of the other pages in this module, this one configures the Bacula
storage daemon rather than the director. It allows you to control which tape
devices and directories are used for backups. Each entry on the list defines
a storage device, each of which must have a unique name, a device file or
directory (like <i>/dev/st0</i> or <i>/backup</i>), and a media type name. <p>
Devices defined here can be referenced on the <b>Storage Daemons</b> page,
which can in turn be used in backup jobs. This if you want to create a new
directory to backup to, it must be added both here and to the daemons list.
In addition, any new directory must be labelled first (using the <b>Label
Volume</b> page) before Bacula will write to it. <p>
Be aware that changes made to this page will only be activated when the
<b>Restart Bacula</b> button is clicked on the module's main page. <p>
<footer>

View File

@@ -0,0 +1,13 @@
<header>Director Configuration</header>
This page allows you to configure the Bacula director process, which is
responsible for actually controlling and scheduling all backup jobs. Most of
the options here do not generally need to be adjusted, as the defaults are
typically correct for your system. <p>
The TLS options here can be used to enable secure encypted communication
between the director and the command-line <tt>bconsole</tt> program. Because
these typically run on the same system, TLS does not usually need to be enabled.<p>
<footer>

View File

@@ -0,0 +1,8 @@
<header>Director Status</header>
This page displays all backup jobs that are currently running, the 10 most
recently run, and those that are scheduled to run in future. All jobs known
to the Bacula director on this system will be included. <p>
<footer>

View File

@@ -0,0 +1,12 @@
<header>File Daemon Directors</header>
This page lists all directors that are allowed to connect to this file
daemon. If you are adding this file daemon to a remote director, the password
in its <b>Backup Client</b> entry must match the password listed here. <p>
If TLS is enabled for a director, communication between that director and
this file daemon will be encrypted and verified using the selected certificate
and key. <p>
<footer>

View File

@@ -0,0 +1,10 @@
<header>File Daemon Configuration</header>
This form can be used to adjust settings for the Bacula file daemon running
on the system. The defaults will typically be correct, although you can adjust
the daemon name and number of concurrent jobs. If your Bacula system supports
TLS security, the TLS options on this page can be used to secure communication
between the file daemon, director and storage daemons. <p>
<footer>

View File

@@ -0,0 +1,10 @@
<header>File Sets</header>
A file set is a list of files and directories that Bacula can back up as part
of a job. Each set must have a unique name, a list of files to include and an
optional list of files to exclude. This latter feature can be useful for
skipping non-critical files or directories under one of the directories to
exclude. <p>
<footer>

View File

@@ -0,0 +1,9 @@
<header>Run Bacula Group Job</header>
This form can be used to start the immediate execution of a Bacula backup
job that runs on all hosts in a Bacula group. To start it, just select it from
the list and click the <b>Backup Now</b> button. Because the job runs on
multiple hosts, its final status will not be displayed. <p>
<footer>

View File

@@ -0,0 +1,10 @@
<header>Bacula Group Backup Jobs</header>
This page lists backup jobs that are set up to run on all hosts in a Bacula
group at once. They have the same settings as standard backup jobs, except
that you cannot define default jobs to share settings between jobs. Also,
instead of selecting a client to backup, you must instead select a previously
defined Bacula group. <p>
<footer>

View File

@@ -0,0 +1,13 @@
<header>Bacula Groups</header>
This page lists host groups, each of which is a set of hosts that can be
simultaneously backed by a single <b>Bacula Group Backup Job</b>. The hosts
in a group are taken from either an OCM Manager node group database or the
Webmin Servers Index module, depending on the configuration of this module.<p>
For bacula group backups to work, each must have at least the Bacula file daemon
installed, and all hosts in the group must have the same password for this
director. <p>
<footer>

View File

@@ -0,0 +1,29 @@
<header>Bacula Backup</header>
Bacula is a set of computer programs that permits you (or the system administrator) to manage backup, recovery, and verification of computer data across a network of computers of different kinds. Bacula can also run entirely upon a single computer, and can backup to various types of media, including tape and disk.<p>
In technical terms, it is a network Client/Server based backup program. Bacula is relatively easy to use and efficient, while offering many advanced storage management features that make it easy to find and recover lost or damaged files. Due to its modular design, Bacula is scalable from small single computer systems to systems consisting of hundreds of computers located over a large network.<p>
The Bacula system is divided into three separate daemons, which can theoretically run on different hosts. These are:<br>
<dl>
<dt>Director
<dd>The director stores jobs, clients and most other configuration setttings,
and is responsible for initiating backup jobs. This Webmin module must be
run on the system that has the director installed.
<dt>File Daemon
<dd>This daemon is responsible for reading the actual files to be backed up.
A Bacula configuration can have more that one file daemon, each run on
a system to be backed up.
<dt>Storage Daemon
<dd>The storage daemon is responsible for writing data to the final backup
media, such as a tape drive or file. Typically you will only need one
such daemon (usually run on the same host as the director), but a more
complex Bacula setup may have multiple systems with different tape drives,
to spread the backup load.
</dl>
This Webmin module can manage a system that has one or more of the Bacula
daemons installed. <p>
<footer>

View File

@@ -0,0 +1,31 @@
<header>Backup Jobs</header>
A job is the most important configurable object in Bacula, as it brings togethera client, fileset and other settings to control exactly what is backed up. For this reason, it is generally best to define your file sets and clients first
before creating a job. <p>
Each job has the following important attributes :<br>
<dl>
<dt>Job name
<dd>A unique name for this job.
<dt>Job type
<dd>This determines what kind of action the job will perform. In almost all cases this should be set to <b>Backup</b>.
<dt>Backup level
<dd>Determines if the job will do a complete or partial backup of the selected files.
<dt>Client to backup
<dd>If your Bacula system has multiple clients, this option determines which one the files are read from by this backup job.
<dt>File set to backup
<dd>The selected file set determines which actual files and directories are included in the backup.
<dt>Backup on schedule
<dd>This optional option determines if the job is automatically run on schedule, and if so when.
<dt>Destination storage device
<dd>If your Bacula configuration is set up with more than one storage daemon, this option determines which one the backup is written to.
</dl><p>
To simplify the job-creation process, Bacula lets you create <b>Default definition</b> jobs that do not actually run themselves, but rather specify settings to
be inherited by real jobs. When editing a job, the <b>Default type</b> field
determines if it is a default definition, if it inherits settings from some
default, or neither. <p>
<footer>

View File

@@ -0,0 +1,13 @@
<header>Label Volume</header>
Labelling marks a volume (such as a loaded tape or backup directory) as being
part of a selected volume pool, and thus usable for backups. You must label
at least one volume before any backups done via Bacula will work - failure to
do so will cause the backup to halt until a suitable volume is labelled. <p>
For backups to files, the volume name determines the name of the file in
the destination directory that will actually be written to. For tapes, the
name will be the tape label. <p>
<footer>

View File

@@ -0,0 +1,8 @@
<header>Mount or Unmount</header>
When using Bacula to backup to a tape drive, you must use this page to mount the
inserted tape before it can be used, so that Bacula knows which volume it
contains. Mounting is not generally needed for backups to files. <p>
<footer>

View File

@@ -0,0 +1,13 @@
<header>Volume Pools</header>
In the Bacula context, a pool is a set of volumes that are dedicated to some
purpose. A volume is typically a specific tape or destination directory, each
of which is labelled with a unique name. When creating a backup job you can
select which pool will be used for destination files, and thus which volumes.
<p>
A volume can be added to a pool using the <b>Label Volume</b> page, which
marks an inserted tape or destination directory with a unique name. <p>
<footer>

View File

@@ -0,0 +1,8 @@
<header>Volumes In Pool</header>
This page can be used to list all volumes that have been marked as members
of a selected backup pool. Volumes are added to a pool using the <b>Label
Volume</b> page. <p>
<footer>

View File

@@ -0,0 +1,12 @@
<header>Backup Schedules</header>
This page lists schedules that can be applied to backup jobs, in order to have
them automatically executed by Bacula on a regular basis. Each schedule has
a unique name, and a list of backup levels and run times. Each run time must
be formatted like <i>mon-fri at 9:00</i> or <i>sat at 23:00</i>, indicating the
days of the week and time to execute. Days can also be specified as days
of the month, like <i>1st sun</i> or <i>on 5</i>. See the Bacula online
documentation for the full details of allowed formats. <p>
<footer>

View File

@@ -0,0 +1,12 @@
<header>Storage Daemon Directors</header>
This page lists all directors that are allowed to connect to this storage
daemon. If you are adding this storage daemon to a remote director, the password
in its <b>Storage Daemon</b> entry must match the password listed here. <p>
If TLS is enabled for a director, communication between that director and
this storage daemon will be encrypted and verified using the selected certificate
and key. <p>
<footer>

View File

@@ -0,0 +1,10 @@
<header>Storage Daemon Configuration</header>
This form can be used to adjust settings for the Bacula storage daemon running
on the system. The defaults will typically be correct, although you can adjust
the daemon name and number of concurrent jobs. If your Bacula system supports
TLS security, the TLS options on this page can be used to secure communication
between the storage and file daemons. <p>
<footer>

View File

@@ -0,0 +1,32 @@
<header>Storage Daemons</header>
Each entry on this page defines a connection to a particular device on a
Bacula storage daemon. Typically the daemon runs on the same system, but it
is possible to define more than one daemon, some of which are on remote hosts
with different tape drive types or more disk space. <p>
The important attributes for each daemon are :<br>
<dl>
<dt>Storage name
<dd>A unique name used on this system to identify the daemon.
<dt>Bacula SD password
<dd>This field must contain the password used by the storage daemon on the remote system, which can be found in the <tt>/etc/bacula/bacula-sd.conf</tt> file.
<dt>Hostname or IP address
<dd>The fully qualified hostname or IP of the system running the storage daemon.
<dt>Storage device name
<dd>Each storage daemon can define one or more devices, each of which corresponds to a different directory or tape drive. This field determines which device this particular daemon connection uses.
<dt>Media type name
<dd>This field must contain a short name for the type of media used by the storage device, such as <i>File</i> or <i>DDS-2</i>. It must be the same as the media type in the <b>Storage Devices</b> section on the storage server.
</dl>
Often it is useful to have more than one entry for the same host on this page,
each of which has a different storage device. This allows you to create backups
that write to different directories or tape drives. <p>
If the TLS options are shown on the storage daemon form, they can be used
to enable secure communication between the director and the remote storage
server. This is typically not necessary in a simple Bacula configuration, as
the storage and director daemons usually run on the same system. <p>
<footer>

View File

@@ -0,0 +1,8 @@
<header>Storage Daemon Status</header>
This page displays backup jobs that are currently running and the 10 most
recently run, on a selected Bacula storage daemon system. Those running or run
on different daemons will not be displayed. <p>
<footer>

View File

@@ -0,0 +1,11 @@
<header>Bacula Group Synchronization</header>
Because the hosts in a Bacula group can be changed after they have been created
in this module, this page can be used to set up the automatic updating of
group membership information. This Webmin module caches the member hosts of
each group in the Bacula configuration, and so will not automatically detect
changes to membership unless synchronization is set up.<p>
<footer>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,5 @@
P7 332
#IMGINFO:48x48 Indexed (2313 bytes)
#END_OF_COMMENTS
48 48 255
I$IIÛ¶¶¶IH%IÛ¶¶Ú%HI%Û¶Ú¶%HII·Ú¶¶%HIIÛ¶¶¶I$IIÛ¶¶ÛI$IIÛ¶¶¶IH%IÛ¶¶Ú%HI%Û¶Ú¶%HII·Ú¶¶%HIIÛ¶¶¶I$IIÛ¶¶ÛI$IIÛ¶¶¶IH%IÛ¶¶Ú%HI%Û¶ÚnmmImmnmmÛÛ$IÚ·Ú¶$II%Ú·Ú¶I$IIÛ¶¶¶IH%IÛ¶¶Ú%HI%ÛµIÛÚ·ÚÛµ“µnmnÚ¶Û¶¶$IIIÚ·¶¶Û¶¶¶I$IIÛ¶¶Ú%H%IÛ¶Ú¶·H¶·Ú·¶¶¶·¶mm·HI·Ú¶¶%HIIÛ¶¶¶I$IIÛ¶¶Ú%H%IÛ¶ÚÛHÛÚ·µ·¶¶m¶·¶¶Ú·HÛÚ¶·¶H%IHÛ¶¶¶I$IIÛ¶¶Ú%H%IÛ¶ÚnlÛ·ÚÛ¶ÚÛ¶Û¶¶¶Û¶mmnµÛ·$IHIÛ¶¶¶I$IIÛ¶¶Ú%H%IÛ¶Ú%¶ÚÛÚn¶¶ÛÚÛÚ·¶¶¶ÛÚnHnmÚ%H%I$IIÛ¶¶¶IH%IÛ¶¶Ú%H·HÛÛÚÛÚ·¶ÛÚ·µ·¶¶ÛÚÛH¶nmmÛ¶I$IIÛ¶¶¶IH%IÛ¶¶Ú%ÛHÛµ“ÚÛÚÛÚÛ¶¶mÛ¶ÚÛÚ·Ú·HÛ¶I$IIÛ¶¶¶IH%IÛ¶¶Ú%mm·Ú¶ÚÛÛÚ·þ·ÚÛµn¶ÛÚÛ¶mn¶¶Ú·mÚ·I$IIÛ¶¶¶IH%IÛ¶¶ÚI¶ÛÚÛ¶ÛÚÛ¶Ú·¶ÚÛÚÛÚ·þ·In¶¶Ú·mÛ¶Û¶¶¶I$IIÛ¶¶Ú%H%ÿIÚÛÚÛÚÛ¶¶¶·Ú¶Û¶¶Ú·Ú·ln$·µ·¶mÿ$Û¶¶¶I$IIÛ¶¶Ú%H%ÚÛÚ·Ú¶ÿ·Ú¶·ÚnmmIm·Ú¶IH%Û¶¶¶I$IIÛ¶¶Ú%HÛ%m¶¶ÛÚ¶·þ·ÚÛmmnmIÚÛ¶IIHÛ¶¶¶I$IIÛ¶¶Ú%HnIÚ·µ·nµ“Ú¶Û¶ÚÛ¶n¶mmnmmmÛ¶mI$I$IIÛ¶¶¶IH%IÛÚ$“µ¶··Ú¶¶·HImnmmImÛmÿ¶¶I$IIÛ¶¶¶IH%IÛmH·¶Ú¶ÚnÚnHIII$mInÛ¶Û¶¶I$IIÛ¶¶¶IH%IÛH¶¶“¶¶mnHnI$IIHnI¶ÛÚ¶¶·I$IIÛ¶¶¶IH%ImIÛ¶¶ÚÚmÚmImII$IIImI¶%Ú·Ú¶Û¶¶¶I$IIÛ¶¶¶Hn¶Ú·¶¶mm·Ûn“HmmII%HIImJÚ¶I$IIÛ¶¶¶I$IIÛ¶ÚIm·¶ÚÚ¶·nI¶HJmIm$I%HnImÿ¶$IIIÛ¶¶¶I$IIÛ¶IH·¶¶·µ·µ“¶·ÚIIImIIH%IImmÛ¶Ú%H%IÛ¶¶¶I$IIÛm$mnÚ·µ“µ·µ·¶¶¶·HJlIImII%Hnÿ¶¶Ú%H%II$IIÛ¶¶¶¶$IImm¶¶“µÚ¶·m%mIImIImmÚ·$IIH·Ú·¶I$IIÛ¶¶Ú%HnnImm¶¶¶µJHIIm%mI·ÚÛ¶¶I$IIÛ¶¶ÚI$IIÛ¶ÚII¶ImImnm$“µ·¶m%mIIIImÚÿ¶·¶Ú$I%IÚ·Ú¶I$IIÛ¶m$n¶nI%“HIm%mImImÿ$I·Ú¶·H%HIÛ¶¶·Û¶¶¶IHnInmm¶mnHnm¶IHIIIImI¶Û¶Ú¶%HI%ÛÚ¶¶%HIIÛ¶¶¶Û$mnm¶¶IHn%Imm$nlJÛ$Û¶¶Û$I%HÛ¶·Ú$II$Û¶¶ÛHI¶ImII¶%mm¶$Im%mIm¶I$ÛÚ·¶$IIH·Ú·¶H%IIÛ¶¶%·nHnmImIn$mnmÛþ%H·Ú·¶$IIHÛ¶·¶H%IHI$ÿIIHJl·ÚmI$·mIIHII¶ÛÚ¶·$IHI·Ú¶·H%HIÛ¶¶ÛI$mImn$In·nHnmnmHJmÿ¶¶Ú·$IH%ÛÚ¶·$IHI·Ú¶·IÚImIII¶m%mmI¶ÛnHnH“$Immÿ$Û¶·¶H%IIÚ·¶Ú$I%IÚ·Ú¶I¶mIImIIm·¶mH%$“lmnHIImÛÛ$Û¶Ú¶%HI%ÛÚ¶¶%HII·Ú¶¶Û¶mmmII%ImÚ¶¶n¶$%¶¶m%Hnÿ·¶$IIH·Ú·¶H%IHÛ¶·¶HI%HÛ¶mmnlJ$IIHJµ·Ú·¶¶¶$IImÛ¶Ú·$IH%ÛÚ¶·$IHI·Ú¶·H%HIÛ¶¶mImmI%IH%IHnÚ·µ%$Im·ÚÛ¶¶$IIIÚ·¶¶I$IIÛ¶¶Ú%H%IÛ¶¶JmmIH%IH%%H%HJHI%mÛ·¶Ú¶%HII·Ú¶¶I$IIÛ¶¶¶IH%II$IÛmmmJHI$I%$I$%$%HJmÿ¶$I%HÛ¶Û¶$II$ÛÚ·¶$IIH·Ú·¶I$II¶mnHJl%I$%$$%$%Im¶ÿ¶%IHIÛ¶¶·H%HIÛ¶¶Û$I$IÛ¶Ú·I$IIÛmJlIIII$I%$%Hnÿ·¶$IIH·Ú·¶H%IHÛ¶·¶HI%HÛ¶·ÚI$IIÛ¶¶mmIIIIH%II$IÛÚ¶¶%HII·Ú¶¶I$IIÛ¶¶Ú%H%IÛ¶¶ÚÛ¶¶¶I$IÿmmIIIHI%ImÛ$I$IÛ¶Ú·$IH%ÛÚ·¶$IIH·Ú·¶H%IHÛ¶¶¶I$IIÛÚmImIIIm¶Û$IIH·Ú·¶H%IHÛ¶·Ú$I%IÚ·¶Ú$II%Û¶¶¶I$IIÛ¶¶ÿ¶mmÿ¶$II$ÛÚ·¶$IIH·Ú·¶H%IHÛ¶·Ú$I%IÛ¶¶¶I$IIÛ¶¶Ú%H%ÿÿ¶·Ú$I%HÛ¶·Ú$II$Û¶Û¶$IIH·Ú·¶$IIH

Binary file not shown.

View File

@@ -0,0 +1,5 @@
P7 332
#IMGINFO:48x48 Indexed (2154 bytes)
#END_OF_COMMENTS
48 48 255
I$II鄱抖IH%I鄱囤%HI%鄱诙%HII汾抖%HII鄱抖I$II鄱钝I$II鄱抖IH%I鄱囤%HI%鄱诙%HII汾抖%HII鄱抖I$II鄱钝I$II鄱抖IH%I鄱囤%HI%鄱诙%HII汾抖%HII鄱抖I$II鄱钝I$II鄱抖IH%I鄱囤%HI%鄱诙%HII汾抖%HII鄱抖I$II鄱钝鄱抖I$IE恢憾%HII缀抖I$II鄱吨)H%I鄱趾%HI%鄱诜$IHI鄱抖I$%E恢憾E(II缀吨%H)I鄱吨)D<>粬瞨<E7B2AC><E79EA8><EFBFBD>$I只抖I$II鄱抖%D)%鄱侄)HEI恢逗%HIE鄱憾窉窉斗摱禢庅逗址(EH)鄱<>$%E(%鄱锥(EIH恢泛$IEH鄱咦椂搾枔挿挿扢庅逗D)IEI$I%$E)%D%I%$E)<29>(EH)鄱诌谆挿拻抮拵s憦v挸<76>)<29>$鄱趾I$%E(%E%(E%%H%E籇)HE鄱粧硸挀憮拻巖抧巖r彇ni(鄱锥I$%E(%E%(E%%H%E籇)HE<48>怀挷棐帓拻搎弎搉msn挆$鄱锥篒$I%$E)%D%I%$E)<29>(E<>蹢矖矑抮帗r憮m搷smrnns<6E>%捼范痕抖$%E(%E%(E%E(E畸粧窉瞫憦rr巖s巕弎nnnmsN稩I<E7A8A9>$II鄱抖%D)%鄱侄)HE<48>环挸柍r扤iJMnnrn抧抦nnnNr稭E籇I%鄱抖I$%E恢憾E(I蹞稈搾抧III*I%msnr巑N嶯moR譓%禘(I鄱抖I$I%鄱囤%<25>凡棐抧扟mNI嶳iNirNnm嶫mnmOn籱E<E7B1B1>$IHI$II鄱抖IH%I<>窉摱巗mJMjIMnjr扟rjqnnMjnmN窉<4E>%鄱趾I$II鄱抖IH%<25>贩拻拸q&MIIjI)JIMjRnnmnnmjmN蹞慐<E8B99E>悍諭$II鄱抖IH%蹞拻搾nIIIJIIII*InnmnnmnmnJm范<6D>(弛斗禝$II鄱抖IH蹞拻抯巕&iMJIIIIJrJmnrinmnmnn麞<6E>%叨址痕抖禝$II圳棐帗q弐NIIIJ)IEnrnIrnmn峃jmn<6D>棽I捴(E)I鄱抖I$II鄱搑帓n扤<6E>%MFMENr巖n峮nmnmnmi刍窉E<E7AA89><45>(EI)鄱抖I$II<49>搾r帓ms嶯慜inmrnnn憂n峮mnmn圩欢%鄱<>(EII鄱抖I$II窎巖n抧巒SnnNnmN巑r巑nn峮mn圹圹$范诙%HI)I$II鄱钝r砿rn抧巑nnmnnmnr峮巑r妐n庅捋踤<E68D8B>)HE)壑逗I$II鄱蹝枔nr巑拲拺畳mn憂n峮抦n巑<6E><E5B791>圹踡挾%HII汾抖I$II鄱挆挀Mn帒挱憥懖mnnmn峮巕巒<E5B795><E5B792>圹邘懛篋I%I诜褐I$II鄱搈梠qn拲睅憤諱j峮mrn峮崚<E5B3AE><E5B49A>刍鶱埠斗DI(I缀分鄱抖I抯m搉rN嵅睄幈眓mnmn峮n嵶<6E><E5B5B6>圻譹%跠)E诜诙$II)鄱抖踤Rj挅OnMn崕懎rinmn峮n<E5B3AE><6E><EFBFBD>秐n<E7A790>%IHE鄱悍D)HI鄱抖搾MnJ挆JRJnmJmN巑jm捽<6D><E68DBD><EFBFBD>窉扙<E7AA89>$IID悔范D)IH鄱抖搑InmN挸rnNNjmnm撝<6D><E6929D>圹埝蹝柗搇摱DI)I只吨(EI)I$I<>oRinMnmn摲跅宗圹圹圹<E59CB9>谯扢庅穜i<E7A99C>$恢泛D)ID鄱恢I$I遪nNinMJims不纷痕圹<E79795>范扞I捽窉I跦%鄱诜$IHI汾斗I$I<>NomIJImJmmJ帠矖拻抧iInI捽恢)稤I)只侄$III鹤抖I$I<>nSIIJiMIJIIIIIIJiInmjM槽环H稤)IE诜褐$I)I只吨鄱抖桸Ni*HjIIIJIMiJmIniMj谯贩I篋恢范(IEI诜逗D)IE鄱抖跱OMJIIIIIJiMIjImJi钝鄯杋<E984AF>$I鄱痘D)HE鄱鹤$I(I鄱抖I桸NNJIImJImIJmIn掹坊譺捽D)H鄱分(IE(鄱缀$IID鄱抖I$穜N/JMJIiNIin槽刍范捼稤)HI缀范DI)H鄱分(EI(I$II鄱鹯抮snsNn挿钝坊范综$I)宗抖)DII恢逗E(EI鄱囤I$II鄱抖秊r扯范窏范贩<E88C83><E8B4A9><EFBFBD>$IIE鹤憾%HII缀抖E(II鄱吨I$II鄱抖I<E68A96>挀抧矖捕圹只抖H%II诜吨(I%I诜趾$II%诜诙I$II鄱抖IH%I鄱囤%HI%鄱诙%HII汾抖%HII鄱抖I$II鄱钝鄱抖I$II鄱囤%H%I鄱诙%HI%鄱诙%HII汾抖I$II鄱斗HI$I鄱抖I$II鄱囤%H%I鄱诙%HI%鄱诙%HII汾抖I$II鄱斗HI$I鄱抖I$II鄱囤%H%I鄱诙%HI%鄱诙%HII汾抖I$II鄱斗HI$I鄱抖I$II鄱囤%H%I鄱诙%HI%鄱诙%HII汾抖I$II鄱斗HI$I

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More