1#!/bin/sh
2#
3# Copyright (c) 2018-2021, Christer Edwards <christer.edwards@gmail.com>
4# All rights reserved.
5#
6# Redistribution and use in source and binary forms, with or without
7# modification, are permitted provided that the following conditions are met:
8#
9# * Redistributions of source code must retain the above copyright notice, this
10#   list of conditions and the following disclaimer.
11#
12# * Redistributions in binary form must reproduce the above copyright notice,
13#   this list of conditions and the following disclaimer in the documentation
14#   and/or other materials provided with the distribution.
15#
16# * Neither the name of the copyright holder nor the names of its
17#   contributors may be used to endorse or promote products derived from
18#   this software without specific prior written permission.
19#
20# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31. /usr/local/share/bastille/common.sh
32. /usr/local/etc/bastille/bastille.conf
33
34usage() {
35    error_exit "Usage: bastille upgrade release newrelease | target newrelease | target install | [force]"
36}
37
38# Handle special-case commands first.
39case "$1" in
40help|-h|--help)
41    usage
42    ;;
43esac
44
45if [ $# -gt 3 ] || [ $# -lt 2 ]; then
46    usage
47fi
48
49TARGET="$1"
50NEWRELEASE="$2"
51OPTION="$3"
52
53# Check for unsupported actions
54if [ "${TARGET}" = "ALL" ]; then
55    error_exit "Batch upgrade is unsupported."
56fi
57
58if [ -f "/bin/midnightbsd-version" ]; then
59    echo -e "${COLOR_RED}Not yet supported on MidnightBSD.${COLOR_RESET}"
60    exit 1
61fi
62
63if freebsd-version | grep -qi HBSD; then
64    error_exit "Not yet supported on HardenedBSD."
65fi
66
67# Handle options
68case "${OPTION}" in
69    -f|--force)
70        OPTION="-F"
71        ;;
72    *)
73        OPTION=
74        ;;
75esac
76
77jail_check() {
78    # Check if the jail is thick and is running
79    if [ ! "$(/usr/sbin/jls name | awk "/^${TARGET}$/")" ]; then
80        error_exit "[${TARGET}]: Not started. See 'bastille start ${TARGET}'."
81    else
82        if grep -qw "${bastille_jailsdir}/${TARGET}/root/.bastille" "${bastille_jailsdir}/${TARGET}/fstab"; then
83            error_exit "${TARGET} is not a thick container."
84        fi
85    fi
86}
87
88release_check() {
89    # Validate the release
90    if ! echo "${NEWRELEASE}" | grep -q "[0-9]\{2\}.[0-9]-RELEASE"; then
91        error_exit "${NEWRELEASE} is not a valid release."
92    fi
93}
94
95release_upgrade() {
96    # Upgrade a release
97    if [ -d "${bastille_releasesdir}/${TARGET}" ]; then
98        release_check
99        env PAGER="/bin/cat" freebsd-update ${OPTION} --not-running-from-cron -b "${bastille_releasesdir}/${TARGET}" --currently-running "${TARGET}" -r "${NEWRELEASE}" upgrade
100        echo
101        echo -e "${COLOR_YELLOW}Please run 'bastille upgrade ${TARGET} install' to finish installing updates.${COLOR_RESET}"
102    else
103        error_exit "${TARGET} not found. See 'bastille bootstrap'."
104    fi
105}
106
107jail_upgrade() {
108    # Upgrade a thick container
109    if [ -d "${bastille_jailsdir}/${TARGET}" ]; then
110        jail_check
111        release_check
112        CURRENT_VERSION=$(jexec -l ${TARGET} freebsd-version)
113        env PAGER="/bin/cat" freebsd-update ${OPTION} --not-running-from-cron -b "${bastille_jailsdir}/${TARGET}/root" --currently-running "${CURRENT_VERSION}" -r ${NEWRELEASE} upgrade
114        echo
115        echo -e "${COLOR_YELLOW}Please run 'bastille upgrade ${TARGET} install' to finish installing updates.${COLOR_RESET}"
116    else
117        error_exit "${TARGET} not found. See 'bastille bootstrap'."
118    fi
119}
120
121jail_updates_install() {
122    # Finish installing upgrade on a thick container
123    if [ -d "${bastille_jailsdir}/${TARGET}" ]; then
124        jail_check
125        env PAGER="/bin/cat" freebsd-update ${OPTION} --not-running-from-cron -b "${bastille_jailsdir}/${TARGET}/root" install
126    else
127        error_exit "${TARGET} not found. See 'bastille bootstrap'."
128    fi
129}
130
131release_updates_install() {
132    # Finish installing upgrade on a release
133    if [ -d "${bastille_releasesdir}/${TARGET}" ]; then
134        env PAGER="/bin/cat" freebsd-update ${OPTION} --not-running-from-cron -b "${bastille_releasesdir}/${TARGET}" install
135    else
136        error_exit "${TARGET} not found. See 'bastille bootstrap'."
137    fi
138}
139
140# Check what we should upgrade
141if echo "${TARGET}" | grep -q "[0-9]\{2\}.[0-9]-RELEASE"; then
142    if [ "${NEWRELEASE}" = "install" ]; then
143        release_updates_install
144    else
145        release_upgrade
146    fi
147elif [ "${NEWRELEASE}" = "install" ]; then
148    jail_updates_install
149else
150    jail_upgrade
151fi
152