oops
[build.git] / mkfedora
1 #!/bin/bash
2 #
3 # Builds a Fedora reference image. Requires the build server to
4 # host a local yum repository in one of:
5 #
6 # /usr/share/mirrors/fedora
7 # /var/www/html/mirrors/fedora
8 #
9 # Otherwise, tries using CoBlitz:
10 #
11 # http://coblitz.planet-lab.org/pub/fedora
12 #
13 # Mark Huang <mlhuang@cs.princeton.edu>
14 # Copyright (C) 2004-2006 The Trustees of Princeton University
15 #
16 # $Id$
17 #
18
19 # for pkgs parsing functions
20 . build.common
21
22 export PATH=/sbin:/bin:/usr/sbin:/usr/bin
23
24 function mkfedora_usage()
25 {
26     echo "Usage: mkfedora [OPTION]... [basedir]"
27     echo "      -l url          Fedora mirror location. Defaults to try:"
28     for mirror in "${mirrors[@]}" ; do
29         echo "                  $mirror"
30     done
31     echo "      -f pkgsfile     use this pkgs file for packages, groups, excludes.."
32     echo "      -k              Exclude kernel* packages from all repositories except bootstrap"
33     echo "      -v              Be verbose"
34     echo "      -h              This message"
35     echo " target selection (defaults based on current build vserver)"
36     echo "      -r release      Fedora release number (default: $releasever)"
37     echo "      -a arch         Fedora architecture (default: $basearch)"
38     echo " legacy (use -f instead)"
39     echo "      -g group1 -g group2 ..."
40     echo "                      Yumgroups to install (default: none)"
41     echo "      -p package1 -p package2 ..."
42     echo "                      Additional packages to install (default: none)"
43     echo "      -x package1 -x package2 ..."
44     echo "                      Packages to exclude (default: none)"
45     exit 1
46 }
47
48 function mkfedora () {
49
50 echo "* Entering mkfedora " "$@"
51
52 # Verbosity
53 verbose=0
54
55 # Default yum repositories to try
56 mirrors=(
57 file:///data/fedora
58 http://localhost/fedora
59 http://build.planet-lab.org/fedora
60 http://coblitz.codeen.org/coblitz.planet-lab.org/pub/fedora
61 ftp://mirror.cs.princeton.edu/pub/mirrors/fedora
62 ftp://mirror.stanford.edu/pub/mirrors/fedora
63 ftp://rpmfind.net/linux/fedora
64 )
65
66 # Release and architecture to install
67 releasever=7
68 basearch=i386
69
70 # Yum groups to install
71 groups=()
72
73 # Packages to install
74 packages=()
75
76 # Packages to exclude
77 exclude=()
78
79 # Exclude kernel* (and related) packages from all repositories except bootstrap
80 exclude_kernel=
81
82 # PlanetLab development environment
83 if [ -f /etc/planetlab/plc_config ] ; then
84     . /etc/planetlab/plc_config
85     if [ -n "$PLC_DEVEL_FEDORA_URL" ] ; then
86         echo "* mkfedora : setting mirrors from /etc/planetlab/config"
87         mirrors=($PLC_DEVEL_FEDORA_URL)
88     fi
89 fi
90
91 # Get options
92 while getopts "l:r:a:g:p:x:f:kvh" opt ; do
93     case $opt in
94         l)
95             if echo $OPTARG | grep -q -i '^\(file\|http[s]*\)://' ; then
96                 mirrors=($OPTARG)
97             else
98                 mirrors=(file://$OPTARG)
99             fi
100             ;;
101         r)
102             releasever=$OPTARG
103             ;;
104         a)
105             basearch=$OPTARG
106             ;;
107         g)
108             groups[${#groups[*]}]="$OPTARG"
109             ;;
110         p)
111             packages[${#packages[*]}]="$OPTARG"
112             ;;
113         x)
114             exclude[${#exclude[*]}]="$OPTARG"
115             ;;
116         f)
117             pkgsfile=$OPTARG
118             ;;
119         k)
120             exclude_kernel="exclude=kernel* ulogd iptables"
121             ;;
122         v)
123             verbose=1
124             set -x
125             ;;
126         h|*)
127             mkfedora_usage
128             ;;
129     esac
130 done
131
132 shift $(($OPTIND - 1))
133 if [ ! -d "$1" ] ; then
134     mkfedora_usage
135 fi
136
137 vroot=$(cd $1 && pwd -P)
138
139 if [ $UID -ne 0 ] ; then
140     echo "Error: You must run this script as root."
141     exit 1
142 fi
143
144 function mkfedora_fetch ()
145 {
146     curl --fail --silent --max-time 60 "$1"
147 }
148
149 # hard to find two mirrors with a similar layout
150 # set list of attempted locations according to releasever
151 if [ $releasever -ge 7 ] ; then
152     attempts="
153 linux/releases/$releasever/Everything/$basearch/os
154 $releasever/Everything/$basearch/os
155 core/$releasever/Everything/$basearch/os
156 linux/core/$releasever/$basearch/os
157 "
158 else
159     attempts="
160 linux/core/$releasever/$basearch/os 
161 core/$releasever/$basearch/os 
162 $releasever/$basearch/os
163 "
164 fi
165
166 echo "$0: candidate mirrors"
167 for mirror in "${mirrors[@]}" ; do
168     echo "* candidate mirror $mirror"
169 done
170 baseurl=""
171 for mirror in "${mirrors[@]}" ; do
172     for attempt in $attempts; do 
173         attempturl=$mirror/$attempt
174         if mkfedora_fetch $attempturl/repodata/repomd.xml >/dev/null ; then
175             baseurl=$attempturl
176             break 2
177         fi
178     done
179 done
180
181 if [ -z "$baseurl" ] ; then
182     echo "Error: $releasever/$basearch/os/repodata/repomd.xml"
183     echo "       could not be found in any of the following locations:"
184     echo
185     for mirror in ${mirrors[@]} ; do
186         for attempt in $attempts ; do
187             echo $mirror/$attempt
188         done
189     done
190     echo
191     mkfedora_usage
192 fi
193
194 # this used to be for when mkfedora was called within myplc 
195 # that is, when the bootcd was recomputed from scratch
196 ### exec 3>&1
197 ### exec 4>&2
198 ### if [ $verbose -eq 0 ] ; then
199 ###     exec 1>/dev/null
200 ###     exec 2>/dev/null
201 ### fi
202
203 # Do not tolerate errors
204 set -e
205
206 ## make rpms ignore installing stuff to special fs entries like /proc
207 # Because of https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=52725
208 # you have to use at least one language beside 'C'
209 # Prevent all locales from being installed in reference image
210 mkdir -p $vroot/etc/rpm
211 cat > $vroot/etc/rpm/macros <<EOF
212 %_install_langs C:en_US:en
213 %_netsharedpath /proc:/dev/pts
214 %_excludedocs 1
215 %__file_context_path /dev/null
216 EOF
217
218 # Trick rpm and yum, who read the real root /etc/rpm/macros file
219 # rather than the one installed in the reference image, despite what
220 # you might expect the --root and --installroot options to mean. Both
221 # programs always read $HOME/.rpmmacros.
222 export HOME=$vroot/tmp
223 mkdir -p $vroot/tmp
224 cp $vroot/etc/rpm/macros $vroot/tmp/.rpmmacros
225
226 ### Checking whether this is really needed
227 ### # copy to the vserver's rpm macros
228 ### # xxx fixme - this must be reviewed once we get the stuff running
229 ### cp $vroot/etc/rpm/macros /etc/rpm/macros 
230
231 # Mount in reference image
232 mount -t devpts none $vroot/dev/pts
233 mount -t tmpfs none $vroot/dev/shm
234 mkdir -p $vroot/proc
235 mount -t proc none $vroot/proc
236
237 function mkfedora_cleanup ()
238 {
239     umount -l $vroot/proc
240     umount -l $vroot/dev/shm
241     umount -l $vroot/dev/pts
242 }
243
244 # Clean up before exiting if anything goes wrong
245 trap "mkfedora_cleanup" ERR INT
246
247 # Create a /var/lib dirs for yum & rpm
248 mkdir -p $vroot/var/lib/yum
249 mkdir -p $vroot/var/lib/rpm
250 mkdir -p $vroot/usr/share/info
251
252 # Create a dummy /etc/fstab in reference image
253 mkdir -p $vroot/etc
254 cat >$vroot/etc/fstab <<EOF
255 # This fake fstab exists only to please df and linuxconf.
256 /dev/hdv1       /       ext2    defaults        1 1
257 EOF
258 cp $vroot/etc/fstab $vroot/etc/mtab
259
260 # Necessary for some scripts
261 mkdir -p $vroot/etc/sysconfig
262 echo "NETWORKING=yes" > $vroot/etc/sysconfig/network
263
264 # Initialize RPM database in reference image
265 mkdir -p $vroot/var/lib/rpm
266 rpm --root $vroot --initdb
267 rpm --root $vroot --import $baseurl/RPM-GPG-KEY-fedora
268
269 # Initialize yum in reference image
270 mkdir -p $vroot/var/cache/yum $vroot/var/log
271 if [ $releasever -lt 7 ] ; then
272         corename="Core "
273 else
274         corename=""
275 fi
276
277 cat >$vroot/etc/yum.conf <<EOF
278 [main]
279 cachedir=/var/cache/yum
280 debuglevel=2
281 logfile=/var/log/yum.log
282 pkgpolicy=newest
283 distroverpkg=redhat-release
284 tolerant=1
285 exactarch=1
286 retries=20
287 obsoletes=1
288 gpgcheck=0
289 # Prevent yum-2.4 from loading additional repository definitions
290 # (e.g., from /etc/yum.repos.d/)
291 reposdir=/dev/null
292
293 [base]
294 name=Fedora ${corename}${releasever} - $basearch - base
295 baseurl=$baseurl/
296 $exclude_kernel
297 EOF
298
299 for optional in updates extras ; do
300     for optionalurl in \
301         $mirror/linux/core/$optional/$releasever/$basearch \
302         $mirror/core/$optional/$releasever/$basearch \
303         $mirror/linux/$optional/$releasever/$basearch \
304         $mirror/$optional/$releasever/$basearch ; do
305         if mkfedora_fetch $optionalurl/repodata/repomd.xml ; then
306             cat >>$vroot/etc/yum.conf <<EOF
307
308 [$(basename $optional)]
309 name=Fedora ${corename}${releasever} - $basearch - $(basename $optional)
310 baseurl=$optionalurl/
311 $exclude_kernel
312 EOF
313             break
314         fi
315     done
316 done
317
318 # If we are being built as part of an automated RPM build, solve the
319 # bootstrap problem by including any just built packages in the yum
320 # configuration. This cooperates with the PlanetLab build system.
321 if [ -n "$RPM_BUILD_DIR" ] ; then
322     RPM_RPMS_DIR=$(cd $(dirname $RPM_BUILD_DIR)/RPMS && pwd -P)
323     # yum-2.0.x
324     if [ -x /usr/bin/yum-arch ] ; then
325         yum-arch -q $RPM_RPMS_DIR
326     fi
327     # yum-2.4.x
328     if [ -x /usr/bin/createrepo ] ; then
329         if [ -f $RPM_RPMS_DIR/yumgroups.xml ] ; then
330             groupfile="-g yumgroups.xml"
331         fi
332         createrepo --quiet $groupfile $RPM_RPMS_DIR
333     fi
334     # If run under sudo, allow user to delete the headers/ and
335     # repodata/ directories.
336     if [ -n "$SUDO_USER" ] ; then
337         chown -R $SUDO_USER $RPM_RPMS_DIR
338     fi
339     cat >>$vroot/etc/yum.conf <<EOF
340
341 [bootstrap]
342 name=Bootstrap - $basearch - $RPM_RPMS_DIR/
343 baseurl=file://$RPM_RPMS_DIR/
344 EOF
345 fi
346
347 # pkgs file
348 if [ -n "$pkgsfile" ] ; then
349     # parse pkgsfile and add to local vars
350     fcdistro=$(pl_getReleaseName "Fedora" $releasever)
351     for i in $(pl_parsePkgs package $fcdistro $pkgsfile)  ; do
352         packages[${#packages[*]}]="$i"
353     done
354     for i in $(pl_parsePkgs group $fcdistro $pkgsfile) ; do
355         groups[${#groups[*]}]="$i"
356     done
357     for i in $(pl_parsePkgs exclude $fcdistro $pkgsfile) ; do
358         exclude[${#exclude[*]}]="$i"
359     done
360     junk=$(pl_parsePkgs junk $fcdistro $pkgsfile)
361     precious=$(pl_parsePkgs precious $fcdistro $pkgsfile)
362 fi
363
364 excludes=
365 for package in "${exclude[@]}" ; do
366     excludes="$excludes --exclude=$package"
367 done
368
369 # glibc must be specified explicitly for the correct arch to be
370 # chosen.
371 echo "* Installing glibc"
372 yum -c $vroot/etc/yum.conf --installroot=$vroot -y $excludes install glibc
373
374 # Go, baby, go
375 if [ ${#packages[*]} -gt 0 ] ; then
376    echo "* Installing optional packages" "${packages[@]}" 
377    yum -c $vroot/etc/yum.conf --installroot=$vroot -y $excludes \
378           install "${packages[@]}"
379    if ! rpm --root $vroot -q "${packages[@]}" >/dev/null ; then
380        echo "* Warning: Missing packages"
381        rpm --root $vroot -q "${packages[@]}" | grep "not installed"
382    fi
383 fi
384
385 if [ ${#groups[*]} -gt 0 ] ; then
386    ## call yum sequentially to get finer-grained info on dependencies
387    for grp in "${groups[@]}" ; do
388       echo "* Installing optional group $grp" 
389       yum -c $vroot/etc/yum.conf --installroot=$vroot -y $excludes \
390         groupinstall "$grp"
391    done
392 fi
393
394 # FC2 dev %preinstall checks /proc/mounts to make sure that /dev is
395 # not currently mounted as devfs. If it thinks it is, it will refuse
396 # to install the package. On a modern system running udev that mounts
397 # /dev as tmpfs, this check fails. Since we are installing into a
398 # chroot, whether /dev is mounted on the host system or not doesn't
399 # matter. If dev was explicitly mentioned in the packages list, force
400 # its installation.
401 if [ "$releasever" = "2" ] ; then
402     for package in "${packages[@]}" ; do
403         if [ "$package" = "dev" ] && ! rpm --root $vroot -q dev >/dev/null 2>&1 ; then
404             rpm --root $vroot -Uvh --noscripts $baseurl/Fedora/RPMS/dev-3.3.13-1.i386.rpm
405             break
406         fi
407     done
408 fi
409
410 # Clean yum cache
411 echo "* Cleaning up"
412 yum -c $vroot/etc/yum.conf --installroot=$vroot -y clean all
413
414 # Clean RPM state
415 rm -f $vroot/var/lib/rpm/__db*
416
417 # Set time zone to UTC
418 if [ -f $vroot/usr/share/zoneinfo/UTC -a -f $vroot/etc/localtime ] ; then
419     rm -f $vroot/etc/localtime
420     ln -s /usr/share/zoneinfo/UTC $vroot/etc/localtime
421 fi
422
423 # formerly in bootcd/prep.sh : to optimize footprint
424 echo "* Removing unnecessary junk"
425
426 pushd $vroot
427
428 # Save precious files
429 [ -n "$precious" ] && tar --ignore-failed-read -cpf precious.tar $precious
430
431 # Remove unnecessary junk
432 [ -n "$junk" ] && rm -rf $junk
433
434 # Restore precious files
435 [ -n "$precious" ] && tar -xpf precious.tar && rm -f precious.tar
436
437 popd
438
439 # remove trap handler, as we are about to call it directly.
440 trap - ERR INT
441
442 # Clean up
443 mkfedora_cleanup
444
445 return 0
446 }
447
448 mkfedora "$@"