Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 3 Feb 2002 11:23:27 +0100
From:      Rogier Steehouder <r.j.s@gmx.net>
To:        jaime aguirre <jaimea@3web.net>
Cc:        questions@FreeBSD.org
Subject:   Re: checksum verifying.
Message-ID:  <20020203112327.A685@localhost>
In-Reply-To: <000801c1ac1a$bc9b3520$a8bafea9@jim>; from jaimea@3web.net on Sat, Feb 02, 2002 at 01:52:15PM -0500
References:  <000801c1ac1a$bc9b3520$a8bafea9@jim>

next in thread | previous in thread | raw e-mail | index | archive | help

--GvXjxJ+pjyke8COw
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

On 02-02-2002 13:52 (-0500), jaime aguirre wrote:
> I downloaded to a windows box the 4.5 mini-iso of FreeBSD.
> Is there a way to verify the checksum before it is burn into a cd?

I started learning perl around the time 4.3 came out, so I solved it by
writing a small script. Of course this would require you to install perl
on windows.

With kind regards, Rogier Steehouder

PS. This was a programming exercise. No guarantees whatsoever.

-- 
                          ___                          _
-O_\                                                  //
 | /               Rogier Steehouder                 //\
/ \                  r.j.s@gmx.net                  //  \
  <---------------------- 25m ---------------------->

--GvXjxJ+pjyke8COw
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="checksum.pl"

#!/usr/bin/perl -w
use strict;
use Cwd;
use Getopt::Std;
use Digest::MD5;

# Basic program help is provided in pod format below.
sub Help { exec("perldoc $0"); }

#+-------------------------------------------------------------------+
#| Main Program                                                      |
#+-------------------------------------------------------------------+
my(%cmdopts, $sumfile, @dirlist, $origdir);

# Process options
getopts('cf:hrR', \%cmdopts);
if      ($cmdopts{'h'})             { &Help; }
unless  ($sumfile = $cmdopts{'f'})  { $sumfile = 'CHECKSUM.MD5'; }

# List of all files/dirs to be checked
@dirlist = @ARGV;
unless  ($dirlist[0])               { $dirlist[0] = '.'; }

# Current directory
$origdir = getcwd;

# Loop through all files/dirs
foreach my $dir (@dirlist) {
    my(%checksums);
    # Directory: scan all files
    if (-d $dir) {
        chdir($dir) or next;
        if (-r $sumfile) { %checksums = &ReadSumfile($sumfile); }
        # Read filenames in directory
        opendir(DIR, '.') or die("Could not open directory $dir");
        my @files = readdir(DIR);
        closedir(DIR);
        # Join existing filenames and filenames from checksum file
        push(@files, keys(%checksums));
        @files = &uniq(@files);
        # Check each file
        foreach my $file (@files) {
            # Ignore . and ..
            next if ($file =~ m/^\.\.?$/);
            # Ignore dirs, but if -r, add to dirlist
            if (-d $file) {
                if ($cmdopts{'r'}) { push(@dirlist, "$dir/$file"); }
                next;
            }
            # Ignore checksum file
            next if ($file eq $sumfile);
            # File does not exist: GONE or REMOVED
            if      (! -e $file)                            {
                if ($cmdopts{'R'}) {
                    delete($checksums{$file});
                    print("REMOVED\t$dir/$file\n");
                } else {
                    print("GONE\t$dir/$file\n");
                }
            }
            # If exists but cannot be read: UNREAD or Ignore
            elsif   (! -r $file)                            {
                if ($checksums{$file}) {
                    print("UNREAD\t$dir/$file\n");
                } else {
                    next;
                }
            }
            # If checksum not present: NEW
            elsif   (! $checksums{$file})                   {
                # Ignore if -c
                next if ($cmdopts{'c'});
                $checksums{$file} = &CalcSum($file);
                print("NEW\t$dir/$file\n");
            }
            # If checksum matches: OK
            elsif   ($checksums{$file} eq &CalcSum($file))  {
                print("OK\t$dir/$file\n");
            }
            # No match: ERROR or CHANGED
            else                                            {
                if ($cmdopts{'R'}) {
                    $checksums{$file} = &CalcSum($file);
                    print("CHANGED\t$dir/$file\n");
                } else {
                    print("ERROR\t$dir/$file\n");
                }
            }
        }
        # Write new checksum file unless -c
        unless ($cmdopts{'c'}) { &WriteSumfile($sumfile, %checksums); }
        chdir($origdir);
    # File: scan file if exists
    } elsif (-e $dir) {
        print("Specifying files on the command line is yet unsupported. Stick to directories.\n");
    # Ignore non-existing files
    } else {
        print("$dir does not exist.\n");
        next;
    }
}

#+-------------------------------------------------------------------+
#| Subroutines                                                       |
#+-------------------------------------------------------------------+
    #+-----------------------------------------------------------+
    #| Read checksums from checksum file                         |
    #+-----------------------------------------------------------+
sub ReadSumfile {
    my($filename) = shift;
    my(%checksums);

    open(FH, "< $filename") or die("Could not read from $filename");
    while (<FH>) {
        chomp;
        if (m/^MD5 \(([^\)]*)\) = (.*)$/) { $checksums{$1} = $2; }
    }
    close(FH);

    return(%checksums);
}

    #+-----------------------------------------------------------+
    #| Write checksums to checksum file                          |
    #+-----------------------------------------------------------+
sub WriteSumfile {
    my($filename) = shift;
    my(%checksums) = @_;

    open(FH, "> $filename") or die("Could not write to $filename");
    foreach my $file (sort(keys(%checksums))) {
        print(FH "MD5 ($file) = ", $checksums{$file}, "\n");
    }
    close(FH);
}

    #+-----------------------------------------------------------+
    #| Calculate the checksum of a given file                    |
    #+-----------------------------------------------------------+
sub CalcSum {
    my($filename) = shift;
    my($sum);

    open(DATA, "< $filename") or die("Could not read from $filename");
    binmode(DATA);
    $sum = Digest::MD5->new->addfile(*DATA)->hexdigest;
    close(DATA);

    return($sum);
}

    #+-----------------------------------------------------------+
    #| Remove duplicates from an array                           |
    #+-----------------------------------------------------------+
sub uniq { # @list -> @list
    my(@list) = @_;
    my(%list);
    map { $list{$_} = 1 } @list;
    return(sort(keys(%list)));
}

__END__

=pod

=head1 NAME

checksum - check and/or generate checksums for files in directories

=head1 SYNOPSIS

B<checksum> [I<options>] <I<files or dirs>>

=head1 DESCRIPTION

B<checksum> checks and/or generates checksums for each file in a
directory. The checksums are stored in a file, by default
CHECKSUM.MD5

By default, the program will scan all files in the directory,
report files that are okay, missing or changed and adds new
files to the checksum file.

=head1 OPTIONS

=over 4

=item B<-c>

Check only. Do not alter checksum file(s).

=item B<-f> <I<filename>>

Specify checksum file name. Default: 'CHECKSUM.MD5'.

=item B<-h>

Print help.

=item B<-r>

Recurse into subdirectories. Every subdirectory has its own
checksum file.

=item B<-R>

Replace checksum file. Assume all files are valid and update
sums that do not match.

=back

If no files or directories are specified on the command line,
the current directory is checked.

=head1 OUTPUT

In the output, files can be labelled:

=over 4

=item B<OK>

No problem.

=item B<NEW>

No checksum recorded. Checksum is added to checksum file unless
-c is set.

=item B<GONE>

Checksum is present, but the file is not.

=item B<REMOVED>

Checksum is present, but the file is not. The checksum has been
removed from the checksum file. (See -R)

=item B<ERROR>

Checksum did not match. The file has been altered.

=item B<CHANGED>

Checksum did not match. The checksum has been updated in the
checksum file. (See -R)

=item B<UNREAD>

Checksum could not be verified, because the file is no longer
readable.

=back

Files that cannot be read from and have no previous checksum are
ignored.

=head1 BUGS

No wildcards are accepted. Usually this is handled fine by the
shell.

Currently only works with directories. The program will not
accept filenames on the command line, only directories.

=head1 AUTHOR

Rogier Steehouder <r.j.s@gmx.net>

=cut

# vim: set ts=4 sw=4 et :

--GvXjxJ+pjyke8COw--

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-questions" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20020203112327.A685>