]> git.pld-linux.org Git - packages/bacula-backup-mysql.git/blob - bacula-backup-mysql
48441c7ea472513343f824894072a4474617edb8
[packages/bacula-backup-mysql.git] / bacula-backup-mysql
1 #!/usr/bin/perl -ws
2 # Rudimentary switch parsing. Must be in main package.
3 our $cleanup;
4
5 package BBM;
6 use strict;
7 use POSIX qw(setuid setgid);
8 use DBI;
9 use File::Temp qw(tempdir);
10 use File::Path qw(rmtree);
11
12
13 # path to Apache HTTPd-style config
14 my $config = '/etc/bacula/backup-mysql.conf';
15 my $c = new BBM::Config($config);
16
17 # now change to user mysql after we've read config
18 unless ($<) {
19         my $uid = getpwnam('mysql');
20         my $gid = getgrnam('mysql');
21         die "Can't find user/group mysql\n" unless $uid or $gid;
22
23         # CWD could not be accessible for mysql user
24         chdir("/");
25
26         $) = "$gid $gid";
27         $( = $gid;
28         $> = $< = $uid;
29 }
30
31 # setup tmpdir
32 my $backup_dir = $c->get('options', 'outdir') or die "'outdir' not defined in config\n";
33 my $tmpdir = $c->get('options', 'tmpdir')  or die "'tmpdir' not defined in config\n";
34
35 if (!-d $backup_dir && !mkdir($backup_dir) && !-d $backup_dir) {
36         die "backup dir '$backup_dir' not present and can't be created\n";
37 }
38 if (!-d $tmpdir && !mkdir($tmpdir) && !-d $tmpdir) {
39         die "tmpdir '$tmpdir' not present and can't be created\n";
40 }
41
42 # process each cluster
43 for my $cluster ($c->get('clusters', 'cluster')) {
44         print ">>> $cluster\n";
45         if ($cleanup) {
46                 cleanup_cluster($cluster);
47         } else {
48                 backup_cluster($cluster);
49         }
50         print "<<< $cluster\n";
51 }
52
53
54 # Usage: mysqlhotcopy $CLUSTER $DATABASE $USERNAME $PASSWORD $SOCKET
55 #
56 sub mysqlhotcopy {
57         my ($cluster, $database, $user, $password, $socket) = @_;
58
59         print ">>>> mysqlhotcopy $database\n";
60
61         my $dstdir = tempdir("bbm.XXXXXX", DIR => $tmpdir);
62
63         # make backup with mysqlhotcopy
64         my @shell = ('mysqlhotcopy');
65         push(@shell, '-u', $user) if $user;
66         push(@shell, '-p', $password) if $password;
67         push(@shell, '-S', $socket) if $socket;
68         push(@shell, $database, $dstdir);
69         system(@shell) == 0 or die "mysqlhotcopy failed: $?\n";
70
71         # put it to "production dir"
72         my $cluster_dir = "$backup_dir/$cluster";
73         if (!-d $cluster_dir && !mkdir($cluster_dir) && !-d $cluster_dir) {
74                 die "cluster dir '$cluster_dir' not present and can't be created\n";
75         }
76
77         my $dirname = "$backup_dir/$cluster/$database";
78         if (-d $dirname) {
79                 rmtree($dirname);
80         }
81
82         my $srcdir= "$dstdir/$database";
83         rename($srcdir, $dirname) or die "Rename '$srcdir'->'$dirname' failed: $!\n";
84
85         rmdir($dstdir) or warn $!;
86
87         print "<<<< mysqlhotcopy $database\n";
88 }
89
90 sub cleanup_cluster {
91         my ($cluster) = @_;
92         my $cluster_dir = "$backup_dir/$cluster";
93         print ">>>> cleanup $cluster_dir\n";
94         rmtree($cluster_dir);
95         print "<<<< cleanup $cluster_dir\n";
96 }
97
98 sub backup_cluster {
99         my ($cluster) = @_;
100
101         # get db connection info
102         my $user = $c->get($cluster, 'user') || $c->get('client', 'user');
103         my $password = $c->get($cluster, 'password') || $c->get('client', 'password');
104         my $socket = $c->get($cluster, 'socket') || $c->get('client', 'socket');
105
106         # get databases to backup
107         my @include = $c->get($cluster, 'include_database');
108         my @exclude = $c->get($cluster, 'exclude_database');
109
110         # start with include list
111         my %dbs = map { $_ => 1 } @include;
112
113         if (@exclude or !@include) {
114                 my $dbh = new BBM::DB($user, $password, $socket);
115                 my $sth = $dbh->prepare("show databases");
116                 $sth->execute();
117                 while (my($dbname) = $sth->fetchrow_array) {
118                         next if lc($dbname) eq 'information_schema';
119                         $dbs{$dbname} = 1;
120                 }
121                 undef $dbh;
122         }
123
124         # remove excluded databases
125         delete @dbs{@exclude};
126
127         # now do the backup
128         foreach my $db (keys %dbs) {
129                 mysqlhotcopy($cluster, $db, $user, $password, $socket);
130         }
131 }
132
133 package BBM::DB;
134 use strict;
135
136 # DB class for simple Database connection
137 sub new {
138         my $self = shift;
139         my $class = ref($self) || $self;
140
141         my ($user, $password, $socket) = @_;
142         my $dsn = '';
143         $dsn .= "mysql_socket=$socket" if $socket;
144         my $dbh = DBI->connect("DBI:mysql:$dsn", $user, $password, { PrintError => 0, RaiseError => 1 });
145         return $dbh;
146 }
147
148 package BBM::Config;
149 use strict;
150 use Config::General;
151
152 sub new {
153         my $self = shift;
154         my $class = ref($self) || $self;
155         my $file = shift;
156
157         my $config = new Config::General(-ConfigFile => $file, -LowerCaseNames => 1);
158         my $this = { $config->getall() };
159         bless($this, $class);
160 }
161
162 sub get {
163         my ($self, $section, $key) = @_;
164         my $h = $self;
165
166         # descend to [cluster] if $section not present in root tree
167         unless (exists $h->{$section}) {
168                 $h = $h->{cluster};
169         }
170
171         # pay attention if callee wanted arrays
172         return wantarray ? () : undef unless exists $h->{$section};
173         return wantarray ? () : undef unless exists $h->{$section}->{$key};
174
175         # deref if wanted array and is arrayref
176         return @{$h->{$section}->{$key}} if wantarray && ref $h->{$section}->{$key} eq 'ARRAY';
177
178         return $h->{$section}->{$key};
179 }
This page took 0.051557 seconds and 2 git commands to generate.