aboutsummaryrefslogtreecommitdiff
path: root/src/autoupdate
blob: 04e432b20e62b5451ee68c718868c752ef854d98 (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
#!/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.
export REBOOT_TIME="${REBOOT_TIME:-""}"

# Packages are copied here on successful download.
export PACKAGE_DIR="${PACKAGE_DIR:-/var/spool/slack-autoupdate}"

# Packages are temperarily stored here until success.
export STAGING_DIR="${STAGING_DIR:-/var/cache/slack-autoupdate/staging}"

# Information of interest to the admin on success.
export UPDATE_INFO="${UPDATE_INFO:-$STAGING_DIR/info.txt}"

# Information of interest to the admin on failure.
export UPDATE_ERROR="${UPDATE_ERROR:-$STAGING_DIR/error.txt}"

# Slackware mirror containing packages.
export SLACKWARE_MIRROR="${SLACKWARE_MIRROR:-rsync://mirrors.kernel.org/slackware/slackware64-15.0}"

# A local Slackware mirror with just enough information to support slackpkg.
#
# This step could be skipped if slackpkg supports downloading updates without
# installing them.
export LOCAL_MIRROR=${LOCAL_MIRROR:-"/var/cache/slack-autoupdate/mirror"}

# 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

# This is slackpkg's exit code when updates are available.
SLACKPKG_UPDATES_PENDING=100

slackpkg -mirror="file:///$LOCAL_MIRROR/" check-updates >/dev/null 2>&1
if [ "$?" -eq "$SLACKPKG_UPDATES_PENDING" ]; then
  exit 0
fi

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

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

  (
    echo "downloading updates from $SLACKWARE_MIRROR..."

    # Support slackpkg with the least required files for patches.
    mkdir --parents "$LOCAL_MIRROR"
    cd "$LOCAL_MIRROR" \
      && rsync "$SLACKWARE_MIRROR/CHECKSUMS.md5" . \
      && rsync "$SLACKWARE_MIRROR/CHECKSUMS.md5.asc" . \
      && rsync "$SLACKWARE_MIRROR/ChangeLog.txt" . \
      && rsync "$SLACKWARE_MIRROR/FILELIST.TXT" . \
      && rsync "$SLACKWARE_MIRROR/GPG-KEY" . \
      && rsync "$SLACKWARE_MIRROR/extra" . \
      && rsync "$SLACKWARE_MIRROR/pasture" . \
      && rsync "$SLACKWARE_MIRROR/patches" . \
      && rsync "$SLACKWARE_MIRROR/testing" . \
      && rsync "$SLACKWARE_MIRROR/slackware64/PACKAGES.TXT" slackware64
  ) || exit $?

  slackpkg -mirror="file:///$LOCAL_MIRROR/" check-updates
  if [ "$?" -ne "$SLACKPKG_UPDATES_PENDING" ]; then
    exit 0
  fi

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

    echo "Slackware updates"
    echo
    slackpkg show-changelog | diff - "$LOCAL_MIRROR/ChangeLog.txt"
    echo
  )
)"; then
  >>"$UPDATE_ERROR" echo -e "slackpkg:\n\n$OUTPUT"
fi

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

  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

  UPDATE_INFO=$(mktemp /tmp/sbocheck.XXXXXX)

  (sbocheck | tee $UPDATE_INFO) || exit 1
  if grep -i "no updates available" "$UPDATE_INFO"; then
    exit 0
  fi

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

  (
    exec 1>>"$UPDATE_INFO"

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

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

# Make updates atomic.
if [ -f "$UPDATE_ERROR" ]; then
  mv "$UPDATE_ERROR" "$PACKAGE_DIR"
  mv "$UPDATE_INFO" "$PACKAGE_DIR"

  exit 1
fi


mv "$STAGING_DIR"/* "$PACKAGE_DIR/"
rm -fr "$STAGING_DIR"

if [ -z "$(find "$PACKAGE_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 [ -n "$REBOOT_TIME" ]; then
  nohup shutdown -r "$REBOOT_TIME" >/dev/null 2>&1 &
fi