slack-autoupdate (6962B)
1 #!/bin/bash 2 # 3 # Update your system automatically! 4 # 5 # Packages from different sources are downloaded, under sub-shells, into the 6 # PACKAGE_DIR where they can be installed on reboot. 7 # 8 # A failure encountered at any point should abort any pending package updates 9 # to install. 10 # 11 # To enable sbotools updates, make the /etc/sbotools/sbotools.conf file exist 12 # and configure PKG_DIR to point to the same path as STAGING_DIR. 13 14 # Set to "yes" to send notification to stdout, causing cron to send an email. 15 NOTIFY="${NOTIFY:-no}" 16 17 # Reboot after this period for install after a successful update. 18 # 19 # Set to empty to disable reboot or 'now' to reboot immediately. 20 REBOOT_TIME="${REBOOT_TIME:-""}" 21 22 # Packages are copied here on successful download. All contents of this 23 # directory will be deleted. 24 PACKAGE_DIR="${PACKAGE_DIR:-/var/spool/slack-autoupdate}" 25 26 # Packages are temporarily stored here until success. All contents of this 27 # directory are deleted. 28 STAGING_DIR="/var/cache/slack-autoupdate/staging" 29 30 # Information of interest to the admin on success. 31 UPDATE_INFO="$STAGING_DIR/info.txt" 32 33 # Information of interest to the admin on failure. 34 UPDATE_ERROR="$STAGING_DIR/error.txt" 35 36 # Avoid concurrently running with another instance. 37 if [ "$(ls /var/lock/autoupdate.* 2>/dev/null)" ]; then 38 echo "Another instance of autoupdate is running. If this is not correct, you can remove /var/lock/autoupdate.* files and run autoupdate again." \ 39 >>"$PACKAGE_DIR/$(basename "$UPDATE_ERROR")" 40 if [ "$NOTIFY" = "yes" ]; then 41 cat "$PACKAGE_DIR/$(basename "$UPDATE_ERROR")" 42 fi 43 44 exit 1 45 fi 46 47 touch /var/lock/autoupdate.$$ 48 trap "rm -f /var/lock/autoupdate.$$" EXIT 49 50 # Keep it simple stupid, install pending updates first. 51 mkdir --parents "$PACKAGE_DIR" 52 if [ -n "$(find "$PACKAGE_DIR" -name "*.t*z")" ]; then 53 exit 0 54 fi 55 56 # Make the set of package updates available atomically by storing them in a 57 # temporary location until completion. 58 mkdir --parents "$STAGING_DIR" 59 find "$STAGING_DIR" -mindepth 1 | xargs rm -fr 60 61 # Following are bash functions to check one or more package sources for 62 # updates. 63 # 64 # The functions must use the naming format "[source_name]_source". They 65 # take two arguments. 66 # 67 # - First argument is the file path to save packages. 68 # - Second argument is the file path to append update information. 69 # 70 71 slackpkg_source() { 72 local staging_dir="$1" 73 local update_info="$2" 74 75 yes | slackpkg -batch=on -default_answer=yes update || exit "$?" 76 77 local changelog_txt="$(mktemp /tmp/slack-autoupdate.XXXXXX)" 78 local package_updates="$(mktemp /tmp/slack-autoupdate.XXXXXX)" 79 trap "rm -f ${changelog_txt} ${package_updates}" EXIT 80 81 local output="$(slackpkg -batch=on -default_answer=n upgrade-all)" || exit_code="$?" 82 if [[ $exit_code -ne 0 ]] && [[ $exit_code -ne 20 ]] && [[ $exit_code -ne 100 ]]; then 83 # Slackpkg has several safe exit codes. 84 exit exit_code 85 fi 86 87 echo "$output" \ 88 | grep "\.t.z$" \ 89 | tee "$package_updates" 90 if [ ! -s "$package_updates" ]; then 91 # No updates 92 exit 0 93 fi 94 95 # 96 # This script needs to download updates from slackpkg into a particular 97 # directory, which slackpkg does not support. The following is a work 98 # around. 99 # 100 101 local mirror=$(sed -n ' 102 # Remove leading and trailing blanks 103 s/^[[:blank:]]*// 104 s/[[:blank:]]*$// 105 # Only one token is allowed per line 106 /[[:blank:]]/d 107 # A single solidus should end the URI 108 s,[/]*$,/, 109 # Print the lines beginning with one of the URI schemes we look for 110 \@^file://@p 111 \@^cdrom://@p 112 \@^local://@p 113 \@^https\{0,1\}://@p 114 \@^ftps\{0,1\}://@p' /etc/slackpkg/mirrors) 115 116 while read pkg; do 117 local pkg_url="$( 118 grep "${pkg}$" /var/lib/slackpkg/CHECKSUMS.md5 \ 119 | tr -s ' ' \ 120 | cut -f 2 -d ' ' 121 )" || exit "$?" 122 123 wget \ 124 --quiet \ 125 --directory-prefix="$staging_dir" \ 126 "${mirror}${pkg_url}" \ 127 "${mirror}${pkg_url}.asc" \ 128 || exit "$?" 129 done <"$package_updates" 130 131 echo arg $1 132 echo staging_dir $staging_dir 133 gpg2 --verify-files "$staging_dir"/*.asc || exit "$?" 134 135 ( 136 # Provide update information to the user. 137 138 # Redirect this subshell's standard output to info file. 139 exec 1>>"$update_info" 140 141 local last_installed_package="$( 142 grep \ 143 "$(ls /var/log/packages | sed "s/$/\\\|/g" | tr --delete '\n')v4EcFvjXKlWB" \ 144 /var/lib/slackpkg/ChangeLog.txt \ 145 | head -n 1 146 )" 147 148 while read pkg; do 149 echo " - $pkg" 150 done <"$package_updates" 151 echo 152 echo "### Recent Changelog Entries" 153 echo "" 154 grep --before-context 10000 "$last_installed_package" /var/lib/slackpkg/ChangeLog.txt 155 ) 156 } 157 158 sbotools_source() { 159 local staging_dir="$1" 160 local update_info="$2" 161 162 if [ ! -f /etc/sbotools/sbotools.conf ] \ 163 || [ "$(sed -n 's/PKG_DIR=//p' /etc/sbotools/sbotools.conf)" != "$staging_dir" ]; then 164 # Assume sbotools is disabled. 165 exit 0 166 fi 167 168 source /etc/profile.d/*.sh 169 170 local package_updates=$(mktemp /tmp/slack-autoupdate.XXXXXX) 171 trap "rm -f ${package_updates}" EXIT 172 173 (sbocheck | tee $package_updates) || exit 1 174 175 # Avoid checking for 'no updates available'. It will not 176 # work if you host 'overrides' purposely different than what is 177 # on SBO. 178 if ! grep "needs updating" "$package_updates"; then 179 exit 0 180 fi 181 182 sboupgrade \ 183 --all \ 184 --noinstall \ 185 --nointeractive \ 186 || exit "$?" 187 188 ( 189 exec 1>>"$update_info" 190 191 cat "$package_updates" 192 ) 193 } 194 195 update_sources=(slackpkg_source sbotools_source) 196 for update_source in ${update_sources[@]}; do 197 source_name="$(echo "${update_source}" | sed "s/_source$//" | sed "s/_/ /")" 198 199 if [ -f "$UPDATE_INFO" ]; then 200 >>"$UPDATE_INFO" echo "" 201 fi 202 >>"$UPDATE_INFO" echo "## ${source_name} updates" 203 >>"$UPDATE_INFO" echo "" 204 205 if ! OUTPUT="$( 206 exec 2>&1 207 208 echo "Checking updates for ${source_name}..." 209 210 $update_source "$STAGING_DIR" "$UPDATE_INFO" 211 )"; then 212 if [ -f "$UPDATE_ERROR" ]; then 213 >>"$UPDATE_ERROR" echo "" 214 >>"$UPDATE_ERROR" echo "" 215 fi 216 217 >>"$UPDATE_ERROR" echo -e "${source_name}:\n\n$OUTPUT" 218 fi 219 done 220 221 if [ -z "$(find "$STAGING_DIR" -name "*.t*z" -or -name "info.txt" -or -name "error.txt")" ]; then 222 # No updates 223 exit 0 224 fi 225 226 if [ "$NOTIFY" = "yes" ]; then 227 if [ -f "$UPDATE_ERROR" ]; then 228 echo "Failures were encountered while trying to download updates" 229 echo "" 230 cat "$UPDATE_ERROR" 231 elif [ -f "$UPDATE_INFO" ]; then 232 echo "# Updates pending installation" 233 echo "" 234 cat "$UPDATE_INFO" 235 fi 236 fi 237 238 if [ -f "$UPDATE_ERROR" ]; then 239 mv "$UPDATE_ERROR" "$PACKAGE_DIR" 240 if [ -f "$UPDATE_INFO" ]; then 241 mv "$UPDATE_INFO" "$PACKAGE_DIR" 242 fi 243 244 exit 1 245 fi 246 247 # Now that everything is successful. 248 find "$PACKAGE_DIR" -mindepth 1 | xargs rm -fr 249 mv "$STAGING_DIR"/* "$PACKAGE_DIR/" 250 251 if [ -n "$REBOOT_TIME" ]; then 252 nohup shutdown -r "$REBOOT_TIME" >/dev/null 2>&1 & 253 fi