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;
22 my $pidfile = new File::Pid;
24 if (my $pid = $pidfile->running ) {
25 die "$0 already running: $pid\n";
26 } elsif ($pidfile->pid ne $$) {
28 $pidfile = new File::Pid;
31 print STDERR "$0 using pid ",$pidfile->pid," file ",$pidfile->file,"\n";
33 my $t_fmt = '%Y-%m-%d %H:%M:%S';
36 my $bpc = BackupPC::Lib->new || die;
37 my %Conf = $bpc->Conf();
38 my $TopDir = $bpc->TopDir();
41 my $dsn = $Conf{SearchDSN} || die "Need SearchDSN in config.pl\n";
42 my $user = $Conf{SearchUser} || '';
44 my $dbh = DBI->connect($dsn, $user, "", { RaiseError => 1, AutoCommit => 0 });
48 if ( !getopts("cdm:v:", \%opt ) ) {
50 usage: $0 [-c|-d] [-m num] [-v|-v level]
53 -c create database on first use
54 -d delete database before import
55 -m num import just num increments for one host
56 -v num set verbosity (debug) level (default $debug)
61 ###################################create tables############################3
65 my $index = shift || return;
66 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_hostid,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,
118 name VARCHAR(255) NOT NULL,
119 path VARCHAR(255) NOT NULL,
120 date integer NOT NULL,
121 type INTEGER NOT NULL,
122 size INTEGER NOT NULL,
123 dvdid INTEGER references dvds(id)
127 print "creating indexes:";
129 foreach my $index (qw(
152 foreach my $table (qw(files dvds backups shares hosts)) {
154 $dbh->do(qq{ DELETE FROM $table });
162 print "Debug level at $opt{v}\n";
166 #################################INSERT VALUES#############################
169 $hosts = $bpc->HostInfoRead();
175 $sth->{insert_hosts} = $dbh->prepare(qq{
176 INSERT INTO hosts (name, IP) VALUES (?,?)
179 $sth->{hosts_by_name} = $dbh->prepare(qq{
180 SELECT ID FROM hosts WHERE name=?
183 $sth->{backups_broj} = $dbh->prepare(qq{
186 WHERE hostID=? AND num=?
189 $sth->{insert_backups} = $dbh->prepare(qq{
190 INSERT INTO backups (hostID, num, date, type)
194 $sth->{insert_files} = $dbh->prepare(qq{
196 (shareID, backupNum, name, path, date, type, size)
197 VALUES (?,?,?,?,?,?,?)
201 my $t = shift || return;
203 my ($ss,$mm,$hh) = gmtime($t);
204 $out .= "${hh}h" if ($hh);
205 $out .= sprintf("%02d:%02d", $mm,$ss);
209 foreach my $host_key (keys %{$hosts}) {
211 my $hostname = $hosts->{$host_key}->{'host'} || die "can't find host for $host_key";
213 $sth->{hosts_by_name}->execute($hosts->{$host_key}->{'host'});
215 unless (($hostID) = $sth->{hosts_by_name}->fetchrow_array()) {
216 $sth->{insert_hosts}->execute(
217 $hosts->{$host_key}->{'host'},
218 $hosts->{$host_key}->{'ip'}
221 $hostID = $dbh->last_insert_id(undef,undef,'hosts',undef);
224 print("host ".$hosts->{$host_key}->{'host'}.": ");
226 # get backups for a host
227 my @backups = $bpc->BackupInfoRead($hostname);
228 print scalar @backups, " increments\n";
232 foreach my $backup (@backups) {
235 last if ($opt{m} && $inc_nr > $opt{m});
237 my $backupNum = $backup->{'num'};
238 my @backupShares = ();
240 print $hosts->{$host_key}->{'host'},
241 "\t#$backupNum\t", $backup->{type} || '?', " ",
242 $backup->{nFilesNew} || '?', "/", $backup->{nFiles} || '?',
244 strftime($t_fmt,localtime($backup->{startTime})),
246 fmt_time($backup->{endTime} - $backup->{startTime}),
249 $sth->{backups_broj}->execute($hostID, $backupNum);
250 my ($broj) = $sth->{backups_broj}->fetchrow_array();
253 $sth->{insert_backups}->execute(
256 $backup->{'endTime'},
261 my $files = BackupPC::View->new($bpc, $hostname, \@backups, 1);
262 foreach my $share ($files->shareList($backupNum)) {
266 print strftime($t_fmt,localtime())," ", $share;
267 $shareID = getShareID($share, $hostID, $hostname);
269 my ($f, $nf, $d, $nd) = recurseDir($bpc, $hostname, $files, $backupNum, $share, "", $shareID);
270 my $dur = (time() - $t) || 1;
271 printf(" %d/%d files %d/%d dirs [%.2f/s dur: %s]\n",
285 print "total duration: ",fmt_time(time() - $start_t),"\n";
291 my ($share, $hostID, $hostname) = @_;
293 $sth->{share_id} ||= $dbh->prepare(qq{
294 SELECT ID FROM shares WHERE hostID=? AND name=?
297 $sth->{share_id}->execute($hostID,$share);
299 my ($id) = $sth->{share_id}->fetchrow_array();
301 return $id if (defined($id));
303 $sth->{insert_share} ||= $dbh->prepare(qq{
305 (hostID,name,share,localpath)
309 my $drop_down = $hostname . '/' . $share;
310 $drop_down =~ s#//+#/#g;
312 $sth->{insert_share}->execute($hostID,$share, $drop_down ,undef);
313 return $dbh->last_insert_id(undef,undef,'shares',undef);
321 my ($key, $shareID,undef,$name,$path,undef,$date,undef,$size) = @_;
323 return $beenThere->{$key} if (defined($beenThere->{$key}));
325 $sth->{file_in_db} ||= $dbh->prepare(qq{
327 WHERE shareID = ? and
334 my @param = ($shareID,$path,$name,$date,$size);
335 $sth->{file_in_db}->execute(@param);
336 my $rows = $sth->{file_in_db}->rows;
337 print STDERR "## found_in_db ",( $rows ? '+' : '-' ), join(" ",@param), "\n" if ($debug >= 3);
339 $beenThere->{$key}++;
341 $sth->{'insert_files'}->execute(@data) unless ($rows);
345 ####################################################
346 # recursing through filesystem structure and #
347 # and returning flattened files list #
348 ####################################################
349 sub recurseDir($$$$$$$$) {
351 my ($bpc, $hostname, $files, $backupNum, $share, $dir, $shareID) = @_;
353 print STDERR "\nrecurse($hostname,$backupNum,$share,$dir,$shareID)\n" if ($debug >= 1);
355 my ($nr_files, $new_files, $nr_dirs, $new_dirs) = (0,0,0,0);
360 print STDERR "# dirAttrib($backupNum, $share, $dir)\n" if ($debug >= 2);
361 my $filesInBackup = $files->dirAttrib($backupNum, $share, $dir);
363 # first, add all the entries in current directory
364 foreach my $path_key (keys %{$filesInBackup}) {
369 $filesInBackup->{$path_key}->{'relPath'},
370 $filesInBackup->{$path_key}->{'mtime'},
371 $filesInBackup->{$path_key}->{'type'},
372 $filesInBackup->{$path_key}->{'size'}
375 my $key = join(" ", (
379 $filesInBackup->{$path_key}->{'mtime'},
380 $filesInBackup->{$path_key}->{'size'}
384 if (! defined($beenThere->{$key}) && ! found_in_db($key, @data)) {
385 print STDERR "# key: $key [", $beenThere->{$key},"]" if ($debug >= 2);
387 if ($filesInBackup->{$path_key}->{'type'} == BPC_FTYPE_DIR) {
389 print STDERR " dir\n" if ($debug >= 2);
392 print STDERR " file\n" if ($debug >= 2);
396 if ($filesInBackup->{$path_key}->{'type'} == BPC_FTYPE_DIR) {
399 my $full_path = $dir . '/' . $path_key;
400 push @stack, $full_path;
401 print STDERR "### store to stack: $full_path\n" if ($debug >= 3);
403 # my ($f,$nf,$d,$nd) = recurseDir($bpc, $hostname, $backups, $backupNum, $share, $path_key, $shareID) unless ($beenThere->{$key});
415 print STDERR "## STACK ",join(", ", @stack),"\n" if ($debug >= 2);
417 while ( my $dir = shift @stack ) {
418 my ($f,$nf,$d,$nd) = recurseDir($bpc, $hostname, $files, $backupNum, $share, $dir, $shareID);
419 print STDERR "# $dir f: $f nf: $nf d: $d nd: $nd\n" if ($debug >= 1);
427 return ($nr_files, $new_files, $nr_dirs, $new_dirs);