/[psinib]/psinib.pl
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /psinib.pl

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.19 - (show annotations)
Mon Oct 27 19:07:32 2003 UTC (20 years, 6 months ago) by dpavlin
Branch: MAIN
Changes since 1.18: +6 -2 lines
File MIME type: text/plain
remove non-valid latest links

1 #!/usr/bin/perl -w
2 #
3 # psinib - Perl Snapshot Is Not Incremental Backup
4 #
5 # written by Dobrica Pavlinusic <dpavlin@rot13.org> 2003-01-03
6 # released under GPL v2 or later.
7 #
8 # Backup SMB directories using file produced by LinNeighbourhood (or some
9 # other program [vi :-)] which produces file in format:
10 #
11 # smbmount service mountpoint options
12 #
13 #
14 # usage:
15 # $ psinib.pl mountscript
16
17 use strict 'vars';
18 use Data::Dumper;
19 use Net::Ping;
20 use POSIX qw(strftime);
21 use List::Compare;
22 use Filesys::SmbClient;
23 #use Taint;
24 use Fcntl qw(LOCK_EX LOCK_NB);
25 use Digest::MD5;
26 use File::Basename;
27 use Getopt::Long;
28
29 # configuration
30 my $LOG_TIME_FMT = '%Y-%m-%d %H:%M:%S'; # strftime format for logfile
31 my $DIR_TIME_FMT = '%Y%m%d'; # strftime format for backup dir
32
33 # define timeout for ping
34 my $PING_TIMEOUT = 5;
35
36 my $LOG = '/var/log/backup.log'; # add path here...
37 #$LOG = '/tmp/backup.log';
38
39 # store backups in which directory
40 my $BACKUP_DEST = '/backup/isis_backup';
41 #my $BACKUP_DEST = '/tmp/backup/';
42
43 # files to ignore in backup
44 my @ignore = ('.md5sum', '.backupignore', 'backupignore.txt');
45
46 # open log
47 open(L, ">> $LOG") || die "can't open log $LOG: $!";
48 select((select(L), $|=1)[0]); # flush output
49
50 # make a lock on logfile
51
52 my $c = 0;
53 {
54 flock L, LOCK_EX | LOCK_NB and last;
55 sleep 1;
56 redo if ++$c < 10;
57 # no response for 10 sec, bail out
58 xlog("ABORT","can't take lock on $LOG -- another $0 running?");
59 exit 1;
60 }
61
62 # taint path: nmblookup should be there!
63 $ENV{'PATH'} = "/usr/bin:/bin";
64
65 my $use_ping = 1; # default: use syn tcp ping to verify that host is up
66 my $verbose = 1; # default verbosity level
67 my $quiet = 0;
68
69 my $result = GetOptions(
70 "ping!" => \$use_ping, "backupdest!" => \$BACKUP_DEST,
71 "verbose+" => \$verbose, "quiet+" => \$quiet,
72 );
73
74 $verbose -= $quiet;
75
76 my $mounts = shift @ARGV ||
77 'mountscript';
78 # die "usage: $0 mountscript";
79
80
81 my @in_backup; # shares which are backeduped this run
82
83 # init Net::Ping object
84 my $ping;
85 if ($use_ping) {
86 $ping = new Net::Ping->new("syn", 2);
87 # ping will try tcp connect to netbios-ssn (139)
88 $ping->{port_num} = getservbyname("netbios-ssn", "tcp");
89 }
90
91 # do syn ping to cifs port
92 sub host_up {
93 my $ping = shift || return;
94 my $host_ip = shift || xlog("host_up didn't get IP");
95 my $timeout = shift;
96 return 1 if (! $use_ping);
97
98 $ping->ping($host_ip,$timeout);
99 my $return = 0;
100
101 while (my ($host,$rtt,$ip) = $ping->ack) {
102 xlog("","HOST: $host [$ip] ACKed in $rtt seconds");
103 $return = 1 if ($ip eq $host_ip);
104 }
105 return $return;
106 }
107
108 my $backup_ok = 0;
109
110 my $smb;
111 my %smb_atime;
112 my %smb_mtime;
113 my %file_md5;
114
115 open(M, $mounts) || die "can't open $mounts: $!";
116 while(<M>) {
117 chomp;
118 next if !/^\s*smbmount\s/;
119 my (undef,$share,undef,$opt) = split(/\s+/,$_,4);
120
121 my ($user,$passwd,$workgroup,$ip);
122
123 foreach (split(/,/,$opt)) {
124 my ($n,$v) = split(/=/,$_,2);
125 if ($n =~ m/username/i) {
126 if ($v =~ m#^(.+)/(.+)%(.+)$#) {
127 ($user,$passwd,$workgroup) = ($1,$2,$3);
128 } elsif ($v =~ m#^(.+)/(.+)$#) {
129 ($user,$workgroup) = ($1,$2);
130 } elsif ($v =~ m#^(.+)%(.+)$#) {
131 ($user,$passwd) = ($1,$2);
132 } else {
133 $user = $v;
134 }
135 } elsif ($n =~ m#workgroup#i) {
136 $workgroup = $v;
137 } elsif ($n =~ m#ip#i) {
138 $ip = $v;
139 }
140 }
141
142 push @in_backup,$share;
143
144
145 my ($host,$dir,$date_dir) = share2host_dir($share);
146 my $bl = "$BACKUP_DEST/$host/$dir/latest"; # latest backup
147 my $bc = "$BACKUP_DEST/$host/$dir/$date_dir"; # current one
148 my $real_bl;
149 if (-l $bl) {
150 $real_bl=readlink($bl) || die "can't read link $bl: $!";
151 $real_bl="$BACKUP_DEST/$host/$dir/$real_bl" if (substr($real_bl,0,1) ne "/");
152 if (-l $bc && $real_bl eq $bc) {
153 xlog($share,"allready backuped...");
154 $backup_ok++;
155 next;
156 }
157
158 }
159
160
161 xlog($share,"working on $share...");
162
163 # try to nmblookup IP
164 $ip = get_ip($share) if (! $ip);
165
166 if ($ip) {
167 xlog($share,"IP is $ip");
168 if (host_up($ping, $ip,$PING_TIMEOUT)) {
169 if (snap_share($share,$user,$passwd,$workgroup)) {
170 $backup_ok++;
171 }
172 }
173 }
174 }
175 close(M);
176
177 xlog("","$backup_ok backups completed of total ".($#in_backup+1)." this time (".int($backup_ok*100/($#in_backup+1))." %)");
178
179 1;
180
181 #-------------------------------------------------------------------------
182
183
184 # get IP number from share
185 sub get_ip {
186 my $share = shift;
187
188 my $host = $1 if ($share =~ m#//([^/]+)/#);
189
190 my $ip = `nmblookup $host`;
191 if ($ip =~ m/(\d+\.\d+\.\d+\.\d+)\s$host/i) {
192 return $1;
193 }
194 }
195
196
197 # write entry to screen and log
198 sub xlog {
199 my $share = shift;
200 my $t = strftime $LOG_TIME_FMT, localtime;
201 my $m = shift || '[no log entry]';
202 my $l = shift;
203 $l = 1 if (! defined $l); # default verbosity is 1
204 print STDERR $m,"\n" if ($verbose >= $l);
205 print L "$t $share\t$m\n";
206 }
207
208 # dump warn and dies into log
209 BEGIN { $SIG{'__WARN__'} = sub { xlog('WARN',$_[0],1) ; warn $_[0] } }
210 BEGIN { $SIG{'__DIE__'} = sub { xlog('DIE',$_[0],0) ; die $_[0] } }
211
212
213 # split share name to host, dir and currnet date dir
214 sub share2host_dir {
215 my $share = shift;
216 my ($host,$dir);
217 if ($share =~ m#//([^/]+)/(.+)$#) {
218 ($host,$dir) = ($1,$2);
219 $dir =~ s/\W/_/g;
220 $dir =~ s/^_+//;
221 $dir =~ s/_+$//;
222 } else {
223 xlog($share,"Can't parse share $share into host and directory!",1);
224 return;
225 }
226 return ($host,$dir,strftime $DIR_TIME_FMT, localtime);
227 }
228
229
230 # make a snapshot of a share
231 sub snap_share {
232
233 my $share = shift;
234
235 my %param = ( debug => 0 );
236
237 $param{username} = shift || warn "can't find username for share $share";
238 $param{password} = shift || warn "can't find passwod for share $share";
239 $param{workgroup} = shift || warn "can't find workgroup for share $share";
240
241 my ($host,$dir,$date_dir) = share2host_dir($share);
242
243 # latest backup directory
244 my $bl = "$BACKUP_DEST/$host/$dir/latest";
245 # current backup directory
246 my $bc = "$BACKUP_DEST/$host/$dir/$date_dir";
247
248 my $real_bl;
249 if (-l $bl) {
250 $real_bl=readlink($bl) || die "can't read link $bl: $!";
251 $real_bl="$BACKUP_DEST/$host/$dir/$real_bl" if (substr($real_bl,0,1) ne "/");
252 if (! -e $real_bl) {
253 xlog($share,"latest link $bl -> $real_bl not valid, removing it");
254 unlink $bl || die "can't remove link $bl: $!";
255 undef $real_bl;
256 }
257 }
258 if (! $real_bl) {
259 xlog($share,"no old backup, trying to find last backup");
260 if (opendir(BL_DIR, "$BACKUP_DEST/$host/$dir")) {
261 my @bl_dirs = sort grep { !/^\./ && -d "$BACKUP_DEST/$host/$dir/$_" } readdir(BL_DIR);
262 closedir(BL_DIR);
263 $real_bl=pop @bl_dirs;
264 xlog($share,"using $real_bl as latest...");
265 $real_bl="$BACKUP_DEST/$host/$dir/$real_bl" if (substr($real_bl,0,1) ne "/");
266 if ($real_bl eq $bc) {
267 xlog($share,"latest from today (possible partial backup)");
268 rename $real_bl,$real_bl.".partial" || warn "can't reaname partial backup: $!";
269 $real_bl .= ".partial";
270 }
271 } else {
272 xlog($share,"this is first run...");
273 }
274 }
275
276 if (-l $bc && $real_bl && $real_bl eq $bc) {
277 xlog($share,"allready backuped...");
278 return 1;
279 }
280
281 die "You should really create BACKUP_DEST [$BACKUP_DEST] by hand! " if (!-e $BACKUP_DEST);
282
283 if (! -e "$BACKUP_DEST/$host") {
284 mkdir "$BACKUP_DEST/$host" || die "can't make dir for host $host, $BACKUP_DEST/$host: $!";
285 xlog($share,"created host directory $BACKUP_DEST/$host...");
286 }
287
288 if (! -e "$BACKUP_DEST/$host/$dir") {
289 mkdir "$BACKUP_DEST/$host/$dir" || die "can't make dir for share $share, $BACKUP_DEST/$host/$dir $!";
290 xlog($share,"created dir for this share $BACKUP_DEST/$host/$dir...");
291 }
292
293 mkdir $bc || die "can't make dir for current backup $bc: $!";
294
295 my @dirs = ( "/" );
296 my @smb_dirs = ( "/" );
297
298 my $transfer = 0; # bytes transfered over network
299
300 # this will store all available files and sizes
301 my @files;
302 my %file_size;
303 my %file_atime;
304 my %file_mtime;
305 #my %file_md5;
306 %file_md5 = ();
307
308 my @smb_files;
309 my %smb_size;
310 #my %smb_atime;
311 #my %smb_mtime;
312
313 sub norm_dir {
314 my $foo = shift;
315 my $prefix = shift;
316 $foo =~ s#//+#/#g;
317 $foo =~ s#/+$##g;
318 $foo =~ s#^/+##g;
319 return $prefix.$foo if ($prefix);
320 return $foo;
321 }
322
323 # read local filesystem
324 my $di = 0;
325 while ($di <= $#dirs && $real_bl) {
326 my $d=$dirs[$di++];
327 opendir(DIR,"$real_bl/$d") || warn "opendir($real_bl/$d): $!\n";
328
329 # read .backupignore if exists
330 if (-f "$real_bl/$d/.backupignore") {
331 open(I,"$real_bl/$d/.backupignore");
332 while(<I>) {
333 chomp;
334 push @ignore,norm_dir("$d/$_");
335 }
336 close(I);
337 #print STDERR "ignore: ",join("|",@ignore),"\n";
338 link "$real_bl/$d/.backupignore","$bc/$d/.backupignore" ||
339 warn "can't copy $real_bl/$d/.backupignore to current backup dir: $!\n";
340 }
341
342 # read .md5sum if exists
343 if (-f "$real_bl/$d/.md5sum") {
344 open(I,"$real_bl/$d/.md5sum");
345 while(<I>) {
346 chomp;
347 my ($md5,$f) = split(/\s+/,$_,2);
348 $file_md5{$f}=$md5;
349 }
350 close(I);
351 }
352
353 my @clutter = readdir(DIR);
354 foreach my $f (@clutter) {
355 next if ($f eq '.');
356 next if ($f eq '..');
357 my $pr = norm_dir("$d/$f"); # path relative
358 my $pf = norm_dir("$d/$f","$real_bl/"); # path full
359 if (grep(/^\Q$pr\E$/,@ignore) == 0) {
360 if (-f $pf) {
361 push @files,$pr;
362 $file_size{$pr}=(stat($pf))[7];
363 $file_atime{$pr}=(stat($pf))[8];
364 $file_mtime{$pr}=(stat($pf))[9];
365 } elsif (-d $pf) {
366 push @dirs,$pr;
367 } else {
368 xlog($share,"not file or directory: $pf",0);
369 }
370 } else {
371 xlog($share,"ignored: $pr");
372 }
373 }
374 }
375
376 # local dir always include /
377 xlog($share,($#files+1)." files and ".($#dirs)." dirs on local disk before backup");
378
379 # read smb filesystem
380
381 xlog($share,"smb to $share as $param{username}/$param{workgroup}");
382
383 # FIX: how to aviod creation of ~/.smb/smb.conf ?
384 $smb = new Filesys::SmbClient(%param) || die "SmbClient :$!\n";
385
386 $di = 0;
387 while ($di <= $#smb_dirs) {
388 my $d=$smb_dirs[$di];
389 my $pf = norm_dir($d,"smb:$share/"); # path full
390 my $D = $smb->opendir($pf);
391 if (! $D) {
392 xlog($share,"FATAL: $share [$pf] as $param{username}/$param{workgroup}: $!",0);
393 # remove failing dir
394 delete $smb_dirs[$di];
395 return 0; # failed
396 }
397 $di++;
398
399 my @clutter = $smb->readdir_struct($D);
400 foreach my $item (@clutter) {
401 my $f = $item->[1];
402 next if ($f eq '.');
403 next if ($f eq '..');
404 my $pr = norm_dir("$d/$f"); # path relative
405 my $pf = norm_dir("$d/$f","smb:$share/"); # path full
406 if (grep(/^\Q$pr\E$/,@ignore) == 0) {
407 if ($item->[0] == main::SMBC_FILE) {
408 push @smb_files,$pr;
409 $smb_size{$pr}=($smb->stat($pf))[7];
410 $smb_atime{$pr}=($smb->stat($pf))[10];
411 $smb_mtime{$pr}=($smb->stat($pf))[11];
412 } elsif ($item->[0] == main::SMBC_DIR) {
413 push @smb_dirs,$pr;
414 } else {
415 xlog($share,"not file or directory [".$item->[0]."]: $pf",0);
416 }
417 } else {
418 xlog($share,"smb ignored: $pr");
419 }
420 }
421 }
422
423 xlog($share,($#smb_files+1)." files and ".($#smb_dirs)." dirs on remote share");
424
425 # sync dirs
426 my $lc = List::Compare->new(\@dirs, \@smb_dirs);
427
428 my @dirs2erase = $lc->get_Lonly;
429 my @dirs2create = $lc->get_Ronly;
430 xlog($share,($#dirs2erase+1)." dirs to erase and ".($#dirs2create+1)." dirs to create");
431
432 # create new dirs
433 foreach (sort @smb_dirs) {
434 mkdir "$bc/$_" || warn "mkdir $_: $!\n";
435 }
436
437 # sync files
438 $lc = List::Compare->new(\@files, \@smb_files);
439
440 my @files2erase = $lc->get_Lonly;
441 my @files2create = $lc->get_Ronly;
442 xlog($share,($#files2erase+1)." files to erase and ".($#files2create+1)." files to create");
443
444 sub smb_copy {
445 my $smb = shift;
446
447 my $from = shift;
448 my $to = shift;
449
450
451 my $l = 0;
452
453 foreach my $f (@_) {
454 #print "smb_copy $from/$f -> $to/$f\n";
455 my $md5 = Digest::MD5->new;
456
457 my $fd = $smb->open("$from/$f");
458 if (! $fd) {
459 xlog("WARNING","can't open smb file $from/$f: $!");
460 next;
461 }
462
463 if (! open(F,"> $to/$f")) {
464 xlog("WARNING","can't open new file $to/$f: $!");
465 next;
466 }
467
468 while (defined(my $b=$smb->read($fd,4096))) {
469 print F $b;
470 $l += length($b);
471 $md5->add($b);
472 }
473
474 $smb->close($fd);
475 close(F);
476
477 $file_md5{$f} = $md5->hexdigest;
478
479 # FIX: this fails with -T
480 my ($a,$m) = ($smb->stat("$from/$f"))[10,11];
481 utime $a, $m, "$to/$f" ||
482 warn "can't update utime on $to/$f: $!\n";
483
484 }
485 return $l;
486 }
487
488 # copy new files
489 foreach (@files2create) {
490 $transfer += smb_copy($smb,"smb:$share",$bc,$_);
491 }
492
493 my $size_sync = 0;
494 my $atime_sync = 0;
495 my $mtime_sync = 0;
496 my @sync_files;
497 my @ln_files;
498
499 foreach ($lc->get_intersection) {
500
501 my $f;
502
503 if ($file_size{$_} != $smb_size{$_}) {
504 $f=$_;
505 $size_sync++;
506 }
507 if ($file_atime{$_} != $smb_atime{$_}) {
508 $f=$_;
509 $atime_sync++;
510 }
511 if ($file_mtime{$_} != $smb_mtime{$_}) {
512 $f=$_;
513 $mtime_sync++;
514 }
515
516 if ($f) {
517 push @sync_files, $f;
518 } else {
519 push @ln_files, $_;
520 }
521 }
522
523 xlog($share,($#sync_files+1)." files will be updated (diff: $size_sync size, $atime_sync atime, $mtime_sync mtime), ".($#ln_files+1)." will be linked.");
524
525 foreach (@sync_files) {
526 $transfer += smb_copy($smb,"smb:$share",$bc,$_);
527 }
528
529 xlog($share,"$transfer bytes transfered...");
530
531 foreach (@ln_files) {
532 link "$real_bl/$_","$bc/$_" || warn "link $real_bl/$_ -> $bc/$_: $!\n";
533 }
534
535 # remove files
536 foreach (sort @files2erase) {
537 unlink "$bc/$_" || warn "unlink $_: $!\n";
538 delete $file_md5{$_};
539 }
540
541 # remove not needed dirs (after files)
542 foreach (sort @dirs2erase) {
543 rmdir "$bc/$_" || warn "rmdir $_: $!\n";
544 }
545
546 # remove old .md5sum
547 foreach (sort @dirs) {
548 unlink "$bc/$_/.md5sum" if (-e "$bc/$_/.md5sum");
549 }
550
551 # erase stale entries in .md5sum
552 my @md5_files = keys %file_md5;
553 $lc = List::Compare->new(\@md5_files, \@smb_files);
554 foreach my $file ($lc->get_Lonly) {
555 xlog("NOTICE","removing stale '$file' from .md5sum");
556 delete $file_md5{$file};
557 }
558
559 # create .md5sum
560 my $last_dir = '';
561 my $md5;
562 foreach my $f (sort { $file_md5{$a} cmp $file_md5{$b} } keys %file_md5) {
563 my $dir = dirname($f);
564 my $file = basename($f);
565 #print "$f -- $dir / $file<--\n";
566 if ($dir ne $last_dir) {
567 close($md5) if ($md5);
568 open($md5, ">> $bc/$dir/.md5sum") || warn "can't create $bc/$dir/.md5sum: $!";
569 $last_dir = $dir;
570 #print STDERR "writing $last_dir/.md5sum\n";
571 }
572 print $md5 $file_md5{$f}," $file\n";
573 }
574 close($md5) if ($md5);
575
576 # create leatest link
577 #print "ln -s $bc $real_bl\n";
578 if (-l $bl) {
579 unlink $bl || warn "can't remove old latest symlink $bl: $!\n";
580 }
581 symlink $bc,$bl || warn "can't create latest symlink $bl -> $bc: $!\n";
582
583 # FIX: sanity check -- remove for speedup
584 xlog($share,"failed to create latest symlink $bl -> $bc...") if (readlink($bl) ne $bc || ! -l $bl);
585
586 xlog($share,"backup completed...");
587
588 return 1;
589 }
590 __END__
591 #-------------------------------------------------------------------------
592
593
594 =head1 NAME
595
596 psinib - Perl Snapshot Is Not Incremental Backup
597
598 =head1 SYNOPSIS
599
600 ./psinib.pl [OPTION]... [mount script]
601
602 =head1 DESCRIPTION
603
604 Option can be one of more of following:
605
606 =over 8
607
608 =item C<--backupdest=dir>
609
610 Specify backup destination directory (defaults is /data/
611
612 =item C<--noping>
613
614 Don't use ping to check if host is up (default is ti use tcp syn to cifs
615 port)
616
617 =item C<--verbose -v>
618
619 Increase verbosity level. Defailt is 1 which prints moderate amount of data
620 on STDOUT and STDERR.
621
622 =item C<--quiet -q>
623
624 Decrease verbosity level
625
626 =back
627
628 This script in current version support just backup of Samba (or Micro$oft
629 Winblowz) shares to central disk space. Central disk space is organized in
630 multiple directories named after:
631
632 =over 4
633
634 =item *
635 server which is sharing files to be backed up
636
637 =item *
638 name of share on server
639
640 =item *
641 dated directory named like standard ISO date format (YYYYMMDD).
642
643 =back
644
645 In each dated directory you will find I<snapshot> of all files on
646 exported share on that particular date.
647
648 You can also use symlink I<latest> which will lead you to
649 last completed backup. After that you can use some other backup
650 software to transfer I<snapshot> to tape, CD-ROM or some other media.
651
652 =head2 Design considerations
653
654 Since taking of share snapshot every day requires a lot of disk space and
655 network bandwidth, B<psinib> uses several techniques to keep disk usage and
656 network traffic at acceptable level:
657
658 =over 3
659
660 =item - usage of hard-links to provide same files in each snapshot (as opposed
661 to have multiple copies of same file)
662
663 =item - usage of file size, atime and mtime to find changes of files without
664 transferring whole file over network (just share browsing is transfered
665 over network)
666
667 =item - usage of C<.md5sum> files (compatible with command-line utility
668 C<md5sum>) to keep file between snapshots hard-linked
669
670 =back
671
672 =head1 CONFIGURATION
673
674 This section is not yet written.
675
676 =head1 HACKS, TRICKS, BUGS and LIMITATIONS
677
678 This chapter will have all content that doesn't fit anywhere else.
679
680 =head2 Can snapshots be more frequent than daily?
681
682 There is not real reason why you can't take snapshot more often than
683 once a day. Actually, if you are using B<psinib> to backup Windows
684 workstations you already know that they tend to come-and-go during the day
685 (reboots probably ;-), so running B<psinib> several times a day increases
686 your chance of having up-to-date backup (B<psinib> will not make multiple
687 snapshots for same day, nor will it update snapshot for current day if
688 it already exists).
689
690 However, changing B<psinib> to produce snapshots which are, for example, hourly
691 is a simple change of C<$DIR_TIME_FMT> which is currently set to
692 C<'%Y%m%d'> (see I<strftime> documentation for explanation of that
693 format). If you change that to C<'%Y%m%d-%H> you can have hourly snapshots
694 (if your network is fast enough, that is...). Also, some of messages in
695 program will sound strange, but other than that it should work.
696 I<You have been warned>.
697
698 =head2 Do I really need to share every directory which I want to snapshot?
699
700 Actually, no. Due to usage of C<Filesys::SmbClient> module, you can also
701 specify sub-directory inside your share that you want to backup. This feature
702 is most useful if you want to use administrative shares (but, have in mind
703 that you have to enter your Win administrator password in unencrypted file on
704 disk to do that) like this:
705
706 smbmount //server/c$/WinNT/fonts /mnt -o username=administrator%win
707
708 After that you will get directories with snapshots like:
709
710 server/c_WinNT_fonts/yyyymmdd/....
711
712 =head2 Won't I run out of disk space?
713
714 Of course you will... Snapshots and logfiles will eventually fill-up your disk.
715 However, you can do two things to stop that:
716
717 =head3 Clean snapshort older than x days
718
719 You can add following command to your C<root> crontab:
720
721 find /backup/isis_backup -type d -mindepth 3 -maxdepth 3 -mtime +11 -exec rm -Rf {} \;
722
723 I assume that C</backup/isis_backup> is directory in which are your snapshots
724 and that you don't want to keep snapshots older than 11 days (that's
725 C<-mtime +11> part of command).
726
727 =head3 Rotate your logs
728
729 I will leave that to you. I relay on GNU/Debian's C<logrotate> to do it for me.
730
731 =head2 What are I<YYYYMMDD.partial> directories?
732
733 If there isn't I<latest> symlink in snapshot directory, it's preatty safe to
734 assume that previous backup from that day failed. So, that directory will
735 be renamed to I<YYYYMMDD.partial> and snapshot will be performed again,
736 linking same files (other alternative would be to erase that dir and find
737 second-oldest directory, but this seemed like more correct approach).
738
739 =head2 I can't connect to any share
740
741 Please verify that nmblookup (which is part of samba package) is in /bin or
742 /usr/bin. Also verify that nmblookup returns IP address for your server
743 using:
744
745 $ nmblookup tvhouse
746 querying tvhouse on 192.168.34.255
747 192.168.34.30 tvhouse<00>
748
749 If you don't get any output, your samba might not listen to correct interface
750 (see interfaces in smb.conf).
751
752 =head1 AUTHOR
753
754 Dobrica Pavlinusic <dpavlin@rot13.org>
755
756 L<http:E<sol>E<sol>www.rot13.orgE<sol>~dpavlinE<sol>>
757
758 =head1 LICENSE
759
760 This product is licensed under GNU Public License (GPL) v2 or later.
761
762 =cut

  ViewVC Help
Powered by ViewVC 1.1.26