1 #!/usr/local/bin/perl -w
5 use lib "__INSTALLDIR__/lib";
10 use Time::HiRes qw/time/;
12 use POSIX qw/strftime/;
13 use constant BPC_FTYPE_DIR => 5;
18 my $pidfile = new File::Pid;
20 if (my $pid = $pidfile->running ) {
21 die "$0 already running: $pid\n";
22 } elsif ($pidfile->pid ne $$) {
24 $pidfile = new File::Pid;
27 print STDERR "$0 using pid ",$pidfile->pid," file ",$pidfile->file,"\n";
29 my $t_fmt = '%Y-%m-%d %H:%M:%S';
32 my $bpc = BackupPC::Lib->new || die;
33 my %Conf = $bpc->Conf();
34 my $TopDir = $bpc->TopDir();
37 my $dsn = "dbi:SQLite:dbname=$TopDir/$Conf{SearchDB}";
39 my $dbh = DBI->connect($dsn, "", "", { RaiseError => 1, AutoCommit => 0 });
43 if ( !getopts("cdm:v:", \%opt ) ) {
45 usage: $0 [-c|-d] [-m num] [-v|-v level]
48 -c create database on first use
49 -d delete database before import
50 -m num import just num increments for one host
51 -v num set verbosity (debug) level (default $debug)
56 ###################################create tables############################3
59 print "creating tables...\n";
63 ID INTEGER PRIMARY KEY,
64 name VARCHAR(30) NOT NULL,
71 ID INTEGER PRIMARY KEY,
72 hostID INTEGER NOT NULL references hosts(id),
73 name VARCHAR(30) NOT NULL,
74 share VARCHAR(200) NOT NULL,
75 localpath VARCHAR(200)
80 create table backups (
81 hostID INTEGER NOT NULL references hosts(id),
85 PRIMARY KEY(hostID, num)
91 ID INTEGER PRIMARY KEY,
93 name VARCHAR(255) NOT NULL,
100 ID INTEGER NOT NULL PRIMARY KEY,
101 shareID INTEGER NOT NULL references shares(id),
102 backupNum INTEGER NOT NULL references backups(num),
103 name VARCHAR(255) NOT NULL,
104 path VARCHAR(255) NOT NULL,
105 fullpath VARCHAR(255) NOT NULL,
106 date TIMESTAMP NOT NULL,
107 type INTEGER NOT NULL,
108 size INTEGER NOT NULL,
109 dvdid INTEGER references dvds(id)
113 print "creating indexes...\n";
115 foreach my $index (qw(
127 my ($table,$col) = split(/_/, $index);
128 $dbh->do(qq{ create index $index on $table($col) });
136 foreach my $table (qw(hosts shares files dvds backups)) {
138 $dbh->do(qq{ DELETE FROM $table });
144 print "Debug level at $opt{v}\n";
148 #################################INSERT VALUES#############################
151 $hosts = $bpc->HostInfoRead();
157 $sth->{insert_hosts} = $dbh->prepare(qq{
158 INSERT INTO hosts (name, IP) VALUES (?,?)
161 $sth->{hosts_by_name} = $dbh->prepare(qq{
162 SELECT ID FROM hosts WHERE name=?
165 $sth->{backups_broj} = $dbh->prepare(qq{
168 WHERE hostID=? AND num=?
171 $sth->{insert_backups} = $dbh->prepare(qq{
172 INSERT INTO backups (hostID, num, date, type)
176 $sth->{insert_files} = $dbh->prepare(qq{
178 (shareID, backupNum, name, path, fullpath, date, type, size)
179 VALUES (?,?,?,?,?,?,?,?)
182 foreach my $host_key (keys %{$hosts}) {
184 my $hostname = $hosts->{$host_key}->{'host'} || die "can't find host for $host_key";
186 $sth->{hosts_by_name}->execute($hosts->{$host_key}->{'host'});
188 unless (($hostID) = $sth->{hosts_by_name}->fetchrow_array()) {
189 $sth->{insert_hosts}->execute(
190 $hosts->{$host_key}->{'host'},
191 $hosts->{$host_key}->{'ip'}
194 $hostID = $dbh->func('last_insert_rowid');
197 print("host ".$hosts->{$host_key}->{'host'}.": ");
199 # get backups for a host
200 my @backups = $bpc->BackupInfoRead($hostname);
201 print scalar @backups, " increments\n";
205 foreach my $backup (@backups) {
208 last if ($opt{m} && $inc_nr > $opt{m});
210 my $backupNum = $backup->{'num'};
211 my @backupShares = ();
213 print $hosts->{$host_key}->{'host'},
214 "\t#$backupNum\t", $backup->{type} || '?', " ",
215 $backup->{nFilesNew} || '?', "/", $backup->{nFiles} || '?',
218 $sth->{backups_broj}->execute($hostID, $backupNum);
219 my ($broj) = $sth->{backups_broj}->fetchrow_array();
222 my $files = BackupPC::View->new($bpc, $hostname, \@backups, 1);
223 foreach my $share ($files->shareList($backupNum)) {
227 print strftime($t_fmt,localtime())," ", $share;
228 $shareID = getShareID($share, $hostID, $hostname);
230 my ($f, $nf, $d, $nd) = recurseDir($bpc, $hostname, $files, $backupNum, $share, "", $shareID);
231 printf(" %d/%d files %d/%d dirs [%.2f/s]\n",
233 ( ($f+$d) / ((time() - $t) || 1) )
238 $sth->{insert_backups}->execute(
241 $backup->{'endTime'},
256 my ($share, $hostID, $hostname) = @_;
258 $sth->{share_id} ||= $dbh->prepare(qq{
259 SELECT ID FROM shares WHERE hostID=? AND name=?
262 $sth->{share_id}->execute($hostID,$share);
264 my ($id) = $sth->{share_id}->fetchrow_array();
266 return $id if (defined($id));
268 $sth->{insert_share} ||= $dbh->prepare(qq{
270 (hostID,name,share,localpath)
274 my $drop_down = $hostname . '/' . $share;
275 $drop_down =~ s#//+#/#g;
277 $sth->{insert_share}->execute($hostID,$share, $drop_down ,undef);
278 return $dbh->func('last_insert_rowid');
283 my ($shareID,undef,$name,$path,undef,$date,undef,$size) = @_;
285 $sth->{file_in_db} ||= $dbh->prepare(qq{
286 SELECT count(*) FROM files
287 WHERE shareID = ? and
294 my @param = ($shareID,$path,$name,$date,$size);
295 $sth->{file_in_db}->execute(@param);
296 my ($rows) = $sth->{file_in_db}->fetchrow_array();
297 # print STDERR ( $rows ? '+' : '-' ), join(" ",@param), "\n";
301 ####################################################
302 # recursing through filesystem structure and #
303 # and returning flattened files list #
304 ####################################################
305 sub recurseDir($$$$$$$$) {
307 my ($bpc, $hostname, $files, $backupNum, $share, $dir, $shareID) = @_;
309 print STDERR "\nrecurse($hostname,$backupNum,$share,$dir,$shareID)\n" if ($debug >= 1);
311 my ($nr_files, $new_files, $nr_dirs, $new_dirs) = (0,0,0,0);
316 my $filesInBackup = $files->dirAttrib($backupNum, $share, $dir);
318 # first, add all the entries in current directory
319 foreach my $path_key (keys %{$filesInBackup}) {
324 $filesInBackup->{$path_key}->{'relPath'},
325 $filesInBackup->{$path_key}->{'fullPath'},
326 # $filesInBackup->{$path_key}->{'sharePathM'},
327 $filesInBackup->{$path_key}->{'mtime'},
328 $filesInBackup->{$path_key}->{'type'},
329 $filesInBackup->{$path_key}->{'size'}
332 my $key = join(" ", (
336 $filesInBackup->{$path_key}->{'mtime'},
337 $filesInBackup->{$path_key}->{'size'}
341 if (! $beenThere->{$key} && ! found_in_db(@data)) {
342 print STDERR "# key: $key [", $beenThere->{$key},"]" if ($debug >= 2);
343 $sth->{'insert_files'}->execute(@data);
344 if ($filesInBackup->{$path_key}->{'type'} == BPC_FTYPE_DIR) {
346 print STDERR " dir\n" if ($debug >= 2);
349 print STDERR " file\n" if ($debug >= 2);
352 $beenThere->{$key}++;
354 if ($filesInBackup->{$path_key}->{'type'} == BPC_FTYPE_DIR) {
357 my $full_path = $dir . '/' . $path_key;
358 push @stack, $full_path;
359 print STDERR "### store to stack: $full_path\n" if ($debug >= 3);
361 # my ($f,$nf,$d,$nd) = recurseDir($bpc, $hostname, $backups, $backupNum, $share, $path_key, $shareID) unless ($beenThere->{$key});
373 print STDERR "## STACK ",join(", ", @stack),"\n" if ($debug >= 2);
375 while ( my $dir = shift @stack ) {
376 my ($f,$nf,$d,$nd) = recurseDir($bpc, $hostname, $files, $backupNum, $share, $dir, $shareID);
377 print STDERR "# $dir f: $f nf: $nf d: $d nd: $nd\n" if ($debug >= 1);
385 return ($nr_files, $new_files, $nr_dirs, $new_dirs);