Whamcloud - gitweb
295fc2506daf31b90aba59d457048fbb7ca35d06
[fs/lustre-release.git] / build / lbuild
1 #!/bin/bash
2
3 # vim:expandtab:shiftwidth=4:softtabstop=4:tabstop=4:
4
5 #set -x
6 shopt -s extdebug
7
8 # include the exit_traps library
9 . ${0%/lbuild}/exit_traps.sh
10
11 # our children should die when we do
12 push_exit_trap "kill -INT -$$ || true" kill_children
13
14 TOPDIR=$PWD
15
16 # CVSROOT is inherited from the environment
17 KERNELDIR=
18 LINUX=
19 LUSTRE=
20 RELEASE=false
21 # XXX - some recent hacking has pretty much neutered this option.
22 #       search through this file (and lbuild.old_school -- but that will
23 #       be going away soon) for "-bb" and see how many places
24 #       simply don't account for this option
25 DO_SRC=true
26 DOWNLOAD=true
27 TAG=
28 CANONICAL_TARGET=
29 TARGET=
30 TARGET_ARCH=$(uname -m)
31 TARGET_ARCHS=
32 TARGET_ARCHS_ALL=$TARGET_ARCH
33 [ "$TARGET_ARCH" = "i686" ] && TARGET_ARCHS_ALL="i686 i586 i386"
34 CONFIGURE_FLAGS=
35 EXTERNAL_PATCHES=
36 EXTRA_VERSION=
37 LUSTRE_EXTRA_VERSION=
38 STAGEDIR=
39 TMPDIR=${TMPDIR:-"/var/tmp"}
40 TIMESTAMP=
41 # XXX - i think these two parameters/arguments/variables need to be
42 #       cleaned up and merged.  they effectively do the same thing
43 REUSERPM=
44 REUSEBUILD=
45 # what does this do exactly?  does it imply no kernel build?
46 NORPM=false
47 LDISKFSRPM=true
48 SKIPLDISKFSRPM="v1_4_* b1_4"
49 SMPTYPES="smp bigsmp default ''"
50 PATCHLESS=false
51 XEN=false
52 LINUXOBJ=
53 DISTRO=
54 KERNELTREE=
55 # default to not adding -lustre- into the kernel RPM package names
56 KERNEL_LUSTRE_NAMING=false
57
58 # patchless build
59 KERNELRPMSBASE=
60 RPMSMPTYPE=
61
62 # from target file
63 SERIES=
64 BASE_ARCHS=
65 BIGMEM_ARCHS=
66 BOOT_ARCHS=
67 JENSEN_ARCHS=
68 SMP_ARCHS=
69 BIGSMP_ARCHS=
70 PSERIES64_ARCHS=
71 UP_ARCHS=
72
73 # not in the target file any more
74 CONFIG=
75
76 DATE=$(date)
77
78 USE_DATESTAMP=1
79 RPMBUILD=
80
81 OLD_SCHOOL=false
82
83 export CC=${CC:-gcc}
84
85 # Readlink is not present on some older distributions: emulate it.
86 readlink() {
87     local path=$1 ll
88
89     if [ -L "$path" ]; then
90         ll="$(LC_ALL=C ls -l "$path" 2> /dev/null)" &&
91         echo "${ll/* -> }"
92     else
93         return 1
94     fi
95 }
96
97 cleanup() {
98
99     true
100 }
101
102 error() {
103     local msg="$1"
104
105     [ -n "$msg" ] && echo -e "\n${0##*/}: $msg" >&2
106
107 }
108
109 fatal() {
110
111     cleanup
112     error "$2"
113     exit $1
114
115 }
116
117 usage() {
118     cat <<EOF
119 Usage: ${0##*/} [OPTION]... [-- <lustre configure options>]
120
121   -d CVSROOT
122     Specifies the CVS Root to use when pulling files from CVS.  The
123     environment variable \$CVSROOT is used if this option is not
124     present.
125
126   --external-patches=EXTERNAL_PATCHES
127     Directory similar to lustre/lustre/kernel_patches/ that lbuild should
128     look for seres and config files in before looking in the lustre
129     tree.
130
131   --extraversion=EXTRAVERSION
132     Text to use for the rpm release and kernel extraversion.
133
134   --timestamp=TIMESTAMP
135     Date of building lustre in format YYYYMMDDhhmmss
136
137   --reuserpm=DIR
138     Try to reuse old kernel RPMs from DIR
139
140   --reusebuild=DIR
141     Try to reuse old kernel builds from DIR
142
143   --kernelrpm=DIR
144     Path to distro kernel RPM collection
145
146   --ccache
147     Use ccache
148
149   --norpm
150     Do not build RPMs (compile only mode)
151
152   --patchless
153     Build lustre client only
154
155   --distro=DISTRO
156     Which distro using. Autodetect by default
157
158   --kerneldir=KERNELDIR
159     Directory containing Linux source tarballs referenced by target
160     files.
161
162   --kerneltree=KERNELTREE
163     Directory containing dirs with Linux source tarballs referenced by target
164     files. Dir names in format kernel version ('2.6.9', etc.)
165
166   --linux=LINUX --with-linux=LINUX
167     Directory of Linux kernel sources.  When this option is used, only
168     Lustre modules and userspace are built.
169
170   --lustre=LUSTRE
171     Path to an existing lustre source tarball to use instead of
172     pulling from CVS.
173
174   --nodownload
175     Do not try to download a kernel from downloads.lustre.org
176
177   --nosrc
178     Do not build a .src.rpm, a full kernel patch, or a patched kernel
179     tarball.
180
181   --ldiskfs
182     Do ldiskfs RPM. Now true by default
183
184   --publish
185     Unused.
186
187   --release
188     Specifies that the files generated do not include timestamps, and
189     that this is an official release.
190
191   --src
192     Build a .src.rpm, a full kernel patch, and a patched kernel tarball.
193
194   --stage=DIR
195     Directory used to stage packages for release.  RPMs will be placed
196     more or less in DIR/<target>-<arch>, and the tarball will be
197     placed in DIR.
198
199   --tag=TAG
200     A CVS branch/tag name to build from when pulling from CVS.
201
202   --target=TARGET
203     The name of the target to build.  The available targets are listed
204     below.
205
206   --target-archs=TARGET_ARCHS
207     A (space delimited) list of architectures to build.  By default,
208     all of the archs supported by the TARGET will be built, in
209     addition to a .src.rpm.  This option can limit those, for machines
210     that can only build certain archs or if you only want a certain
211     arch built (for testing, or a one-off kernel).
212
213     Also note that by using a non-"base" arch (eg, i386) only kernels
214     will be built - there will be no lustre-lite-utils package.
215
216   --disable-datestamp
217     Prevents the datestamp flag (-D) from being passed to cvs for
218     checkouts. This is a workaround for a problem encountered when
219     using lbuild with tinderbox.
220
221   --xen
222     Builds a Xen domX kernel.
223
224 EOF
225
226 #   list_targets
227
228     fatal "$1" "$2"
229 }
230
231 # canonicalize a relative path
232 canon_path() {
233     local PATH="$1"
234
235     if [ ! -d "$PATH" ]; then
236         return 1
237     fi
238
239     pushd "$PATH" >/dev/null || return 1
240     local CANONPATH=$PWD
241     popd >/dev/null
242
243     echo "$CANONPATH"
244     return 0
245 }
246
247 check_options() {
248
249     if [ "$LUSTRE" ]; then
250         [ -r "$LUSTRE" ] || \
251             usage 1 "Could not find Lustre source tarball '$LUSTRE'."
252     else
253         [ "$CVSROOT" ] || \
254             usage 1 "Either specify a CVS Root with -d, or a Lustre source tarball with --lustre."
255         [ "$TAG" ] || \
256             usage 1 "A branch/tag name must be specified with --tag when not building from a tarball."
257     fi
258
259     if [ -z "$LINUX" ]; then
260         [ "$KERNELDIR" -o "$KERNELTREE" ] || \
261             usage 1 "A kernel directory must be specified with --kerneldir or --kerneltree."
262
263         [ -d "$KERNELDIR" -o -d "$KERNELTREE" ] || \
264             usage 1 "$KERNELDIR and $KERNELTREE are not a directory."
265
266         if ! $RELEASE; then
267             [ "$TAG" ] || \
268                 usage 1 "When building a snapshot, a tag name must be used."
269         fi
270
271         [ "$TARGET" ] || usage 1 "A target must be specified with --target."
272 #       TARGET_FILE="$TOPDIR/lustre/kernel_patches/targets/$TARGET.target"
273 #       [ -r "$TARGET_FILE" ] || \
274 #               usage 1 "Target '$TARGET' was not found."
275     fi
276
277     case $TARGET in
278         2.6-rhel5)
279             CANONICAL_TARGET="rhel5"
280             ;;
281         2.6-rhel4)
282             CANONICAL_TARGET="rhel-2.6"
283             ;;
284         2.6-suse)
285             CANONICAL_TARGET="sles-2.6"
286             ;;
287         2.6-sles10)
288             CANONICAL_TARGET="sles10-2.6"
289             ;;
290         2.6-sles11)
291             CANONICAL_TARGET="sles11"
292             ;;
293         2.6-oel5)
294             CANONICAL_TARGET="oel5"
295             ;;
296         hp_pnnl-2.4)
297             CANONICAL_TARGET="hp-pnnl-2.4"
298             ;;
299         2.6-vanilla \
300             | suse-2.4.21-2 \
301             | rh-2.4 \
302             | rhel-2.4 \
303             | sles-2.4 \
304             | 2.6-patchless)
305                 CANONICAL_TARGET="$TARGET"
306                 ;;
307     esac
308
309     local timestampnodig=$(echo $TIMESTAMP | sed -e s/[0-9]*//g)
310     [ "$timestampnodig" = "" ] || TIMESTAMP=$(date -d "$DATE" "+%Y%m%d%H%M%S")
311     local timestamplength="${#TIMESTAMP}"
312     if [ $timestamplength -eq 12 ]; then
313         TIMESTAMP="${TIMESTAMP}00"
314     elif [ $timestamplength -ne 14 ]; then
315         TIMESTAMP=$(date -d "$DATE" "+%Y%m%d%H%M%S")
316     fi
317
318     RPMBUILD=$(which rpmbuild 2>/dev/null | head -1)
319     if [ ! "$RPMBUILD" -o "$RPMBUILD" == "" ]; then
320         RPMBUILD=$(which rpm 2>/dev/null | head -1)
321         if [ ! "$RPMBUILD" -o "$RPMBUILD" == "" ]; then
322             usage 1 "Could not find binary for making rpms (tried rpmbuild and rpm)."
323         fi
324     fi
325
326     if [ -n "$CCACHE" ]; then
327         which "$DISTCC" 2>/dev/null && export DISTCC RPM_BUILD_NCPUS
328
329         if which "$CCACHE" 2>/dev/null; then
330             local ccache=$(which "$CCACHE")
331             local bindir="$TOPDIR/bin"
332
333             [ -d $bindir ] || mkdir -p $bindir
334             if [ -d $bindir ]; then
335                 rm ${bindir}/* > /dev/null 2>&1
336                 ln -s "$ccache" ${bindir}/ccache
337                 ln -s "$ccache" ${bindir}/cc
338                 ln -s "$ccache" ${bindir}/$CC
339                 export PATH=$bindir:$PATH
340             fi
341             export CCACHE && export CC="ccache $CC"
342             # zero the cache so we can see how effective we are being with it
343             ccache -z
344         fi
345     fi
346
347     [ -z "$DISTRO" ] && DISTRO=$(autodetect_distro)
348 }
349
350 # autodetect used Distro
351 autodetect_distro() {
352
353     local name
354     local version
355
356     if [ -f /etc/SuSE-release ]; then
357         name=sles
358         version=$(grep ^VERSION /etc/SuSE-release)
359         version=${version#*= }
360     elif [ -f /etc/redhat-release ]; then
361         name=$(head -1 /etc/redhat-release)
362         version=$(echo "$distroname" |
363                   sed -e 's/^[^0-9.]*//g' | sed -e 's/[ \.].*//')
364     fi
365     if [ -z "$name" -o -z "$version" ]; then
366         fatal 1 "I don't know how to determine distro type/version.\n" \
367                 "Either update autodetect_distro() or use the --distro argument"
368     fi
369
370     echo ${name}${version}
371     return 0
372
373 }
374
375 uniqify() {
376
377     echo $(echo "$*" | xargs -n 1 | sort -u)
378
379 }
380
381 download_srpm() {
382     local target=$1
383     local srpm=$2
384     local force="${3:-false}"
385
386     if $force || [ ! -r "$KERNELDIR/$srpm" ] ||
387        [ ! -s "$KERNELDIR/$srpm" ]; then
388         if $DOWNLOAD; then
389             local location="http://downloads.lustre.org/public/kernels/$target/old"
390             echo "Downloading $location/$srpm..."
391             if ! wget -nv "$location/$srpm" -O "$KERNELDIR/$srpm" ||
392                [ ! -s "$KERNELDIR/$srpm" ]; then
393                 rm -f $KERNELDIR/$srpm
394                 fatal 1 "Could not download target $target's kernel SRPM" \
395                         "$srpm from $location."
396             fi
397         else
398             fatal 1 "$srpm not found in directory $KERNELDIR."
399         fi
400     fi
401
402 }
403
404 download_file() {
405     local from="$1"
406     local to="$2"
407     local force="$3"
408
409     local file=${from##*/}
410
411     if [ -d $to ]; then
412         to="$to/$file"
413     fi
414
415     local semaphore="$to-downloading"
416
417     is_downloading() {
418         if [ ! -f $semaphore ]; then
419             return 1
420         fi
421
422         # make sure the download has not been aborted
423         local now=$(date +%s)
424         local file_mtime=$(stat -c %Y "$to")
425         local staleness=$((now - file_mtime))
426         # let's assume an active download will write at least once a minute
427         if [ $staleness -gt 60 ]; then
428             return 1
429         fi
430
431         return 0
432     }
433
434     is_downloaded() {
435         # if the semaphore file exists, the file is either still downloading
436         # or a download was aborted and we cannot trust the target file
437         if [ -f $semaphore ]; then
438             return 1
439         fi
440
441         if ! $(is_downloading) && [ -r "$to" ] && [ -s "$to" ]; then
442             return 0
443         fi
444
445         return 1
446     }
447
448     if $force || ! $(is_downloaded); then
449         if $(is_downloading); then
450             echo "Somebody else is downloading $from..."
451             while $(is_downloading); do
452                 echo "Waiting for $to to finish downloading"
453                 sleep 60
454             done
455             if $(is_downloaded); then
456                 return 0
457             else
458                 echo "The download we were waiting for seems to have been aborted"
459             fi
460
461         fi
462
463         if $DOWNLOAD; then
464             echo "Downloading $from..."
465             # flag others so they don't try to download also
466             push_exit_trap "rm -f $to $semaphore" "download"
467             touch $semaphore
468             if ! wget -nv "$from" -O "$to" || [ ! -s "$to" ]; then
469                 # the trap will remove the files via the fatal below
470                 fatal 1 "Could not download ${to##*/} from ${from%%/*}/."
471             fi
472             rm -f $semaphore
473             delete_exit_trap "download"
474         else
475             fatal 1 "${to##*/} not found in directory ${to%/*}."
476         fi
477     fi
478
479     return 0
480
481 }
482
483 download_ofed() {
484     local force="${1:-false}"
485
486     local location="http://downloads.lustre.org/public/OFED/"
487
488     local Mmv daily
489     if [[ $OFED_VERSION = daily-* ]]; then
490         OFED_VERSION=${OFED_VERSION/daily-/}
491         Mmv=${OFED_VERSION%%-*}
492         daily=${OFED_VERSION##$Mmv-}
493         location="http://www.openfabrics.org/downloads/OFED/ofed-${Mmv}-daily/"
494         # find the filename for the version for the date specified
495         OFED_VERSION=$(curl -s "$location" | sed -nre "/${daily}-/s/.*href=\"OFED-([0-9]+\.[0-9]+-${daily}-[0-9]{4,4}).tgz.*$/\1/p" | tail -1)
496         if [ -z "$OFED_VERSION" ]; then
497             fatal 1 "Could not determine the filename of the OFED snapshot for ${daily}"
498         fi
499     fi
500
501     if [ -z "$OFED_VERSION" -o "$OFED_VERSION" = "inkernel" ]; then
502         return 0
503     fi
504
505     local file="OFED-${OFED_VERSION}.tgz"
506     download_file "$location/$file" "$KERNELTREE" "$force"
507
508 }
509
510 download_rdac() {
511     local force="${1:-false}"
512
513             local location="http://downloads.lustre.org/public/RDAC/"
514
515     if [ -z "$RDAC_VERSION" -o "$RDAC_VERSION" = "inkernel" ]; then
516     return 0
517     fi
518
519     local file="rdac-LINUX-${RDAC_VERSION}-source.tar.gz"
520     download_file "$location/$file" "$KERNELTREE" "$force"
521
522 }
523
524 download_mptlinux() {
525     local force="${1:-false}"
526
527             local location="http://downloads.lustre.org/public/MPTLINUX/"
528
529     if [ -z "$MPTLINUX_VERSION" -o "$MPTLINUX_VERSION" = "inkernel" ]; then
530     return 0
531     fi
532
533     file="MPTLINUX_RHEL5_SLES10_PH15-${MPTLINUX_VERSION}.zip"
534     download_file "$location/$file" "$KERNELTREE" "$force"
535
536 }
537
538 load_target() {
539
540     EXTRA_VERSION_save="$EXTRA_VERSION"
541     for patchesdir in "$EXTERNAL_PATCHES" \
542                       "$TOPDIR/lustre/lustre/kernel_patches"; do
543         TARGET_FILE="$patchesdir/targets/$TARGET.target"
544         [ -r "$TARGET_FILE" ] && break
545     done
546     [ -r "$TARGET_FILE" ] || fatal 1 "Target $TARGET was not found."
547
548     echo "Loading target config file $TARGET.target..."
549
550     # if the caller specified an OFED_VERSION it should override whatever
551     # the target file specifies
552     local env_OFED_VERSION="$OFED_VERSION"
553
554     . "$TARGET_FILE"
555
556     if [ -n "$env_OFED_VERSION" ]; then
557         OFED_VERSION="$env_OFED_VERSION"
558     fi
559
560     # doesn't make any sense to build OFED for xen domX's
561     if $XEN; then
562         OFED_VERSION=""
563     fi
564
565     # XXX - set_rpm_smp_type is an ugly undeterministic hack.  it needs to
566     #       go away and the target just specify the $RPMSMPTYPE
567     [ -z "$RPMSMPTYPE" ] && set_rpm_smp_type
568
569     # CC might have been overwriten in TARGET_FILE
570     if [[ $CC != ccache\ * ]] && which "$CCACHE" 2>/dev/null; then
571         export CCACHE && export CC="ccache $CC"
572     fi
573
574     if [ ! "$KERNELTREE" = "" ] && [ -d "$KERNELTREE" ]; then
575         KERNELDIR="$KERNELTREE/${lnxmaj}"
576         [ -d "$KERNELDIR" ] || mkdir "$KERNELDIR"
577     fi
578
579     # verify the series is available
580     if [ "$SERIES" ]; then
581         for series in $SERIES; do
582             for patchesdir in "$EXTERNAL_PATCHES" "$TOPDIR/lustre/lustre/kernel_patches"; do
583                 [ -r "$patchesdir/series/$series" ] && continue 2
584             done
585             fatal 1 "Target $TARGET's series $SERIES could not be" \
586                     "found.\nSearched:\n\t$EXTERNAL_PATCHES/series\n" \
587                     "\t$TOPDIR/lustre/lustre/kernel_patches/series."
588         done
589     fi
590
591     # set the location of the .config file
592     local XENPOSTFIX=""
593     if $XEN; then
594         XENPOSTFIX="-xen"
595     fi
596
597     if [ -f $TOPDIR/lustre/lustre/kernel_patches/kernel_configs/kernel-$lnxmaj-$TARGET-$TARGET_ARCH.config ]; then
598         CONFIG_FILE="$TOPDIR/lustre/lustre/kernel_patches/kernel_configs/kernel-$lnxmaj-$TARGET$XENPOSTFIX-$TARGET_ARCH${RPMSMPTYPE:+-}${RPMSMPTYPE}.config"
599     fi
600
601     local lnxrelnew=${lnxrel//-/_}
602
603     # remember the EXTRA_VERSION before we diddle it here
604     # XXX - we really should not diddle with any values read in from the
605     #       target file.  if we want to modify a value, we should create
606     #       a new variable.
607     PRISTINE_EXTRA_VERSION=$EXTRA_VERSION
608
609     if ! $PATCHLESS && [ ! -f "$CONFIG_FILE" ]; then
610         fatal 1 "Config file for target $TARGET missing from" \
611                 "$TOPDIR/lustre/lustre/kernel_patches/kernel_configs/."
612     fi
613
614     if [ "$EXTRA_VERSION_save" ]; then
615         EXTRA_VERSION="$EXTRA_VERSION_save"
616     elif ! $RELEASE; then
617         # if there is no patch series, then this is not a lustre specific
618         # kernel.  don't make it look like one
619         if [ -n "$SERIES" ]; then
620             #remove the @VERSION@ (lustre version)
621 #            EXTRA_VERSION=$(echo $EXTRA_VERSION | sed -e "s/\(.*_lustre\)\..*/\1/")
622 #            EXTRA_VERSION="${EXTRA_VERSION}-${TAG}.${TIMESTAMP}"
623             ! ( $PATCHLESS ) && EXTRA_VERSION="${EXTRA_VERSION}.${TIMESTAMP}"
624         fi
625     fi
626     # EXTRA_VERSION=${EXTRA_VERSION//-/_}
627
628     ALL_ARCHS="$BASE_ARCHS $BIGMEM_ARCHS $BOOT_ARCHS $JENSEN_ARCHS $SMP_ARCHS $BIGSMP_ARCHS $PSERIES64_ARCHS $UP_ARCHS"
629
630     BUILD_ARCHS=
631     for arch in $(uniqify "$ALL_ARCHS"); do
632         if [ -z "$TARGET_ARCHS" ] ||
633            [[ \ $TARGET_ARCHS\  = *\ $arch\ * ]]; then
634             BUILD_ARCHS="$BUILD_ARCHS $arch"
635         fi
636     done
637     [ "$BUILD_ARCHS" ] || usage 1 "No available target archs to build."
638     echo "Building for: $BUILD_ARCHS"
639 }
640
641 tarflags() {
642     local file="$1"
643
644     case "$file" in
645         '')
646             fatal 1 "tarflags(): File name argument missing."
647             ;;
648         *.tar.gz | *.tgz)
649             echo 'zxf'
650             ;;
651         *.tar.bz2)
652             echo 'jxf'
653             ;;
654         *.tar)
655             echo 'xf'
656             ;;
657         *)
658             fatal 1 "tarflags(): Unrecognized tar extension in file: $1"
659             ;;
660     esac
661
662 }
663
664 untar() {
665     local file="$1"
666
667     echo "Untarring ${file##*/}..."
668     tar $(tarflags "$file") "$file"
669
670 }
671
672 unpack_ofed() {
673
674     if ! untar "$KERNELTREE/OFED-${OFED_VERSION}.tgz"; then
675         return 1
676     fi
677     [ -d OFED ] || ln -sf OFED-[0-9].[0-9]* OFED
678
679 }
680
681 unpack_rdac() {
682
683     if ! untar "$KERNELTREE/rdac-LINUX-${RDAC_VERSION}-source.tar.gz"; then
684         return 1
685     fi
686     [ -d rdac-LINUX ] || ln -sf rdac-LINUX-[0-9][0-9].* rdac-LINUX
687
688 }
689
690 unpack_mptlinux() {
691
692     if ! unzip -p $KERNELTREE/MPTLINUX_RHEL5_SLES10_PH15-4.16.00.00-2.zip | tar xzvf - srpms-2/mptlinux-4.16.00.00-2.src.rpm; then
693         return 1
694     fi
695     mv srpms-2/mptlinux-4.16.00.00-2.src.rpm .
696
697 }
698
699 unpack_lustre() {
700
701     if [ -z "$LUSTRE" ]; then
702         local DATESTAMP=""
703
704         if [ -n "$USE_DATESTAMP" ]; then
705             DATESTAMP="-D '$DATE'"
706         fi
707
708         local DIRNAME="lustre-$TAG-$TIMESTAMP"
709
710         cvs -d "$CVSROOT" -qz3 co $DATESTAMP -d "$DIRNAME" lustre || \
711             fatal 1 "There was an error checking out toplevel Lustre from CVS."
712         pushd "$DIRNAME" > /dev/null
713         ./lustrecvs "$TAG" || \
714             fatal 1 "There was an error checking out Lustre/Portals/Build from CVS."
715         echo "Creating lustre tarball..."
716         sh autogen.sh || fatal 1 "There was an error running autogen.sh."
717         ./configure --disable-{modules,utils,liblustre,tests,doc} || \
718             fatal 1 "There was an error running ./configure to create makefiles."
719         make dist || fatal 1 "There was an error running 'make dist'."
720         LUSTRE=$PWD/lustre-*.tar.gz
721         popd > /dev/null
722     fi
723
724     untar "$LUSTRE" || fatal 1 "Error unpacking Lustre tarball"
725     [ -d lustre ] || ln -sf lustre-[0-9].[0-9]* lustre
726
727 }
728
729 do_patch_linux() {
730
731     local do_patch=${1:-true}
732
733     FULL_PATCH="$PWD/lustre-kernel-${TARGET}${EXTRA_VERSION_DELIMITER}${EXTRA_VERSION}.patch"
734     [ -f "$FULL_PATCH" ] && rm -f "$FULL_PATCH"
735     $do_patch && pushd linux >/dev/null
736     for series in $SERIES; do
737         echo -n "Applying series $series:"
738         for patchesdir in "$EXTERNAL_PATCHES" "$TOPDIR/lustre/lustre/kernel_patches"; do
739             [ -r "$patchesdir/series/$series" ] || continue
740             SERIES_FILE="$patchesdir/series/$series"
741             for patch in $(<"$SERIES_FILE"); do
742                 echo -n " $patch"
743                 PATCH_FILE="$patchesdir/patches/$patch"
744                 [ -r "$PATCH_FILE" ] || \
745                     fatal 1 "Patch $patch does not exist in Lustre tree."
746                 cat "$PATCH_FILE" >> "$FULL_PATCH" || {
747                     rm -f $FULL_PATCH
748                     fatal 1 "Error adding patch $patch to full patch."
749                 }
750                 if $do_patch; then
751                     patch -s -p1 < "$PATCH_FILE" || {
752                         rm -f $FULL_PATCH
753                         fatal 1 "Error applying patch $patch."
754                     }
755                 fi
756             done
757             break
758         done
759         echo
760     done
761     $do_patch && popd >/dev/null
762     echo "Full patch has been saved in ${FULL_PATCH##*/}."
763
764 }
765
766 build_lustre() {
767     local linux="$1"
768     local linuxobj="$2"
769
770     cp "$LUSTRE" SOURCES
771
772     pushd lustre >/dev/null
773
774     echo "Building Lustre RPMs for: $BUILD_ARCHS..."
775     local targets arch
776     for arch in $BUILD_ARCHS; do
777         targets="--target $arch $targets"
778     done
779
780     local confoptions="--with-linux=${linux}"
781     if $PATCHLESS; then
782         confoptions="--with-linux=${linux} --disable-server"
783     fi
784     if [ "$linuxobj" != "" ]; then
785         confoptions="$confoptions --with-linux-obj=${linuxobj}"
786     fi
787
788     ./configure $confoptions ${CONFIGURE_FLAGS}
789     if [ "$?" != "0" ]; then
790         local saved_config="../config.log.$(date +%s)"
791         cp config.log $saved_config
792         chmod a+r $saved_config
793         echo "Saved config.log is at $saved_config"
794         cat /proc/mounts
795         ls -l /proc/$$
796         pwd
797         echo "config.log contents:"
798         cat config.log
799         popd
800         return 255
801     fi
802
803     gen_lustre_version
804
805     # hack. Somebody move build/lustre.spec to lustre.spec for b1_6
806     local lustre_spec
807     [ -f lustre.spec ] && lustre_spec=lustre.spec
808     [ -f build/lustre.spec ] && lustre_spec=build/lustre.spec
809
810     [ -f "$lustre_spec" ] && sed \
811         -e "s^Release: .*$^Release: $LUSTRE_EXTRA_VERSION^" \
812         < $lustre_spec \
813         > ../lustre.spec
814
815     local rpmbuildopt='-bb'
816     if $NORPM; then
817         rpmbuildopt='-bc'
818         echo NORPM mode. Only compiling.
819     fi
820
821     # convert the $PATCHLESS boolean to an empty/no-empty boolean
822     # as silly as this seems, it makes the syntax of the rpmbuild command
823     # simpler and not need an eval to deal with the quotes in the quotes 
824     local is_patchless=""
825     if $PATCHLESS; then
826         is_patchless="yes"
827     fi
828     $RPMBUILD $targets $rpmbuildopt ../lustre.spec \
829         ${is_patchless:+--define "lustre_name lustre-client"} \
830         --define "_tmppath $TMPDIR" \
831         --define "_topdir $TOPDIR" || \
832         fatal 1 "Error building rpms for $BUILD_ARCHS."
833
834     popd >/dev/null
835     ( $(skeep_ldiskfs_rpm $TAG) ) && return
836
837     pushd lustre/ldiskfs || return 255
838     make dist
839     if [ "$?" != "0" ]; then
840         popd
841         return 255
842     fi
843     cp lustre-ldiskfs*.tar.gz $TOPDIR/SOURCES
844
845     gen_lustre_version
846
847     local ldiskfs_spec=lustre-ldiskfs.spec
848     [ -f "$ldiskfs_spec" ] && sed \
849     -e "s^Release: .*$^Release: $LUSTRE_EXTRA_VERSION^" \
850     < $ldiskfs_spec \
851     > ../lustre-ldiskfs.spec
852
853     $RPMBUILD $targets $rpmbuildopt ../lustre-ldiskfs.spec \
854         --define "_tmppath /var/tmp" \
855         --define "_topdir $TOPDIR"
856     if [ "$?" != "0" ]; then
857         popd
858         return 255
859     fi
860
861     if $DO_SRC; then
862             $RPMBUILD -bs ../lustre-ldiskfs.spec \
863             --define "_tmppath /var/tmp" \
864             --define "_topdir $TOPDIR"
865         if [ "$?" != "0" ]; then
866             popd
867             return 255
868         fi
869     fi
870     popd
871
872 }
873
874 stage() {
875
876     [ "$STAGEDIR" ] || return 0
877
878     for arch in $BUILD_ARCHS; do
879         rpmdir="${STAGEDIR}/${CANONICAL_TARGET}-${arch}"
880         echo "${0##*/}: Copying RPMs into ${rpmdir}"
881         mkdir -p "${rpmdir}"
882         cp -v RPMS/${arch}/*.rpm "${rpmdir}"
883         if [ -d RPMS/noarch ]; then
884             cp -v RPMS/noarch/*.rpm "${rpmdir}"
885         fi
886     done
887
888     cp -v "$LUSTRE" "$STAGEDIR"
889
890 }
891
892 #check if we need to build separate ldiskfs RPM
893 skeep_ldiskfs_rpm() {
894         local tag="$1"
895
896         local skip=false
897
898         if ! $LDISKFSRPM; then
899             skip=true
900         elif $PATCHLESS; then
901             skip=true
902         else
903             for skiptag in $SKIPLDISKFSRPM; do
904                 [[ $tag == $skiptag ]] && skip=true && break
905             done
906         fi
907
908         pushd $TOPDIR/BUILD/lustre-[1-9]* >/dev/null
909         grep -q '^SERVER_TRUE[ \t]=[ \t]#$' autoMakefile && skip=true
910         popd >/dev/null
911
912         echo $skip
913
914 }
915
916 #generate LUSTRE_EXTRA_VERSION from EXTRA_VERSION
917 gen_lustre_version() {
918
919     LUSTRE_EXTRA_VERSION="${lnxmaj}${EXTRA_VERSION_DELIMITER}${EXTRA_VERSION}${TARGET_DELIMITER}${RPMSMPTYPE}"
920     LUSTRE_EXTRA_VERSION=${LUSTRE_EXTRA_VERSION//-/_}
921
922 }
923
924 set_rpm_smp_type() {
925
926     local infact_arch="${TARGET_ARCH}"
927
928     RPMSMPTYPE=""
929     [ "$infact_arch" == "i586" ] && infact_arch="i686"
930
931     local smp_type
932     for smp_type in $SMP_ARCHS; do
933         [ $infact_arch == $smp_type ] && RPMSMPTYPE=smp && break
934     done
935
936     for smp_type in $BIGSMP_ARCHS; do
937         [ $infact_arch == $smp_type ] && RPMSMPTYPE=bigsmp && break
938     done
939
940     for smp_type in $DEFAULT_ARCHS; do
941         [ $infact_arch == $smp_type ] && RPMSMPTYPE=default && break
942     done
943
944 }
945
946 # This function takes a linux source pool and digs out the linux release
947 # from it
948 find_linux_release() {
949     local SRCDIR="$1"
950
951     local LINUXRELEASEHEADER=$SRCDIR/include/linux/version.h
952     if [ -s $SRCDIR/include/linux/utsrelease.h ]; then
953         LINUXRELEASEHEADER=$SRCDIR/include/linux/utsrelease.h
954     fi
955
956     sed -ne 's/#define UTS_RELEASE "\(.*\)"$/\1/p' $LINUXRELEASEHEADER
957
958 }
959
960 # XXX this needs to be re-written as a wrapper around find_rpm
961 #     or just gotten rid of.  :-)
962 find_linux_rpm() {
963     local prefix="$1"
964     local delimiter=${2:-"-"}
965
966     local pathtorpms="${KERNELRPMSBASE}/${lnxmaj}/${DISTRO}"
967     [ -d $pathtorpms ] || return 255
968
969     local kernelbinaryrpm rpmfile
970     local wanted_kernel="${lnxmaj}${delimiter}${lnxrel}"
971
972     local arch ret=1
973     for arch in $TARGET_ARCHS_ALL; do
974         local found_rpm="" rpm
975         for rpm in ${pathtorpms}/${arch}/*.rpm; do
976             if rpm -q --provides -p "$rpm" | grep -q "kernel${prefix} = $wanted_kernel"; then
977                 found_rpm="$rpm"
978                 ret=0
979                 break
980             fi
981         done
982         [ -f "$found_rpm" ] && break
983     done
984
985     echo "$found_rpm"
986     return $ret
987
988 }
989
990 # unpack kernel(/source/devel) RPM
991 #
992 # This function and it's setting of $LINUX and $LINUXOBJ is a total hack that
993 # needs to completely refactored.  It completely ingores that $BUILD_ARCHS may
994 # contain a list of arches for which rpmbuild commands (including the one for
995 # lustre itself)
996 unpack_linux_devel_rpm() {
997     local kernelrpm="${1}"
998     # it's worth noting that neither sles10 nor rhel5 appear to use their
999     # extra_version delimiter for the dirname under /usr/src, so we could
1000     # probably just get rid of this parameter
1001     local delimiter=${2:-"-"}
1002
1003     [ -f "$kernelrpm" ] || return 255
1004     [ -d $TOPDIR/reused ] || mkdir $TOPDIR/reused || return 255
1005
1006     pushd $TOPDIR/reused || return 255
1007
1008     if ! rpm2cpio < "$kernelrpm" | cpio -id > /dev/null 2>&1; then
1009         return 255
1010     fi
1011
1012     # call a distro specific hook, if available
1013     if type -p unpack_linux_devel_rpm-$DISTRO; then
1014         unpack_linux_devel_rpm-$DISTRO "$kernelrpm"
1015     fi
1016
1017     popd
1018
1019     find_linux_devel_paths $TOPDIR/reused
1020
1021     return 0
1022
1023 }
1024
1025 # XXX - this rhel/sles goop needs abstracting out into the
1026 #       lbuild-{rhel5,sles10} method files
1027 find_linux_devel_paths() {
1028     local path="$1"
1029
1030     local RC=0
1031
1032     pushd $path
1033         # RHEL-style and SLES-style rpms
1034         # XXX - until bug 19336 cleans this up, we need to extricate the
1035         #       ${lnxmin}- from the $lnxrel
1036         local paths="kernels/${lnxmaj}${lnxmin}${delimiter}${lnxrel}-${TARGET_ARCH} linux-${lnxmaj}${lnxmin}${delimiter}${lnxrel##${lnxmin#.}-}"
1037
1038         local path
1039         for path in $paths; do
1040             local src='usr/src'
1041
1042             if [ -d "$src/$path/" ]; then
1043                 LINUX="$(pwd)/$src/$path"
1044             fi
1045             # SLES has a separate -obj tree
1046             if [ -d "$src/${path}-obj" ]; then
1047                 local src="$src/${path}-obj"
1048                 local objects="$TARGET_ARCH/$RPMSMPTYPE"
1049
1050                 # Novell, are you *TRYING* to make life hard for me?
1051                 if [ -d "$src/powerpc" ]; then
1052                     objects="powerpc/$TARGET_ARCH"
1053                 elif [ $TARGET_ARCH == 'i686' ]; then
1054                     objects="i386/$RPMSMPTYPE"
1055                 fi
1056
1057                 LINUXOBJ="$(pwd)/$src/$objects"
1058             fi
1059         done
1060         if [ -z "$LINUX" ]; then
1061             RC=255
1062         else
1063             # dig out the release version
1064             LINUXRELEASE=$(find_linux_release ${LINUXOBJ:-$LINUX})
1065             if [ -z "$LINUXRELEASE" ]; then
1066                 echo "Failed to find linux release in ${LINUXOBJ:-$LINUX}"
1067                 RC=255
1068             fi
1069         fi
1070     popd
1071     return $RC
1072 }
1073
1074 build_kernel_ib() {
1075     local linux="$1"
1076
1077     # build kernel-ib{,-devel}
1078     local K_SRC="K_SRC"
1079     # ofed 1.3 had a bug in the rpm spec
1080     if [ "$OFED_VERSION" = "1.3" ]; then
1081         K_SRC="KSRC"
1082     fi
1083
1084     local OFED_CORE="--with-core-mod --with-ipoib-mod --with-sdp-mod --with-user_mad-mod --with-user_access-mod --with-addr_trans-mod --with-rds-mod --with-qlgc_vnic-mod --with-madeye-mod"
1085     local OFED_HARDWARE="--with-mthca-mod --with-mlx4-mod --with-mlx4_en-mod --with-cxgb3-mod --with-nes-mod"
1086     # some I/B drivers are architecture dependent and kernel-ib's configure
1087     # does not figure it out for us ~sigh~
1088     case "$TARGET_ARCH" in
1089         ppc64)
1090             OFED_HARDWARE="$OFED_HARDWARE --with-ehca-mod"
1091             ;;
1092     esac
1093     # we're no longer shipping the OFED iSCSI
1094     #OFED_ISCSI="--with-srp-mod --with-srp-target-mod"
1095     ## ISER module has no backport support as of OFED 1.5 (i.e. only builds on
1096     ##kernels >= 2.6.30)
1097     #if [[ $OFED_VERSION = 1.[0-4]* ]]; then
1098     #   OFED_ISCSI="$OFED_ISCSI --with-iser-mod"
1099     #fi
1100
1101     # assume we are just rebuilding the SRPM
1102     local BUILD_TYPE=${BUILD_TYPE:-"--rebuild"}
1103     local SOURCE="${TOPDIR}/OFED/SRPMS/ofa_kernel-*.src.rpm"
1104
1105     # but switch to building from the SPEC if we need to apply patches
1106     if ls ${TOPDIR}/lustre/build/patches/ofed/* >/dev/null; then
1107         BUILD_TYPE="-bb"
1108         rpm --define "_topdir ${TOPDIR}" -ivh $SOURCE
1109         SOURCE="${TOPDIR}/SPECS/ofa_kernel.spec"
1110         local file ed_fragment1 ed_fragment2 n=1
1111         for file in ${TOPDIR}/lustre/build/patches/ofed/*; do
1112             ed_fragment1="$ed_fragment1
1113 Patch$n: ${file%%*/}"
1114             ed_fragment2="$ed_fragment2
1115 %patch$n -p0"
1116             cp $file ${TOPDIR}/SOURCES
1117             let n=$n+1
1118         done
1119
1120         ed $SOURCE <<EOF
1121 /^Source: /a
1122 $ed_fragment1
1123 .
1124 /^%setup /a
1125 $ed_fragment2
1126 .
1127 wq
1128 EOF
1129     fi
1130
1131     local linuxrelease=$(find_linux_release "$linux")
1132     $RPMBUILD $BUILD_TYPE --define 'build_kernel_ib 1' --define 'build_kernel_ib_devel 1' \
1133               --define "_topdir ${TOPDIR}" --target ${TARGET_ARCH} \
1134               --define "KVERSION ${linuxrelease}" \
1135               --define "$K_SRC ${linux}" \
1136               --define "LIB_MOD_DIR /lib/modules/${linuxrelease}/updates" \
1137               ${OFA_KERNEL_RELEASE:+--define "_release $OFA_KERNEL_RELEASE"} \
1138               --define "configure_options --without-quilt $OFED_CORE $OFED_HARDWARE $OFED_ISCSI" \
1139               ${SOURCE}
1140
1141     if [ ${PIPESTATUS[0]} != 0 ]; then
1142         fatal 1 "Error building kernel-ib"
1143     fi
1144
1145 }
1146
1147 store_for_reuse() {
1148         local articles="$1"
1149         local module="$2"
1150         local location="$3"
1151         local signature="$4"
1152         local use_links="$5"
1153
1154         local linkflag=""
1155         if $use_links; then
1156             linkflag="l"
1157         fi
1158
1159         location="$location"/"$signature"/"$module"
1160         mkdir -p "$location"
1161         # the cleanup script removes any directory that doesn't have a
1162         # .lastused, so let's try to prevent that as soon as we can
1163         # this solution still slightly racy with the cleanup script
1164         # but the race is a lot tighter now
1165         touch -t 197001010000 "$location/.lastused"
1166         ## use eval/echo here to make sure shell expansions are performed
1167         #if ! cp -a${linkflag} $(eval echo $articles) "$location"; then
1168         local article
1169         for article in $(eval echo $articles); do
1170             if ! cp -a${linkflag} "$article" "$location"; then
1171                 error "Failed to copy \"$article\" to \"$location\" in store_for_reuse()"
1172                 # rename the cache location so that it's not cached
1173                 # product, but is around for analysis
1174                 mv "$location"{,-bad-$(date +%s)} || 
1175                     error "failed to clean up a failed cache attempt" \
1176                           "in \"$location\" -- manual cleanup will be" \
1177                           "necessary"
1178                 return 1
1179             fi
1180         done
1181
1182         # flag the cache as complete (i.e. in case lbuild was previously
1183         # interrupted while caching)
1184         touch "$location/.lastused"
1185
1186         return 0
1187
1188 }
1189
1190 reuse() {
1191     local module="$1"
1192     local dest="$2"
1193     local use_links="${3:-false}"
1194     local signature="$4"
1195
1196     if [ -n "$REUSEBUILD" ] && [ -d "$REUSEBUILD/$signature/$module" ]; then
1197         if [ ! -f "$REUSEBUILD/$signature/$module/.lastused" ]; then
1198             # the .lastused flag is populated at the end of the caching to
1199             # signal that the caching was completed.  if that flag is not
1200             # there, then the cache is invalid (and should be removed in fact) 
1201             mv "$REUSEBUILD/$signature/$module"{,-bad-$(date +%s)} || 
1202                 fatal 1 "failed to clean up a bad cache in location" \
1203                       "\"$REUSEBUILD/$signature/$module\" -- manual cleanup" \
1204                       "will be necessary"
1205             return 1
1206         fi
1207
1208         # so that we know how stale this entry is
1209         touch $REUSEBUILD/$signature/$module/.lastused
1210
1211         if $use_links; then
1212             if ls $REUSEBUILD/$signature/$module/* >/dev/null 2>&1; then
1213                 cp -al $REUSEBUILD/$signature/$module/* $dest/
1214             fi
1215         else
1216             # copying is pretty heavy
1217             # cp -a $REUSEBUILD/$signature/$module/* $dest/
1218             # do some creative symlinking instead
1219             local dir
1220             for dir in BUILD SRPMS SPECS; do
1221                 if ls $REUSEBUILD/$signature/$module/$dir/* >/dev/null 2>&1; then
1222                     ln -s $REUSEBUILD/$signature/$module/$dir/* $dest/$dir
1223                 fi
1224             done
1225             # sources have to be copied by file because we need SOURCES to
1226             # be a dir we can write into
1227 # could overrun ls's arg list here
1228             #ls $REUSEBUILD/$signature/$module/SOURCES/* |
1229             find $REUSEBUILD/$signature/$module/SOURCES/ -type f |
1230                 xargs ln -t $dest/SOURCES -s
1231
1232             # same for RPMS/* dirs
1233 # could overrun ls's arg list here
1234             #ls $REUSEBUILD/$signature/$module/RPMS/$TARGET_ARCH/* |
1235             local dir
1236             for dir in $REUSEBUILD/$signature/$module/RPMS/*; do
1237                 mkdir -p $dest/RPMS/${dir##*/}
1238                 find $dir -type f |
1239                   xargs ln -t $dest/RPMS/${dir##*/} -s
1240             done
1241                      
1242         fi
1243         return 0
1244     else
1245         return 1
1246     fi
1247 }
1248
1249 basearch() {
1250     local arch="$1"
1251
1252     if [[ $arch = i[3456]86 ]]; then
1253         echo "i386"
1254     else
1255         echo "$arch"
1256     fi
1257
1258 }
1259
1260 #
1261 # in a given directory, find the first rpm matching given requirements
1262 #
1263 find_rpm() {
1264     local dir="$1"
1265     local match_type="$2"
1266     local match="$3"
1267
1268     pushd "$dir" > /dev/null || \
1269         fatal 1 "Unable to chdir to directory \"$dir\" in find_rpm()"
1270
1271     local file
1272     for file in $(ls *.rpm); do
1273         if [ ! -f "$file" ]; then
1274             continue
1275         fi
1276         case "$match_type" in
1277             provides)
1278                 # match is any valid ERE (i.e. given to egrep) match
1279                 if rpm -q --provides -p "$file" | egrep -q "$match"; then
1280                     echo "$file"
1281                     popd >/dev/null
1282                     return 0
1283                 fi
1284                 ;;
1285             *)
1286                 popd >/dev/null
1287                 fatal 1 "Unknown match type \"$match_type\" given to find_rpm()"
1288                 ;;
1289         esac
1290     done
1291
1292     popd >/dev/null
1293     return 1
1294 }
1295
1296 build_kernel_with_srpm() {
1297
1298     # need to generate the patch for this target
1299     do_patch_linux false >&2    # sets global $FULL_PATCH (yeah, yuck)
1300
1301     # get an md5sum of the kernel patch + config for reuse check
1302     # XXX really, there needs to be a signature and a CONFIG_FILE per arch
1303     #     in BUILD_ARCHS
1304     local release_str
1305     if $RELEASE; then
1306         local release_str="RELEASE=$RELEASE\n"
1307     fi
1308     local REUSE_SIGNATURE=$({ echo -en $release_str; echo $BUILD_GEN; cat $CONFIG_FILE $TARGET_FILE $FULL_PATCH; } | md5sum | cut -d" " -f1)
1309
1310     # see if we can link to the reuse pool
1311     # XXX - hrm.  i'm not convinced this doesn't belong in the reuse "library"
1312     local CAN_LINK_FOR_REUSE=false
1313     touch $REUSEBUILD/$$
1314     if cp -al $REUSEBUILD/$$ $TOPDIR/; then
1315         CAN_LINK_FOR_REUSE=true
1316     fi
1317     rm $REUSEBUILD/$$
1318
1319     # the extra version string to use for the kernel (which might be a reused
1320     # kernel, remember)
1321     local kernel_extra_version=""
1322     if $REUSERPM && ! reuse kernel "$TOPDIR" "$CAN_LINK_FOR_REUSE" \
1323                                    "$REUSE_SIGNATURE"; then
1324         # nothing cached, build from scratch
1325         if [ ! -r "$KERNELDIR/$KERNEL_SRPM" ]; then
1326             download_srpm "$CANONICAL_TARGET" "$KERNEL_SRPM" >&2
1327         fi
1328
1329         if ! rpm -ivh $KERNELDIR/$KERNEL_SRPM \
1330                   --define "_topdir $TOPDIR" >&2; then
1331             # should we clean this up or leave it for analysis?
1332             #rm -rf $RPMTOPDIR
1333             fatal 1 "Error installing kernel SRPM."
1334         fi
1335
1336         # put the Lustre kernel patch into the RPM build tree
1337         cp $FULL_PATCH $TOPDIR/SOURCES/linux-${lnxmaj}-lustre.patch
1338         prepare_and_build_srpm >&2
1339
1340         # store the resulting kernel RPM build tree for future use
1341         if ! store_for_reuse "$TOPDIR/{SPECS,SOURCES,BUILD,SRPMS,RPMS}" \
1342                              "kernel" "$REUSEBUILD" "$REUSE_SIGNATURE" \
1343                              "$CAN_LINK_FOR_REUSE"; then
1344             error "Failed to store kernel RPMS for reuse"
1345             echo "unknown"
1346             return 1
1347         fi
1348     fi  # build reuse
1349
1350     # figure out the EXTRA_VERSION of the kernel we built or are re-using
1351     local KERNEL_RPM
1352     if ! KERNEL_RPM=$(find_rpm "$TOPDIR/RPMS/$TARGET_ARCH/" provides "^kernel ="); then
1353         fatal 1 "Failed to find a kernel RPM in $TOPDIR/RPMS/$TARGET_ARCH/"
1354     fi
1355     kernel_extra_version=$(rpm -q --queryformat "%{RELEASE}" -p $TOPDIR/RPMS/$TARGET_ARCH/$KERNEL_RPM)
1356
1357     # should now have the following RPMs
1358     # $TOPDIR/RPMS/$arch/kernel-lustre-2.6.18-53.1.21.el5_lustre.1.6.5.1.$arch.rpm
1359     # $TOPDIR/RPMS/$arch/kernel-lustre-devel-2.6.18-53.1.21.el5_lustre.1.6.5.1.$arch.rpm
1360     # $TOPDIR/RPMS/$arch/kernel-lustre-headers-2.6.18-53.1.21.el5_lustre.1.6.5.1.$arch.rpm
1361     # $TOPDIR/RPMS/$arch/kernel-lustre-debuginfo-common-2.6.18-53.1.21.el5_lustre.1.6.5.1.$arch.rpm
1362     # $TOPDIR/RPMS/$arch/kernel-lustre-debuginfo-2.6.18-53.1.21.el5_lustre.1.6.5.1.$arch.rpm
1363
1364     echo $kernel_extra_version
1365     return 0
1366
1367 }
1368
1369 build_mptlinux() {
1370     local linux="$1"
1371     local version="$2"
1372
1373     if [ -z "$version" -o "$version" = "inkernel" ]; then
1374         return 0
1375     fi
1376
1377     local targets arch
1378     for arch in $BUILD_ARCHS; do
1379         targets="--target $arch $targets"
1380     done
1381
1382     local rpmbuildopt='-bb'
1383     if $NORPM; then
1384         rpmbuildopt='-bc'
1385         echo NORPM mode. Only compiling.
1386             fi
1387
1388     # if only we could just rebuild the src.rpm.  but the included spec
1389     # is a real pig's breakfast.  just check out the patch we need to
1390     # apply to it to make it useful.
1391     #$RPMBUILD --rebuild \
1392     #          --define "_topdir ${TOPDIR}" --target ${TARGET_ARCH} \
1393     #          ${TOPDIR}/mptlinux-*.src.rpm
1394     rpm -ivh --define "_topdir ${TOPDIR}" ${TOPDIR}/mptlinux-*.src.rpm
1395
1396     # now the big honkin' patch to the spec file
1397     pushd ${TOPDIR}/SPECS
1398     # to regen this patch use:
1399     # !!cd ~/rpm/SPECS/ && diff -u mptlinux.spec{.dist,}
1400     patch -p0 < ${TOPDIR}/lustre/build/mptlinux.spec.patch || fatal 1 "failed to patch mptlinux.spec"
1401     popd
1402
1403     local targets arch
1404         for arch in $BUILD_ARCHS; do
1405         targets="--target $arch $targets"
1406     done
1407
1408     local rpmbuildopt='-bb'
1409     if $NORPM; then
1410         rpmbuildopt='-bc'
1411         echo NORPM mode. Only compiling.
1412     fi
1413
1414     if ! $RPMBUILD $targets $rpmbuildopt \
1415                   --define "_tmppath /var/tmp" \
1416                   --define "_topdir ${TOPDIR}" \
1417                   --define "kernel_obj $linux" \
1418                   ${TOPDIR}/SPECS/mptlinux.spec; then
1419         return 1
1420     fi
1421     if $DO_SRC; then
1422         if ! $RPMBUILD -bs \
1423                       --define "_tmppath /var/tmp" \
1424                       --define "_topdir ${TOPDIR}" \
1425                       --define "kernel_obj $linux" \
1426                       ${TOPDIR}/SPECS/mptlinux.spec; then
1427             return 1
1428         fi
1429     fi
1430
1431     return 0
1432
1433 }
1434
1435 # build RDAC
1436 build_rdac() {
1437     local linux="$1"
1438     local version="$2"
1439
1440     if [ -z "$version" -o "$version" = "inkernel" ]; then
1441         return 0
1442     fi
1443
1444     # note that we use an _, not a . before the spec on purpose.  we are not
1445     # allowed to have more than one file with a .spec trailer in a tarball
1446     # that is supposed to be usable with rpmbuild
1447     cp lustre/build/rdac_spec ${TOPDIR}/SPECS/rdac.spec || fatal 1 "Could not find rdac.spec in lustre/build" 
1448
1449     local targets arch
1450     for arch in $BUILD_ARCHS; do
1451         targets="--target $arch $targets"
1452     done
1453
1454     local rpmbuildopt='-bb'
1455     if $NORPM; then
1456         rpmbuildopt='-bc'
1457         echo NORPM mode. Only compiling.
1458     fi
1459
1460     local distro
1461     case $DISTRO in
1462      rhel5)     distro="REDHAT"
1463                 ;;
1464     sles1*)     distro="SUSE"
1465                 ;;
1466          *)     echo "$DISTRO not supported by RDAC, skipping"
1467                 return 0
1468                 ;;
1469     esac
1470     if ! $RPMBUILD $targets $rpmbuildopt --define "dist $distro" \
1471                   --define "_tmppath /var/tmp" \
1472                   --define "_topdir ${TOPDIR}" \
1473                   --define "kernel_obj $linux" \
1474                   ${TOPDIR}/SPECS/rdac.spec; then
1475         return 1
1476     fi
1477     if $DO_SRC; then
1478         if ! $RPMBUILD -bs --define "dist $distro" \
1479                       --define "_tmppath /var/tmp" \
1480                       --define "_topdir ${TOPDIR}" \
1481                       --define "kernel_obj $linux" \
1482                       ${TOPDIR}/SPECS/rdac.spec; then
1483             return 1
1484         fi
1485     fi
1486
1487     return 0
1488 }
1489
1490 # build OFED
1491 # globals used:
1492 #    TOPDIR
1493 #    REUSEBUILD, REUSERPM
1494 #    CONFIGURE_FLAGS
1495
1496 build_ofed() {
1497     local linux="$1"
1498     local ofed_version="$2"
1499
1500     # before lustre, build kernel-ib
1501     if [ -z "$ofed_version" -o "$ofed_version" = "inkernel" ]; then
1502         return 0
1503     fi
1504
1505     if [ -n "$REUSEBUILD" ]; then
1506         # see if we can link to the reuse pool
1507             # XXX - hrm.  i'm not convinced this doesn't belong in the reuse
1508             #       "library"
1509         local CAN_LINK_FOR_REUSE=false
1510         touch $REUSEBUILD/$$
1511         if cp -al $REUSEBUILD/$$ $TOPDIR/; then
1512             CAN_LINK_FOR_REUSE=true
1513         fi
1514         rm $REUSEBUILD/$$
1515     fi
1516
1517     local REUSE_SIGNATURE=$({ echo "$ofed_version";
1518                               echo "$(find_linux_release ${linux})";
1519                               cat "${linux}/include/linux/autoconf.h"; } |
1520                             md5sum | cut -d" " -f1)
1521     if ! $REUSERPM || ! reuse ofed "$TOPDIR" "$CAN_LINK_FOR_REUSE" \
1522                         "$REUSE_SIGNATURE"; then
1523             # stash away the existing built articles for a moment
1524             mkdir bak
1525             mv {BUILD,{S,}RPMS,S{OURCE,PEC}S} bak
1526             function mv_back {
1527                 pushd bak
1528                 find . | cpio -pudlm ..
1529                 popd
1530                 rm -rf bak
1531             }
1532             create_rpmbuild_dirs
1533             # build it
1534         build_kernel_ib "${linux}"
1535             if ! store_for_reuse "$TOPDIR/{SPECS,SOURCES,BUILD,SRPMS,RPMS}" \
1536                                  "ofed" "$REUSEBUILD" "$REUSE_SIGNATURE" \
1537                                  "$CAN_LINK_FOR_REUSE"; then
1538                 error "Failed to store OFED RPMS for reuse"
1539                 mv_back
1540                 return 1
1541             fi
1542             # put the stuff we stashed away back
1543             mv_back
1544         fi
1545
1546         pushd "$TOPDIR" >/dev/null
1547         rm -rf kernel-ib-devel
1548         mkdir kernel-ib-devel
1549         cd kernel-ib-devel
1550         # the actual ofed RPMs don't have the -rc$n or -$date string appened that
1551         # might be present on the file
1552         local linuxrelease=$(find_linux_release "$linux")
1553         ofed_version=$(echo $ofed_version |
1554                        sed -re 's/-(20[0-9]{6,6}-[0-9]{4,4}|rc[0-9]*)$//')
1555         local rpm=$(ls $TOPDIR/RPMS/*/kernel-ib-devel-${ofed_version}-${linuxrelease//-/_}.*.rpm)
1556         rpm2cpio -itv < $rpm | cpio -id
1557         CONFIGURE_FLAGS="--with-o2ib=$(pwd)/usr/src/ofa_kernel ${CONFIGURE_FLAGS}"
1558         popd >/dev/null
1559
1560 }
1561
1562 build_with_srpm() {
1563
1564     if ! $PATCHLESS; then
1565         local kernel_extra_version
1566         if ! kernel_extra_version=$(build_kernel_with_srpm); then
1567             fatal 1 "Failed to build the kernel from it's SRPM"
1568         fi
1569
1570         for arch in $BUILD_ARCHS; do
1571             local kernel_devel_rpm
1572             if ! kernel_devel_rpm=$(find_rpm "$TOPDIR/RPMS/$arch/" provides "^$(devel_kernel_name $KERNEL_LUSTRE_NAMING) ="); then
1573                 fatal 1 "Failed to find a kernel development RPM in $TOPDIR/RPMS/$arch/"
1574             fi
1575
1576             # install the -devel RPM in preparation for the lustre build
1577             # note that the EXTRA_VERSION_DELIMITER is *NOT* used in the
1578             # version of the directory name under /usr/src
1579             if ! lnxrel="$kernel_extra_version" unpack_linux_devel_rpm \
1580                            "$TOPDIR/RPMS/$arch/$kernel_devel_rpm" "-"; then
1581                 fatal 1 "Could not find the Linux tree in $TOPDIR/RPMS/$arch/$kernel_devel_rpm"
1582             fi
1583         done
1584     else
1585         # need to find and unpack the vendor's own kernel-devel for patchless
1586         # client build
1587         local kernelrpm
1588         if ! kernelrpm=$(find_linux_rpm "-$DEVEL_KERNEL_TYPE" ${EXTRA_VERSION_DELIMITER:-"-"}); then
1589             fatal 1 "Could not find the kernel-$DEVEL_KERNEL_TYPE RPM in ${KERNELRPMSBASE}/${lnxmaj}/${DISTRO}"
1590         fi
1591         if ! lnxrel="$lnxrel" unpack_linux_devel_rpm "$kernelrpm" "-"; then
1592             fatal 1 "Could not find the Linux tree in $kernelrpm"
1593         fi
1594     fi
1595
1596     build_ofed "${LINUXOBJ:-$LINUX}" "$OFED_VERSION" ||
1597         fatal 1 "error building OFED"
1598
1599     build_rdac "${LINUXOBJ:-$LINUX}" "$RDAC_VERSION" || 
1600         fatal 1 "error building RDAC"
1601
1602     build_mptlinux "${LINUXOBJ:-$LINUX}" "$MPTLINUX_VERSION" ||
1603         fatal 1 "error building mptlinux"
1604
1605     # now build Lustre
1606     if build_lustre "$LINUX" "$LINUXOBJ"; then
1607         # the build worked.  resolve any symlinked files (i.e. from reuse)
1608         # in RPMS/$arch to real files so that that that huge mess of
1609         # complication known as LTS can copy them yet somewhere else.
1610         # is it any wonder this whole process is so damn so?  anyone ever
1611         # heard of hardlinks?  it this cool new thing that allows you save
1612         # tons of time and space by creating... well you can go read about
1613         # them if you have not heard about them yet.
1614         # can i say how much the implemenation of all of this really impedes
1615         # RPM reuse?
1616         pushd RPMS/$TARGET_ARCH
1617             for file in *; do
1618                 if [ -h $file ]; then
1619                     cp $file foo
1620                     mv foo $file
1621                 fi
1622             done
1623         popd
1624     else
1625         return 1
1626     fi
1627
1628 }
1629
1630 create_rpmbuild_dirs() {
1631
1632     [ -d RPMS ] || mkdir RPMS
1633     for arch in $BUILD_ARCHS; do
1634         if [[ $arch = i?86 ]]; then
1635             # some stupidity in the sles11 kernel spec requires an RPMS/i386
1636             # even if the target arch is i686
1637             [ -d RPMS/i386 ] || mkdir RPMS/i386
1638         fi
1639         [ -d RPMS/$arch ] || mkdir RPMS/$arch
1640     done
1641     [ -d BUILD ] || mkdir BUILD
1642     [ -d SOURCES ] || mkdir SOURCES
1643     [ -d SPECS ] || mkdir SPECS
1644     [ -d SRPMS ] || mkdir SRPMS
1645
1646 }
1647
1648 new_list() {
1649
1650     echo ""
1651
1652 }
1653
1654 add_list() {
1655     local list="$1"
1656     local item="$2"
1657
1658     echo "$list $item"
1659
1660 }
1661
1662 is_list_member() {
1663     local list="$1"
1664     local item="$2"
1665
1666     [[ $list\  == *\ $item\ * ]]
1667
1668 }
1669
1670 #########################################################################
1671 # Generate a backtrace through the call stack.
1672 #
1673 # Input: None
1674 # Output: None
1675 #########################################################################
1676 backtrace() {
1677     local strip=${1:-1}
1678
1679     local funcname="" sourcefile="" lineno="" n
1680
1681     echo "Call stack: (most recent first)"
1682     for (( n = $strip ; n < ${#FUNCNAME[@]} ; ++n )) ; do
1683         funcname=${FUNCNAME[$n - 1]}
1684         sourcefile=$(basename ${BASH_SOURCE[$n]})
1685         lineno=${BASH_LINENO[$n - 1]}
1686         # Display function arguments
1687         if [[ ! -z "${BASH_ARGV[@]}" ]]; then
1688             local args newarg j p=0
1689             for (( j = ${BASH_ARGC[$n - 1]}; j > 0; j-- )); do
1690                 newarg=${BASH_ARGV[$j + $p - 1]}
1691                 args="${args:+${args} }'${newarg}'"
1692             done
1693             let p+=${BASH_ARGC[$n - 1]}
1694         fi
1695         echo "  ${funcname} ${args:+${args} }at ${sourcefile}:${lineno}"
1696     done
1697
1698     echo
1699     echo "BEGIN BACKTRACE"
1700
1701     #echo ${BASH_LINENO[*]}
1702     #echo ${BASH_SOURCE[*]}
1703     #echo ${FUNCNAME[*]}
1704     local i=$((${#FUNCNAME[@]} - 1))
1705     while [ $i -ge 0 ]; do
1706         local SOURCELINE="${BASH_SOURCE[$i + 1]}:${BASH_LINENO[$i]}"
1707         # Can't figure out how to get function args from other frames...
1708         local FUNCTION="${FUNCNAME[$i]}()"
1709         echo "$SOURCELINE:$FUNCTION"
1710         i=$((i - 1))
1711     done
1712
1713     echo "END BACKTRACE"
1714
1715     echo $BACKTRACE
1716
1717 }
1718
1719 [ -r ~/.lbuildrc ] && . ~/.lbuildrc
1720
1721 options=$(getopt -o d:D:h -l kerneltree:,distro:,kernelrpm:,reusebuild:,patchless,ldiskfs,ccache,reuse:,norpm,disable-datestamp,external-patches:,timestamp:,extraversion:,kerneldir:,linux:,lustre:,nodownload,nosrc,ofed-version:,publish,release,src,stage:,tag:,target:,target-archs:,with-linux:,xen -- "$@")
1722
1723 if [ $? != 0 ]; then
1724     usage 1
1725 fi
1726
1727 eval set -- "$options"
1728
1729 while [ "$1" ]; do
1730     case "$1" in
1731         '')
1732             usage 1
1733             ;;
1734         --ccache)
1735             CCACHE='ccache'
1736             shift
1737             ;;
1738         -d)
1739             CVSROOT=$2
1740             shift 2
1741             ;;
1742         -D)
1743             DATE=$2
1744             shift 2
1745             ;;
1746         --external-patches)
1747             EXTERNAL_PATCHES=$2
1748             shift 2
1749             ;;
1750         --extraversion)
1751             EXTRA_VERSION=$2
1752             shift 2
1753             ;;
1754         --help | -h)
1755             usage 0
1756             ;;
1757         --kerneldir)
1758             KERNELDIR=$2
1759             shift 2
1760             ;;
1761         --kerneltree)
1762             if ! KERNELTREE=$(canon_path "$2"); then
1763                 fatal 1 "Could not determine the canonical location of $2"
1764             fi
1765             shift 2
1766             ;;
1767         --linux | --with-linux)
1768             if ! LINUX=$(canon_path "$2"); then
1769                 fatal 1 "Could not determine the canonical location of $2"
1770             fi
1771             shift 2
1772             ;;
1773         --distro)
1774             DISTRO=$2
1775             shift 2
1776             ;;
1777         --reuserpm)
1778             REUSERPM=$2
1779             shift 2
1780             ;;
1781         --reusebuild)
1782             if ! REUSEBUILD=$(canon_path "$2"); then
1783                 fatal 1 "Could not determine the canonical location of $2"
1784             fi
1785             shift 2
1786             ;;
1787         --norpm)
1788             NORPM=true
1789             shift
1790             ;;
1791         --ldiskfs)
1792             LDISKFSRPM=true
1793             shift
1794             ;;
1795         --patchless)
1796             PATCHLESS=true
1797             shift
1798             ;;
1799         --kernelrpm)
1800             if ! KERNELRPMSBASE=$(canon_path "$2"); then
1801                 fatal 1 "Could not determine the canonical location of $2"
1802             fi
1803             shift 2
1804             ;;
1805         --timestamp)
1806             TIMESTAMP=$2
1807             shift 2
1808             ;;
1809         --lustre)
1810             LUSTRE=$2
1811             shift 2
1812             ;;
1813         --nodownload)
1814             DOWNLOAD=false
1815             shift 1
1816             ;;
1817         --nosrc)
1818             DO_SRC=false
1819             shift 1
1820             ;;
1821         --ofed-version)
1822             OFED_VERSION="$2"
1823             shift 2
1824             ;;
1825         --publish)
1826             shift
1827             ;;
1828         --release)
1829             RELEASE=true
1830             shift
1831             ;;
1832         --src)
1833             DO_SRC=true
1834             shift 1
1835             ;;
1836         --stage)
1837             STAGEDIR=$2
1838             shift 2
1839             ;;
1840         --tag)
1841             TAG=$2
1842             shift 2
1843             ;;
1844         --target)
1845             TARGET=$2
1846             shift 2
1847             ;;
1848         --target-archs)
1849             TARGET_ARCHS=$2
1850             shift 2
1851             ;;
1852         --disable-datestamp)
1853             USE_DATESTAMP=
1854             shift
1855             ;;
1856         --xen)
1857             XEN=true
1858             shift
1859             ;;
1860         --)
1861             shift
1862             CONFIGURE_FLAGS=$@
1863             CONFIGURE_FLAGS="$CONFIGURE_FLAGS --enable-liblustre --enable-liblustre-tests"
1864             break
1865             ;;
1866         *)
1867             usage 1 "Unrecognized option: $1"
1868             ;;
1869     esac
1870 done
1871
1872 check_options
1873
1874 unpack_lustre
1875
1876 load_target
1877 EXTRA_VERSION_DELIMITER=${EXTRA_VERSION_DELIMITER:-"-"}
1878
1879 if [ -n "$OFED_VERSION" -a "$OFED_VERSION" != "inkernel" ]; then
1880     download_ofed
1881     unpack_ofed || fatal 1 "Error unpacking OFED tarball"
1882 fi
1883
1884 if [ -n "$MPTLINUX_VERSION" -a "$MPTLINUX_VERSION" != "inkernel" ]; then
1885     download_mptlinux
1886     unpack_mptlinux || fatal 1 "Error unpacking MPTLINUX distribution"
1887 fi
1888
1889 # make sure the RPM build environment is set up
1890 create_rpmbuild_dirs
1891
1892 if [ -n "$RDAC_VERSION" -a "$RDAC_VERSION" != "inkernel" ]; then
1893     download_rdac
1894     # we don't actually need to unpack this.  just put it in the SOURCES dir
1895     #unpack_rdac || fatal 1 "Error unpacking RDAC tarball"
1896     cp "$KERNELTREE/rdac-LINUX-${RDAC_VERSION}-source.tar.gz" ${TOPDIR}/SOURCES/ ||
1897         fatal 1 "Error copying RDAC source tarball to RPM SOURCES dir"
1898 fi
1899
1900 push_exit_trap '[ -n "$CCACHE" ] && ccache -s' "ccache_summary"
1901 # should remove the ccache trap if lbuild is interrupted
1902 trap 'delete_exit_trap "ccache_summary"; exit 1' INT TERM HUP
1903
1904 # if an unpacked kernel source tree was given on the command line
1905 # just build lustre with it (nothing distro kernel specific here)
1906 if [ -n "$LINUX" ]; then
1907     build_mptlinux "${LINUXOBJ:-$LINUX}" "$MPTLINUX_VERSION" ||
1908         fatal 1 "error building mptlinux"
1909     build_ofed "${LINUXOBJ:-$LINUX}" "$OFED_VERSION" ||
1910         fatal 1 "error building OFED"
1911     build_rdac "${LINUXOBJ:-$LINUX}" "$RDAC_VERSION" ||
1912         fatal 1 "error building RDAC"
1913     build_lustre "$LINUX" "$LINUXOBJ"
1914 else
1915     if [ -f "${0%/*}/lbuild-$DISTRO" ]; then
1916         seen_list=$(new_list)
1917         trap '(echo "Untrapped error"
1918 echo
1919 # have we seen this one
1920 echo "checking seen list for ${BASH_SOURCE[0]}:${BASH_LINENO[0]}"
1921
1922 if is_list_member "$seen_list" "${BASH_SOURCE[0]}:${BASH_LINENO[0]}"; then
1923   echo "seen this one already"
1924 else
1925   seen_list=$(add_list "$seen_list" "${BASH_SOURCE[0]}:${BASH_LINENO[0]}")
1926 fi
1927 backtrace
1928 echo
1929 echo "Environment:"
1930 set
1931 ) | tee >(mail -s "Untrapped error at ${BASH_SOURCE[0]##*/}:${BASH_LINENO[0]} on $HOSTNAME" brian@sun.com) >&2' ERR
1932         set -E
1933
1934         source ${0%/*}/lbuild-$DISTRO
1935
1936         build_with_srpm || fatal 1 "Failed to build_with_srpm"
1937     else
1938         source ${0%/*}/lbuild.old_school
1939
1940         old_school_download_kernel
1941
1942         build_success=false
1943         if $PATCHLESS; then
1944             patchless_build_sequence && build_success=true
1945         else
1946             [ "$DISTRO" = "sles9" ] && build_sequence_rpm_reuse && build_success=true
1947             if ! $build_success; then
1948                 build_sequence_reuse && build_success=true
1949                 if ! $build_success; then
1950                     build_sequence && build_success=true
1951                     if $build_success; then
1952                         store_for_reuse || echo "Cannot store for future reuse"
1953                     fi
1954                 fi
1955             fi
1956         fi
1957         ( $build_success ) || fatal 1 "Cannot build lustre"
1958     fi
1959 fi
1960
1961 stage