/[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.16 - (show annotations)
Sun Oct 26 12:55:56 2003 UTC (20 years, 6 months ago) by dpavlin
Branch: MAIN
Changes since 1.15: +23 -2 lines
File MIME type: text/plain
use tcp syn ping to check if host if up

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

  ViewVC Help
Powered by ViewVC 1.1.26