1#!/bin/bash
2#
3# Copyright (C) 2009 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#      http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
17
18#
19# This script imports new versions of scrypt (http://www.tarsnap.com/scrypt/) into the
20# Android source tree.  To run, (1) fetch the appropriate tarball from the scrypt repository,
21# (2) check the gpg/pgp signature, and then (3) run:
22#   ./import_scrypt.sh import scrypt-*.tar.gz
23#
24# IMPORTANT: See README.android for additional details.
25
26# turn on exit on error as well as a warning when it happens
27set -e
28set -x
29trap  "echo WARNING: Exiting on non-zero subprocess exit code" ERR;
30
31# Ensure consistent sorting order / tool output.
32export LANG=C
33export LC_ALL=C
34
35export DIRNAME=$(dirname $0)
36
37function die() {
38  declare -r message=$1
39
40  echo $message
41  exit 1
42}
43
44function usage() {
45  declare -r message=$1
46
47  if [ ! "$message" = "" ]; then
48    echo $message
49  fi
50  echo "Usage:"
51  echo "  ./import_scrypt.sh import </path/to/scrypt-*.tar.gz>"
52  echo "  ./import_scrypt.sh regenerate <patch/*.patch>"
53  echo "  ./import_scrypt.sh generate <patch/*.patch> </path/to/scrypt-*.tar.gz>"
54  exit 1
55}
56
57function main() {
58  if [ ! -d patches ]; then
59    die "scrypt patch directory patches/ not found"
60  fi
61
62  if [ ! -f scrypt.version ]; then
63    die "scrypt.version not found"
64  fi
65
66  source $DIRNAME/scrypt.version
67  if [ "$SCRYPT_VERSION" == "" ]; then
68    die "Invalid scrypt.version; see README.android for more information"
69  fi
70
71  SCRYPT_DIR=scrypt-$SCRYPT_VERSION
72  SCRYPT_DIR_ORIG=$SCRYPT_DIR.orig
73
74  if [ ! -f scrypt.config ]; then
75    die "scrypt.config not found"
76  fi
77
78  source $DIRNAME/scrypt.config
79  if [ "$CONFIGURE_ARGS" == "" -o "$UNNEEDED_SOURCES" == "" -o "$NEEDED_SOURCES" == "" ]; then
80    die "Invalid scrypt.config; see README.android for more information"
81  fi
82
83  declare -r command=$1
84  shift || usage "No command specified. Try import, regenerate, or generate."
85  if [ "$command" = "import" ]; then
86    declare -r tar=$1
87    shift || usage "No tar file specified."
88    import $tar
89  elif [ "$command" = "regenerate" ]; then
90    declare -r patch=$1
91    shift || usage "No patch file specified."
92    [ -d $SCRYPT_DIR ] || usage "$SCRYPT_DIR not found, did you mean to use generate?"
93    [ -d $SCRYPT_DIR_ORIG_ORIG ] || usage "$SCRYPT_DIR_ORIG not found, did you mean to use generate?"
94    regenerate $patch
95  elif [ "$command" = "generate" ]; then
96    declare -r patch=$1
97    shift || usage "No patch file specified."
98    declare -r tar=$1
99    shift || usage "No tar file specified."
100    generate $patch $tar
101  else
102    usage "Unknown command specified $command. Try import, regenerate, or generate."
103  fi
104}
105
106# Compute the name of an assembly source file generated by one of the
107# gen_asm_xxxx() functions below. The logic is the following:
108# - if "$2" is not empty, output it directly
109# - otherwise, change the file extension of $1 from .pl to .S and output
110#   it.
111# Usage: default_asm_file "$1" "$2"
112#     or default_asm_file "$@"
113#
114# $1: generator path (perl script)
115# $2: optional output file name.
116function default_asm_file () {
117  if [ "$2" ]; then
118    echo "$2"
119  else
120    echo "${1%%.pl}.S"
121  fi
122}
123
124# Generate an ARM assembly file.
125# $1: generator (perl script)
126# $2: [optional] output file name
127function gen_asm_arm () {
128  local OUT
129  OUT=$(default_asm_file "$@")
130  perl "$1" > "$OUT"
131}
132
133function gen_asm_mips () {
134  local OUT
135  OUT=$(default_asm_file "$@")
136  # The perl scripts expect to run the target compiler as $CC to determine
137  # the endianess of the target. Setting CC to true is a hack that forces the scripts
138  # to generate little endian output
139  CC=true perl "$1" o32 > "$OUT"
140}
141
142function gen_asm_x86 () {
143  local OUT
144  OUT=$(default_asm_file "$@")
145  perl "$1" elf -fPIC > "$OUT"
146}
147
148function gen_asm_x86_64 () {
149  local OUT
150  OUT=$(default_asm_file "$@")
151  perl "$1" elf "$OUT" > "$OUT"
152}
153
154
155# Filter all items in a list that match a given pattern.
156# $1: space-separated list
157# $2: egrep pattern.
158# Out: items in $1 that match $2
159function filter_by_egrep() {
160  declare -r pattern=$1
161  shift
162  echo "$@" | tr ' ' '\n' | grep -e "$pattern" | tr '\n' ' '
163}
164
165# Sort and remove duplicates in a space-separated list
166# $1: space-separated list
167# Out: new space-separated list
168function uniq_sort () {
169  echo "$@" | tr ' ' '\n' | sort -u | tr '\n' ' '
170}
171
172function print_autogenerated_header() {
173  echo "# Auto-generated - DO NOT EDIT!"
174  echo "# To regenerate, edit scrypt.config, then run:"
175  echo "#     ./import_scrypt.sh import /path/to/scrypt-$SCRYPT_VERSION.tar.gz"
176  echo "#"
177}
178
179function generate_build_config_mk() {
180  ./configure $CONFIGURE_ARGS
181  #rm -f apps/CA.pl.bak crypto/scryptconf.h.bak
182
183  declare -r tmpfile=$(mktemp)
184  (grep -e -D Makefile | grep -v CONFIGURE_ARGS= | grep -v OPTIONS=) > $tmpfile
185
186  declare -r cflags=$(filter_by_egrep "^-D" $(grep -e "^CFLAG=" $tmpfile))
187  declare -r depflags=$(filter_by_egrep "^-D" $(grep -e "^DEPFLAG=" $tmpfile))
188  rm -f $tmpfile
189
190  echo "Generating $(basename $1)"
191  (
192    print_autogenerated_header
193
194    echo "scrypt_cflags := \\"
195    for cflag in $cflags $depflags; do
196      echo "  $cflag \\"
197    done
198    echo ""
199  ) > $1
200}
201
202# Return the value of a computed variable name.
203# E.g.:
204#   FOO=foo
205#   BAR=bar
206#   echo $(var_value FOO_$BAR)   -> prints the value of ${FOO_bar}
207# $1: Variable name
208# Out: variable value
209var_value() {
210  # Note: don't use 'echo' here, because it's sensitive to values
211  #       that begin with an underscore (e.g. "-n")
212  eval printf \"%s\\n\" \$$1
213}
214
215# Same as var_value, but returns sorted output without duplicates.
216# $1: Variable name
217# Out: variable value (if space-separated list, sorted with no duplicates)
218var_sorted_value() {
219  uniq_sort $(var_value $1)
220}
221
222# Print the definition of a given variable in a GNU Make build file.
223# $1: Variable name (e.g. common_src_files)
224# $2+: Variable value (e.g. list of sources)
225print_vardef_in_mk() {
226  declare -r varname=$1
227  shift
228  if [ -z "$1" ]; then
229    echo "$varname :="
230  else
231    echo "$varname := \\"
232    for src; do
233      echo "  $src \\"
234    done
235  fi
236  echo ""
237}
238
239# Same as print_vardef_in_mk, but print a CFLAGS definition from
240# a list of compiler defines.
241# $1: Variable name (e.g. common_c_flags)
242# $2: List of defines (e.g. SCRYPT_NO_DONKEYS ...)
243print_defines_in_mk() {
244  declare -r varname=$1
245  shift
246  if [ -z "$1" ]; then
247    echo "$varname :="
248  else
249    echo "$varname := \\"
250    for def; do
251    echo "  -D$def \\"
252    done
253  fi
254  echo ""
255}
256
257# Generate a configuration file like Scrypt-config.mk
258# This uses variable definitions from scrypt.config to build a config
259# file that can compute the list of target- and host-specific sources /
260# compiler flags for a given component.
261#
262# $1: Target file name.  (e.g. Scrypt-config.mk)
263function generate_config_mk() {
264  declare -r output="$1"
265  declare -r all_archs="arm arm_neon x86 x86_64 mips"
266
267  echo "Generating $(basename $output)"
268  (
269    print_autogenerated_header
270    echo \
271"# Before including this file, the local Android.mk must define the following
272# variables:
273#
274#    local_c_flags
275#    local_c_includes
276#    local_additional_dependencies
277#
278# This script will define the following variables:
279#
280#    target_c_flags
281#    target_c_includes
282#    target_src_files
283#
284#    host_c_flags
285#    host_c_includes
286#    host_src_files
287#
288
289# Ensure these are empty.
290unknown_arch_c_flags :=
291unknown_arch_src_files :=
292unknown_arch_exclude_files :=
293
294"
295    common_defines=$(var_sorted_value SCRYPT_DEFINES)
296    print_defines_in_mk common_c_flags $common_defines
297
298    common_sources=$(var_sorted_value SCRYPT_SOURCES)
299    print_vardef_in_mk common_src_files $common_sources
300
301    common_includes=$(var_sorted_value SCRYPT_INCLUDES)
302    print_vardef_in_mk common_c_includes $common_includes
303
304    for arch in $all_archs; do
305      arch_defines=$(var_sorted_value SCRYPT_DEFINES_${arch})
306      print_defines_in_mk ${arch}_c_flags $arch_defines
307
308      arch_sources=$(var_sorted_value SCRYPT_SOURCES_${arch})
309      print_vardef_in_mk ${arch}_src_files $arch_sources
310
311      arch_exclude_sources=$(var_sorted_value SCRYPT_SOURCES_EXCLUDES_${arch})
312      print_vardef_in_mk ${arch}_exclude_files $arch_exclude_sources
313
314    done
315
316    echo "\
317target_arch := \$(TARGET_ARCH)
318ifeq (\$(target_arch)-\$(TARGET_HAS_BIGENDIAN),mips-true)
319target_arch := unknown_arch
320endif
321
322target_c_flags    := \$(common_c_flags) \$(\$(target_arch)_c_flags) \$(local_c_flags)
323target_c_includes := \$(addprefix external/scrypt/,\$(common_c_includes)) \$(local_c_includes)
324target_src_files  := \$(common_src_files) \$(\$(target_arch)_src_files)
325target_src_files  := \$(filter-out \$(\$(target_arch)_exclude_files), \$(target_src_files))
326
327# Hacks for ARM NEON support
328ifeq (\$(target_arch),arm)
329ifeq (\$(ARCH_ARM_HAVE_NEON),true)
330target_c_flags   += \$(arm_neon_c_flags)
331target_src_files += \$(arm_neon_src_files)
332target_src_files := \$(filter-out \$(arm_neon_exclude_files), \$(target_src_files))
333endif
334endif
335
336ifeq (\$(HOST_OS)-\$(HOST_ARCH),linux-x86)
337host_arch := x86
338else
339host_arch := unknown_arch
340endif
341
342host_c_flags    := \$(common_c_flags) \$(\$(host_arch)_c_flags) \$(local_c_flags)
343host_c_includes := \$(addprefix external/scrypt/,\$(common_c_includes)) \$(local_c_includes)
344host_src_files  := \$(common_src_files) \$(\$(host_arch)_src_files)
345host_src_files  := \$(filter-out \$(\$(host_arch)_exclude_files), \$(host_src_files))
346
347local_additional_dependencies += \$(LOCAL_PATH)/$(basename $output)
348"
349
350  ) > "$output"
351}
352
353function import() {
354  declare -r SCRYPT_SOURCE=$1
355
356  untar $SCRYPT_SOURCE readonly
357  applypatches $SCRYPT_DIR
358
359  cd $SCRYPT_DIR
360
361  generate_build_config_mk ../build-config.mk
362
363  touch ../MODULE_LICENSE_BSD_LIKE
364
365  cd ..
366
367  generate_config_mk Scrypt-config.mk
368
369  # Prune unnecessary sources
370  prune
371
372  NEEDED_SOURCES="$NEEDED_SOURCES"
373  for i in $NEEDED_SOURCES; do
374    echo "Updating $i"
375    rm -r $i
376    mv $SCRYPT_DIR/$i .
377  done
378
379  cleantar
380}
381
382function regenerate() {
383  declare -r patch=$1
384
385  generatepatch $patch
386}
387
388function generate() {
389  declare -r patch=$1
390  declare -r SCRYPT_SOURCE=$2
391
392  untar $SCRYPT_SOURCE
393  applypatches $SCRYPT_DIR_ORIG $patch
394  prune
395
396  for i in $NEEDED_SOURCES; do
397    echo "Restoring $i"
398    rm -r $SCRYPT_DIR/$i
399    cp -rf $i $SCRYPT_DIR/$i
400  done
401
402  generatepatch $patch
403  cleantar
404}
405
406# Find all files in a sub-directory that are encoded in ISO-8859
407# $1: Directory.
408# Out: list of files in $1 that are encoded as ISO-8859.
409function find_iso8859_files() {
410  find $1 -type f -print0 | xargs -0 file | fgrep "ISO-8859" | cut -d: -f1
411}
412
413# Convert all ISO-8859 files in a given subdirectory to UTF-8
414# $1: Directory name
415function convert_iso8859_to_utf8() {
416  declare -r iso_files=$(find_iso8859_files "$1")
417  for iso_file in $iso_files; do
418    iconv --from-code iso-8859-1 --to-code utf-8 $iso_file > $iso_file.tmp
419    rm -f $iso_file
420    mv $iso_file.tmp $iso_file
421  done
422}
423
424function untar() {
425  declare -r SCRYPT_SOURCE=$1
426  declare -r readonly=$2
427
428  # Remove old source
429  cleantar
430
431  # Process new source
432  tar -zxf $SCRYPT_SOURCE
433  convert_iso8859_to_utf8 $SCRYPT_DIR
434  cp -rfP $SCRYPT_DIR $SCRYPT_DIR_ORIG
435  if [ ! -z $readonly ]; then
436    find $SCRYPT_DIR_ORIG -type f -print0 | xargs -0 chmod a-w
437  fi
438}
439
440function prune() {
441  echo "Removing $UNNEEDED_SOURCES"
442  (cd $SCRYPT_DIR_ORIG && rm -rf $UNNEEDED_SOURCES)
443  (cd $SCRYPT_DIR      && rm -r  $UNNEEDED_SOURCES)
444}
445
446function cleantar() {
447  rm -rf $SCRYPT_DIR_ORIG
448  rm -rf $SCRYPT_DIR
449}
450
451function applypatches () {
452  declare -r dir=$1
453  declare -r skip_patch=$2
454
455  cd $dir
456
457  # Apply appropriate patches
458  for i in $SCRYPT_PATCHES; do
459    if [ ! "$skip_patch" = "patches/$i" ]; then
460      echo "Applying patch $i"
461      patch -p1 --merge < ../patches/$i || die "Could not apply patches/$i. Fix source and run: $0 regenerate patches/$i"
462    else
463      echo "Skiping patch $i"
464    fi
465
466  done
467
468  # Cleanup patch output
469  find . \( -type f -o -type l \) -name "*.orig" -print0 | xargs -0 rm -f
470
471  cd ..
472}
473
474function generatepatch() {
475  declare -r patch=$1
476
477  # Cleanup stray files before generating patch
478  find $SCRYPT_DIR -type f -name "*.orig" -print0 | xargs -0 rm -f
479  find $SCRYPT_DIR -type f -name "*~" -print0 | xargs -0 rm -f
480
481  declare -r variable_name=SCRYPT_PATCHES_`basename $patch .patch | sed s/-/_/`_SOURCES
482  # http://tldp.org/LDP/abs/html/ivr.html
483  eval declare -r sources=\$$variable_name
484  rm -f $patch
485  touch $patch
486  for i in $sources; do
487    LC_ALL=C TZ=UTC0 diff -aup $SCRYPT_DIR_ORIG/$i $SCRYPT_DIR/$i >> $patch && die "ERROR: No diff for patch $path in file $i"
488  done
489  echo "Generated patch $patch"
490  echo "NOTE To make sure there are not unwanted changes from conflicting patches, be sure to review the generated patch."
491}
492
493main $@
494