source: manageBE/manageBE

Last change on this file was 137, checked in by Cristian Yxen, 3 years ago

make usage of freebsd-update work

  • Property svn:keywords set to Id
File size: 12.4 KB
Line 
1#!/bin/sh
2#
3# $Id: manageBE 137 2014-05-21 12:57:16Z cryx $
4#
5
6# manageBE [activate|create|delete|list|src-upgrade|freebsd-update|freebsd-upgrade] {params}
7
8if [ `uname -r |cut -d '.' -f1` -lt "8" ]; then
9    echo "Sorry, only FreeBSD starting with 8.0 is supported."
10fi
11
12type=$1
13
14mgm="manageBE"
15usage_activate="Usage: ${mgm} activate -n <BE> -p <pool>"
16usage_create="Usage: ${mgm} create -n <newBE> -s <sourceBE> -p <pool>"
17usage_delete="Usage: ${mgm} delete -n <BE> -p <pool> -o [yes|no]"
18usage_src_upgrade="Usage: ${mgm} src-upgrade -n <BE> -p <pool>"
19usage_freebsd_update="Usage: ${mgm} freebsd-update -n <BE> -p <pool>"
20usage_freebsd_upgrade="Usage: ${mgm} freebsd-upgrade -n <BE> -p <pool> -r <release>"
21not_supported="Sorry, your FreeBSD version does not support this option"
22
23error_delete="If filesystem has dependent clones, please promote them via 'zfs promote <filesystem>' and re-run ${mgm} delete"
24
25# define our bail out shortcut
26exerr () { echo -e "$*" >&2 ; exit 1; }
27
28check_for_be_existence () {
29    be_status=`/sbin/zfs list -H -o freebsd:boot-environment ${pool}/ROOT/${bootfs} 2> /dev/null` 
30    if [ "${be_status}" != "1" ]; then
31        echo "Sorry, ${bootfs} is no valid boot-environment"
32        exit
33    fi
34}
35
36case ${type} in
37    activate)
38        # activate a boot-environment
39
40        shift; while getopts :n:p: arg; do case ${arg} in
41            n) bootfs=${OPTARG};;
42            p) pool=${OPTARG};;
43            ?) exerr ${usage_activate};;
44        esac; done; shift $(( ${OPTIND} - 1 ))
45
46        [ "${bootfs}" -a "${pool}" ] || exerr ${usage_activate}
47
48        check_for_be_existence
49
50        old_bootfs=`/sbin/zpool list -H -o bootfs ${pool} |/usr/bin/sed s:^$pool/ROOT/::`
51        /sbin/zpool set bootfs=${pool}/ROOT/${bootfs} ${pool}
52
53        for filesystem in `/sbin/zfs list -H -o name -t filesystem -r ${pool}/ROOT/${bootfs}`; do
54          /sbin/zfs promote ${filesystem}
55        done
56    ;;
57    create)
58        # create a boot-environment
59
60        shift; while getopts :n:s:p: arg; do case ${arg} in
61            n) new_bootfs=${OPTARG};;
62            s) bootfs=${OPTARG};;
63            p) pool=${OPTARG};;
64            ?) exerr ${usage_create};;
65        esac; done; shift $(( ${OPTIND} - 1 ))
66
67        [ "${new_bootfs}" -a "${pool}" ] || exerr ${usage_create}
68       
69        if [ -z "${bootfs}" ]; then
70            bootfs=`/sbin/zpool list -H -o bootfs ${pool} | /usr/bin/sed s:${pool}/ROOT/::`
71        fi
72
73        check_for_be_existence
74
75        # create snapshot of the source BE and clone the snapshot to create the new BE
76        /sbin/zfs snapshot -r ${pool}/ROOT/${bootfs}@${new_bootfs}
77        /sbin/zfs clone ${pool}/ROOT/${bootfs}@${new_bootfs} ${pool}/ROOT/${new_bootfs}
78
79        # clone the children snapshot to create the new BE children, mark the filesystem as not being BEs
80        for filesystem in `/sbin/zfs list -H -o name -t filesystem -r ${pool}/ROOT/${bootfs} | /usr/bin/sed s:${pool}/ROOT/${bootfs}:: | /usr/bin/sed s:^/:: | /usr/bin/xargs`; do
81          /sbin/zfs clone ${pool}/ROOT/${bootfs}/${filesystem}@${new_bootfs} ${pool}/ROOT/${new_bootfs}/${filesystem}
82          /sbin/zfs set freebsd:boot-environment=0 ${pool}/ROOT/${new_bootfs}/${filesystem}
83        done
84
85        # mark the BE as boot-environment and mount the freebsd-update dir in the correct path
86        /sbin/zfs set freebsd:boot-environment=1 ${pool}/ROOT/${new_bootfs}
87
88        grep -v '^vfs.root.mountfrom' /boot/loader.conf > /${pool}/ROOT/${new_bootfs}/boot/loader.conf
89        echo vfs.root.mountfrom=\"zfs:${pool}/ROOT/${new_bootfs}\" >> /${pool}/ROOT/${new_bootfs}/boot/loader.conf
90       
91        # fill the fstab with the mounts of the BE children
92        grep -v ${pool}/ROOT/${bootfs} /etc/fstab > /${pool}/ROOT/${new_bootfs}/etc/fstab
93        echo "# Automatically generated by manageBE (${pool}/ROOT/${new_bootfs})" >> /${pool}/ROOT/${new_bootfs}/etc/fstab
94        for filesystem in `/sbin/zfs list -H -o name -t filesystem -r ${pool}/ROOT/${new_bootfs} | /usr/bin/sed s:${pool}/ROOT/${new_bootfs}:: | /usr/bin/sed s:^/:: | /usr/bin/xargs`; do
95          echo "${pool}/ROOT/${new_bootfs}/${filesystem} /${filesystem} zfs rw 0 0" >> /${pool}/ROOT/${new_bootfs}/etc/fstab
96        done
97
98        echo "The new Boot-Environment is ready to be updated and/or activated."
99    ;;
100    delete)
101        # delete a boot-environment
102
103        shift; while getopts :n:p:o: arg; do case ${arg} in
104            n) bootfs=${OPTARG};;
105            p) pool=${OPTARG};;
106            o) delete_origin=${OPTARG};;
107            ?) exerr ${usage_delete};;
108        esac; done; shift $(( ${OPTIND} - 1 ))
109
110        [ "${bootfs}" -a "${pool}" -a "${delete_origin}" ] || exerr ${usage_delete}
111
112        check_for_be_existence
113
114        current_bootfs=`/sbin/zpool list -H -o bootfs ${pool}`
115
116        if [ ! "${pool}/ROOT/${bootfs}" = "${current_bootfs}" ]; then
117            if [ "${delete_origin}" = "yes" ]; then
118               origin=`/sbin/zfs list -H -o origin ${pool}/ROOT/${bootfs}`
119            fi
120            /sbin/zfs destroy -r ${pool}/ROOT/${bootfs} || exerr ${error_delete}
121            if [ "${delete_origin}" = "yes" -a "${origin}" ]; then
122                /sbin/zfs destroy -r ${origin}
123            fi
124        else
125            echo "${bootfs} is ZFS bootfs, unable to delete!"
126        fi
127    ;;
128    list)
129        shift; while getopts :v: arg; do
130            verbose="YES";
131        done; shift $(( ${OPTIND} - 1 ))
132
133    rootfs=`mount | head -n1 | grep 'on / ' |cut -d ' ' -f1`
134    for pool in `/sbin/zpool list -H -o name`; do
135        echo "Poolname: $pool"
136        zpool_bootfs=`/sbin/zpool list -H -o bootfs ${pool}`
137
138        if [ "${zpool_bootfs}" = "-" ]; then
139            echo "No BE setup"
140            echo
141            continue
142        fi
143
144        mountpoint_length=`/sbin/zfs list -H -o mountpoint -t filesystem -r $pool/ROOT | tail +2 |wc -L`
145        if [ "$mountpoint_length" -lt "10" ]; then
146            mountpoint_length=10
147        fi
148        name_length=`/sbin/zfs list -H -o name -t filesystem -r $pool/ROOT | tail +2 | /usr/bin/sed s:^$pool/ROOT/:: |wc -L`
149        if [ "$name_length" -lt "4" ]; then
150            name_length=4
151        fi
152        space_length=`/sbin/zfs list -H -o referenced -t filesystem -r $pool/ROOT | tail +2 |wc -L`
153        if [ "$space_length" -lt "5" ]; then
154            space_length=5
155        fi
156        snapshot_length=`/sbin/zfs list -t snapshot -H -o name -r $pool/ROOT | /usr/bin/sed s:^$pool/ROOT/::  | wc -L`
157
158        printf "%-${name_length}s %-6s %-6s %-${mountpoint_length}s %-${space_length}s\\n" BE Active Active Mountpoint Space
159        printf "%-${name_length}s %-6s %-6s %-${mountpoint_length}s %-${space_length}s\\n" Name Now Reboot - Used
160        printf "%-${name_length}s %-6s %-6s %-${mountpoint_length}s %-${space_length}s\\n" ---- ------ ------ ---------- -----
161
162        for be_filesystem in `/sbin/zfs list -H -S creation -o name -t filesystem -r $pool/ROOT |grep -v "^$pool/ROOT\$"`; do
163
164            if [ `/sbin/zfs list -H -o freebsd:boot-environment ${be_filesystem}` = 1 ]; then
165                be_name=`echo ${be_filesystem}|/usr/bin/sed s:^$pool/ROOT/::`
166
167                be_active='no' 
168                if [ "${be_filesystem}" = "${rootfs}" ]; then
169                    be_active='yes'     
170                fi
171                be_nextboot='no'
172                if [ "${be_filesystem}" = "${zpool_bootfs}" ]; then
173                    be_nextboot='yes'
174                fi
175
176                if [ "${be_active}" = "yes" -a "${be_nextboot}" = "yes" ]; then
177                  used_by_snapshots=`/sbin/zfs list -H -o usedbysnapshots $be_filesystem`
178                  be_space=`/sbin/zfs list -H -o referenced $be_filesystem`
179                  be_mountpoint='/'
180                elif [ "${be_active}" = "no" -a "${be_nextboot}" = "yes" ]; then
181                  used_by_snapshots=`/sbin/zfs list -H -o usedbysnapshots $be_filesystem`
182                  be_space=`/sbin/zfs list -H -o referenced $be_filesystem`
183                  be_mountpoint=`/sbin/zfs list -H -o mountpoint $be_filesystem`
184                elif [ "${be_active}" = "yes" -a "${be_nextboot}" = "no" ]; then
185                  be_origin=`/sbin/zfs list -H -o origin ${be_filesystem}`
186                  be_space=`/sbin/zfs list -H -t snapshot -o used $be_origin`
187                  be_mountpoint='/'
188                else
189                  be_origin=`/sbin/zfs list -H -o origin ${be_filesystem}`
190                  be_space=`/sbin/zfs list -H -t snapshot -o used $be_origin`
191                  be_mountpoint=`/sbin/zfs list -H -o mountpoint $be_filesystem`
192                fi
193                printf "%-${name_length}s %-6s %-6s %-${mountpoint_length}s %${space_length}s\\n" $be_name $be_active $be_nextboot $be_mountpoint $be_space
194
195                if [ "$verbose" = "YES" ]; then
196                    be_created=`/sbin/zfs list -H -S creation -o creation $be_filesystem`
197                    echo
198                    printf "\t%-${snapshot_length}s %-21s\\n" Name Created
199                    printf "\t%-${snapshot_length}s %-21s\\n" $be_name "$be_created"
200                    for snapshot_name in `/sbin/zfs list -t snapshot -H -t filesystem -r -o name $pool/ROOT/$be_name|/usr/bin/sed s:^$pool/ROOT/::`; do
201                        snapshot_created=`/sbin/zfs list -t snapshot -H -S creation -o creation $pool/ROOT/$snapshot_name`
202                        printf "\t%-${snapshot_length}s %-21s\\n" $snapshot_name "$snapshot_created"
203                    done
204                    echo
205                fi
206            fi
207        done
208        echo
209        echo "Used by BE snapshots: ${used_by_snapshots}"
210        echo
211    done
212    ;;
213    src-upgrade)
214        # upgrade a boot-environment
215
216        shift; while getopts :n:p: arg; do case ${arg} in
217            n) bootfs=${OPTARG};;
218            p) pool=${OPTARG};;
219            ?) exerr ${usage_src_upgrade};;
220        esac; done; shift $(( ${OPTIND} - 1 ))
221
222        [ "${bootfs}" -a "${pool}" ] || exerr ${usage_src_upgrade}
223
224        check_for_be_existence
225
226        mount -t nullfs -o ro /usr/src /${pool}/ROOT/${bootfs}/usr/src
227        mount -t nullfs -o ro /usr/obj /${pool}/ROOT/${bootfs}/usr/obj
228
229        echo '#!/bin/sh
230mount -t devfs devfs /dev
231cd /usr/src
232/usr/sbin/mergemaster -p && make -s installkernel && make -s installworld && /usr/sbin/mergemaster -U
233umount /dev' > /${pool}/ROOT/${bootfs}/tmp/manageBE-upgrade.sh
234
235        chmod +x /${pool}/ROOT/${bootfs}/tmp/manageBE-upgrade.sh
236        chroot /${pool}/ROOT/${bootfs}/ /tmp/manageBE-upgrade.sh
237        rm /${pool}/ROOT/${bootfs}/tmp/manageBE-upgrade.sh
238        umount /${pool}/ROOT/${bootfs}/usr/obj
239        umount /${pool}/ROOT/${bootfs}/usr/src
240       
241        echo "Please activate ${bootfs} via manageBE and reboot."
242    ;;
243    freebsd-update)
244        [ `uname -r | cut -d '-' -f1,2` = "8.0-RELEASE" ] && exerr ${not_supported}
245        # update a boot-environment using freebsd-update
246
247        shift; while getopts :n:p: arg; do case ${arg} in
248            n) bootfs=${OPTARG};;
249            p) pool=${OPTARG};;
250            ?) exerr ${usage_freebsd_upgrade};;
251        esac; done; shift $(( ${OPTIND} - 1 ))
252
253        [ "${bootfs}" -a "${pool}" -a ${release} ] || exerr ${usage_freebsd_update}
254
255        check_for_be_existence
256       
257        chroot /${pool}/ROOT/${bootfs} mount -t devfs devfs /dev
258        chroot /${pool}/ROOT/${bootfs} /usr/sbin/freebsd-update fetch
259        chroot /${pool}/ROOT/${bootfs} /usr/sbin/freebsd-update install > /dev/null
260        chroot /${pool}/ROOT/${bootfs} umount /dev
261
262        echo "Please activate ${bootfs} via manageBE and reboot."
263    ;;
264    freebsd-upgrade)
265        [ `uname -r | cut -d '-' -f1,2` = "8.0-RELEASE" ] && exerr ${not_supported}
266        # upgrade a boot-environment using freebsd-update
267
268        shift; while getopts :n:p:r: arg; do case ${arg} in
269            n) bootfs=${OPTARG};;
270            p) pool=${OPTARG};;
271            r) release=${OPTARG};;
272            ?) exerr ${usage_freebsd_upgrade};;
273        esac; done; shift $(( ${OPTIND} - 1 ))
274
275        [ "${bootfs}" -a "${pool}" -a ${release} ] || exerr ${usage_freebsd_upgrade}
276
277        check_for_be_existence
278       
279        chroot /${pool}/ROOT/${bootfs} mount -t devfs devfs /dev
280        chroot /${pool}/ROOT/${bootfs} /usr/sbin/freebsd-update upgrade -r ${release}
281        chroot /${pool}/ROOT/${bootfs} /usr/sbin/freebsd-update install > /dev/null
282        chroot /${pool}/ROOT/${bootfs} umount /dev
283
284        echo "Please activate ${bootfs} via manageBE and reboot. After rebooting, 'freebsd-update install' needs to be run again to install the new userland components, and the system needs to be rebooted again."
285    ;;
286    *)
287        echo echo "Usage: ${mgm} [activate|create|delete|list|src-upgrade|freebsd-update|freebsd-upgrade] {params}"
288    ;;
289esac
Note: See TracBrowser for help on using the repository browser.