OLD | NEW |
| (Empty) |
1 #!/bin/sh | |
2 # | |
3 | |
4 set -e | |
5 export LANG=C | |
6 export LC_ALL=C | |
7 | |
8 PROGDIR=$(dirname "$0") | |
9 PROGNAME=$(basename "$0") | |
10 | |
11 panic () { | |
12 echo "ERROR: $@" | |
13 exit 1 | |
14 } | |
15 | |
16 VERBOSE=1 | |
17 | |
18 # Dump message is $VERBOSE >= $1 | |
19 # $1+: message. | |
20 dump_n () { | |
21 local LOG_LEVEL=$1 | |
22 shift | |
23 if [ "$VERBOSE" -ge "$LOG_LEVEL" ]; then | |
24 printf "%s\n" "$@" | |
25 fi | |
26 } | |
27 | |
28 # Dump a message unless --quiet is used. | |
29 # $1+: message. | |
30 dump () { | |
31 dump_n 1 "$@" | |
32 } | |
33 | |
34 # Dump a message if --verbose is used only. | |
35 # $1+: message. | |
36 log () { | |
37 dump_n 2 "$@" | |
38 } | |
39 | |
40 # Run a command silently, unless --verbose or '--verbose --verbose' | |
41 # is used. | |
42 # $1+: Command | |
43 # Return: command status. | |
44 run () { | |
45 log "COMMAND: $*" | |
46 case $VERBOSE in | |
47 0) | |
48 "$@" >/dev/null 2>&1 || return $? | |
49 ;; | |
50 1) | |
51 "$@" >/dev/null || return $? | |
52 ;; | |
53 *) | |
54 "$@" || return $? | |
55 ;; | |
56 esac | |
57 } | |
58 | |
59 # $1: string | |
60 # Out: input string, with capital letters replaced by small ones. | |
61 tolower () { | |
62 echo "$1" | tr '[A-Z]' '[a-z]' | |
63 } | |
64 | |
65 # Return value of a given variable. | |
66 # $1: Variable name | |
67 var_value () { | |
68 eval printf \"%s\" \"\$$1\" | |
69 } | |
70 | |
71 # Remove some items from a list | |
72 # $1: input space-separated list | |
73 # $2: space-separated list of items to remove from 1 | |
74 # Out: items of $1 without items of $2 | |
75 filter_out () { | |
76 local TMP=$(mktemp) | |
77 local RESULT | |
78 printf "" > $TMP | |
79 echo "$2" | tr ' ' '\n' > $TMP | |
80 RESULT=$(echo "$1" | tr ' ' '\n' | fgrep -x -v -f $TMP | tr '\n' ' ') | |
81 rm -f $TMP | |
82 echo "$RESULT" | |
83 } | |
84 | |
85 src_to_obj () { | |
86 case $1 in | |
87 *.c) | |
88 echo ${1%%.c}.o | |
89 ;; | |
90 *.S) | |
91 echo ${1%%.S}.o | |
92 ;; | |
93 *) | |
94 echo $1 | |
95 ;; | |
96 esac | |
97 } | |
98 | |
99 # Determine host operating system. | |
100 HOST_OS=$(uname -s) | |
101 case $HOST_OS in | |
102 Linux) | |
103 HOST_OS=linux | |
104 ;; | |
105 Darwin) | |
106 HOST_OS=darwin | |
107 ;; | |
108 esac | |
109 | |
110 # Determine host architecture | |
111 HOST_ARCH=$(uname -m) | |
112 case $HOST_ARCH in | |
113 i?86) | |
114 HOST_ARCH=x86 | |
115 ;; | |
116 esac | |
117 | |
118 ANDROID_HOST_TAG=$HOST_OS-$HOST_ARCH | |
119 | |
120 case $ANDROID_HOST_TAG in | |
121 linux-x86_64|darwin-x86-64) | |
122 ANDROID_HOST_TAG=$HOST_OS-x86 | |
123 ;; | |
124 *) | |
125 panic "Sorry, this script can only run on 64-bit Linux or Darwin" | |
126 esac | |
127 | |
128 # Determine number of cores | |
129 case $HOST_OS in | |
130 linux) | |
131 NUM_CORES=$(grep -c "processor" /proc/cpuinfo) | |
132 ;; | |
133 darwin) | |
134 NUM_CORES=$(sysctl -n hw.ncpu) | |
135 ;; | |
136 *) | |
137 NUM_CORES=1 | |
138 ;; | |
139 esac | |
140 | |
141 # The list of supported Android target architectures. | |
142 ANDROID_ARCHS="arm x86 mips" | |
143 | |
144 BUILD_TYPES= | |
145 for ARCH in $ANDROID_ARCHS; do | |
146 BUILD_TYPES="$BUILD_TYPES android-$ARCH" | |
147 done | |
148 ANDROID_BUILD_TYPES=$BUILD_TYPES | |
149 | |
150 # NOTE: The $HOST_OS-x86_64 is currently broken because the single | |
151 # <openssl/opensslconf.h> header is tailored for 32-bits. | |
152 HOST_BUILD_TYPES="$HOST_OS-x86 $HOST_OS-generic32 $HOST_OS-generic64" | |
153 | |
154 BUILD_TYPES="$ANDROID_BUILD_TYPES $HOST_BUILD_TYPES" | |
155 | |
156 # Parse command-line | |
157 DO_HELP= | |
158 SRC_DIR=$(cd $PROGDIR && pwd) | |
159 OUT_DIR=out | |
160 BUILD_DIR= | |
161 BUILD_TYPES= | |
162 NUM_JOBS=$NUM_CORES | |
163 ANDROID_BUILD_TOP=$(cd $PROGDIR/../.. && pwd) | |
164 for OPT; do | |
165 case $OPT in | |
166 --help|-h|-?) | |
167 DO_HELP=true | |
168 ;; | |
169 --build-dir=*) | |
170 BUILD_DIR=${OPT##--build-dir=} | |
171 ;; | |
172 --verbose) | |
173 VERBOSE=$(( $VERBOSE + 1 )) | |
174 ;; | |
175 --jobs=*) | |
176 NUM_JOBS=${OPT##--jobs=} | |
177 ;; | |
178 --quiet) | |
179 VERBOSE=$(( $VERBOSE - 1 )) | |
180 ;; | |
181 -j*) | |
182 NUM_JOBS=${OPT##-j} | |
183 ;; | |
184 -*) | |
185 panic "Unknown option '$OPT', see --help for details." | |
186 ;; | |
187 *) | |
188 BUILD_TYPES="$BUILD_TYPES $OPT" | |
189 ;; | |
190 esac | |
191 done | |
192 | |
193 # Print help when needed. | |
194 if [ "$DO_HELP" ]; then | |
195 echo \ | |
196 "Usage: $PROGNAME [options] [<build-type> ...] | |
197 | |
198 This script is used to ensure that all OpenSSL build variants compile | |
199 properly. It can be used after modifying external/openssl/openssl.config | |
200 and re-running import_openssl.sh to check that any changes didn't break | |
201 the build. | |
202 | |
203 A <build-type> is a description of a given build of the library and its | |
204 program. Its format is: | |
205 | |
206 <compiler>-<system>-<arch> | |
207 | |
208 Where: <compiler> is either 'gcc' or 'clang'. | |
209 <system> is 'android', 'linux' or 'darwin'. | |
210 <arch> is 'arm', 'x86' or 'mips'. | |
211 | |
212 By default, it rebuilds the sources for the following build types: | |
213 " | |
214 for BUILD_TYPE in $BUILD_TYPES; do | |
215 echo " $BUILD_TYPE" | |
216 done | |
217 | |
218 echo \ | |
219 "However, you can pass custom values on the command-line instead. | |
220 | |
221 This scripts generates a custom Makefile in a temporary directory, then | |
222 launches 'make' in it to build all binaries in parallel. In case of | |
223 problem, you can use the --build-dir=<path> option to specify a custom | |
224 build-directory, which will _not_ be removed when the script exits. | |
225 | |
226 For example, to better see why a build fails: | |
227 | |
228 ./$PROGNAME --build-dir=/tmp/mydir | |
229 make -C /tmp/mydir V=1 | |
230 | |
231 Valid options: | |
232 | |
233 --help|-h|-? Print this message. | |
234 --build-dir=<path> Specify build directory. | |
235 --jobs=<count> Run <count> parallel build jobs [$NUM_JOBS]. | |
236 -j<count> Same as --jobs=<count>. | |
237 --verbose Increase verbosity. | |
238 --quiet Decrease verbosity. | |
239 " | |
240 exit 0 | |
241 fi | |
242 | |
243 log "Host OS: $HOST_OS" | |
244 log "Host arch: $HOST_ARCH" | |
245 log "Host CPU count: $NUM_CORES" | |
246 | |
247 if [ -z "$BUILD_TYPES" ]; then | |
248 BUILD_TYPES="$ANDROID_BUILD_TYPES $HOST_BUILD_TYPES" | |
249 fi | |
250 log "Build types: $BUILD_TYPES" | |
251 | |
252 if [ -z "$BUILD_DIR" ]; then | |
253 # Create a temporary directory, ensure it gets destroyed properly | |
254 # when the script exits. | |
255 BUILD_DIR=$(mktemp -d) | |
256 clean_build_dir () { | |
257 log "Cleaning up temporary directory: $BUILD_DIR" | |
258 rm -rf "$BUILD_DIR" | |
259 exit $1 | |
260 } | |
261 trap "clean_build_dir 0" EXIT | |
262 trap "clean_build_dir \$?" INT HUP QUIT TERM | |
263 log "Using temporary build directory: $BUILD_DIR" | |
264 else | |
265 log "Using user build directory: $BUILD_DIR" | |
266 fi | |
267 | |
268 mkdir -p "$BUILD_DIR" && rm -rf "$BUILD_DIR"/* | |
269 | |
270 MAKEFILE=$BUILD_DIR/GNUmakefile | |
271 | |
272 # Return source files for a given module and architecture. | |
273 # $1: module prefix (e.g. CRYPTO) | |
274 # $2: build arch. | |
275 get_module_src_files_for_arch () { | |
276 local prefix=$1 | |
277 local arch=$2 | |
278 local src_files="$(var_value OPENSSL_${prefix}_SOURCES)" | |
279 src_files="$src_files $(var_value OPENSSL_${prefix}_SOURCES_${arch})" | |
280 local exclude_files="$(var_value OPENSSL_${prefix}_SOURCES_EXCLUDES_${arch})" | |
281 src_files=$(filter_out "$src_files" "$exclude_files") | |
282 echo "$src_files" | |
283 } | |
284 | |
285 # Return the compiler defines for a given module and architecture | |
286 # $1: module prefix (e.g. CRYPTO) | |
287 # $2 build arch. | |
288 get_module_defines_for_arch () { | |
289 local prefix=$1 | |
290 local arch=$2 | |
291 local defines="$(var_value OPENSSL_${prefix}_DEFINES)" | |
292 defines="$defines $(var_value OPENSSL_${prefix}_DEFINES_${arch})" | |
293 echo "$defines" | |
294 } | |
295 | |
296 # $1: module prefix (e.g. CRYPTO) | |
297 get_module_c_includes () { | |
298 var_value OPENSSL_$1_INCLUDES | |
299 } | |
300 | |
301 # $1: build type (e.g. gcc-android-arm) | |
302 # Out: build arch. | |
303 get_build_arch () { | |
304 echo "$1" | cut -d- -f3 | |
305 } | |
306 | |
307 # $1: build arch | |
308 # Out: GNU configuration target (e.g. arm-linux-androideabi) | |
309 get_build_arch_target () { | |
310 case $1 in | |
311 arm) | |
312 echo "arm-linux-androideabi" | |
313 ;; | |
314 x86) | |
315 echo "i686-linux-android" | |
316 ;; | |
317 mips) | |
318 echo "mipsel-linux-android" | |
319 ;; | |
320 *) | |
321 echo "$1-linux-android" | |
322 ;; | |
323 esac | |
324 } | |
325 | |
326 GCC_VERSION=4.7 | |
327 CLANG_VERSION=3.1 | |
328 | |
329 get_prebuilt_gcc_dir_for_arch () { | |
330 local arch=$1 | |
331 local target=$(get_build_arch_target $arch) | |
332 echo "$ANDROID_BUILD_TOP/prebuilts/gcc/$ANDROID_HOST_TAG/$arch/$target-$GCC_VE
RSION" | |
333 } | |
334 | |
335 get_prebuilt_clang () { | |
336 echo "$ANDROID_BUILD_TOP/prebuilts/clang/$ANDROID_HOST_TAG/$CLANG_VERSION/clan
g" | |
337 } | |
338 | |
339 get_prebuilt_ndk_sysroot_for_arch () { | |
340 echo "$ANDROID_BUILD_TOP/prebuilts/ndk/current/platforms/android-9/arch-$1" | |
341 } | |
342 | |
343 get_c_runtime_file () { | |
344 local build_type=$1 | |
345 local arch=$(get_build_arch $build_type) | |
346 local filename=$2 | |
347 echo "$(get_prebuilt_ndk_sysroot_for_arch $arch)/usr/lib/$filename" | |
348 } | |
349 | |
350 # $1: build type (e.g. gcc-android-arm) | |
351 get_build_compiler () { | |
352 local arch=$(get_build_arch $1) | |
353 local target=$(get_build_arch_target $arch) | |
354 local gcc_dir=$(get_prebuilt_gcc_dir_for_arch $arch); | |
355 local result | |
356 | |
357 # Get the toolchain binary. | |
358 case $1 in | |
359 gcc-android-*) | |
360 result="$gcc_dir/bin/$target-gcc" | |
361 ;; | |
362 clang-android-*) | |
363 result="$(get_prebuilt_clang) -target $target -B$gcc_dir/$target/bin -I$gc
c_dir/lib/gcc/$target/$GCC_VERSION/include" | |
364 ;; | |
365 gcc-*) | |
366 result=gcc | |
367 ;; | |
368 clang-*) # Must have host clang compiler. | |
369 result=clang | |
370 ;; | |
371 esac | |
372 | |
373 compiler_check=$(which $result 2>/dev/null || echo "") | |
374 if [ -z "$compiler_check" ]; then | |
375 panic "Could not find compiler: $result" | |
376 fi | |
377 | |
378 # Get the Android sysroot if needed. | |
379 case $1 in | |
380 *-android-*) | |
381 result="$result --sysroot=$(get_prebuilt_ndk_sysroot_for_arch $arch)" | |
382 ;; | |
383 esac | |
384 | |
385 # Force -m32 flag when needed for 32-bit builds. | |
386 case $1 in | |
387 *-linux-x86|*-darwin-x86|*-generic32) | |
388 result="$result -m32" | |
389 ;; | |
390 esac | |
391 echo "$result" | |
392 } | |
393 | |
394 # $1: build type. | |
395 # Out: common compiler flags for this build. | |
396 get_build_c_flags () { | |
397 local result="-O2 -fPIC" | |
398 case $1 in | |
399 *-android-arm) | |
400 result="$result -march=armv7-a -mfpu=vfpv3-d16" | |
401 ;; | |
402 esac | |
403 | |
404 case $1 in | |
405 *-generic32|*-generic64) | |
406 # Generic builds do not compile without this flag. | |
407 result="$result -DOPENSSL_NO_ASM" | |
408 ;; | |
409 esac | |
410 echo "$result" | |
411 } | |
412 | |
413 # $1: build type. | |
414 # Out: linker for this build. | |
415 get_build_linker () { | |
416 get_build_compiler $1 | |
417 } | |
418 | |
419 clear_sources () { | |
420 g_all_objs="" | |
421 } | |
422 | |
423 # Generate build instructions to compile source files. | |
424 # Also update g_all_objs. | |
425 # $1: module prefix (e.g. CRYPTO) | |
426 # $2: build type | |
427 build_sources () { | |
428 local prefix=$1 | |
429 local build_type=$2 | |
430 echo "## build_sources prefix='$prefix' build_type='$build_type'" | |
431 local arch=$(get_build_arch $build_type) | |
432 local src_files=$(get_module_src_files_for_arch $prefix $arch) | |
433 local c_defines=$(get_module_defines_for_arch $prefix $arch) | |
434 local c_includes=$(get_module_c_includes $prefix "$SRC_DIR") | |
435 local build_cc=$(get_build_compiler $build_type) | |
436 local build_cflags=$(get_build_c_flags $build_type) | |
437 local build_linker=$(get_build_linker $build_type) | |
438 local src obj def inc | |
439 | |
440 printf "OUT_DIR := $OUT_DIR/$build_type\n\n" | |
441 printf "BUILD_CC := $build_cc\n\n" | |
442 printf "BUILD_LINKER := $build_linker\n\n" | |
443 printf "BUILD_CFLAGS := $build_cflags" | |
444 for inc in $c_includes; do | |
445 printf " -I\$(SRC_DIR)/$inc" | |
446 done | |
447 for def in $c_defines; do | |
448 printf " -D$def" | |
449 done | |
450 printf "\n\n" | |
451 printf "BUILD_OBJECTS :=\n\n" | |
452 | |
453 case $build_type in | |
454 clang-android-*) | |
455 # The version of clang that comes with the platform build doesn't | |
456 # support simple linking of shared libraries and executables. One | |
457 # has to provide the C runtime files explicitely. | |
458 local crtbegin_so=$(get_c_runtime_file $build_type crtbegin_so.o) | |
459 local crtend_so=$(get_c_runtime_file $build_type crtend_so.o) | |
460 local crtbegin_exe=$(get_c_runtime_file $build_type crtbegin_dynamic.o) | |
461 local crtend_exe=$(get_c_runtime_file $build_type crtend_android.o) | |
462 printf "CRTBEGIN_SO := $crtbegin_so\n" | |
463 printf "CRTEND_SO := $crtend_so\n" | |
464 printf "CRTBEGIN_EXE := $crtbegin_exe\n" | |
465 printf "CRTEND_EXE := $crtend_exe\n" | |
466 printf "\n" | |
467 ;; | |
468 esac | |
469 | |
470 for src in $src_files; do | |
471 obj=$(src_to_obj $src) | |
472 g_all_objs="$g_all_objs $obj" | |
473 printf "OBJ := \$(OUT_DIR)/$obj\n" | |
474 printf "BUILD_OBJECTS += \$(OBJ)\n" | |
475 printf "\$(OBJ): PRIVATE_CC := \$(BUILD_CC)\n" | |
476 printf "\$(OBJ): PRIVATE_CFLAGS := \$(BUILD_CFLAGS)\n" | |
477 printf "\$(OBJ): \$(SRC_DIR)/$src\n" | |
478 printf "\t@echo [$build_type] CC $src\n" | |
479 printf "\t@mkdir -p \$\$(dirname \$@)\n" | |
480 printf "\t\$(hide) \$(PRIVATE_CC) \$(PRIVATE_CFLAGS) -c -o \$@ \$<\n" | |
481 printf "\n" | |
482 done | |
483 printf "\n" | |
484 } | |
485 | |
486 # $1: library name (e.g. crypto). | |
487 # $2: module prefix (e.g. CRYPTO). | |
488 # $3: build type. | |
489 # $4: source directory. | |
490 # $5: output directory. | |
491 build_shared_library () { | |
492 local name=$1 | |
493 local prefix=$2 | |
494 local build_type=$3 | |
495 local src_dir="$4" | |
496 local out_dir="$5" | |
497 local shlib="lib${name}.so" | |
498 local build_linker=$(get_build_linker $build_type) | |
499 clear_sources | |
500 build_sources $prefix $build_type | |
501 | |
502 # TODO(digit): Make the clang build link properly. | |
503 printf "SHLIB=\$(OUT_DIR)/$shlib\n" | |
504 printf "\$(SHLIB): PRIVATE_LINKER := \$(BUILD_LINKER)\n" | |
505 case $build_type in | |
506 clang-android-*) | |
507 printf "\$(SHLIB): PRIVATE_CRTBEGIN := \$(CRTBEGIN_SO)\n" | |
508 printf "\$(SHLIB): PRIVATE_CRTEND := \$(CRTEND_SO)\n" | |
509 ;; | |
510 esac | |
511 printf "\$(SHLIB): \$(BUILD_OBJECTS)\n" | |
512 printf "\t@echo [$build_type] SHARED_LIBRARY $(basename $shlib)\n" | |
513 printf "\t@mkdir -p \$\$(dirname \$@)\n" | |
514 case $build_type in | |
515 clang-android-*) | |
516 printf "\t\$(hide) \$(PRIVATE_LINKER) -nostdlib -shared -o \$@ \$(PRIVATE_
CRTBEGIN) \$^ \$(PRIVATE_CRTEND)\n" | |
517 ;; | |
518 *) | |
519 printf "\t\$(hide) \$(PRIVATE_LINKER) -shared -o \$@ \$^\n" | |
520 ;; | |
521 esac | |
522 printf "\n" | |
523 } | |
524 | |
525 # $1: executable name. | |
526 # $2: module prefix (e.g. APPS). | |
527 # $3: build type. | |
528 # $4: source directory. | |
529 # $5: output directory. | |
530 # $6: dependent shared libraries (e.g. 'crypto ssl') | |
531 build_executable () { | |
532 local name=$1 | |
533 local prefix=$2 | |
534 local build_type=$3 | |
535 local src_dir="$4" | |
536 local out_dir="$5" | |
537 local shlibs="$6" | |
538 local build_linker=$(get_build_linker $build_type) | |
539 clear_sources | |
540 build_sources $prefix $build_type | |
541 | |
542 # TODO(digit): Make the clang build link properly. | |
543 exec=$name | |
544 all_shlibs= | |
545 printf "EXEC := \$(OUT_DIR)/$name\n" | |
546 printf "openssl_all: \$(EXEC)\n" | |
547 printf "\$(EXEC): PRIVATE_LINKER := \$(BUILD_LINKER)\n" | |
548 printf "\$(EXEC): \$(BUILD_OBJECTS)" | |
549 for lib in $shlibs; do | |
550 printf " \$(OUT_DIR)/lib${lib}.so" | |
551 done | |
552 printf "\n" | |
553 printf "\t@echo [$build_type] EXECUTABLE $name\n" | |
554 printf "\t@mkdir -p \$\$(dirname \$@)\n" | |
555 printf "\t\$(hide) \$(PRIVATE_LINKER) -o \$@ \$^\n" | |
556 printf "\n" | |
557 } | |
558 | |
559 ALL_BUILDS= | |
560 | |
561 generate_openssl_build () { | |
562 local build_type=$1 | |
563 local out="$OUT_DIR/$build_type" | |
564 ALL_BUILDS="$ALL_BUILDS $build_type" | |
565 echo "# Build type: $build_type" | |
566 build_shared_library crypto CRYPTO $build_type "$SRC_DIR" "$out" | |
567 build_shared_library ssl SSL $build_type "$SRC_DIR" "$out" | |
568 build_executable openssl APPS $build_type "$SRC_DIR" "$out" "crypto ssl" | |
569 } | |
570 | |
571 generate_makefile () { | |
572 echo \ | |
573 "# Auto-generated by $PROGDIR - do not edit | |
574 | |
575 .PHONY: openssl_all | |
576 | |
577 all: openssl_all | |
578 | |
579 # Use 'make V=1' to print build commands. | |
580 ifeq (1,\$(V)) | |
581 hide := | |
582 else | |
583 hide := @ | |
584 endif | |
585 | |
586 SRC_DIR=$SRC_DIR | |
587 OUT_DIR=$OUT_DIR | |
588 " | |
589 | |
590 for BUILD_TYPE in $BUILD_TYPES; do | |
591 generate_openssl_build gcc-$BUILD_TYPE | |
592 done | |
593 | |
594 # TODO(digit): Make the Clang build run. | |
595 # for BUILD_TYPE in $ANDROID_BUILD_TYPES; do | |
596 # generate_openssl_build clang-$BUILD_TYPE | |
597 # done | |
598 } | |
599 | |
600 . $SRC_DIR/openssl.config | |
601 | |
602 | |
603 | |
604 dump "Generating Makefile" | |
605 log "Makefile path: $MAKEFILE" | |
606 generate_makefile > $MAKEFILE | |
607 | |
608 dump "Building libraries with $NUM_JOBS jobs" | |
609 dump "For the following builds:" | |
610 for BUILD in $ALL_BUILDS; do | |
611 dump " $BUILD" | |
612 done | |
613 MAKE_FLAGS="-j$NUM_JOBS" | |
614 if [ "$VERBOSE" -gt 2 ]; then | |
615 MAKE_FLAGS="$MAKE_FLAGS V=1" | |
616 fi | |
617 run make $MAKE_FLAGS -f "$MAKEFILE" -C "$BUILD_DIR" | |
618 case $? in | |
619 0) | |
620 dump "All OK, congratulations!" | |
621 ;; | |
622 *) | |
623 dump "Error, try doing the following to inspect the issues:" | |
624 dump " $PROGNAME --build-dir=/tmp/mybuild" | |
625 dump " make -C /tmp/mybuild V=1" | |
626 dump "" | |
627 ;; | |
628 esac | |
OLD | NEW |