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 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 });
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 (?,?,?,?,?,?,?,?)
202 my $t = shift || return;
204 my ($ss,$mm,$hh) = gmtime($t);
205 $out .= "${hh}h" if ($hh);
206 $out .= sprintf("%02d:%02d", $mm,$ss);
210 foreach my $host_key (keys %{$hosts}) {
212 my $hostname = $hosts->{$host_key}->{'host'} || die "can't find host for $host_key";
214 $sth->{hosts_by_name}->execute($hosts->{$host_key}->{'host'});
216 unless (($hostID) = $sth->{hosts_by_name}->fetchrow_array()) {
217 $sth->{insert_hosts}->execute(
218 $hosts->{$host_key}->{'host'},
219 $hosts->{$host_key}->{'ip'}
222 $hostID = $dbh->last_insert_id(undef,undef,'hosts',undef);
225 print("host ".$hosts->{$host_key}->{'host'}.": ");
227 # get backups for a host
228 my @backups = $bpc->BackupInfoRead($hostname);
229 print scalar @backups, " increments\n";
233 foreach my $backup (@backups) {
236 last if ($opt{m} && $inc_nr > $opt{m});
238 my $backupNum = $backup->{'num'};
239 my @backupShares = ();
241 print $hosts->{$host_key}->{'host'},
242 "\t#$backupNum\t", $backup->{type} || '?', " ",
243 $backup->{nFilesNew} || '?', "/", $backup->{nFiles} || '?',
246 $sth->{backups_broj}->execute($hostID, $backupNum);
247 my ($broj) = $sth->{backups_broj}->fetchrow_array();
250 $sth->{insert_backups}->execute(
253 $backup->{'endTime'},
258 my $files = BackupPC::View->new($bpc, $hostname, \@backups, 1);
259 foreach my $share ($files->shareList($backupNum)) {
263 print strftime($t_fmt,localtime())," ", $share;
264 $shareID = getShareID($share, $hostID, $hostname);
266 my ($f, $nf, $d, $nd) = recurseDir($bpc, $hostname, $files, $backupNum, $share, "", $shareID);
267 my $dur = (time() - $t) || 1;
268 printf(" %d/%d files %d/%d dirs [%.2f/s dur: %s]\n",
282 print "total duration: ",fmt_time(time() - $start_t),"\n";
288 my ($share, $hostID, $hostname) = @_;
290 $sth->{share_id} ||= $dbh->prepare(qq{
291 SELECT ID FROM shares WHERE hostID=? AND name=?
294 $sth->{share_id}->execute($hostID,$share);
296 my ($id) = $sth->{share_id}->fetchrow_array();
298 return $id if (defined($id));
300 $sth->{insert_share} ||= $dbh->prepare(qq{
302 (hostID,name,share,localpath)
306 my $drop_down = $hostname . '/' . $share;
307 $drop_down =~ s#//+#/#g;
309 $sth->{insert_share}->execute($hostID,$share, $drop_down ,undef);
310 return $dbh->last_insert_id(undef,undef,'shares',undef);
318 my ($key, $shareID,undef,$name,$path,undef,$date,undef,$size) = @_;
320 return $beenThere->{$key} if (defined($beenThere->{$key}));
322 $sth->{file_in_db} ||= $dbh->prepare(qq{
324 WHERE shareID = ? and
331 my @param = ($shareID,$path,$name,$date,$size);
332 $sth->{file_in_db}->execute(@param);
333 my $rows = $sth->{file_in_db}->rows;
334 print STDERR "## found_in_db ",( $rows ? '+' : '-' ), join(" ",@param), "\n" if ($debug >= 3);
336 $beenThere->{$key}++;
338 $sth->{'insert_files'}->execute(@data) unless ($rows);
342 ####################################################
343 # recursing through filesystem structure and #
344 # and returning flattened files list #
345 ####################################################
346 sub recurseDir($$$$$$$$) {
348 my ($bpc, $hostname, $files, $backupNum, $share, $dir, $shareID) = @_;
350 print STDERR "\nrecurse($hostname,$backupNum,$share,$dir,$shareID)\n" if ($debug >= 1);
352 my ($nr_files, $new_files, $nr_dirs, $new_dirs) = (0,0,0,0);
357 print STDERR "# dirAttrib($backupNum, $share, $dir)\n" if ($debug >= 2);
358 my $filesInBackup = $files->dirAttrib($backupNum, $share, $dir);
360 # first, add all the entries in current directory
361 foreach my $path_key (keys %{$filesInBackup}) {
366 $filesInBackup->{$path_key}->{'relPath'},
367 $filesInBackup->{$path_key}->{'fullPath'},
368 # $filesInBackup->{$path_key}->{'sharePathM'},
369 $filesInBackup->{$path_key}->{'mtime'},
370 $filesInBackup->{$path_key}->{'type'},
371 $filesInBackup->{$path_key}->{'size'}
374 my $key = join(" ", (
378 $filesInBackup->{$path_key}->{'mtime'},
379 $filesInBackup->{$path_key}->{'size'}
383 if (! defined($beenThere->{$key}) && ! found_in_db($key, @data)) {
384 print STDERR "# key: $key [", $beenThere->{$key},"]" if ($debug >= 2);
386 if ($filesInBackup->{$path_key}->{'type'} == BPC_FTYPE_DIR) {
388 print STDERR " dir\n" if ($debug >= 2);
391 print STDERR " file\n" if ($debug >= 2);
395 if ($filesInBackup->{$path_key}->{'type'} == BPC_FTYPE_DIR) {
398 my $full_path = $dir . '/' . $path_key;
399 push @stack, $full_path;
400 print STDERR "### store to stack: $full_path\n" if ($debug >= 3);
402 # my ($f,$nf,$d,$nd) = recurseDir($bpc, $hostname, $backups, $backupNum, $share, $path_key, $shareID) unless ($beenThere->{$key});
414 print STDERR "## STACK ",join(", ", @stack),"\n" if ($debug >= 2);
416 while ( my $dir = shift @stack ) {
417 my ($f,$nf,$d,$nd) = recurseDir($bpc, $hostname, $files, $backupNum, $share, $dir, $shareID);
418 print STDERR "# $dir f: $f nf: $nf d: $d nd: $nd\n" if ($debug >= 1);
426 return ($nr_files, $new_files, $nr_dirs, $new_dirs);