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);
68 $dbh->do(qq{ create $unique index $index on $table($col) });
71 print "creating tables...\n";
75 ID SERIAL PRIMARY KEY,
76 name VARCHAR(30) NOT NULL,
83 ID SERIAL PRIMARY KEY,
84 hostID INTEGER NOT NULL references hosts(id),
85 name VARCHAR(30) NOT NULL,
86 share VARCHAR(200) NOT NULL,
87 localpath VARCHAR(200)
92 create table backups (
93 hostID INTEGER NOT NULL references hosts(id),
95 date integer NOT NULL,
96 type CHAR(4) not null,
97 PRIMARY KEY(hostID, num)
101 do_index('backups_num_unique');
105 ID SERIAL PRIMARY KEY,
106 num INTEGER NOT NULL,
107 name VARCHAR(255) NOT NULL,
114 ID SERIAL PRIMARY KEY,
115 shareID INTEGER NOT NULL references shares(id),
116 backupNum INTEGER NOT NULL references backups(num),
117 name VARCHAR(255) NOT NULL,
118 path VARCHAR(255) NOT NULL,
119 fullpath 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, fullpath, 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} || '?',
245 $sth->{backups_broj}->execute($hostID, $backupNum);
246 my ($broj) = $sth->{backups_broj}->fetchrow_array();
249 $sth->{insert_backups}->execute(
252 $backup->{'endTime'},
257 my $files = BackupPC::View->new($bpc, $hostname, \@backups, 1);
258 foreach my $share ($files->shareList($backupNum)) {
262 print strftime($t_fmt,localtime())," ", $share;
263 $shareID = getShareID($share, $hostID, $hostname);
265 my ($f, $nf, $d, $nd) = recurseDir($bpc, $hostname, $files, $backupNum, $share, "", $shareID);
266 my $dur = (time() - $t) || 1;
267 printf(" %d/%d files %d/%d dirs [%.2f/s dur: %s]\n",
281 print "total duration: ",fmt_time(time() - $start_t),"\n";
287 my ($share, $hostID, $hostname) = @_;
289 $sth->{share_id} ||= $dbh->prepare(qq{
290 SELECT ID FROM shares WHERE hostID=? AND name=?
293 $sth->{share_id}->execute($hostID,$share);
295 my ($id) = $sth->{share_id}->fetchrow_array();
297 return $id if (defined($id));
299 $sth->{insert_share} ||= $dbh->prepare(qq{
301 (hostID,name,share,localpath)
305 my $drop_down = $hostname . '/' . $share;
306 $drop_down =~ s#//+#/#g;
308 $sth->{insert_share}->execute($hostID,$share, $drop_down ,undef);
309 return $dbh->last_insert_id(undef,undef,'shares',undef);
317 my ($key, $shareID,undef,$name,$path,undef,$date,undef,$size) = @_;
319 return $beenThere->{$key} if (defined($beenThere->{$key}));
321 $sth->{file_in_db} ||= $dbh->prepare(qq{
323 WHERE shareID = ? and
330 my @param = ($shareID,$path,$name,$date,$size);
331 $sth->{file_in_db}->execute(@param);
332 my $rows = $sth->{file_in_db}->rows;
333 print STDERR "## found_in_db ",( $rows ? '+' : '-' ), join(" ",@param), "\n" if ($debug >= 3);
335 $beenThere->{$key}++;
337 $sth->{'insert_files'}->execute(@data) unless ($rows);
341 ####################################################
342 # recursing through filesystem structure and #
343 # and returning flattened files list #
344 ####################################################
345 sub recurseDir($$$$$$$$) {
347 my ($bpc, $hostname, $files, $backupNum, $share, $dir, $shareID) = @_;
349 print STDERR "\nrecurse($hostname,$backupNum,$share,$dir,$shareID)\n" if ($debug >= 1);
351 my ($nr_files, $new_files, $nr_dirs, $new_dirs) = (0,0,0,0);
356 print STDERR "# dirAttrib($backupNum, $share, $dir)\n" if ($debug >= 2);
357 my $filesInBackup = $files->dirAttrib($backupNum, $share, $dir);
359 # first, add all the entries in current directory
360 foreach my $path_key (keys %{$filesInBackup}) {
365 $filesInBackup->{$path_key}->{'relPath'},
366 $filesInBackup->{$path_key}->{'fullPath'},
367 # $filesInBackup->{$path_key}->{'sharePathM'},
368 $filesInBackup->{$path_key}->{'mtime'},
369 $filesInBackup->{$path_key}->{'type'},
370 $filesInBackup->{$path_key}->{'size'}
373 my $key = join(" ", (
377 $filesInBackup->{$path_key}->{'mtime'},
378 $filesInBackup->{$path_key}->{'size'}
382 if (! defined($beenThere->{$key}) && ! found_in_db($key, @data)) {
383 print STDERR "# key: $key [", $beenThere->{$key},"]" if ($debug >= 2);
385 if ($filesInBackup->{$path_key}->{'type'} == BPC_FTYPE_DIR) {
387 print STDERR " dir\n" if ($debug >= 2);
390 print STDERR " file\n" if ($debug >= 2);
394 if ($filesInBackup->{$path_key}->{'type'} == BPC_FTYPE_DIR) {
397 my $full_path = $dir . '/' . $path_key;
398 push @stack, $full_path;
399 print STDERR "### store to stack: $full_path\n" if ($debug >= 3);
401 # my ($f,$nf,$d,$nd) = recurseDir($bpc, $hostname, $backups, $backupNum, $share, $path_key, $shareID) unless ($beenThere->{$key});
413 print STDERR "## STACK ",join(", ", @stack),"\n" if ($debug >= 2);
415 while ( my $dir = shift @stack ) {
416 my ($f,$nf,$d,$nd) = recurseDir($bpc, $hostname, $files, $backupNum, $share, $dir, $shareID);
417 print STDERR "# $dir f: $f nf: $nf d: $d nd: $nd\n" if ($debug >= 1);
425 return ($nr_files, $new_files, $nr_dirs, $new_dirs);