#!/usr/bin/env bash # # TROUBLESHOOTING # - If you see 'undefined reference to `AES_encrypt'', # make sure you have openssl installed. # If libcrypto.a is in a non-standard directory, try ./build -L[your-lib-dir] # - If you see 'undefined reference to `clock_gettime'', # try ./build -lrt instead. # - If you see 'x86.S:202: Error: junk at end of line, first unrecognized character is `,'', # try commenting the line in lib/bcrypt/x86.S. # - Take a look at the "Optional features" section. Some features have dependencies, # either make sure you have them or disable those features. # # BUGS # masterpassword@lyndir.com # # AUTHOR # Maarten Billemont # cd "${BASH_SOURCE%/*}" shopt -s extglob set -e ### CONFIGURATION # Targets to build. if [[ $targets ]]; then read -ra targets <<< "$targets" else # Default targets. # Modify here or override using targets='mpw mpw-bench' ./build targets=( mpw # C CLI version of Master Password. mpw-bench # C CLI Master Password benchmark utility. mpw-tests # C Master Password algorithm tester. ) fi # Optional features. mpw_color=1 # Colorized Identicon, requires libncurses-dev # Distribution specific configuration. # Homebrew if hash brew 2>/dev/null; then opensslPath=$(brew --prefix openssl) export CFLAGS="$CFLAGS -I$opensslPath/include" export LDFLAGS="$LDFLAGS -L$opensslPath/lib" fi ### DEPENDENCIES digest() { openssl sha -sha256 -binary < "$1" | od -t x1 -An -v | tr -d '[:space:]' } fetch() { if hash wget 2>/dev/null; then wget -O "${1##*/}" "$1" elif hash curl 2>/dev/null; then curl "$1" > "${1##*/}" fi } unpack() { printf 'Verifying package: %s, against digest: %s...' "$1" "$2" [[ $(digest "$1") = $2 ]] || { printf ' mismatch!\n' echo 2>&1 "Downloaded package doesn't match digest." exit 1 } printf ' OK!\n' if [[ $1 = *.tar.gz || $1 = *.tgz ]]; then tar -xvzf "$1" elif [[ $1 = *.tar.bz2 || $1 = *.tbz2 ]]; then tar -xvjf "$1" elif [[ $1 = *.tar ]]; then tar -xvf "$1" else echo 2>&1 "Don't know how to unpack: $1" fi files=( * ) if [[ -d $files ]] && (( ${#files[@]} == 1 )); then mv "$files"/* . rmdir "$files" fi } fetchSource() ( local name=${PWD##*/} source .source if [[ -e .unpacked ]]; then true elif [[ $pkg && -e "${pkg##*/}" ]]; then [[ -e src ]] || { echo echo "Unpacking: $name, using package..." ( mkdir src && cd src && unpack "../${pkg##*/}" "$pkg_sha256" ) touch .unpacked } elif [[ $git ]] && hash git 2>/dev/null; then [[ -e .git ]] || { echo echo "Fetching: $name, using git..." git clone "$git" src touch .unpacked } elif [[ $svn ]] && hash git 2>/dev/null && [[ -x "$(git --exec-path)/git-svn" ]]; then [[ -e .git ]] || { echo echo "Fetching: $name, using git-svn..." git svn clone --prefix=origin/ --stdlayout "$svn" src touch .unpacked } elif [[ $svn ]] && hash svn 2>/dev/null; then [[ -e .svn ]] || { echo echo "Fetching: $name, using svn..." svn checkout "$svn/trunk" src touch .unpacked } elif [[ $pkg ]]; then [[ -e src ]] || { echo echo "Fetching: $name, using package..." fetch "$pkg" ( mkdir src && cd src && unpack "../${pkg##*/}" "$pkg_sha256" ) touch .unpacked } else echo >&2 "error: Missing git-svn or svn." echo >&2 "error: Please install either or manually check out the sources" echo >&2 "error: from: $home" echo >&2 "error: into: $PWD/src" exit 1 fi if [[ ! -e .patched ]] && (( ${#patches[@]} )); then pushd src for patch in "${patches[@]}"; do echo echo "Patching: $name, for $patch..." patch -p0 < "../$patch.patch" done popd touch .patched fi ) depend() { local name=$1 echo echo "Checking dependency: $name..." [[ -e "lib/include/$name" ]] && return pushd "lib/$name" fetchSource pushd "src" echo echo "Configuring dependency: $name..." if [[ -e configure.ac ]]; then if [[ ! -e configure ]]; then # create configure using autotools. if ! hash aclocal || ! hash automake; then echo >&2 "Need autotools to build $name. Please install automake and autoconf." exit 1 fi aclocal autoheader autoconf mkdir -p config.aux automake --add-missing fi fi if [[ -e configure ]]; then ./configure fi echo echo "Building dependency: $name..." if [[ -e Makefile ]]; then if ! hash make; then echo >&2 "Need make to build $name. Please install GNU make." exit 1 fi make install -d "../../include/$name/" find . -name '*.h' -exec install -m 444 {} "../../include/$name/" \; else echo >&2 "error: Don't know how to build: $name" exit 1 fi popd popd } ### MPW mpw() { depend scrypt echo echo "Building target: $target..." local CFLAGS=( # include paths -I"lib/include" ) local LDFLAGS=( # scrypt "lib/scrypt/src/libcperciva/"*/*.o "lib/scrypt/src/lib/crypto/"*.o # library paths -L"." -L"lib/scrypt/src" # link libraries -l"crypto" ) # optional features (( mpw_color )) && CFLAGS+=( -DCOLOR ) LDFLAGS+=( -l"curses" ) cc "${CFLAGS[@]}" "$@" -c mpw-algorithm.c -o mpw-algorithm.o cc "${CFLAGS[@]}" "$@" -c mpw-types.c -o mpw-types.o cc "${CFLAGS[@]}" "$@" -c mpw-util.c -o mpw-util.o cc "${CFLAGS[@]}" "$@" "mpw-algorithm.o" "mpw-types.o" "mpw-util.o" \ "${LDFLAGS[@]}" "mpw-cli.c" -o "mpw" echo "done! Now run ./install or use ./mpw" } ### MPW-BENCH mpw-bench() { depend scrypt depend bcrypt echo echo "Building target: $target..." local CFLAGS=( # include paths -I"lib/include" ) local LDFLAGS=( # scrypt "lib/scrypt/src/libcperciva/"*/*.o "lib/scrypt/src/lib/crypto/"*.o # bcrypt "lib/bcrypt/src/crypt_blowfish.o" "lib/bcrypt/src/crypt_gensalt.o" "lib/bcrypt/src/wrapper.o" "lib/bcrypt/src/x86.o" # library paths -L"." -L"lib/scrypt/src" -L"lib/bcrypt/src" # link libraries -l"crypto" ) cc "${CFLAGS[@]}" "$@" -c mpw-algorithm.c -o mpw-algorithm.o cc "${CFLAGS[@]}" "$@" -c mpw-types.c -o mpw-types.o cc "${CFLAGS[@]}" "$@" -c mpw-util.c -o mpw-util.o cc "${CFLAGS[@]}" "$@" "mpw-algorithm.o" "mpw-types.o" "mpw-util.o" \ "${LDFLAGS[@]}" "mpw-bench.c" -o "mpw-bench" echo "done! Now use ./mpw-bench" } ### MPW-TESTS mpw-tests() { depend scrypt echo echo "Building target: $target..." local CFLAGS=( # include paths -I"lib/include" -I"/usr/include/libxml2" -I"/usr/local/include/libxml2" ) local LDFLAGS=( # scrypt "lib/scrypt/src/libcperciva/"*/*.o "lib/scrypt/src/lib/crypto/"*.o # library paths -L"." -L"lib/scrypt/src" # link libraries -l"crypto" -l"xml2" ) cc "${CFLAGS[@]}" "$@" -c mpw-algorithm.c -o mpw-algorithm.o cc "${CFLAGS[@]}" "$@" -c mpw-types.c -o mpw-types.o cc "${CFLAGS[@]}" "$@" -c mpw-util.c -o mpw-util.o cc "${CFLAGS[@]}" "$@" -c mpw-tests-util.c -o mpw-tests-util.o cc "${CFLAGS[@]}" "$@" "mpw-algorithm.o" "mpw-types.o" "mpw-util.o" "mpw-tests-util.o" \ "${LDFLAGS[@]}" "mpw-tests.c" -o "mpw-tests" echo "done! Now use ./mpw-tests" } ### TARGETS haslib() { ! LC_ALL=C cc -l"$1" 2>&1 | grep -q 'library not found' } cc() { if hash llvm-gcc 2>/dev/null; then llvm-gcc "$@" elif hash gcc 2>/dev/null; then gcc -std=gnu99 "$@" elif hash clang 2>/dev/null; then clang "$@" else echo >&2 "Need a compiler. Please install GCC or LLVM." exit 1 fi } echo "Will build targets: ${targets[*]}..." for target in "${targets[@]}"; do "$target" "$@" done