/[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.17 - (show annotations)
Sun Oct 26 14:04:17 2003 UTC (20 years, 6 months ago) by dpavlin
Branch: MAIN
Changes since 1.16: +47 -17 lines
File MIME type: text/plain
verbose, quiet options and added documentation for command line options

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 || 1;
203 print STDERR $m,"\n" if ($verbose >= $l);
204 print L "$t $share\t$m\n";
205 }
206
207 # dump warn and dies into log
208 BEGIN { $SIG{'__WARN__'} = sub { xlog('WARN',$_[0]) ; warn $_[0] } }
209 BEGIN { $SIG{'__DIE__'} = sub { xlog('DIE',$_[0]) ; die $_[0] } }
210
211
212 # split share name to host, dir and currnet date dir
213 sub share2host_dir {
214 my $share = shift;
215 my ($host,$dir);
216 if ($share =~ m#//([^/]+)/(.+)$#) {
217 ($host,$dir) = ($1,$2);
218 $dir =~ s/\W/_/g;
219 $dir =~ s/^_+//;
220 $dir =~ s/_+$//;
221 } else {
222 xlog($share,"Can't parse share $share into host and directory!",1);
223 return;
224 }
225 return ($host,$dir,strftime $DIR_TIME_FMT, localtime);
226 }
227
228
229 # make a snapshot of a share
230 sub snap_share {
231
232 my $share = shift;
233
234 my %param = ( debug => 0 );
235
236 $param{username} = shift || warn "can't find username for share $share";
237 $param{password} = shift || warn "can't find passwod for share $share";
238 $param{workgroup} = shift || warn "can't find workgroup for share $share";
239
240 my ($host,$dir,$date_dir) = share2host_dir($share);
241
242 # latest backup directory
243 my $bl = "$BACKUP_DEST/$host/$dir/latest";
244 # current backup directory
245 my $bc = "$BACKUP_DEST/$host/$dir/$date_dir";
246
247 my $real_bl;
248 if (-l $bl) {
249 $real_bl=readlink($bl) || die "can't read link $bl: $!";
250 $real_bl="$BACKUP_DEST/$host/$dir/$real_bl" if (substr($real_bl,0,1) ne "/");
251 } else {
252 xlog($share,"no old backup, trying to find last backup,");
253 if (opendir(BL_DIR, "$BACKUP_DEST/$host/$dir")) {
254 my @bl_dirs = sort grep { !/^\./ && -d "$BACKUP_DEST/$host/$dir/$_" } readdir(BL_DIR);
255 closedir(BL_DIR);
256 $real_bl=pop @bl_dirs;
257 xlog($share,"using $real_bl as latest...");
258 $real_bl="$BACKUP_DEST/$host/$dir/$real_bl" if (substr($real_bl,0,1) ne "/");
259 if ($real_bl eq $bc) {
260 xlog($share,"latest from today (possible partial backup)");
261 rename $real_bl,$real_bl.".partial" || warn "can't reaname partial backup: $!";
262 $real_bl .= ".partial";
263 }
264 } else {
265 xlog($share,"this is first run...");
266 }
267 }
268
269 if (-l $bc && $real_bl && $real_bl eq $bc) {
270 xlog($share,"allready backuped...");
271 return 1;
272 }
273
274 die "You should really create BACKUP_DEST [$BACKUP_DEST] by hand! " if (!-e $BACKUP_DEST);
275
276 if (! -e "$BACKUP_DEST/$host") {
277 mkdir "$BACKUP_DEST/$host" || die "can't make dir for host $host, $BACKUP_DEST/$host: $!";
278 xlog($share,"created host directory $BACKUP_DEST/$host...");
279 }
280
281 if (! -e "$BACKUP_DEST/$host/$dir") {
282 mkdir "$BACKUP_DEST/$host/$dir" || die "can't make dir for share $share, $BACKUP_DEST/$host/$dir $!";
283 xlog($share,"created dir for this share $BACKUP_DEST/$host/$dir...");
284 }
285
286 mkdir $bc || die "can't make dir for current backup $bc: $!";
287
288 my @dirs = ( "/" );
289 my @smb_dirs = ( "/" );
290
291 my $transfer = 0; # bytes transfered over network
292
293 # this will store all available files and sizes
294 my @files;
295 my %file_size;
296 my %file_atime;
297 my %file_mtime;
298 #my %file_md5;
299 %file_md5 = ();
300
301 my @smb_files;
302 my %smb_size;
303 #my %smb_atime;
304 #my %smb_mtime;
305
306 sub norm_dir {
307 my $foo = shift;
308 my $prefix = shift;
309 $foo =~ s#//+#/#g;
310 $foo =~ s#/+$##g;
311 $foo =~ s#^/+##g;
312 return $prefix.$foo if ($prefix);
313 return $foo;
314 }
315
316 # read local filesystem
317 my $di = 0;
318 while ($di <= $#dirs && $real_bl) {
319 my $d=$dirs[$di++];
320 opendir(DIR,"$real_bl/$d") || warn "opendir($real_bl/$d): $!\n";
321
322 # read .backupignore if exists
323 if (-f "$real_bl/$d/.backupignore") {
324 open(I,"$real_bl/$d/.backupignore");
325 while(<I>) {
326 chomp;
327 push @ignore,norm_dir("$d/$_");
328 }
329 close(I);
330 #print STDERR "ignore: ",join("|",@ignore),"\n";
331 link "$real_bl/$d/.backupignore","$bc/$d/.backupignore" ||
332 warn "can't copy $real_bl/$d/.backupignore to current backup dir: $!\n";
333 }
334
335 # read .md5sum if exists
336 if (-f "$real_bl/$d/.md5sum") {
337 open(I,"$real_bl/$d/.md5sum");
338 while(<I>) {
339 chomp;
340 my ($md5,$f) = split(/\s+/,$_,2);
341 $file_md5{$f}=$md5;
342 }
343 close(I);
344 }
345
346 my @clutter = readdir(DIR);
347 foreach my $f (@clutter) {
348 next if ($f eq '.');
349 next if ($f eq '..');
350 my $pr = norm_dir("$d/$f"); # path relative
351 my $pf = norm_dir("$d/$f","$real_bl/"); # path full
352 if (grep(/^\Q$pr\E$/,@ignore) == 0) {
353 if (-f $pf) {
354 push @files,$pr;
355 $file_size{$pr}=(stat($pf))[7];
356 $file_atime{$pr}=(stat($pf))[8];
357 $file_mtime{$pr}=(stat($pf))[9];
358 } elsif (-d $pf) {
359 push @dirs,$pr;
360 } else {
361 xlog($share,"not file or directory: $pf",0);
362 }
363 } else {
364 xlog($share,"ignored: $pr");
365 }
366 }
367 }
368
369 # local dir always include /
370 xlog($share,($#files+1)." files and ".($#dirs)." dirs on local disk before backup");
371
372 # read smb filesystem
373
374 xlog($share,"smb to $share as $param{username}/$param{workgroup}");
375
376 # FIX: how to aviod creation of ~/.smb/smb.conf ?
377 $smb = new Filesys::SmbClient(%param) || die "SmbClient :$!\n";
378
379 $di = 0;
380 while ($di <= $#smb_dirs) {
381 my $d=$smb_dirs[$di];
382 my $pf = norm_dir($d,"smb:$share/"); # path full
383 my $D = $smb->opendir($pf);
384 if (! $D) {
385 xlog($share,"FATAL: $share [$pf]: $!");
386 # remove failing dir
387 delete $smb_dirs[$di];
388 return 0; # failed
389 }
390 $di++;
391
392 my @clutter = $smb->readdir_struct($D);
393 foreach my $item (@clutter) {
394 my $f = $item->[1];
395 next if ($f eq '.');
396 next if ($f eq '..');
397 my $pr = norm_dir("$d/$f"); # path relative
398 my $pf = norm_dir("$d/$f","smb:$share/"); # path full
399 if (grep(/^\Q$pr\E$/,@ignore) == 0) {
400 if ($item->[0] == main::SMBC_FILE) {
401 push @smb_files,$pr;
402 $smb_size{$pr}=($smb->stat($pf))[7];
403 $smb_atime{$pr}=($smb->stat($pf))[10];
404 $smb_mtime{$pr}=($smb->stat($pf))[11];
405 } elsif ($item->[0] == main::SMBC_DIR) {
406 push @smb_dirs,$pr;
407 } else {
408 xlog($share,"not file or directory [".$item->[0]."]: $pf",0);
409 }
410 } else {
411 xlog($share,"smb ignored: $pr");
412 }
413 }
414 }
415
416 xlog($share,($#smb_files+1)." files and ".($#smb_dirs)." dirs on remote share");
417
418 # sync dirs
419 my $lc = List::Compare->new(\@dirs, \@smb_dirs);
420
421 my @dirs2erase = $lc->get_Lonly;
422 my @dirs2create = $lc->get_Ronly;
423 xlog($share,($#dirs2erase+1)." dirs to erase and ".($#dirs2create+1)." dirs to create");
424
425 # create new dirs
426 foreach (sort @smb_dirs) {
427 mkdir "$bc/$_" || warn "mkdir $_: $!\n";
428 }
429
430 # sync files
431 $lc = List::Compare->new(\@files, \@smb_files);
432
433 my @files2erase = $lc->get_Lonly;
434 my @files2create = $lc->get_Ronly;
435 xlog($share,($#files2erase+1)." files to erase and ".($#files2create+1)." files to create");
436
437 sub smb_copy {
438 my $smb = shift;
439
440 my $from = shift;
441 my $to = shift;
442
443
444 my $l = 0;
445
446 foreach my $f (@_) {
447 #print "smb_copy $from/$f -> $to/$f\n";
448 my $md5 = Digest::MD5->new;
449
450 my $fd = $smb->open("$from/$f");
451 if (! $fd) {
452 xlog("WARNING","can't open smb file $from/$f: $!");
453 next;
454 }
455
456 if (! open(F,"> $to/$f")) {
457 xlog("WARNING","can't open new file $to/$f: $!");
458 next;
459 }
460
461 while (defined(my $b=$smb->read($fd,4096))) {
462 print F $b;
463 $l += length($b);
464 $md5->add($b);
465 }
466
467 $smb->close($fd);
468 close(F);
469
470 $file_md5{$f} = $md5->hexdigest;
471
472 # FIX: this fails with -T
473 my ($a,$m) = ($smb->stat("$from/$f"))[10,11];
474 utime $a, $m, "$to/$f" ||
475 warn "can't update utime on $to/$f: $!\n";
476
477 }
478 return $l;
479 }
480
481 # copy new files
482 foreach (@files2create) {
483 $transfer += smb_copy($smb,"smb:$share",$bc,$_);
484 }
485
486 my $size_sync = 0;
487 my $atime_sync = 0;
488 my $mtime_sync = 0;
489 my @sync_files;
490 my @ln_files;
491
492 foreach ($lc->get_intersection) {
493
494 my $f;
495
496 if ($file_size{$_} != $smb_size{$_}) {
497 $f=$_;
498 $size_sync++;
499 }
500 if ($file_atime{$_} != $smb_atime{$_}) {
501 $f=$_;
502 $atime_sync++;
503 }
504 if ($file_mtime{$_} != $smb_mtime{$_}) {
505 $f=$_;
506 $mtime_sync++;
507 }
508
509 if ($f) {
510 push @sync_files, $f;
511 } else {
512 push @ln_files, $_;
513 }
514 }
515
516 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.");
517
518 foreach (@sync_files) {
519 $transfer += smb_copy($smb,"smb:$share",$bc,$_);
520 }
521
522 xlog($share,"$transfer bytes transfered...");
523
524 foreach (@ln_files) {
525 link "$real_bl/$_","$bc/$_" || warn "link $real_bl/$_ -> $bc/$_: $!\n";
526 }
527
528 # remove files
529 foreach (sort @files2erase) {
530 unlink "$bc/$_" || warn "unlink $_: $!\n";
531 delete $file_md5{$_};
532 }
533
534 # remove not needed dirs (after files)
535 foreach (sort @dirs2erase) {
536 rmdir "$bc/$_" || warn "rmdir $_: $!\n";
537 }
538
539 # remove old .md5sum
540 foreach (sort @dirs) {
541 unlink "$bc/$_/.md5sum" if (-e "$bc/$_/.md5sum");
542 }
543
544 # erase stale entries in .md5sum
545 my @md5_files = keys %file_md5;
546 $lc = List::Compare->new(\@md5_files, \@smb_files);
547 foreach my $file ($lc->get_Lonly) {
548 xlog("NOTICE","removing stale '$file' from .md5sum");
549 delete $file_md5{$file};
550 }
551
552 # create .md5sum
553 my $last_dir = '';
554 my $md5;
555 foreach my $f (sort { $file_md5{$a} cmp $file_md5{$b} } keys %file_md5) {
556 my $dir = dirname($f);
557 my $file = basename($f);
558 #print "$f -- $dir / $file<--\n";
559 if ($dir ne $last_dir) {
560 close($md5) if ($md5);
561 open($md5, ">> $bc/$dir/.md5sum") || warn "can't create $bc/$dir/.md5sum: $!";
562 $last_dir = $dir;
563 #print STDERR "writing $last_dir/.md5sum\n";
564 }
565 print $md5 $file_md5{$f}," $file\n";
566 }
567 close($md5) if ($md5);
568
569 # create leatest link
570 #print "ln -s $bc $real_bl\n";
571 if (-l $bl) {
572 unlink $bl || warn "can't remove old latest symlink $bl: $!\n";
573 }
574 symlink $bc,$bl || warn "can't create latest symlink $bl -> $bc: $!\n";
575
576 # FIX: sanity check -- remove for speedup
577 xlog($share,"failed to create latest symlink $bl -> $bc...") if (readlink($bl) ne $bc || ! -l $bl);
578
579 xlog($share,"backup completed...");
580
581 return 1;
582 }
583 __END__
584 #-------------------------------------------------------------------------
585
586
587 =head1 NAME
588
589 psinib - Perl Snapshot Is Not Incremental Backup
590
591 =head1 SYNOPSIS
592
593 ./psinib.pl [OPTION]... [mount script]
594
595 =head1 DESCRIPTION
596
597 Option can be one of more of following:
598
599 =over 8
600
601 =item C<--backupdest=dir>
602
603 Specify backup destination directory (defaults is /data/
604
605 =item C<--noping>
606
607 Don't use ping to check if host is up (default is ti use tcp syn to cifs
608 port)
609
610 =item C<--verbose -v>
611
612 Increase verbosity level. Defailt is 1 which prints moderate amount of data
613 on STDOUT and STDERR.
614
615 =item C<--quiet -q>
616
617 Decrease verbosity level
618
619 =back
620
621 This script in current version support just backup of Samba (or Micro$oft
622 Winblowz) shares to central disk space. Central disk space is organized in
623 multiple directories named after:
624
625 =over 4
626
627 =item *
628 server which is sharing files to be backed up
629
630 =item *
631 name of share on server
632
633 =item *
634 dated directory named like standard ISO date format (YYYYMMDD).
635
636 =back
637
638 In each dated directory you will find I<snapshot> of all files on
639 exported share on that particular date.
640
641 You can also use symlink I<latest> which will lead you to
642 last completed backup. After that you can use some other backup
643 software to transfer I<snapshot> to tape, CD-ROM or some other media.
644
645 =head2 Design considerations
646
647 Since taking of share snapshot every day requires a lot of disk space and
648 network bandwidth, B<psinib> uses several techniques to keep disk usage and
649 network traffic at acceptable level:
650
651 =over 3
652
653 =item - usage of hard-links to provide same files in each snapshot (as opposed
654 to have multiple copies of same file)
655
656 =item - usage of file size, atime and mtime to find changes of files without
657 transferring whole file over network (just share browsing is transfered
658 over network)
659
660 =item - usage of C<.md5sum> files (compatible with command-line utility
661 C<md5sum>) to keep file between snapshots hard-linked
662
663 =back
664
665 =head1 CONFIGURATION
666
667 This section is not yet written.
668
669 =head1 HACKS, TRICKS, BUGS and LIMITATIONS
670
671 This chapter will have all content that doesn't fit anywhere else.
672
673 =head2 Can snapshots be more frequent than daily?
674
675 There is not real reason why you can't take snapshot more often than
676 once a day. Actually, if you are using B<psinib> to backup Windows
677 workstations you already know that they tend to come-and-go during the day
678 (reboots probably ;-), so running B<psinib> several times a day increases
679 your chance of having up-to-date backup (B<psinib> will not make multiple
680 snapshots for same day, nor will it update snapshot for current day if
681 it already exists).
682
683 However, changing B<psinib> to produce snapshots which are, for example, hourly
684 is a simple change of C<$DIR_TIME_FMT> which is currently set to
685 C<'%Y%m%d'> (see I<strftime> documentation for explanation of that
686 format). If you change that to C<'%Y%m%d-%H> you can have hourly snapshots
687 (if your network is fast enough, that is...). Also, some of messages in
688 program will sound strange, but other than that it should work.
689 I<You have been warned>.
690
691 =head2 Do I really need to share every directory which I want to snapshot?
692
693 Actually, no. Due to usage of C<Filesys::SmbClient> module, you can also
694 specify sub-directory inside your share that you want to backup. This feature
695 is most useful if you want to use administrative shares (but, have in mind
696 that you have to enter your Win administrator password in unencrypted file on
697 disk to do that) like this:
698
699 smbmount //server/c$/WinNT/fonts /mnt -o username=administrator%win
700
701 After that you will get directories with snapshots like:
702
703 server/c_WinNT_fonts/yyyymmdd/....
704
705 =head2 Won't I run out of disk space?
706
707 Of course you will... Snapshots and logfiles will eventually fill-up your disk.
708 However, you can do two things to stop that:
709
710 =head3 Clean snapshort older than x days
711
712 You can add following command to your C<root> crontab:
713
714 find /backup/isis_backup -type d -mindepth 3 -maxdepth 3 -mtime +11 -exec rm -Rf {} \;
715
716 I assume that C</backup/isis_backup> is directory in which are your snapshots
717 and that you don't want to keep snapshots older than 11 days (that's
718 C<-mtime +11> part of command).
719
720 =head3 Rotate your logs
721
722 I will leave that to you. I relay on GNU/Debian's C<logrotate> to do it for me.
723
724 =head2 What are I<YYYYMMDD.partial> directories?
725
726 If there isn't I<latest> symlink in snapshot directory, it's preatty safe to
727 assume that previous backup from that day failed. So, that directory will
728 be renamed to I<YYYYMMDD.partial> and snapshot will be performed again,
729 linking same files (other alternative would be to erase that dir and find
730 second-oldest directory, but this seemed like more correct approach).
731
732 =head2 I can't connect to any share
733
734 Please verify that nmblookup (which is part of samba package) is in /bin or
735 /usr/bin. Also verify that nmblookup returns IP address for your server
736 using:
737
738 $ nmblookup tvhouse
739 querying tvhouse on 192.168.34.255
740 192.168.34.30 tvhouse<00>
741
742 If you don't get any output, your samba might not listen to correct interface
743 (see interfaces in smb.conf).
744
745 =head1 AUTHOR
746
747 Dobrica Pavlinusic <dpavlin@rot13.org>
748
749 L<http:E<sol>E<sol>www.rot13.orgE<sol>~dpavlinE<sol>>
750
751 =head1 LICENSE
752
753 This product is licensed under GNU Public License (GPL) v2 or later.
754
755 =cut

  ViewVC Help
Powered by ViewVC 1.1.26