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;
26 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]
48 -c create database on first use
49 -d delete database before import
50 -m num import just num increments for one host
55 ###################################create tables############################3
58 print "creating tables...\n";
62 ID INTEGER PRIMARY KEY,
63 name VARCHAR(30) NOT NULL,
70 ID INTEGER PRIMARY KEY,
71 hostID INTEGER NOT NULL references hosts(id),
72 name VARCHAR(30) NOT NULL,
73 share VARCHAR(200) NOT NULL,
74 localpath VARCHAR(200)
79 create table backups (
80 hostID INTEGER NOT NULL references hosts(id),
84 PRIMARY KEY(hostID, num)
90 ID INTEGER PRIMARY KEY,
92 name VARCHAR(255) NOT NULL,
99 ID INTEGER NOT NULL PRIMARY KEY,
100 shareID INTEGER NOT NULL references shares(id),
101 backupNum INTEGER NOT NULL references backups(num),
102 name VARCHAR(255) NOT NULL,
103 path VARCHAR(255) NOT NULL,
104 fullpath VARCHAR(255) NOT NULL,
105 date TIMESTAMP NOT NULL,
106 type INTEGER NOT NULL,
107 size INTEGER NOT NULL,
108 dvdid INTEGER references dvds(id)
112 print "creating indexes...\n";
114 foreach my $index (qw(
126 my ($table,$col) = split(/_/, $index);
127 $dbh->do(qq{ create index $index on $table($col) });
135 foreach my $table (qw(hosts shares files dvds backups)) {
137 $dbh->do(qq{ DELETE FROM $table });
143 print "Debug level at $opt{v}\n";
147 #################################INSERT VALUES#############################
150 $hosts = $bpc->HostInfoRead();
156 $sth->{insert_hosts} = $dbh->prepare(qq{
157 INSERT INTO hosts (name, IP) VALUES (?,?)
160 $sth->{hosts_by_name} = $dbh->prepare(qq{
161 SELECT ID FROM hosts WHERE name=?
164 $sth->{backups_broj} = $dbh->prepare(qq{
167 WHERE hostID=? AND num=?
170 $sth->{insert_backups} = $dbh->prepare(qq{
171 INSERT INTO backups (hostID, num, date, type)
175 $sth->{insert_files} = $dbh->prepare(qq{
177 (shareID, backupNum, name, path, fullpath, date, type, size)
178 VALUES (?,?,?,?,?,?,?,?)
181 foreach my $host_key (keys %{$hosts}) {
183 my $hostname = $hosts->{$host_key}->{'host'} || die "can't find host for $host_key";
185 $sth->{hosts_by_name}->execute($hosts->{$host_key}->{'host'});
187 unless (($hostID) = $sth->{hosts_by_name}->fetchrow_array()) {
188 $sth->{insert_hosts}->execute(
189 $hosts->{$host_key}->{'host'},
190 $hosts->{$host_key}->{'ip'}
193 $hostID = $dbh->func('last_insert_rowid');
196 print("host ".$hosts->{$host_key}->{'host'}.": ");
198 # get backups for a host
199 my @backups = $bpc->BackupInfoRead($hostname);
200 print scalar @backups, " increments\n";
204 foreach my $backup (@backups) {
206 last if ($opt{m} && $inc_nr > $opt{m});
208 my $backupNum = $backup->{'num'};
209 my @backupShares = ();
211 print $hosts->{$host_key}->{'host'}, "\t#$backupNum\n";
213 $sth->{backups_broj}->execute($hostID, $backupNum);
214 my ($broj) = $sth->{backups_broj}->fetchrow_array();
217 my $files = BackupPC::View->new($bpc, $hostname, \@backups, 1);
218 foreach my $share ($files->shareList($backupNum)) {
222 print strftime($t_fmt,localtime())," ", $share;
223 $shareID = getShareID($share, $hostID, $hostname);
225 my ($f, $nf, $d, $nd) = recurseDir($bpc, $hostname, $files, $backupNum, $share, "", $shareID);
226 printf(" %d/%d files %d/%d dirs [%.2f/s]\n",
228 ( ($f+$d) / ((time() - $t) || 1) )
233 $sth->{insert_backups}->execute(
236 $backup->{'endTime'},
251 my ($share, $hostID, $hostname) = @_;
253 $sth->{share_id} ||= $dbh->prepare(qq{
254 SELECT ID FROM shares WHERE hostID=? AND name=?
257 $sth->{share_id}->execute($hostID,$share);
259 my ($id) = $sth->{share_id}->fetchrow_array();
261 return $id if (defined($id));
263 $sth->{insert_share} ||= $dbh->prepare(qq{
265 (hostID,name,share,localpath)
269 my $drop_down = $hostname . '/' . $share;
270 $drop_down =~ s#//+#/#g;
272 $sth->{insert_share}->execute($hostID,$share, $drop_down ,undef);
273 return $dbh->func('last_insert_rowid');
278 my ($shareID,undef,$name,$path,undef,$date,undef,$size) = @_;
280 $sth->{file_in_db} ||= $dbh->prepare(qq{
281 SELECT count(*) FROM files
282 WHERE shareID = ? and
289 my @param = ($shareID,$path,$name,$date,$size);
290 $sth->{file_in_db}->execute(@param);
291 my ($rows) = $sth->{file_in_db}->fetchrow_array();
292 # print STDERR ( $rows ? '+' : '-' ), join(" ",@param), "\n";
296 ####################################################
297 # recursing through filesystem structure and #
298 # and returning flattened files list #
299 ####################################################
300 sub recurseDir($$$$$$$$) {
302 my ($bpc, $hostname, $files, $backupNum, $share, $dir, $shareID) = @_;
304 print STDERR "recurse($hostname,$backupNum,$share,$dir,$shareID)\n" if ($debug >= 1);
306 my ($nr_files, $new_files, $nr_dirs, $new_dirs) = (0,0,0,0);
311 my $filesInBackup = $files->dirAttrib($backupNum, $share, $dir);
313 # first, add all the entries in current directory
314 foreach my $path_key (keys %{$filesInBackup}) {
319 $filesInBackup->{$path_key}->{'relPath'},
320 $filesInBackup->{$path_key}->{'fullPath'},
321 # $filesInBackup->{$path_key}->{'sharePathM'},
322 $filesInBackup->{$path_key}->{'mtime'},
323 $filesInBackup->{$path_key}->{'type'},
324 $filesInBackup->{$path_key}->{'size'}
327 my $key = join(" ", (
331 $filesInBackup->{$path_key}->{'mtime'},
332 $filesInBackup->{$path_key}->{'size'}
336 if (! $beenThere->{$key} && ! found_in_db(@data)) {
337 print STDERR "# key: $key [", $beenThere->{$key},"]" if ($debug >= 2);
338 $sth->{'insert_files'}->execute(@data);
339 if ($filesInBackup->{$path_key}->{'type'} == BPC_FTYPE_DIR) {
341 print STDERR " dir\n" if ($debug >= 2);
344 print STDERR " file\n" if ($debug >= 2);
347 $beenThere->{$key}++;
349 if ($filesInBackup->{$path_key}->{'type'} == BPC_FTYPE_DIR) {
352 my $full_path = $dir . '/' . $path_key;
353 push @stack, $full_path;
354 print STDERR "### store to stack: $full_path\n" if ($debug >= 3);
356 # my ($f,$nf,$d,$nd) = recurseDir($bpc, $hostname, $backups, $backupNum, $share, $path_key, $shareID) unless ($beenThere->{$key});
368 print STDERR "## STACK ",join(", ", @stack),"\n" if ($debug >= 2);
370 while ( my $dir = shift @stack ) {
371 my ($f,$nf,$d,$nd) = recurseDir($bpc, $hostname, $files, $backupNum, $share, $dir, $shareID);
372 print STDERR "# $dir f: $f nf: $nf d: $d nd: $nd\n" if ($debug >= 1);
380 return ($nr_files, $new_files, $nr_dirs, $new_dirs);