TODO file added with some ideas.
[febootstrap.git] / febootstrap.sh
1 #!/bin/bash -
2 # febootstrap
3 # (C) Copyright 2009 Red Hat Inc.
4 #
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2 of the License, or
8 # (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 #
19 # Written by Richard W.M. Jones <rjones@redhat.com>
20
21 TEMP=`getopt \
22         -o g:i: \
23         --long groupinstall:,group-install:,help,install:,noclean,no-clean \
24         -n febootstrap -- "$@"`
25 if [ $? != 0 ]; then
26     echo "febootstrap: problem parsing the command line arguments"
27     exit 1
28 fi
29 eval set -- "$TEMP"
30
31 declare -a packages
32 packages[0]="@Core"
33 i=0
34
35 clean=yes
36
37 usage ()
38 {
39     echo "Usage: febootstrap [--options] REPO TARGET [MIRROR]"
40     echo "Please read febootstrap(8) man page for more information."
41 }
42
43 while true; do
44     case "$1" in
45         -i|--install)
46             packages[i++]="$2"
47             shift 2;;
48         --groupinstall|--group-install)
49             packages[i++]="@$2"
50             shift 2;;
51         --noclean|--no-clean)
52             clean=no
53             shift;;
54         --help)
55             usage
56             exit 0;;
57         --)
58             shift
59             break;;
60         *)
61             echo "Internal error!"
62             exit 1;;
63     esac
64 done
65
66 if [ $# -lt 2 -o $# -gt 3 ]; then
67     usage
68     exit 1
69 fi
70
71 repo="$1"
72 target="$2"
73 mirror="$3"
74
75 # Architecture is currently always the same as the current arch.  We
76 # cannot do --foreign builds.  See discussion in the manpage.
77 arch=$(arch)
78 case $arch in
79     i?86) arch=i386 ;;
80 esac
81
82 # Create a temporary directory, make sure it gets cleaned up at the end.
83 tmpdir=$(mktemp -d)
84 remove_tmpdir ()
85 {
86   status=$?
87   rm -rf "$tmpdir" && exit $status
88 }
89 trap remove_tmpdir EXIT
90
91 # Create the temporary repository configuration.  The name of the
92 # repository is always 'febootstrap'.
93 cat > $tmpdir/febootstrap.repo <<__EOF__
94 [febootstrap]
95 name=febootstrap $repo $arch
96 failovermethod=priority
97 enabled=1
98 gpgcheck=0
99 __EOF__
100
101 # "Mirror" parameter is a bit misnamed, but it means a local mirror,
102 # instead of the public Fedora mirrors.
103 if [ -n "$mirror" ]; then
104     echo "baseurl=$mirror" >> "$tmpdir"/febootstrap.repo
105 else
106     echo "mirrorlist=http://mirrors.fedoraproject.org/mirrorlist?repo=$repo&arch=$arch" >> "$tmpdir"/febootstrap.repo
107 fi
108
109 # Create the target filesystem.
110 rm -rf "$target"
111 mkdir "$target"
112
113 # Target must be an absolute path.
114 target=$(cd "$target"; pwd)
115
116 # This is necessary to keep yum happy.  It's not clear why yum can't
117 # just create this file itself.
118 mkdir -p "$target"/var/cache/yum/febootstrap/packages
119
120 # NB: REQUIRED for useradd/groupadd to run properly.
121 #
122 # However this causes 'filesystem' RPM install to give the
123 # following error.  Not sure how serious the error is:
124 # error: unpacking of archive failed on file /proc: cpio: utime
125 export FAKECHROOT_EXCLUDE_PATH=/proc
126
127 # Make the device nodes inside the fake chroot.
128 # (Copied from mock/backend.py)  Why isn't there a base package which
129 # creates these?
130 make_device_nodes ()
131 {
132     mkdir "$target"/proc
133     mkdir "$target"/sys
134     mkdir "$target"/dev
135     (
136         cd "$target"/dev
137         mkdir pts
138         mkdir shm
139         mkdir mapper
140         mknod null c 1 3;    chmod 0666 null
141         mknod full c 1 7;    chmod 0666 full
142         mknod zero c 1 5;    chmod 0666 zero
143         mknod random c 1 8;  chmod 0666 random
144         mknod urandom c 1 9; chmod 0444 urandom
145         mknod tty c 5 0;     chmod 0666 tty
146         mknod console c 5 1; chmod 0600 console
147         mknod ptmx c 5 2;    chmod 0666 ptmx
148         ln -sf /proc/self/fd/0 stdin
149         ln -sf /proc/self/fd/1 stdout
150         ln -sf /proc/self/fd/2 stderr
151     )
152 }
153 export -f make_device_nodes
154 export target
155
156 if [ $(id -u) -ne 0 ]; then
157     fakeroot -s "$target"/fakeroot.log \
158     make_device_nodes
159 else
160     make_device_nodes
161 fi
162
163 # Run yum.
164 run_yum ()
165 {
166     yum \
167         -y -c "$tmpdir"/febootstrap.repo \
168         --disablerepo=* --enablerepo=febootstrap \
169         --noplugins --nogpgcheck \
170         --installroot="$target" \
171         install "$@"
172 }
173 export -f run_yum
174 export tmpdir
175
176 if [ $(id -u) -ne 0 ]; then
177     # Bash doesn't support exporting array variables, hence this
178     # tortuous workaround.
179     fakeroot -i "$target"/fakeroot.log -s "$target"/fakeroot.log \
180     fakechroot -s \
181     bash -c 'run_yum "$@"' run_yum "${packages[@]}"
182 else
183     run_yum "${packages[@]}"
184 fi
185
186 # Clean up the yum repository.
187 if [ "$clean" = "yes" ]; then
188     rm -rf "$target"/var/cache/yum/febootstrap
189 fi