aboutsummaryrefslogtreecommitdiff
path: root/src/slack-autoupdate
blob: 250c678b5f60af528949468922aecb3ce0362f79 (plain)
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
#!/bin/bash
#
# Update your system automatically!
#
# Packages from different sources are downloaded, under sub-shells, into the
# PACKAGE_DIR where they can be installed on reboot.
#
# A failure encountered at any point should abort any pending package updates
# to install.
#
# To enable sbotools updates, make the /etc/sbotools/sbotools.conf file exist
# and configure PKG_DIR to point to the same path as STAGING_DIR.

# Set to "yes" to send notification to stdout, causing cron to send an email.
NOTIFY="${NOTIFY:-no}"

# Reboot after this period for install after a successful update.
#
# Set to empty to disable reboot or 'now' to reboot immediately.
REBOOT_TIME="${REBOOT_TIME:-""}"

# Packages are copied here on successful download.  All contents of this
# directory will be deleted.
PACKAGE_DIR="${PACKAGE_DIR:-/var/spool/slack-autoupdate}"

# Packages are temporarily stored here until success.  All contents of this
# directory are deleted.
STAGING_DIR="/var/cache/slack-autoupdate/staging"

# Information of interest to the admin on success.
UPDATE_INFO="$STAGING_DIR/info.txt"

# Information of interest to the admin on failure.
UPDATE_ERROR="$STAGING_DIR/error.txt"

# Avoid concurrently running with another instance.
if [ "$(ls /var/lock/autoupdate.* 2>/dev/null)" ]; then
  echo "Another instance of autoupdate is running.  If this is not correct, you can remove /var/lock/autoupdate.* files and run autoupdate again." \
    >>"$PACKAGE_DIR/$(basename "$UPDATE_ERROR")"
  if [ "$NOTIFY" = "yes" ]; then
    cat "$PACKAGE_DIR/$(basename "$UPDATE_ERROR")"
  fi

  exit 1
fi

touch /var/lock/autoupdate.$$
trap "rm -f /var/lock/autoupdate.$$" EXIT

# Keep it simple stupid, install pending updates first.
mkdir --parents "$PACKAGE_DIR"
if [ -n "$(find "$PACKAGE_DIR" -name "*.t*z")" ]; then
  exit 0
fi

# Make the set of package updates available atomically by storing them in a
# temporary location until completion. 
mkdir --parents "$STAGING_DIR"
find "$STAGING_DIR" -mindepth 1 | xargs rm -fr

if ! OUTPUT="$(
  # Capture this subshell's error output to standard output.
  exec 2>&1

  echo "Checking updates for slackpkg..."

  yes | slackpkg -batch=on -default_answer=yes update || exit "$?"

  CHANGELOG_TXT="$(mktemp /tmp/slack-autoupdate.XXXXXX)"
  PACKAGE_UPDATES="$(mktemp /tmp/slack-autoupdate.XXXXXX)"
  trap "rm -f ${CHANGELOG_TXT} ${PACKAGE_UPDATES}" EXIT

  slackpkg -batch=on -default_answer=n upgrade-all \
    | grep "\.t.z$" \
    | tee "$PACKAGE_UPDATES"  \
    || exit "$?"

  if [ ! -s "$PACKAGE_UPDATES" ]; then
    # No updates
    exit 0
  fi

  #
  # This script needs to download updates from slackpkg into a particular
  # directory, which slackpkg does not support.  The following is a work
  # around.
  #

  SOURCE=$(sed -n '
          # Remove leading and trailing blanks
          s/^[[:blank:]]*//
          s/[[:blank:]]*$//
          # Only one token is allowed per line
          /[[:blank:]]/d
          # A single solidus should end the URI
          s,[/]*$,/,
          # Print the lines beginning with one of the URI schemes we look for
          \@^file://@p
          \@^cdrom://@p
          \@^local://@p
          \@^https\{0,1\}://@p
          \@^ftps\{0,1\}://@p' /etc/slackpkg/mirrors)

  while read PKG; do
    PKG_URL="$(
      grep "${PKG}$" /var/lib/slackpkg/CHECKSUMS.md5 \
        | tr -s ' ' \
        | cut -f 2 -d ' '
      )" || exit "$?"

    wget \
      --quiet \
      --directory-prefix="$STAGING_DIR" \
      "${SOURCE}${PKG_URL}" \
      "${SOURCE}${PKG_URL}.asc" \
      || exit "$?"
  done <"$PACKAGE_UPDATES"

  gpg2 --verify-files "$STAGING_DIR"/*.asc || exit "$?"

  (
    # Provide update information to the user.

    # Redirect this subshell's standard output to info file.
    exec 1>>"$UPDATE_INFO"

    LAST_INSTALLED_PACKAGE="$(
      grep \
        "$(ls /var/log/packages | sed "s/$/\\\|/g" | tr --delete '\n')v4EcFvjXKlWB" \
        /var/lib/slackpkg/ChangeLog.txt \
        | head -n 1
    )"

    echo "## Slackware updates"
    echo
    while read PKG; do
      echo " - $PKG"
    done <"$PACKAGE_UPDATES"
    echo
    echo "### Recent Changelog Entries"
    grep --before-context 10000 "$LAST_INSTALLED_PACKAGE" /var/lib/slackpkg/ChangeLog.txt
    echo
  )
)"; then
  >>"$UPDATE_ERROR" echo -e "slackpkg:\n\n$OUTPUT"
fi

if ! OUTPUT="$(
  exec 2>&1

  echo "Checking updates for sbotools..."

  if [ ! -f /etc/sbotools/sbotools.conf ] \
    || [ "$(sed -n 's/PKG_DIR=//p' /etc/sbotools/sbotools.conf)" != "$STAGING_DIR" ]; then
    # Assume sbotools is disabled.
    exit 0
  fi

  source /etc/profile.d/*.sh

  PACKAGE_UPDATES=$(mktemp /tmp/slack-autoupdate.XXXXXX)
  trap "rm -f ${PACKAGE_UPDATES}" EXIT

  (sbocheck | tee $PACKAGE_UPDATES) || exit 1

  # Avoid checking for 'no updates available'.  It will not
  # work if you host 'overrides' purposely different than what is
  # on SBO.
  if ! grep "needs updating" "$PACKAGE_UPDATES"; then
    exit 0
  fi

  sboupgrade \
    --all \
    --noinstall \
    --nointeractive \
    || exit "$?"

  (
    exec 1>>"$UPDATE_INFO"

    echo "## Slackbuild updates"
    echo
    cat "$PACKAGE_UPDATES"
    echo
  )
)"; then
  if [ -f "$UPDATE_ERROR" ]; then
    >>"$UPDATE_ERROR" echo ""
    >>"$UPDATE_ERROR" echo ""
  fi

  >>"$UPDATE_ERROR" echo -e "sbotools:\n\n$OUTPUT"
fi

if [ -z "$(find "$STAGING_DIR" -name "*.t*z" -or -name "info.txt" -or -name "error.txt")" ]; then
  # No updates
  exit 0
fi

if [ "$NOTIFY" = "yes" ]; then
  if [ -f "$UPDATE_ERROR" ]; then
    echo "Failures were encountered while trying to download updates"
    echo ""
    cat "$UPDATE_ERROR"
  elif [ -f "$UPDATE_INFO" ]; then
    echo "# Updates pending installation"
    echo ""
    cat "$UPDATE_INFO"
  fi
fi

if [ -f "$UPDATE_ERROR" ]; then
  mv "$UPDATE_ERROR" "$PACKAGE_DIR"
  if [ -f "$UPDATE_INFO" ]; then
    mv "$UPDATE_INFO" "$PACKAGE_DIR"
  fi

  exit 1
fi

# Now that everything is successful.
find "$PACKAGE_DIR" -mindepth 1 | xargs rm -fr
mv "$STAGING_DIR"/* "$PACKAGE_DIR/"

if [ -n "$REBOOT_TIME" ]; then
  nohup shutdown -r "$REBOOT_TIME" >/dev/null 2>&1 &
fi