-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathdebian-upgrade
241 lines (230 loc) · 11.9 KB
/
debian-upgrade
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
#!/bin/sh
#
# Update script for Debian.
#
# Your system must be configured to get packages from a version-specific
# codename, such as stretch or buster, not a rolling release class, such
# as "stable" or "testing". This script can then be used to perform normal
# package updates for this version, but more importantly it will check if
# a new version is released to a release class to be monitored, and performs
# a major upgrade to that new version. So running this regularly it will
# be more like a rolling release where you track a release class, but where
# the transition when a new version arrives that class is handled through a
# full upgrade process and not just a normal package update.
#
# By default this script will monitor the "stable" release class. When running
# this script it will look up the codename of the version currently in "stable".
# If the codename is different from the codename currently configured in the
# running system, then an upgrade will be performed. If same codename then
# a normal package update will be performed.
#
# The release channel to monitor is by default "stable", but can be customized:
# - Command-line argument (takes precedence)
# - Environment variable (if not command-line argument)
# You should normally use one of the high level rolling release class codes,
# such as stable, testing or unstable. In some cases you may want to specify
# a version-specific codename. E.g. if currently installed Debian 9 stretch,
# and latest stable is Debian 11 bullseye, then you would normally want to
# upgrade via Debian 10 buster. Then you would have to run this script first
# with customized channel "buster" (or "oldstable") to make the first upgrade,
# before running it again with the default "stable" channel to perform the
# final upgrade.
#
# Uses the following logic.
# - Get and report information about current and latest version
# according to a specific channel: Default "stable", can be
# customized by environment variable RELEASE_CHANNEL or
# command line argument (takes precedence).
# - Always starts with a plain package update+upgrade
# sudo apt update
# sudo apt upgrade
# - Compares version codenames, if different then perform full upgrade
# by updating package sources and run the commands as recommended
# by debian, including full-upgrade:
# sudo apt update
# sudo apt-get upgrade
# sudo apt full-upgrade
# sudo apt --purge autoremove
# - Always on normal return (no errors) runs package cache cleanup:
# sudo apt clean
#
# NOTE:
# - Be careful if there are more than one major version between the current
# and the latest version. You sould probably upgrade one version at a time.
# Specify version code as command line argument to control this.
# - The script has no logic on version numbers or ordering of versions,
# so if running the script with argument "testing" upgrading to latest testing
# release, then running without arguments where it defaults to "stable", it
# will detect different version codename and trigger the upgrade process,
# although this would be a downgrade - which is generally not supported in Debian!
# - Read the upgrade guide to see if there are any additional considerations
# when upgrading to a new major release:
# https://www.debian.org/releases/<versioncode>/amd64/release-notes/ch-upgrading
# - Script is interactive! Will prompt user before doing any changes!
# - When upgrading to new releases the package source configuration
# is automatically updated by simple search/replace, but if other
# changes this will not be enough, and it must be updated manually.
# One such change were introduced with Debian 11 bullseye, where the
# security repository distribution names were changed, but this specific
# one is handled automatically by this script!
# - If performing full-upgrade fails, then the changes to package
# sources list will be kept, to next time package update is performed,
# it will be from the upgraded package source. Running this script
# again will retry the upgrade!
#
if ! cat /etc/os-release | grep -q '^ID=debian$'; then
echo "This is not a Debian system!"
exit 1
fi
# Not straight forward to get accurate version information of current system,
# but the most important thing is to detect when there are differences in the
# version codename - which means there are major version upgrade!
# - Stable versions:
# - Version number major.minor from /etc/debian_version
# - Version code from /etc/os-release.
# - Debian 10 (and newer?) has a separate 'VERSION_CODENAME', but
# Debian 9 (and older?) does not, so for compatibility parsing 'VERSION' instead.
# - Testing versions:
# - No version number!
# - Code name of next testing _and_ unstable in /etc/os-release as part of string
# PRETTY_NAME="Debian GNU/Linux bullseye/sid"
# - Code name of next testing _and_ unstable in /etc/debian_version, e.g. 'bullseye/sid'
# - What we do here:
# - Codename:
# - First try to parse from VERSION in /etc/os-release
# Example: VERSION="10 (buster)"
# - Next try to parse from PRETTY_NAME in /etc/os-release, and if it contains a
# slash then pick the first one.
# Examples:
# PRETTY_NAME="Debian GNU/Linux 10 (buster)"
# PRETTY_NAME="Debian GNU/Linux bullseye/sid"
# - Version:
# - Read from /etc/debian_version. It may contain major.minor version number (stable releases)
# or it may be the complete codename as in the pretty name!
echo "Looking up current release information..."
RELEASE_CHANNEL=${1:-${RELEASE_CHANNEL:-stable}}
echo "Channel: ${RELEASE_CHANNEL}"
CURRENT_CODENAME=$(cat /etc/os-release | sed -rn 's/^VERSION="[0-9]+\s+\((.*)\)"/\1/p')
[ -z "$CURRENT_CODENAME" ] && CURRENT_CODENAME=$(cat /etc/os-release | sed -rn 's/^PRETTY_NAME="Debian GNU\/Linux ([0-9]+ )?\(?([a-z]*)(\/[a-z]*)?\)?"/\2/p')
[ -z "$CURRENT_CODENAME" ] && echo "ERROR: Unable to find installed release codename" && exit 1
CURRENT_VERSION=$(cat /etc/debian_version)
[ -z "$CURRENT_VERSION" ] && echo "ERROR: Unable to find installed version info" && exit 1
echo "Installed version: $CURRENT_VERSION ($CURRENT_CODENAME)"
# Start by updating package cache
echo
echo "Loading package index..."
if ! sudo apt update ; then
echo "ERROR: Update command returned with error code $?"
exit 1
fi
# Make sure wget is installed, because we need it to further decide what to do.
# On clean WSL install of Debian 10 (Buster) version 10.8 it is missing!
echo
echo "Ensuring latest version of wget is installed..."
if ! sudo apt install wget; then
echo "ERROR: install command returned with error code $?"
exit 1
fi
# Fetch release information
echo
echo "Fetching latest release information..."
LATEST_CODENAME=$(wget --quiet --timeout=10 --output-document=- http://deb.debian.org/debian/dists/${RELEASE_CHANNEL}/Release | grep '^Codename:' | cut -d' ' -f2)
[ -z "$LATEST_CODENAME" ] && echo "ERROR: Unable to find latest release codename" && exit 1
LATEST_VERSION=$(wget --quiet --timeout=10 --output-document=- http://deb.debian.org/debian/dists/${RELEASE_CHANNEL}/Release | grep '^Version:' | cut -d' ' -f2)
# If latest version has not reached stable yet, it will not have a version number!
#[ -z "$LATEST_VERSION" ] && echo "ERROR: Unable to find latest version major.minor" && exit 1
[ -z "$LATEST_VERSION" ] && echo "Latest release version info not available, but this can be normal for releases newer than current stable"
echo "Available version: ${LATEST_VERSION:-?} ($LATEST_CODENAME)"
echo
if [ "$LATEST_CODENAME" = "$CURRENT_CODENAME" ]; then
# No major version change.
# Always run a simple package update just in case.
echo "No major upgrade available, updating packages..."
if ! sudo apt upgrade ; then
echo "ERROR: Upgrade command returned with error code $?"
exit 1
fi
echo
if [ -z "$LATEST_VERSION" -o "$CURRENT_VERSION" = "$LATEST_VERSION" ]; then
echo "Your system is up to date: $CURRENT_VERSION ($CURRENT_CODENAME)"
else
echo "Your system was updated and is on latest release codename '${CURRENT_CODENAME}', but version '${CURRENT_VERSION}' differs from latest '${LATEST_VERSION}'"
fi
else
echo "Performing major upgrade from '${CURRENT_CODENAME}' to '${LATEST_CODENAME}'..."
# Get current channel configured for main binary packages source.
CURRENT_SOURCE_CHANNEL=$(cat /etc/apt/sources.list | sed -rn 's/^deb\s+https?:\/\/deb.debian.org\/debian\s+([a-z]*)\s+main$/\1/p')
[ -z "$CURRENT_SOURCE_CHANNEL" ] && echo "FAILED: Unable to find current configured main package source version codename" && exit 1
if [ "$CURRENT_SOURCE_CHANNEL" = "$LATEST_CODENAME" ]; then
# Note: In this case we do not want to run simple package update (sudo apt upgrade),
# because we want to use the full upgrade procedure since the package sources have changed!
echo "WARNING: Main package source is already configured for latest release, will not update it:"
echo
cat /etc/apt/sources.list
echo
else
# Run a simple package update for existing release
echo "Updating packages to latest version for current release..."
if ! sudo apt upgrade; then
echo "ERROR: Upgrade command returned with error code $?"
exit 1
fi
echo
# Switch package source to new release
if [ "$CURRENT_SOURCE_CHANNEL" != "$CURRENT_CODENAME" ]; then
echo "WARNING: Main package source are currently configured to a release different from both current and latest release!"
fi
echo "Will perform a full-upgrade after changing /etc/apt/sources.list from this:"
echo
cat /etc/apt/sources.list
echo "To this:"
echo
if [ "${LATEST_CODENAME}" = "bullseye" ]; then
# Note: Additional change introduced with Debian 11 bullseye: In the security
# repository the distributions are called <version>-security instead of <version>/updates.
# Also changes from url security.debian.org/debian-security/ to just security.debian.org,
# although this is not critical as they are just aliases to the same repository.
cat /etc/apt/sources.list | sed -r -e "s/${CURRENT_CODENAME}/${LATEST_CODENAME}/" -e "s/security.debian.org\/debian-security\/?\s+${LATEST_CODENAME}\/updates/security.debian.org ${LATEST_CODENAME}-security/"
else
cat /etc/apt/sources.list | sed "s/${CURRENT_CODENAME}/${LATEST_CODENAME}/"
fi
echo
read -p "Do you want to continue? [Y/n] " choice
case "$choice" in
""|y|Y ) ;;
* ) echo "Aborted";exit 1;;
esac
if [ "${LATEST_CODENAME}" = "bullseye" ]; then
if ! sudo sed -i -r -e "s/${CURRENT_CODENAME}/${LATEST_CODENAME}/" -e "s/security.debian.org\/debian-security\/?\s+${LATEST_CODENAME}\/updates/security.debian.org ${LATEST_CODENAME}-security/" /etc/apt/sources.list; then
echo "ERROR: Could not update /etc/apt/sources.list"
exit 1
fi
else
if ! sudo sed -i "s/${CURRENT_CODENAME}/${LATEST_CODENAME}/" /etc/apt/sources.list; then
echo "ERROR: Could not update /etc/apt/sources.list"
exit 1
fi
fi
echo
echo "Reloading package index for changed source..."
if ! sudo apt update ; then
echo "ERROR: Update command returned with error code $?"
exit 1
fi
fi
# Run full upgrade from changed package source
# Note: Using 'apt-get upgrade' instead of 'apt upgrade' in this case, as recommended by debian!
if ! sudo apt-get upgrade || ! sudo apt full-upgrade ; then
echo "ERROR: Upgrade commands returned with error code $?"
exit 1
fi
if ! sudo apt --purge autoremove ; then
echo "WARNING: Cleanup of unused dependencies failed with error code $?"
exit 1
fi
fi
# Package cache cleanup
if ! sudo apt clean ; then
echo "WARNING: Cleanup of package cache failed with error code $?"
exit 1
fi