3 #=======================================================================
5 # File ID: 29b2405c-f742-11dd-894f-000475e441b9
6 # Lagrer alle nye versjoner av en fil.
9 # ©opyleft 2001– Øyvind A. Holm <sunny@sunbase.org>
10 # License: GNU General Public License version 2 or later, see end of
11 # file for legal stuff.
12 #=======================================================================
14 # FIXME: Finn en standard Perl-måte for å erstatte kjøring av /bin/pwd .
40 $progname =~ s/^.*\/(.*?)$/$1/;
41 our $VERSION = "0.00";
43 Getopt
::Long
::Configure
("bundling");
46 "debug" => \
$Opt{'debug'},
47 "directory|d=s" => \
$Opt{'directory'},
48 "help|h" => \
$Opt{'help'},
49 "loop|l=i" => \
$Opt{'loop'},
50 "stop|s" => \
$Opt{'stop'},
51 "verbose|v+" => \
$Opt{'verbose'},
52 "version" => \
$Opt{'version'},
54 ) || die("$progname: Option error. Use -h for help.\n");
56 $Opt{'debug'} && ($Debug = 1);
57 $Opt{'help'} && usage
(0);
58 if ($Opt{'version'}) {
63 unless (length($Opt{'directory'})) {
64 defined($ENV{AFVROOT
}) || die("AFVROOT er ikke definert");
68 my $root_dir = length($Opt{'directory'}) ?
$Opt{'directory'} : $ENV{AFVROOT
};
71 my ($do_loop, $sleep_time, $orig_dir) = (0, 5, `/bin/pwd`); # FIXME
75 chomp($curr_dir = `/bin/pwd`);
76 $dest_dir = "$root_dir$curr_dir";
77 if (-d
"$dest_dir/.") {
78 print("Stopper afv’er i $curr_dir...");
79 if (open(StopFP
, ">$dest_dir/stop")) {
82 unlink("$dest_dir/stop") || die("$dest_dir/stop: Klarte ikke å slette fila: $!");
86 die("$root_dir/stop: Klarte ikke å lage fila: $!");
89 die("$root_dir: Finner ikke katalogen.");
93 if (length($Opt{'loop'})) {
94 if ($Opt{'loop'} =~ /^\d+$/) {
96 $sleep_time = $Opt{'loop'};
98 die("Parameteret til -l må være et tall.\n");
106 foreach my $FullCurr (@Files) {
108 my $Curr = $FullCurr;
111 next LOOP
if (!-f
$Curr || -l
$Curr);
112 if ($Curr =~ m
#(.*)/(.*?)$#) {
115 warn("Klarte ikke chdir(\"$1\"): $!");
120 chomp($curr_dir = `/bin/pwd`); # FIXME
121 $dest_dir = "$root_dir$curr_dir";
122 -d
$dest_dir || mkpath
($dest_dir, 1) || die("mkpath($dest_dir): $!");
123 my $afv_dir = "$dest_dir/$Dir";
124 -d
$afv_dir || mkpath
($afv_dir, 1) || die("mkpath($Dir): $!");
125 my $lock_dir = "$afv_dir/$Curr.lock";
126 my $lastmd5_file = "$afv_dir/$Curr.lastmd5";
127 my $currmd5_file = "$afv_dir/$Curr.currmd5";
128 my $start_lock = time;
130 until (mkdir($lock_dir, 0777)) {
131 warn(sec_to_string
(time) . ": $lock_dir: Venter på lockdir, " . (time-$start_lock) . " sekunder");
134 if (open(FromFP
, "<$Curr")) {
136 if (flock(FromFP
, LOCK_EX
)) {
138 my ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size, $atime, $mtime, $ctime, $blksize, $blocks) = stat(FromFP
);
139 my $date_str = sec_to_string
($mtime);
140 my $to_file = "$dest_dir/$date_str.$Curr";
145 seek(FromFP
, 0, 0) || die("$Curr: Klarte ikke å seeke til starten: $!");
147 my $curr_md5 = Digest
::MD5
->new->addfile(*FromFP
)->hexdigest;
148 D
("curr_md5 = $curr_md5");
149 open(CurrMD5FP
, ">$currmd5_file") || die("$currmd5_file: Klarte ikke å åpne fila for skriving: $!");
150 print(CurrMD5FP
"$curr_md5\n") || die("$currmd5_file: Feil under skriving til fila. $!");
154 if (-e
$lastmd5_file) {
155 if (open(LastMD5FP
, "<$lastmd5_file")) {
156 chomp($last_md5 = <LastMD5FP
>);
157 $last_md5 =~ s/^([0-9a-fA-F]{32})/\L$1\E/;
160 warn("$lastmd5_file: Feil under åpning for lesing: $!");
164 D
("last_md5 = \"$last_md5\", curr_md5 = \"$curr_md5\"");
165 if ($curr_md5 ne $last_md5) {
166 print("$date_str.$Curr\n") unless $do_loop;
167 if (seek(FromFP
, 0, 0)) {
168 if (open(ToFP
, ">$to_file")) {
169 if (flock(ToFP
, LOCK_EX
)) {
174 warn("$to_file: Klarte ikke flock(): $!");
177 unlink("$lastmd5_file");
178 rename("$currmd5_file", "$lastmd5_file") || die(qq{Klarte ikke
rename("$currmd5_file", "$lastmd5_file")});
180 warn("$Curr: Klarte ikke å åpne fila for skriving: $!");
183 warn("$Curr: Klarte ikke å seeke til starten: $!");
188 warn("$Curr: Klarte ikke flock(): $!");
192 warn("$Curr: Klarte ikke å åpne fila for lesing: $!");
196 rmdir($lock_dir) || warn("$lock_dir: Klarte ikke å fjerne lockdir: $!");
198 chdir($orig_dir) || die("$orig_dir: Klarte ikke chdir() til originalkatalogen: $!");
206 my_sleep
($sleep_time);
213 # Konverter antall sekunder sia 1970-01-01 00:00:00 GMT til
216 my @TA = gmtime(shift);
217 my $Retval = sprintf("%04u%02u%02uT%02u%02u%02uZ", $TA[5]+1900, $TA[4]+1, $TA[3], $TA[2], $TA[1], $TA[0]);
223 # Returnerer en array med filnavn som samsvarer med parametrene. {{{
227 push(@Files, glob $_);
231 push(@Files, glob $_);
238 # Sjekk om stop-fila finnes og i så fall avbrytes alt. {{{
239 foreach ($root_dir, $dest_dir) {
241 if (-e
"$_/protected") {
242 print(STDERR
"$curr_dir: $_/stop finnes, men katalogen er beskyttet, så vi avslutter ikke.\n");
244 print(STDERR
"$curr_dir: $_/stop finnes, avslutter.\n");
255 my $start_time = time;
260 until (time >= $start_time+$Secs) {
269 # Print program version {{{
270 print("$progname v$VERSION\n");
275 # Send the help message to stdout {{{
278 if ($Opt{'verbose'}) {
284 Syntax: $0 [valg] [fil [flere filer [...]]]
286 Lagrer flere versjoner av en eller flere filer i katalogen som \$AFVROOT
287 er satt til. Hvis ingen filer er spesifisert på kommandolinja, leses
293 De forskjellige versjonene skal lagres under X. Overstyrer \$AFVROOT .
297 Kjør i loop, sjekk filene hvert X. sekund. Eksempel:
299 afv -l5 foo.txt bar.pl &
300 find /etc | afv -l 15 &
302 for å kjøre den i bakgrunnen. Bruk afvctl(1) for å stoppe afv’er som
303 kjører. Filnavn på filer som lagres blir ikke skrevet ut når
304 "-l"-parameteret brukes.
306 Stopp afv-looper som kjører i denne katalogen.
308 Increase level of verbosity. Can be repeated.
310 Print version information.
312 Print debugging messages.
314 Som filnavn kan jokertegn (wildcards) også brukes. Hvis disse escapes,
315 brukes den innebygde glob’en og nye filer blir lagt til når den går i
320 sjekker alle filer hvert femte sekund og kjører også ny glob hver gang
329 # Print a status message to stderr based on verbosity level {{{
330 my ($verbose_level, $Txt) = @_;
332 if ($Opt{'verbose'} >= $verbose_level) {
333 print(STDERR
"$progname: $Txt\n");
339 # Print a debugging message {{{
341 my @call_info = caller;
342 chomp(my $Txt = shift);
343 my $File = $call_info[1];
345 $File =~ s
#^.*/(.*?)$#$1#;
346 print(STDERR
"$File:$call_info[2] $$ $Txt\n");
353 # Plain Old Documentation (POD) {{{
363 [options] [file [files [...]]]
373 =item B<-h>, B<--help>
375 Print a brief help summary.
377 =item B<-v>, B<--verbose>
379 Increase level of verbosity. Can be repeated.
383 Print version information.
387 Print debugging messages.
397 Made by Øyvind A. Holm S<E<lt>sunny@sunbase.orgE<gt>>.
401 Copyleft © Øyvind A. Holm E<lt>sunny@sunbase.orgE<gt>
402 This is free software; see the file F<COPYING> for legalese stuff.
406 This program is free software: you can redistribute it and/or modify it
407 under the terms of the GNU General Public License as published by the
408 Free Software Foundation, either version 2 of the License, or (at your
409 option) any later version.
411 This program is distributed in the hope that it will be useful, but
412 WITHOUT ANY WARRANTY; without even the implied warranty of
413 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
414 See the GNU General Public License for more details.
416 You should have received a copy of the GNU General Public License along
418 If not, see L<http://www.gnu.org/licenses/>.
426 # vim: set fenc=UTF-8 ft=perl fdm=marker ts=4 sw=4 sts=4 et fo+=w :