1# Copyright (C) 2009 The Android Open Source Project 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14# 15 16# A collection of shell function definitions used by various build scripts 17# in the Android NDK (Native Development Kit) 18# 19 20# Get current script name into PROGNAME 21PROGNAME=`basename $0` 22 23# Find the Android NDK root, assuming we are invoked from a script 24# within its directory structure. 25# 26# $1: Variable name that will receive the path 27# $2: Path of invoking script 28find_ndk_root () 29{ 30 # Try to auto-detect the NDK root by walking up the directory 31 # path to the current script. 32 local PROGDIR="`dirname \"$2\"`" 33 while [ -n "1" ] ; do 34 if [ -d "$PROGDIR/build/core" ] ; then 35 break 36 fi 37 if [ -z "$PROGDIR" -o "$PROGDIR" = '/' ] ; then 38 return 1 39 fi 40 PROGDIR="`cd \"$PROGDIR/..\" && pwd`" 41 done 42 eval $1="$PROGDIR" 43} 44 45# Put location of Android NDK into ANDROID_NDK_ROOT and 46# perform a tiny amount of sanity check 47# 48if [ -z "$ANDROID_NDK_ROOT" ] ; then 49 find_ndk_root ANDROID_NDK_ROOT "$0" 50 if [ $? != 0 ]; then 51 echo "Please define ANDROID_NDK_ROOT to point to the root of your" 52 echo "Android NDK installation." 53 exit 1 54 fi 55fi 56 57echo "$ANDROID_NDK_ROOT" | grep -q -e " " 58if [ $? = 0 ] ; then 59 echo "ERROR: The Android NDK installation path contains a space !" 60 echo "Please install to a different location." 61 exit 1 62fi 63 64if [ ! -d $ANDROID_NDK_ROOT ] ; then 65 echo "ERROR: Your ANDROID_NDK_ROOT variable does not point to a directory." 66 exit 1 67fi 68 69if [ ! -f $ANDROID_NDK_ROOT/build/core/ndk-common.sh ] ; then 70 echo "ERROR: Your ANDROID_NDK_ROOT variable does not point to a valid directory." 71 exit 1 72fi 73 74## Logging support 75## 76VERBOSE=${VERBOSE-yes} 77VERBOSE2=${VERBOSE2-no} 78 79 80# If NDK_LOGFILE is defined in the environment, use this as the log file 81TMPLOG= 82if [ -n "$NDK_LOGFILE" ] ; then 83 mkdir -p `dirname "$NDK_LOGFILE"` && touch "$NDK_LOGFILE" 84 TMPLOG="$NDK_LOGFILE" 85fi 86 87# Setup a log file where all log() and log2() output will be sent 88# 89# $1: log file path (optional) 90# 91setup_default_log_file () 92{ 93 if [ -n "$NDK_LOGFILE" ] ; then 94 return 95 fi 96 if [ -n "$1" ] ; then 97 NDK_LOGFILE="$1" 98 else 99 NDK_LOGFILE=/tmp/ndk-log-$$.txt 100 fi 101 export NDK_LOGFILE 102 TMPLOG="$NDK_LOGFILE" 103 rm -rf "$TMPLOG" && mkdir -p `dirname "$TMPLOG"` && touch "$TMPLOG" 104 echo "To follow build in another terminal, please use: tail -F $TMPLOG" 105} 106 107dump () 108{ 109 if [ -n "$TMPLOG" ] ; then 110 echo "$@" >> $TMPLOG 111 fi 112 echo "$@" 113} 114 115dump_n () 116{ 117 if [ -n "$TMPLOG" ] ; then 118 printf %s "$@" >> $TMPLOG 119 fi 120 printf %s "$@" 121} 122 123log () 124{ 125 if [ "$VERBOSE" = "yes" ] ; then 126 echo "$@" 127 else 128 if [ -n "$TMPLOG" ] ; then 129 echo "$@" >> $TMPLOG 130 fi 131 fi 132} 133 134log_n () 135{ 136 if [ "$VERBOSE" = "yes" ] ; then 137 printf %s "$@" 138 else 139 if [ -n "$TMPLOG" ] ; then 140 printf %s "$@" >> $TMPLOG 141 fi 142 fi 143} 144 145log2 () 146{ 147 if [ "$VERBOSE2" = "yes" ] ; then 148 echo "$@" 149 else 150 if [ -n "$TMPLOG" ] ; then 151 echo "$@" >> $TMPLOG 152 fi 153 fi 154} 155 156run () 157{ 158 if [ "$VERBOSE" = "yes" ] ; then 159 echo "## COMMAND: $@" 160 "$@" 2>&1 161 else 162 if [ -n "$TMPLOG" ] ; then 163 echo "## COMMAND: $@" >> $TMPLOG 164 "$@" >>$TMPLOG 2>&1 165 else 166 "$@" > /dev/null 2>&1 167 fi 168 fi 169} 170 171run2 () 172{ 173 if [ "$VERBOSE2" = "yes" ] ; then 174 echo "## COMMAND: $@" 175 "$@" 2>&1 176 elif [ "$VERBOSE" = "yes" ]; then 177 echo "## COMMAND: $@" 178 if [ -n "$TMPLOG" ]; then 179 echo "## COMMAND: $@" >> $TMPLOG 180 "$@" >>$TMPLOG 2>&1 181 else 182 "$@" > /dev/null 2>&1 183 fi 184 else 185 if [ -n "$TMPLOG" ]; then 186 "$@" >>$TMPLOG 2>&1 187 else 188 "$@" > /dev/null 2>&1 189 fi 190 fi 191} 192 193panic () 194{ 195 dump "ERROR: $@" 196 exit 1 197} 198 199fail_panic () 200{ 201 if [ $? != 0 ] ; then 202 dump "ERROR: $@" 203 exit 1 204 fi 205} 206 207fail_warning () 208{ 209 if [ $? != 0 ] ; then 210 dump "WARNING: $@" 211 fi 212} 213 214 215## Utilities 216## 217 218# Return the value of a given named variable 219# $1: variable name 220# 221# example: 222# FOO=BAR 223# BAR=ZOO 224# echo `var_value $FOO` 225# will print 'ZOO' 226# 227var_value () 228{ 229 # find a better way to do that ? 230 eval echo "$`echo $1`" 231} 232 233# convert to uppercase 234# assumes tr is installed on the platform ? 235# 236to_uppercase () 237{ 238 echo $1 | tr "[:lower:]" "[:upper:]" 239} 240 241## First, we need to detect the HOST CPU, because proper HOST_ARCH detection 242## requires platform-specific tricks. 243## 244HOST_EXE="" 245HOST_OS=`uname -s` 246case "$HOST_OS" in 247 Darwin) 248 HOST_OS=darwin 249 ;; 250 Linux) 251 # note that building 32-bit binaries on x86_64 is handled later 252 HOST_OS=linux 253 ;; 254 FreeBsd) # note: this is not tested 255 HOST_OS=freebsd 256 ;; 257 CYGWIN*|*_NT-*) 258 HOST_OS=windows 259 HOST_EXE=.exe 260 if [ "x$OSTYPE" = xcygwin ] ; then 261 HOST_OS=cygwin 262 fi 263 ;; 264esac 265 266log2 "HOST_OS=$HOST_OS" 267log2 "HOST_EXE=$HOST_EXE" 268 269## Now find the host architecture. This must correspond to the bitness of 270## the binaries we're going to run with this NDK. Certain platforms allow 271## you to use a 64-bit kernel with a 32-bit userland, and unfortunately 272## commands like 'uname -m' only report the kernel bitness. 273## 274HOST_ARCH=`uname -m` 275case "$HOST_ARCH" in 276 i?86) HOST_ARCH=x86 277 # "uname -m" reports i386 on Snow Leopard even though its architecture is 278 # 64-bit. In order to use it to build 64-bit toolchains we need to fix the 279 # reporting anomoly here. 280 if [ "$HOST_OS" = darwin ] ; then 281 if ! echo __LP64__ | (CCOPTS= gcc -E - 2>/dev/null) | grep -q __LP64__ ; then 282 # or if gcc -dM -E - < /dev/null | grep -q __LP64__; then 283 HOST_ARCH=x86_64 284 fi 285 fi 286 ;; 287 amd64) HOST_ARCH=x86_64 288 ;; 289 powerpc) HOST_ARCH=ppc 290 ;; 291esac 292 293case "$HOST_OS-$HOST_ARCH" in 294 linux-x86_64|darwin-x86_64) 295 ## On Linux or Darwin, a 64-bit kernel doesn't mean that the user-land 296 ## is always 32-bit, so use "file" to determine the bitness of the shell 297 ## that invoked us. The -L option is used to de-reference symlinks. 298 ## 299 ## Note that on Darwin, a single executable can contain both x86 and 300 ## x86_64 machine code, so just look for x86_64 (darwin) or x86-64 (Linux) 301 ## in the output. 302 ## 303 file -L "$SHELL" | grep -q "x86[_-]64" 304 if [ $? != 0 ]; then 305 # $SHELL is not a 64-bit executable, so assume our userland is too. 306 log2 "Detected 32-bit userland on 64-bit kernel system!" 307 HOST_ARCH=x86 308 fi 309 ;; 310esac 311 312log2 "HOST_ARCH=$HOST_ARCH" 313 314# at this point, the supported values for HOST_ARCH are: 315# x86 316# x86_64 317# ppc 318# 319# other values may be possible but haven't been tested 320# 321# at this point, the value of HOST_OS should be one of the following: 322# linux 323# darwin 324# windows (MSys) 325# cygwin 326# 327# Note that cygwin is treated as a special case because it behaves very differently 328# for a few things. Other values may be possible but have not been tested 329# 330 331# define HOST_TAG as a unique tag used to identify both the host OS and CPU 332# supported values are: 333# 334# linux-x86 335# linux-x86_64 336# darwin-x86 337# darwin-x86_64 338# darwin-ppc 339# windows 340# windows-x86_64 341# 342# other values are possible but were not tested. 343# 344compute_host_tag () 345{ 346 HOST_TAG=${HOST_OS}-${HOST_ARCH} 347 # Special case for windows-x86 => windows 348 case $HOST_TAG in 349 windows-x86|cygwin-x86) 350 HOST_TAG="windows" 351 ;; 352 esac 353 log2 "HOST_TAG=$HOST_TAG" 354} 355 356compute_host_tag 357 358# Compute the number of host CPU cores an HOST_NUM_CPUS 359# 360case "$HOST_OS" in 361 linux) 362 HOST_NUM_CPUS=`cat /proc/cpuinfo | grep processor | wc -l` 363 ;; 364 darwin|freebsd) 365 HOST_NUM_CPUS=`sysctl -n hw.ncpu` 366 ;; 367 windows|cygwin) 368 HOST_NUM_CPUS=$NUMBER_OF_PROCESSORS 369 ;; 370 *) # let's play safe here 371 HOST_NUM_CPUS=1 372esac 373 374log2 "HOST_NUM_CPUS=$HOST_NUM_CPUS" 375 376# If BUILD_NUM_CPUS is not already defined in your environment, 377# define it as the double of HOST_NUM_CPUS. This is used to 378# run Make commands in parralles, as in 'make -j$BUILD_NUM_CPUS' 379# 380if [ -z "$BUILD_NUM_CPUS" ] ; then 381 BUILD_NUM_CPUS=`expr $HOST_NUM_CPUS \* 2` 382fi 383 384log2 "BUILD_NUM_CPUS=$BUILD_NUM_CPUS" 385 386 387## HOST TOOLCHAIN SUPPORT 388## 389 390# force the generation of 32-bit binaries on 64-bit systems 391# 392FORCE_32BIT=no 393force_32bit_binaries () 394{ 395 if [ "$HOST_ARCH" = x86_64 ] ; then 396 log2 "Forcing generation of 32-bit host binaries on $HOST_ARCH" 397 FORCE_32BIT=yes 398 HOST_ARCH=x86 399 log2 "HOST_ARCH=$HOST_ARCH" 400 compute_host_tag 401 fi 402} 403 404# On Windows, cygwin binaries will be generated by default, but 405# you can force mingw ones that do not link to cygwin.dll if you 406# call this function. 407# 408disable_cygwin () 409{ 410 if [ $HOST_OS = cygwin ] ; then 411 log2 "Disabling cygwin binaries generation" 412 CFLAGS="$CFLAGS -mno-cygwin" 413 LDFLAGS="$LDFLAGS -mno-cygwin" 414 HOST_OS=windows 415 compute_host_tag 416 fi 417} 418 419# Various probes are going to need to run a small C program 420mkdir -p /tmp/ndk-$USER/tmp/tests 421 422TMPC=/tmp/ndk-$USER/tmp/tests/test-$$.c 423TMPO=/tmp/ndk-$USER/tmp/tests/test-$$.o 424TMPE=/tmp/ndk-$USER/tmp/tests/test-$$$EXE 425TMPL=/tmp/ndk-$USER/tmp/tests/test-$$.log 426 427# cleanup temporary files 428clean_temp () 429{ 430 rm -f $TMPC $TMPO $TMPL $TMPE 431} 432 433# cleanup temp files then exit with an error 434clean_exit () 435{ 436 clean_temp 437 exit 1 438} 439 440# this function will setup the compiler and linker and check that they work as advertised 441# note that you should call 'force_32bit_binaries' before this one if you want it to 442# generate 32-bit binaries on 64-bit systems (that support it). 443# 444setup_toolchain () 445{ 446 if [ -z "$CC" ] ; then 447 CC=gcc 448 fi 449 if [ -z "$CXX" ] ; then 450 CXX=g++ 451 fi 452 if [ -z "$CXXFLAGS" ] ; then 453 CXXFLAGS="$CFLAGS" 454 fi 455 if [ -z "$LD" ] ; then 456 LD="$CC" 457 fi 458 459 log2 "Using '$CC' as the C compiler" 460 461 # check that we can compile a trivial C program with this compiler 462 mkdir -p $(dirname "$TMPC") 463 cat > $TMPC <<EOF 464int main(void) {} 465EOF 466 467 if [ "$FORCE_32BIT" = yes ] ; then 468 CC="$CC -m32" 469 CXX="$CXX -m32" 470 LD="$LD -m32" 471 compile 472 if [ $? != 0 ] ; then 473 # sometimes, we need to also tell the assembler to generate 32-bit binaries 474 # this is highly dependent on your GCC installation (and no, we can't set 475 # this flag all the time) 476 CFLAGS="$CFLAGS -Wa,--32" 477 compile 478 fi 479 fi 480 481 compile 482 if [ $? != 0 ] ; then 483 echo "your C compiler doesn't seem to work:" 484 cat $TMPL 485 clean_exit 486 fi 487 log "CC : compiler check ok ($CC)" 488 489 # check that we can link the trivial program into an executable 490 link 491 if [ $? != 0 ] ; then 492 OLD_LD="$LD" 493 LD="$CC" 494 compile 495 link 496 if [ $? != 0 ] ; then 497 LD="$OLD_LD" 498 echo "your linker doesn't seem to work:" 499 cat $TMPL 500 clean_exit 501 fi 502 fi 503 log2 "Using '$LD' as the linker" 504 log "LD : linker check ok ($LD)" 505 506 # check the C++ compiler 507 log2 "Using '$CXX' as the C++ compiler" 508 509 cat > $TMPC <<EOF 510#include <iostream> 511using namespace std; 512int main() 513{ 514 cout << "Hello World!" << endl; 515 return 0; 516} 517EOF 518 519 compile_cpp 520 if [ $? != 0 ] ; then 521 echo "your C++ compiler doesn't seem to work" 522 cat $TMPL 523 clean_exit 524 fi 525 526 log "CXX : C++ compiler check ok ($CXX)" 527 528 # XXX: TODO perform AR checks 529 AR=ar 530 ARFLAGS= 531} 532 533# try to compile the current source file in $TMPC into an object 534# stores the error log into $TMPL 535# 536compile () 537{ 538 log2 "Object : $CC -o $TMPO -c $CFLAGS $TMPC" 539 $CC -o $TMPO -c $CFLAGS $TMPC 2> $TMPL 540} 541 542compile_cpp () 543{ 544 log2 "Object : $CXX -o $TMPO -c $CXXFLAGS $TMPC" 545 $CXX -o $TMPO -c $CXXFLAGS $TMPC 2> $TMPL 546} 547 548# try to link the recently built file into an executable. error log in $TMPL 549# 550link() 551{ 552 log2 "Link : $LD -o $TMPE $TMPO $LDFLAGS" 553 $LD -o $TMPE $TMPO $LDFLAGS 2> $TMPL 554} 555 556# run a command 557# 558execute() 559{ 560 log2 "Running: $*" 561 $* 562} 563 564# perform a simple compile / link / run of the source file in $TMPC 565compile_exec_run() 566{ 567 log2 "RunExec : $CC -o $TMPE $CFLAGS $TMPC" 568 compile 569 if [ $? != 0 ] ; then 570 echo "Failure to compile test program" 571 cat $TMPC 572 cat $TMPL 573 clean_exit 574 fi 575 link 576 if [ $? != 0 ] ; then 577 echo "Failure to link test program" 578 cat $TMPC 579 echo "------" 580 cat $TMPL 581 clean_exit 582 fi 583 $TMPE 584} 585 586pattern_match () 587{ 588 echo "$2" | grep -q -E -e "$1" 589} 590 591# Let's check that we have a working md5sum here 592check_md5sum () 593{ 594 A_MD5=`echo "A" | md5sum | cut -d' ' -f1` 595 if [ "$A_MD5" != "bf072e9119077b4e76437a93986787ef" ] ; then 596 echo "Please install md5sum on this machine" 597 exit 2 598 fi 599} 600 601# Find if a given shell program is available. 602# We need to take care of the fact that the 'which <foo>' command 603# may return either an empty string (Linux) or something like 604# "no <foo> in ..." (Darwin). Also, we need to redirect stderr 605# to /dev/null for Cygwin 606# 607# $1: variable name 608# $2: program name 609# 610# Result: set $1 to the full path of the corresponding command 611# or to the empty/undefined string if not available 612# 613find_program () 614{ 615 local PROG RET 616 PROG=`which $2 2>/dev/null` 617 RET=$? 618 if [ $RET != 0 ]; then 619 PROG= 620 fi 621 eval $1=\"$PROG\" 622 return $RET 623} 624 625prepare_download () 626{ 627 find_program CMD_WGET wget 628 find_program CMD_CURL curl 629 find_program CMD_SCRP scp 630} 631 632find_pbzip2 () 633{ 634 if [ -z "$_PBZIP2_initialized" ] ; then 635 find_program PBZIP2 pbzip2 636 _PBZIP2_initialized="yes" 637 fi 638} 639 640# Download a file with either 'curl', 'wget' or 'scp' 641# 642# $1: source URL (e.g. http://foo.com, ssh://blah, /some/path) 643# $2: target file 644download_file () 645{ 646 # Is this HTTP, HTTPS or FTP ? 647 if pattern_match "^(http|https|ftp):.*" "$1"; then 648 if [ -n "$CMD_WGET" ] ; then 649 run $CMD_WGET -O $2 $1 650 elif [ -n "$CMD_CURL" ] ; then 651 run $CMD_CURL -o $2 $1 652 else 653 echo "Please install wget or curl on this machine" 654 exit 1 655 fi 656 return 657 fi 658 659 # Is this SSH ? 660 # Accept both ssh://<path> or <machine>:<path> 661 # 662 if pattern_match "^(ssh|[^:]+):.*" "$1"; then 663 if [ -n "$CMD_SCP" ] ; then 664 scp_src=`echo $1 | sed -e s%ssh://%%g` 665 run $CMD_SCP $scp_src $2 666 else 667 echo "Please install scp on this machine" 668 exit 1 669 fi 670 return 671 fi 672 673 # Is this a file copy ? 674 # Accept both file://<path> or /<path> 675 # 676 if pattern_match "^(file://|/).*" "$1"; then 677 cp_src=`echo $1 | sed -e s%^file://%%g` 678 run cp -f $cp_src $2 679 return 680 fi 681} 682 683 684# Unpack a given archive 685# 686# $1: archive file path 687# $2: optional target directory (current one if omitted) 688# 689unpack_archive () 690{ 691 local ARCHIVE="$1" 692 local DIR=${2-.} 693 local RESULT TARFLAGS ZIPFLAGS 694 mkdir -p "$DIR" 695 if [ "$VERBOSE2" = "yes" ] ; then 696 TARFLAGS="vxpf" 697 ZIPFLAGS="" 698 else 699 TARFLAGS="xpf" 700 ZIPFLAGS="q" 701 fi 702 case "$ARCHIVE" in 703 *.zip) 704 (cd $DIR && run unzip $ZIPFLAGS "$ARCHIVE") 705 ;; 706 *.tar) 707 run tar $TARFLAGS "$ARCHIVE" -C $DIR 708 ;; 709 *.tar.gz) 710 run tar z$TARFLAGS "$ARCHIVE" -C $DIR 711 ;; 712 *.tar.bz2) 713 find_pbzip2 714 if [ -n "$PBZIP2" ] ; then 715 run tar --use-compress-prog=pbzip2 -$TARFLAGS "$ARCHIVE" -C $DIR 716 else 717 run tar j$TARFLAGS "$ARCHIVE" -C $DIR 718 fi 719 # remove ._* files by MacOSX to preserve resource forks we don't need 720 find $DIR -name "\._*" -exec rm {} \; 721 ;; 722 *) 723 panic "Cannot unpack archive with unknown extension: $ARCHIVE" 724 ;; 725 esac 726} 727 728# Pack a given archive 729# 730# $1: archive file path (including extension) 731# $2: source directory for archive content 732# $3+: list of files (including patterns), all if empty 733pack_archive () 734{ 735 local ARCHIVE="$1" 736 local SRCDIR="$2" 737 local SRCFILES 738 local TARFLAGS ZIPFLAGS 739 shift; shift; 740 if [ -z "$1" ] ; then 741 SRCFILES="*" 742 else 743 SRCFILES="$@" 744 fi 745 if [ "`basename $ARCHIVE`" = "$ARCHIVE" ] ; then 746 ARCHIVE="`pwd`/$ARCHIVE" 747 fi 748 mkdir -p `dirname $ARCHIVE` 749 if [ "$VERBOSE2" = "yes" ] ; then 750 TARFLAGS="vcf" 751 ZIPFLAGS="-9r" 752 else 753 TARFLAGS="cf" 754 ZIPFLAGS="-9qr" 755 fi 756 case "$ARCHIVE" in 757 *.zip) 758 (cd $SRCDIR && run zip $ZIPFLAGS "$ARCHIVE" $SRCFILES) 759 ;; 760 *.tar) 761 (cd $SRCDIR && run tar $TARFLAGS "$ARCHIVE" $SRCFILES) 762 ;; 763 *.tar.gz) 764 (cd $SRCDIR && run tar z$TARFLAGS "$ARCHIVE" $SRCFILES) 765 ;; 766 *.tar.bz2) 767 find_pbzip2 768 if [ -n "$PBZIP2" ] ; then 769 (cd $SRCDIR && run tar --use-compress-prog=pbzip2 -$TARFLAGS "$ARCHIVE" $SRCFILES) 770 else 771 (cd $SRCDIR && run tar j$TARFLAGS "$ARCHIVE" $SRCFILES) 772 fi 773 ;; 774 *) 775 panic "Unsupported archive format: $ARCHIVE" 776 ;; 777 esac 778} 779 780# Copy a directory, create target location if needed 781# 782# $1: source directory 783# $2: target directory location 784# 785copy_directory () 786{ 787 local SRCDIR="$1" 788 local DSTDIR="$2" 789 if [ ! -d "$SRCDIR" ] ; then 790 panic "Can't copy from non-directory: $SRCDIR" 791 fi 792 log "Copying directory: " 793 log " from $SRCDIR" 794 log " to $DSTDIR" 795 mkdir -p "$DSTDIR" && (cd "$SRCDIR" && 2>/dev/null tar cf - *) | (tar xf - -C "$DSTDIR") 796 fail_panic "Cannot copy to directory: $DSTDIR" 797} 798 799# This is the same than copy_directory(), but symlinks will be replaced 800# by the file they actually point to instead. 801copy_directory_nolinks () 802{ 803 local SRCDIR="$1" 804 local DSTDIR="$2" 805 if [ ! -d "$SRCDIR" ] ; then 806 panic "Can't copy from non-directory: $SRCDIR" 807 fi 808 log "Copying directory (without symlinks): " 809 log " from $SRCDIR" 810 log " to $DSTDIR" 811 mkdir -p "$DSTDIR" && (cd "$SRCDIR" && tar chf - *) | (tar xf - -C "$DSTDIR") 812 fail_panic "Cannot copy to directory: $DSTDIR" 813} 814 815# Copy certain files from one directory to another one 816# $1: source directory 817# $2: target directory 818# $3+: file list (including patterns) 819copy_file_list () 820{ 821 local SRCDIR="$1" 822 local DSTDIR="$2" 823 shift; shift; 824 if [ ! -d "$SRCDIR" ] ; then 825 panic "Cant' copy from non-directory: $SRCDIR" 826 fi 827 log "Copying file: $@" 828 log " from $SRCDIR" 829 log " to $DSTDIR" 830 mkdir -p "$DSTDIR" && (cd "$SRCDIR" && tar cf - "$@") | (tar xf - -C "$DSTDIR") 831 fail_panic "Cannot copy files to directory: $DSTDIR" 832} 833 834# Rotate a log file 835# If the given log file exist, add a -1 to the end of the file. 836# If older log files exist, rename them to -<n+1> 837# $1: log file 838# $2: maximum version to retain [optional] 839rotate_log () 840{ 841 # Default Maximum versions to retain 842 local MAXVER="5" 843 local LOGFILE="$1" 844 shift; 845 if [ ! -z "$1" ] ; then 846 local tmpmax="$1" 847 shift; 848 tmpmax=`expr $tmpmax + 0` 849 if [ $tmpmax -lt 1 ] ; then 850 panic "Invalid maximum log file versions '$tmpmax' invalid; defaulting to $MAXVER" 851 else 852 MAXVER=$tmpmax; 853 fi 854 fi 855 856 # Do Nothing if the log file does not exist 857 if [ ! -f "${LOGFILE}" ] ; then 858 return 859 fi 860 861 # Rename existing older versions 862 ver=$MAXVER 863 while [ $ver -ge 1 ] 864 do 865 local prev=$(( $ver - 1 )) 866 local old="-$prev" 867 868 # Instead of old version 0; use the original filename 869 if [ $ver -eq 1 ] ; then 870 old="" 871 fi 872 873 if [ -f "${LOGFILE}${old}" ] ; then 874 mv -f "${LOGFILE}${old}" "${LOGFILE}-${ver}" 875 fi 876 877 ver=$prev 878 done 879} 880