root/manageBE/create-zfsboot-gpt_livecd.sh

Revision 108, 10.6 KB (checked in by cryx, 3 weeks ago)

Wrong position.

Line 
1#!/bin/sh
2# Philipp Wuensche
3# This script is considered beer ware (http://en.wikipedia.org/wiki/Beerware)
4#
5# DISCLAIMER: Use at your own risk! Always make backups, don't blame me if this renders your system unusable or you lose any data!
6#
7# This only works with FreeBSD 8.0 (tested with 8.0-RELEASE), you have been warned!
8#
9# Startup the FreeBSD livefs CD. Go into the Fixit console. Create /var/db if you want to use DHCP. Configure
10# your network settings. Fetch http://anonsvn.h3q.com/s/gpt-zfsroot.sh
11# Execute the script with the following parameter:
12#
13# -p sets the geom provider to use, you can use multiple. Add a name for the GPT labels: -p ad4=black -p ad6=white
14# -s sets the swap_partition_size to create, you can use m/M for megabyte or g/G for gigabyte
15# -S sets the zfs_partition_size to create, you can use m/M for megabyte or g/G for gigabyte, default is all available size
16# -n sets the name of the zpool to create
17# -f sets the ftp-server used for getting the freebsd packages, default is ftp.freebsd.org
18# -m sets the zpool raid-mode, stripe (only single disk), mirror (at least two disks) and raidz (at least three disks)
19# -d sets local directory to get distribution packages from
20#
21# You can use more than one device, creating a mirror. To specify more than one device, use multiple -p options.
22# eg. create-zfsboot-gpt_livecd.sh -p ad0 -p ad1 -s 512m -n tank
23
24ftphost='ftp.freebsd.org'
25
26usage="Usage: create-zfsboot-gpt_livecd.sh -p <geom_provider> -s <swap_partition_size> -S <zfs_partition_size> -n <zpoolname> -m <zpool-raidmode> -d <distdir> -f <ftphost>"
27
28exerr () { echo -e "$*" >&2 ; exit 1; }
29
30while getopts p:s:S:n:f:m:d: arg
31do case ${arg} in
32  p) provider="$provider ${OPTARG}";;
33  s) swap_partition_size=${OPTARG};;
34  S) zfs_partition_size=${OPTARG};;
35  n) poolname=${OPTARG};;
36  f) ftphost=${OPTARG};;
37  m) mode=${OPTARG};;
38  d) distdir=${OPTARG};;
39  ?) exerr ${usage};;
40esac; done; shift $(( ${OPTIND} - 1 ))
41
42if [ -z "$poolname" ] || [ -z "$provider" ] ; then
43  exerr ${usage}
44  exit
45fi
46
47if [ "$distdir" -a ! -f "$distdir/base/install.sh" -o ! -f "$distdir/kernels/install.sh" -o ! -f "$distdir/src/install.sh" ]; then
48  echo "Sorry, no distribution files found in ${distdir}!"
49  exit
50fi
51
52# count the number of providers
53devcount=`echo ${provider} |wc -w`
54
55# set our default zpool mirror-mode
56if [ -z "$mode" ]; then
57    if [ "$devcount" -gt "1" ]; then
58        mode='mirror'
59    else
60        mode='stripe'
61    fi
62fi
63
64# check the settings for the users that want to set the mode on their own
65if [ "$devcount" -eq "1" -a "$mode" = "mirror" ]; then
66    echo "A mirror needs at least two disks!"
67    exit
68fi
69if [ "$devcount" -lt "3" -a "$mode" = "raidz" ]; then
70    echo "Sorry, you need at least three disks for a zfs raidz!"
71    exit
72fi
73
74check_size () {
75  ref_disk_size=`gpart list $ref_disk | grep 'Mediasize' | awk '{print $2}'`
76  if [ "${zfs_partition_size}" ]; then
77    _zfs_partition_size=`echo "${zfs_partition_size}"|tr GMKBWX gmkbwx|sed -Ees:g:km:g -es:m:kk:g -es:k:"*2b":g -es:b:"*128w":g -es:w:"*4 ":g -e"s:(^|[^0-9])0x:\1\0X:g" -ey:x:"*":|bc |sed "s:\.[0-9]*$::g"`
78  fi
79  if [ "${swap_partition_size}" ]; then
80    _swap_partition_size=`echo "${swap_partition_size}"|tr GMKBWX gmkbwx|sed -Ees:g:km:g -es:m:kk:g -es:k:"*2b":g -es:b:"*128w":g -es:w:"*4 ":g -e"s:(^|[^0-9])0x:\1\0X:g" -ey:x:"*":|bc |sed "s:\.[0-9]*$::g"`
81  fi
82  total_size=$((${_zfs_partition_size}+${_swap_partition_size}+162))
83  if [ "${total_size}" -gt "${ref_disk_size}" ]; then
84    echo "ERROR: The current settings for the partitions sizes will not fit onto your disk."
85    exit
86  else
87  fi
88}
89
90get_disk_labelname () {
91  label=${disk##*=}
92  disk=${disk%%=*}
93}
94
95echo "Creating GPT label on disks:"
96for disk in $provider; do
97  get_disk_labelname
98  if [ ! -e "/dev/$disk" ]; then
99    echo " -> ERROR: $disk does not exist"
100    exit
101  fi
102  echo " -> $disk"
103  dd if=/dev/zero of=/dev/$disk bs=512 count=79 > /dev/null 2>&1
104  gpart create -s gpt $disk > /dev/null
105done
106
107echo
108sleep 1
109
110smallest_disk_size='0'
111echo "Checking disks for size:"
112for disk in $provider; do
113  get_disk_labelname
114  disk_size=`gpart show $disk | grep '\- free \-' | awk '{print $2}'`
115  echo " -> $disk - total size $disk_size"
116  if [ "$smallest_disk_size" -gt "$disk_size" ] || [ "$smallest_disk_size" -eq "0" ]; then
117    smallest_disk_size=$disk_size
118    ref_disk=$disk
119  fi
120done
121
122# check if the size fits
123check_size
124
125echo
126echo "NOTICE: Using $ref_disk (smallest or only disk) as reference disk for calculation offsets"
127echo
128sleep 2
129
130echo "Creating GPT boot partition on disks:"
131for disk in $provider; do
132  get_disk_labelname
133  echo " ->  ${disk}"
134  gpart add -s 128 -t freebsd-boot $disk > /dev/null
135done
136
137echo
138sleep 2
139
140if [ "$swap_partition_size" ]; then
141  echo "Creating GPT swap partition on with size ${swap_partition_size} on disks: "
142  for disk in $provider; do
143    get_disk_labelname
144    echo " ->  ${disk} (Label: ${label})"
145    gpart add -s $swap_partition_size -t freebsd-swap -l swap-${label} ${disk} > /dev/null
146  done
147fi
148
149echo
150sleep 2
151
152offset=`gpart show $ref_disk | grep '\- free \-' | awk '{print $1}'`
153if [ -z "${zfs_partition_size}" ]; then
154  size=`gpart show $ref_disk | grep '\- free \-' | awk '{print $2}'`
155else
156  size=${zfs_partition_size}
157fi
158
159echo "Creating GPT ZFS partition on with size ${size} on disks: "
160for disk in $provider; do
161  get_disk_labelname
162  echo " ->  ${disk} (Label: ${label})"
163  gpart add -b $offset -s $size -t freebsd-zfs -l system-${label} ${disk} > /dev/null
164  labellist="${labellist} gpt/system-${label}"
165done
166
167echo
168sleep 2
169
170# Make first partition active so the BIOS boots from it
171for disk in $provider; do
172  get_disk_labelname
173  echo 'a 1' | fdisk -f - $disk > /dev/null 2>&1
174done
175
176echo
177sleep 2
178
179kldload /mnt2/boot/kernel/opensolaris.ko
180kldload /mnt2/boot/kernel/zfs.ko
181
182# we need to create /boot/zfs so zpool.cache can be written.
183mkdir /boot/zfs
184
185# Create the pool and the rootfs
186
187if [ "$mode" = "raidz" ]; then
188  zpool create -f $poolname raidz ${labellist}
189fi
190if [ "$mode" = "mirror" ]; then
191  zpool create -f $poolname mirror ${labellist}
192fi
193if [ "$mode" = "stripe" ]; then
194  zpool create -f $poolname ${labellist}
195fi
196
197if [ `zpool list -H -o name $poolname` != "$poolname" ]; then
198  echo "ERROR: Could not create zpool $poolname"
199  exit
200fi
201
202sleep 2
203
204echo "Setting checksum to fletcher4"
205zfs set checksum=fletcher4 ${poolname}
206
207rootzfs="$poolname/ROOT/$poolname"
208
209zfs create -p $rootzfs
210zfs set freebsd:boot-environment=1 $rootzfs
211
212# Now we create some stuff we also would like to have in seperate filesystems
213for filesystem in usr-src usr-obj usr-local tmp; do
214   echo "Creating $poolname/$filesystem"
215   zfs create $poolname/$filesystem
216   if [ "$filesystem" = "tmp" ]; then
217     chmod 1777 /$poolname/tmp
218   fi
219   zfs umount $poolname/$filesystem
220   _filesystem=`echo $filesystem | sed s:-:\/:g`
221   zfs set mountpoint=/${_filesystem} $poolname/${filesystem}
222done
223
224mkdir /$rootzfs/usr
225
226zfs set mountpoint=/$rootzfs/usr/src $poolname/usr-src
227zfs mount $poolname/usr-src
228
229zfs set mountpoint=/$rootzfs/usr/obj $poolname/usr-obj
230zfs mount $poolname/usr-obj
231
232echo ####################################
233if [ -z "$distdir" ]; then
234    echo "Now installing base, ssys, slib and kernels via $ftphost. This may take a while, depending on your network connection."
235    zfs create $poolname/installdata
236    cd /$poolname/installdata
237   
238    if [ `pwd` != "/$poolname/installdata" ]; then
239        echo "ERROR: Could not change directoy to /$poolname/installdata. Aborting."
240        exit
241    fi
242   
243    sleep 2
244    arch=`uname -p`
245    release=`uname -r`
246    echo
247    echo "Fetching FreeBSD ${release}-${arch}:"
248    for pkg in base kernels; do
249        mkdir /$poolname/installdata/${pkg}
250        cd /$poolname/installdata/${pkg}
251        echo " -> $pkg"
252        ftp -V "$ftphost:pub/FreeBSD/releases/${arch}/${release}/${pkg}/*"
253    done
254    mkdir /$poolname/installdata/src
255    cd /$poolname/installdata/src/
256    echo " -> ssys"
257    ftp -V "$ftphost:pub/FreeBSD/releases/${arch}/${release}/src/ssys*"
258    echo " -> slib"
259    ftp -V "$ftphost:pub/FreeBSD/releases/${arch}/${release}/src/slib*"
260    ftp -V "$ftphost:pub/FreeBSD/releases/${arch}/${release}/src/install.sh"
261    distdir="/$poolname/installdata"
262else
263    echo "Using distribution packages from $distdir"
264fi
265
266export DESTDIR=/$rootzfs/
267
268echo
269echo "Extracting base into $DESTDIR"
270cd /$distdir/base ; cat base.?? | tar --unlink -xpzf - -C ${DESTDIR:-/}
271cd /$distdir/src ;     sh ./install.sh sys lib
272echo "Extracting kernel into ${DESTDIR}boot"
273cd /$distdir/kernels ; sh ./install.sh generic
274
275cd /$rootzfs/boot ; cp -rp GENERIC/* /$rootzfs/boot/kernel/
276
277if [ -z "$distdir" ]; then
278    zfs destroy $poolname/installdata
279fi
280
281echo 'LOADER_ZFS_SUPPORT=YES' >> /$rootzfs/etc/make.conf
282
283echo
284echo "I will now build the ZFS aware boot-loader, expect some funky compile output and ignore the errors."
285sleep 2
286echo '#!/bin/sh
287mount -t devfs devfs /dev
288export DESTDIR=""
289cd /usr/src/sys/boot/
290make -s obj
291make -s depend
292make -s
293mkdir -p /usr/share/man/man5
294cd /usr/src/sys/boot/i386/loader; make -s install
295cd /usr/src/sys/boot/i386/zfsboot; make -s install
296cd /usr/src/sys/boot/i386/gptzfsboot; make -s install
297cd /usr/src/sys/boot/i386/pmbr; make -s install
298umount /dev
299exit' > /$rootzfs/tmp/chroot-command.sh
300chmod +x /$rootzfs/tmp/chroot-command.sh
301chroot /$rootzfs/ /tmp/chroot-command.sh
302rm /$rootzfs/tmp/chroot-command.sh
303
304# fix usr/share/man/man8
305rm /$rootzfs/usr/share/man/man8
306
307echo
308echo "Installing new bootcode on disks: "
309for disk in $provider; do
310  get_disk_labelname
311  echo " ->  ${disk}"
312  gpart bootcode -b /$rootzfs/boot/pmbr -p /$rootzfs/boot/gptzfsboot -i 1 $disk > /dev/null
313done
314echo
315
316# We need to fix /usr/src so it is mounted correct when booting from ZFS
317zfs umount $poolname/usr-src
318zfs set mountpoint=/usr/src $poolname/usr-src
319
320# We need to fix /usr/obj so it is mounted correct when booting from ZFS
321zfs umount $poolname/usr-obj
322zfs set mountpoint=/usr/obj $poolname/usr-obj
323
324# Enable the new filesystem as zpool bootfs
325zpool set bootfs=$rootzfs $poolname
326
327# We still need to tell the kernel from where to mount its root-filesystem
328echo 'zfs_load="YES"' >> /$rootzfs/boot/loader.conf
329echo "vfs.root.mountfrom=\"zfs:$rootzfs\"" >> /$rootzfs/boot/loader.conf
330echo 'zfs_enable="YES"' >> /$rootzfs/etc/rc.conf
331touch /$rootzfs/etc/fstab
332
333if [ "$swap_partition_size" ]; then
334  echo "Adding swap partitions in fstab:"
335  for disk in $provider; do
336    get_disk_labelname
337    echo " ->  /dev/gpt/swap-${label}"
338    echo "/dev/gpt/swap-${label} none swap sw 0 0" >> /$rootzfs/etc/fstab
339  done
340fi
341echo
342
343# Copy the zpool.cache to the new filesystem
344cp /boot/zfs/zpool.cache /$rootzfs/boot/zfs/zpool.cache
345
346sleep 5
347
348echo "Please reboot the system from the harddisk(s), remove the FreeBSD CD from you cdrom!"
Note: See TracBrowser for help on using the browser.