1 #!/usr/local/bin/perl -w
4 use lib "__INSTALLDIR__/lib";
11 use Time::HiRes qw/time/;
13 use POSIX qw/strftime/;
15 use constant BPC_FTYPE_DIR => 5;
20 my $pidfile = new File::Pid;
22 if (my $pid = $pidfile->running ) {
23 die "$0 already running: $pid\n";
24 } elsif ($pidfile->pid ne $$) {
26 $pidfile = new File::Pid;
29 print STDERR "$0 using pid ",$pidfile->pid," file ",$pidfile->file,"\n";
31 my $t_fmt = '%Y-%m-%d %H:%M:%S';
34 my $bpc = BackupPC::Lib->new || die;
35 my %Conf = $bpc->Conf();
36 my $TopDir = $bpc->TopDir();
39 my $dsn = "dbi:SQLite:dbname=$TopDir/$Conf{SearchDB}";
43 ($dsn,$user) = qw/dbi:Pg:dbname=backuppc dpavlin/;
45 my $dbh = DBI->connect($dsn, $user, "", { RaiseError => 1, AutoCommit => 0 });
49 if ( !getopts("cdm:v:", \%opt ) ) {
51 usage: $0 [-c|-d] [-m num] [-v|-v level]
54 -c create database on first use
55 -d delete database before import
56 -m num import just num increments for one host
57 -v num set verbosity (debug) level (default $debug)
62 ###################################create tables############################3
66 my $index = shift || return;
67 my ($table,$col,$unique) = split(/_/, $index);
69 $dbh->do(qq{ create $unique index $index on $table($col) });
72 print "creating tables...\n";
76 ID SERIAL PRIMARY KEY,
77 name VARCHAR(30) NOT NULL,
84 ID SERIAL PRIMARY KEY,
85 hostID INTEGER NOT NULL references hosts(id),
86 name VARCHAR(30) NOT NULL,
87 share VARCHAR(200) NOT NULL,
88 localpath VARCHAR(200)
93 create table backups (
94 hostID INTEGER NOT NULL references hosts(id),
96 date integer NOT NULL,
97 type CHAR(4) not null,
98 PRIMARY KEY(hostID, num)
102 do_index('backups_num_unique');
106 ID SERIAL PRIMARY KEY,
107 num INTEGER NOT NULL,
108 name VARCHAR(255) NOT NULL,
115 ID SERIAL PRIMARY KEY,
116 shareID INTEGER NOT NULL references shares(id),
117 backupNum INTEGER NOT NULL references backups(num),
118 name VARCHAR(255) NOT NULL,
119 path VARCHAR(255) NOT NULL,
120 fullpath VARCHAR(255) NOT NULL,
121 date integer NOT NULL,
122 type INTEGER NOT NULL,
123 size INTEGER NOT NULL,
124 dvdid INTEGER references dvds(id)
128 print "creating indexes:";
130 foreach my $index (qw(
153 foreach my $table (qw(files dvds backups shares hosts)) {
155 $dbh->do(qq{ DELETE FROM $table });
159 eval { $dbh->commit; };
163 print "Debug level at $opt{v}\n";
167 #################################INSERT VALUES#############################
170 $hosts = $bpc->HostInfoRead();
176 $sth->{insert_hosts} = $dbh->prepare(qq{
177 INSERT INTO hosts (name, IP) VALUES (?,?)
180 $sth->{hosts_by_name} = $dbh->prepare(qq{
181 SELECT ID FROM hosts WHERE name=?
184 $sth->{backups_broj} = $dbh->prepare(qq{
187 WHERE hostID=? AND num=?
190 $sth->{insert_backups} = $dbh->prepare(qq{
191 INSERT INTO backups (hostID, num, date, type)
195 $sth->{insert_files} = $dbh->prepare(qq{
197 (shareID, backupNum, name, path, fullpath, date, type, size)
198 VALUES (?,?,?,?,?,?,?,?)
201 foreach my $host_key (keys %{$hosts}) {
203 my $hostname = $hosts->{$host_key}->{'host'} || die "can't find host for $host_key";
205 $sth->{hosts_by_name}->execute($hosts->{$host_key}->{'host'});
207 unless (($hostID) = $sth->{hosts_by_name}->fetchrow_array()) {
208 $sth->{insert_hosts}->execute(
209 $hosts->{$host_key}->{'host'},
210 $hosts->{$host_key}->{'ip'}
213 $hostID = $dbh->last_insert_id(undef,undef,'hosts',undef);
216 print("host ".$hosts->{$host_key}->{'host'}.": ");
218 # get backups for a host
219 my @backups = $bpc->BackupInfoRead($hostname);
220 print scalar @backups, " increments\n";
224 foreach my $backup (@backups) {
227 last if ($opt{m} && $inc_nr > $opt{m});
229 my $backupNum = $backup->{'num'};
230 my @backupShares = ();
232 print $hosts->{$host_key}->{'host'},
233 "\t#$backupNum\t", $backup->{type} || '?', " ",
234 $backup->{nFilesNew} || '?', "/", $backup->{nFiles} || '?',
237 $sth->{backups_broj}->execute($hostID, $backupNum);
238 my ($broj) = $sth->{backups_broj}->fetchrow_array();
241 $sth->{insert_backups}->execute(
244 $backup->{'endTime'},
249 my $files = BackupPC::View->new($bpc, $hostname, \@backups, 1);
250 foreach my $share ($files->shareList($backupNum)) {
254 print strftime($t_fmt,localtime())," ", $share;
255 $shareID = getShareID($share, $hostID, $hostname);
257 my ($f, $nf, $d, $nd) = recurseDir($bpc, $hostname, $files, $backupNum, $share, "", $shareID);
258 printf(" %d/%d files %d/%d dirs [%.2f/s]\n",
260 ( ($f+$d) / ((time() - $t) || 1) )
275 my ($share, $hostID, $hostname) = @_;
277 $sth->{share_id} ||= $dbh->prepare(qq{
278 SELECT ID FROM shares WHERE hostID=? AND name=?
281 $sth->{share_id}->execute($hostID,$share);
283 my ($id) = $sth->{share_id}->fetchrow_array();
285 return $id if (defined($id));
287 $sth->{insert_share} ||= $dbh->prepare(qq{
289 (hostID,name,share,localpath)
293 my $drop_down = $hostname . '/' . $share;
294 $drop_down =~ s#//+#/#g;
296 $sth->{insert_share}->execute($hostID,$share, $drop_down ,undef);
297 return $dbh->last_insert_id(undef,undef,'shares',undef);
305 my ($key, $shareID,undef,$name,$path,undef,$date,undef,$size) = @_;
307 return $beenThere->{$key} if (defined($beenThere->{$key}));
309 $sth->{file_in_db} ||= $dbh->prepare(qq{
311 WHERE shareID = ? and
318 my @param = ($shareID,$path,$name,$date,$size);
319 $sth->{file_in_db}->execute(@param);
320 my $rows = $sth->{file_in_db}->rows;
321 print STDERR "## found_in_db ",( $rows ? '+' : '-' ), join(" ",@param), "\n" if ($debug >= 3);
323 $beenThere->{$key}++;
325 $sth->{'insert_files'}->execute(@data) unless ($rows);
329 ####################################################
330 # recursing through filesystem structure and #
331 # and returning flattened files list #
332 ####################################################
333 sub recurseDir($$$$$$$$) {
335 my ($bpc, $hostname, $files, $backupNum, $share, $dir, $shareID) = @_;
337 print STDERR "\nrecurse($hostname,$backupNum,$share,$dir,$shareID)\n" if ($debug >= 1);
339 my ($nr_files, $new_files, $nr_dirs, $new_dirs) = (0,0,0,0);
344 print STDERR "# dirAttrib($backupNum, $share, $dir)\n" if ($debug >= 2);
345 my $filesInBackup = $files->dirAttrib($backupNum, $share, $dir);
347 # first, add all the entries in current directory
348 foreach my $path_key (keys %{$filesInBackup}) {
353 $filesInBackup->{$path_key}->{'relPath'},
354 $filesInBackup->{$path_key}->{'fullPath'},
355 # $filesInBackup->{$path_key}->{'sharePathM'},
356 $filesInBackup->{$path_key}->{'mtime'},
357 $filesInBackup->{$path_key}->{'type'},
358 $filesInBackup->{$path_key}->{'size'}
361 my $key = join(" ", (
365 $filesInBackup->{$path_key}->{'mtime'},
366 $filesInBackup->{$path_key}->{'size'}
370 if (! defined($beenThere->{$key}) && ! found_in_db($key, @data)) {
371 print STDERR "# key: $key [", $beenThere->{$key},"]" if ($debug >= 2);
373 if ($filesInBackup->{$path_key}->{'type'} == BPC_FTYPE_DIR) {
375 print STDERR " dir\n" if ($debug >= 2);
378 print STDERR " file\n" if ($debug >= 2);
382 if ($filesInBackup->{$path_key}->{'type'} == BPC_FTYPE_DIR) {
385 my $full_path = $dir . '/' . $path_key;
386 push @stack, $full_path;
387 print STDERR "### store to stack: $full_path\n" if ($debug >= 3);
389 # my ($f,$nf,$d,$nd) = recurseDir($bpc, $hostname, $backups, $backupNum, $share, $path_key, $shareID) unless ($beenThere->{$key});
401 print STDERR "## STACK ",join(", ", @stack),"\n" if ($debug >= 2);
403 while ( my $dir = shift @stack ) {
404 my ($f,$nf,$d,$nd) = recurseDir($bpc, $hostname, $files, $backupNum, $share, $dir, $shareID);
405 print STDERR "# $dir f: $f nf: $nf d: $d nd: $nd\n" if ($debug >= 1);
413 return ($nr_files, $new_files, $nr_dirs, $new_dirs);