slack-autoupdate

Update your Slackware system automatically
git clone git://git.server.ky/slackcoder/slack-autoupdate
Log | Files | Refs | README

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