[23143] | 1 | #!/bin/sh |
---|
| 2 | |
---|
[23156] | 3 | complain() { |
---|
[23717] | 4 | logger -t "$(hostname --fqdn)" -p user.notice "update: $*" |
---|
[24376] | 5 | updstatus="failed" |
---|
| 6 | updmsg="$*" |
---|
[23156] | 7 | } |
---|
| 8 | |
---|
[24376] | 9 | save_success() { |
---|
| 10 | updstatus="ok" |
---|
| 11 | updmsg=$1 |
---|
| 12 | } |
---|
| 13 | |
---|
| 14 | save_state() { |
---|
| 15 | rm -f $statfile |
---|
| 16 | echo "$updlast|$(date)|$updstatus|$updmsg" > $statfile |
---|
| 17 | } |
---|
| 18 | |
---|
[23156] | 19 | maybe_reboot() { |
---|
| 20 | if [ -f /var/run/reboot-required ]; then |
---|
| 21 | # A package wants us to reboot the machine. Do so if no one is |
---|
| 22 | # logged in. Be paranoid about stale utmp entries. |
---|
| 23 | ttys=$(w -h -s | awk '{print $2}') |
---|
| 24 | for tty in $ttys; do |
---|
| 25 | pids=$(ps --no-heading -j -t "$tty" 2>/dev/null \ |
---|
| 26 | | awk '($1 == $3) {print $1}') |
---|
| 27 | if [ -n "$pids" ]; then |
---|
| 28 | return |
---|
| 29 | fi |
---|
| 30 | done |
---|
| 31 | # screen processes count as logins. |
---|
| 32 | if pgrep '^screen' > /dev/null; then |
---|
| 33 | return |
---|
| 34 | fi |
---|
[24376] | 35 | save_state |
---|
[23156] | 36 | reboot |
---|
| 37 | exit |
---|
| 38 | fi |
---|
| 39 | } |
---|
| 40 | |
---|
[23143] | 41 | if [ 0 != "$(id -u)" ]; then |
---|
| 42 | echo "This script must be run as root." >&2 |
---|
| 43 | exit 1 |
---|
| 44 | fi |
---|
| 45 | |
---|
[24147] | 46 | # Don't run updates during a cluster login. |
---|
| 47 | if [ -e /var/run/athena-login ]; then |
---|
| 48 | exit 0 |
---|
| 49 | fi |
---|
| 50 | |
---|
[23143] | 51 | # Avoid confusing the system by running two updates at once. |
---|
| 52 | pidfile=/var/run/athena-update.pid |
---|
| 53 | if [ -e $pidfile ]; then |
---|
[23148] | 54 | if ! kill -0 "$(cat $pidfile)" 2>/dev/null; then |
---|
[23143] | 55 | rm -f $pidfile |
---|
| 56 | fi |
---|
| 57 | fi |
---|
| 58 | (set -o noclobber; echo $$ > $pidfile) 2>/dev/null || exit |
---|
| 59 | |
---|
[23156] | 60 | trap 'rm -f $pidfile' EXIT |
---|
[23143] | 61 | |
---|
[24376] | 62 | statfile="/var/lib/athena-update-status" |
---|
| 63 | updstatus="unknown" |
---|
| 64 | updmsg="" |
---|
| 65 | updlast=$(date) |
---|
| 66 | |
---|
| 67 | # Get the last successful update |
---|
| 68 | if [ -f $statfile ]; then |
---|
| 69 | updlast=$(awk -F\| '{print $1;}' $statfile) |
---|
| 70 | fi |
---|
| 71 | |
---|
[23156] | 72 | # Make sure nothing expects input on stdin. |
---|
| 73 | exec </dev/null |
---|
| 74 | |
---|
[23717] | 75 | # Redirect further output to a log file. |
---|
| 76 | exec >>/var/log/athena-update 2>&1 |
---|
[23156] | 77 | |
---|
[23717] | 78 | # Write a log header now and a footer at exit. |
---|
[24147] | 79 | # Also write a target for cluster's /etc/nologin symlink. |
---|
[23717] | 80 | echo "-----" |
---|
| 81 | echo "** Beginning Athena auto-update at $(date)" |
---|
| 82 | |
---|
[24147] | 83 | cat > /var/run/athena-nologin << NOLOGIN |
---|
| 84 | This system is currently taking software updates. |
---|
| 85 | Please log in to a different system. |
---|
| 86 | NOLOGIN |
---|
| 87 | |
---|
[23717] | 88 | finish() { |
---|
| 89 | echo "** Ending Athena auto-update at $(date)" |
---|
| 90 | echo "-----" |
---|
| 91 | echo |
---|
| 92 | rm -f $pidfile |
---|
[24147] | 93 | rm -f /var/run/athena-nologin |
---|
[24376] | 94 | save_state |
---|
[23717] | 95 | exit |
---|
| 96 | } |
---|
| 97 | trap finish EXIT |
---|
| 98 | |
---|
| 99 | v() { |
---|
| 100 | echo "** Running:" "$@" |
---|
| 101 | "$@" |
---|
| 102 | } |
---|
| 103 | |
---|
| 104 | |
---|
[23786] | 105 | # Allow hesiod cluster info to specify the debathena apt release. |
---|
[23159] | 106 | # (Will do nothing if debathena-clusterinfo isn't installed.) |
---|
[23717] | 107 | [ -x /usr/sbin/save-cluster-info ] && v /usr/sbin/save-cluster-info |
---|
[23159] | 108 | cinfo=/var/run/athena-clusterinfo.sh |
---|
[23786] | 109 | slist=/etc/apt/sources.list.d/debathena.clusterinfo.list |
---|
| 110 | if [ -r "$cinfo" ] && ( [ ! -e "$slist" ] || [ -w "$slist" ] ); then |
---|
| 111 | echo "** Updating debathena.clusterinfo.list" |
---|
| 112 | [ -e "$slist" ] && rm "$slist" |
---|
| 113 | dsource="$(egrep -h '^deb(-src)? http://debathena\.mit\.edu/apt ' /etc/apt/sources.list /etc/apt/sources.list.d/*.list 2>/dev/null | sort -u)" |
---|
| 114 | if [ -n "$dsource" ]; then |
---|
| 115 | (. $cinfo |
---|
| 116 | echo "# This file is automatically updated by debathena-auto-update" |
---|
| 117 | echo "# based on your Hesiod cluster information. If you want to" |
---|
| 118 | echo "# make changes, do so in another file." |
---|
| 119 | echo |
---|
| 120 | case $APT_RELEASE in |
---|
| 121 | production) ;; |
---|
[23814] | 122 | proposed) echo "$dsource" | awk '$3 !~ /-/ {$3 = $3 "-proposed"; print}' ;; |
---|
| 123 | development) echo "$dsource" | awk '$3 != /-/ {$3 = $3 "-proposed"; print}' |
---|
| 124 | echo "$dsource" | awk '$3 != /-/ {$3 = $3 "-development"; print}' ;; |
---|
[23786] | 125 | esac |
---|
| 126 | ) > $slist |
---|
| 127 | else |
---|
| 128 | echo "Never mind, I can't figure out which sources.list line is Debathena's" |
---|
| 129 | fi |
---|
| 130 | else |
---|
| 131 | echo "** Skipping update of debathena.clusterinfo.list" |
---|
[23159] | 132 | fi |
---|
| 133 | |
---|
[23174] | 134 | # Tell apt not to expect user input during package installation. |
---|
| 135 | export DEBIAN_FRONTEND=noninteractive |
---|
| 136 | |
---|
[24337] | 137 | # Configure any unconfigured packages (Trac #407) |
---|
| 138 | if ! v dpkg --configure -a; then |
---|
| 139 | complain "Failed to configure unconfigured packages." |
---|
| 140 | exit |
---|
| 141 | fi |
---|
| 142 | |
---|
| 143 | # A recently configured package may want a reboot |
---|
[24376] | 144 | save_success "Rebooted after dpkg --configure -a" |
---|
[24337] | 145 | maybe_reboot |
---|
| 146 | |
---|
[23156] | 147 | # Update the aptitude cache. |
---|
[23717] | 148 | if ! v aptitude --quiet --assume-yes update; then |
---|
[23156] | 149 | complain "aptitude update failed" |
---|
| 150 | exit |
---|
| 151 | fi |
---|
| 152 | |
---|
| 153 | # Exit quietly (except for perhaps rebooting) if there are no upgrades |
---|
| 154 | # to take. |
---|
| 155 | pattern='^0 packages upgraded, 0 newly installed, 0 to remove' |
---|
[23717] | 156 | if v aptitude --simulate --assume-yes full-upgrade | grep -q "$pattern"; then |
---|
| 157 | echo "Nothing to do!" |
---|
[24376] | 158 | save_success "No updates" |
---|
[23156] | 159 | maybe_reboot |
---|
| 160 | exit |
---|
| 161 | fi |
---|
| 162 | |
---|
| 163 | # Download packages first. |
---|
[23174] | 164 | if ! v aptitude --quiet --assume-yes --download-only full-upgrade; then |
---|
[23156] | 165 | complain "download failed" |
---|
| 166 | exit |
---|
[23143] | 167 | fi |
---|
| 168 | |
---|
[23156] | 169 | # If the debathena-reactivate package is installed, call into the |
---|
| 170 | # login snapshot script to create a root snapshot for the next update. |
---|
| 171 | if [ -x /usr/sbin/athena-login-snapshot ]; then |
---|
| 172 | echo "** Creating root snapshot" |
---|
| 173 | /usr/sbin/athena-login-snapshot update-start |
---|
| 174 | fi |
---|
| 175 | |
---|
[23143] | 176 | # Perform the update. In some corner cases, aptitude might decide |
---|
| 177 | # that the best course of action is to remove the Debathena |
---|
| 178 | # metapackage, so be paranoid about that. |
---|
[23174] | 179 | v aptitude --quiet --assume-yes keep-all |
---|
[23251] | 180 | v aptitude --quiet --assume-yes --download-only dist-upgrade |
---|
[23250] | 181 | if result=$(aptitude -F "%p" search '~i!~VTARGET(^debathena-cluster$ | ^debathena-workstation$ | ^debathena-login$ | ^debathena-standard$ | ^openafs-modules-~D^linux-image-)') |
---|
| 182 | [ -n "$result" ]; then |
---|
[23220] | 183 | echo "** metapackages would be removed by the update, aborting:" $result |
---|
[23174] | 184 | v aptitude --quiet --assume-yes keep-all |
---|
[23220] | 185 | complain "metapackages would be removed by update:" $result |
---|
[23250] | 186 | elif result=$(aptitude -F "%p" search '~b') |
---|
| 187 | [ -n "$result" ]; then |
---|
| 188 | echo "** packages would be broken by the update, aborting:" $result |
---|
| 189 | v aptitude --quiet --assume-yes keep-all |
---|
| 190 | complain "packages would be broken by update:" $result |
---|
[23156] | 191 | else |
---|
| 192 | v aptitude --quiet --assume-yes install |
---|
[24376] | 193 | # Successful update, reset $updlast |
---|
| 194 | updlast=$(date) |
---|
| 195 | save_success "Successful update" |
---|
[23143] | 196 | fi |
---|
| 197 | |
---|
[23549] | 198 | # Finally, update the apt-file cache |
---|
| 199 | v apt-file update |
---|
| 200 | |
---|
[23156] | 201 | if [ -x /usr/sbin/athena-login-snapshot ]; then |
---|
| 202 | echo "** Cleaning up root snapshot" |
---|
| 203 | /usr/sbin/athena-login-snapshot update-end |
---|
| 204 | fi |
---|
| 205 | |
---|
| 206 | maybe_reboot |
---|
[23143] | 207 | exit |
---|