#!/bin/sh # Copyright (c) 2010, 2011 George Danchev # Copyright (c) 2010, 2011, 2019 Thomas Schmitt # This script is distributed according to the terms of the GNU GPL v2. # This should be better rewritten in C at some future point. Ref: pwd code. # Create a list of checksums encoded in hexadecimal format and print to # standard output. Checksum may be MD5 or SHA256. # Format Description # A line in the emerging file is to be composed as follows: # # The checksum of the file content must be encoded in the aprropriate number # of hex digits. # [0-9afAF] # # Next come two blanks. # # The byte size of the file content must be encoded in 12 decimal digits # or blanks. # # Next come two blanks. # # The rest of the line up to the newline character is a semi-literal file # address. Its basename has to be the same as the basename of the data file # when it is used as one of the input files for the jigdo file generator. # The semi-literal address and the address mapping define what will be # listed as file address in the jigdo file. # The address may bear at its start a literal text that shall be recognized by # the address mapping (e.g. -jigdo-map) of the jigdo file generator. # The rest of the address must be usable as file address in both situations: # When the jigdo file gets generated, and when the jigdo file gets read # to inflate the template file into the original payload image. # The address mappings at both occasions can be used to adapt to a change # of the absolute location of the listed files. # Between both mappings, the parent directory is represented by a symbolic # text, like "Debian:". # A simple strategy to cope with this is to write absolute paths into the # checksum file, and to use matching absolute paths in the -jigdo-map # directives. Keep in mind that mapping is purely literal. Symbolic links # are neither resolved nor can they confuse the mapping. set -e SELF=jigdo-gen-md5-list VER=0.3 OPT_ABSOLUTE=1 # The checksum type to produce: md5 , sha256 checksum_type=md5 hex_length=32 md5_cmd= # On FreeBSD there is "md5" rather than "md5sum". # Furthermore, the FreeBSD shell reports missing commands to inherited stderr, # regardless that the attempt itself has redirected stderr. Thus a sub shell # is needed to hide the protest. choose_checksum_cmd() { if test "$checksum_type" = "md5" then if ( md5sum --help ) >/dev/null 2>&1 then md5_cmd=md5sum elif ( md5 -s test ) >/dev/null 2>&1 then md5_cmd=md5 else echo "$0 : Programs md5sum and md5 failed to work" >&2 exit 2 fi elif test "$checksum_type" = "sha256" then if ( sha256sum --help ) >/dev/null 2>&1 then md5_cmd=sha256sum elif ( sha256 -s test ) >/dev/null 2>&1 then md5_cmd=sha256 else echo "$0 : Programs sha256sum and sha256 failed to work" >&2 exit 2 fi fi } usage() { cat << USAGE usage: $SELF [option] DIR FILE ... Print a Jigdo checksum file to stdout. One line per FILE and per file in DIR. -m, --md5 produce MD5 checksums (default) -s, --sha256 produce SHA256 checksums -a, --make-absolute make absolute paths, avoiding any symlinks (default) -l, --keep-literal leave paths untouched, literally as supplied -v, --version print version -h, --help print help -e, --examples print examples USAGE } examples() { cat << EXAMPLES examples: $SELF datadir datafile $SELF --keep-literal datadir datafile find . -type f | xargs $SELF find . -exec $SELF '{}' ';' EXAMPLES } md5list() { item="$1" if test $OPT_ABSOLUTE -eq 1; then dn=`dirname "$item"` # dirname fn=`basename "$item"` # filename od=`pwd -P` # old dir cd "$dn" || exit 1 item=`pwd -P`/"$fn" # absolute physical file path, avoiding all symlinks cd "$od" || exit 1 fi if test "$md5_cmd" = "md5sum" then MD5=`md5sum "$item" | awk '{print $1}'` elif test "$md5_cmd" = "md5" then MD5=`md5 -q "$item"` elif test "$md5_cmd" = "sha256sum" then MD5=`sha256sum "$item" | awk '{print $1}'` elif test "$md5_cmd" = "sha256" then MD5=`sha256 -q "$item"` else echo "$0 : Internal error : Checksum mode unknown : $md5_cmd" >&2 exit 2 fi SIZ=`ls -ld "$item" | awk '{print $5}'` printf '%'"$hex_length"'s %12s %s\n' "$MD5" "$SIZ" "$item" } walkdir() { DR="$1" for item in `find "$DR" -type f` do md5list "$item" done } # main() if test "$1" = "" ; then usage exit 1 fi for i in "$@" do case "$i" in --md5|-m) checksum_type=md5 hex_length=32 ;; --sha256|-s) checksum_type=sha256 hex_length=64 ;; --make-absolute|-a) OPT_ABSOLUTE=1; shift; ;; --keep-literal|-l) OPT_ABSOLUTE=0; shift; ;; --version|-v) printf '%s %s\n' "$SELF" "$VER" exit 0 ;; --help|-h) usage exit 0 ;; --examples|-e) examples exit 0 # *) # usage # exit 1 # ;; esac done choose_checksum_cmd for i in "$@" do if echo "$i" | grep '^-' >/dev/null ; then dummy=dummy elif test -d "$i" ; then DR="$i" if test $OPT_ABSOLUTE -eq 1; then od=`pwd -P` # old dir cd "$DR" || exit 1 DR=`pwd -P` # absolute physical dir path, avoiding all symlinks cd "$od" || exit 1 fi walkdir "$DR" elif test -f "$i" ; then FL="$i" md5list "$FL" else usage exit 1 fi; done exit 0