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
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
|
#!/bin/sh
#
#set -e
#
# This file understands the following apt configuration variables:
#
# "APT::Periodic::Update-Package-Lists=1"
# - Do "apt-get update" automatically every n-days (0=disable)
#
# "APT::Periodic::Download-Upgradeable-Packages=0",
# - Do "apt-get upgrade --download-only" every n-days (0=disable)
#
# "APT::Periodic::AutocleanInterval"
# - Do "apt-get autoclean" every n-days (0=disable)
#
# "APT::Periodic::Unattended-Upgrade"
# - Run the "unattended-upgrade" security upgrade script
# every n-days (0=disabled)
# Requires the package "unattended-upgrades" and will write
# a log in /var/log/unattended-upgrades
#
# "APT::Archives::MaxAge",
# - Set maximum allowed age of a cache package file. If a cache
# package file is older it is deleted (0=disable)
#
# "APT::Archives::MaxSize",
# - Set maximum size of the cache in MB (0=disable). If the cache
# is bigger, cached package files are deleted until the size
# requirement is met (the biggest packages will be deleted
# first).
#
# "APT::Archives::MinAge"
# - Set minimum age of a package file. If a file is younger it
# will not be deleted (0=disable). Usefull to prevent races
# and to keep backups of the packages for emergency.
#
check_stamp()
{
stamp="$1"
interval="$2"
if [ $interval -eq 0 ]; then
return 1
fi
if [ ! -f $stamp ]; then
return 0
fi
# compare midnight today to midnight the day the stamp was updated
stamp_file="$stamp"
stamp=$(date --date=$(date -r $stamp_file --iso-8601) +%s 2>/dev/null)
if [ "$?" != "0" ]; then
# Due to some timezones returning 'invalid date' for midnight on
# certain dates (eg America/Sao_Paulo), if date returns with error
# remove the stamp file and return 0. See coreutils bug:
# http://lists.gnu.org/archive/html/bug-coreutils/2007-09/msg00176.html
rm -f "$stamp_file"
return 0
fi
now=$(date --date=$(date --iso-8601) +%s 2>/dev/null)
if [ "$?" != "0" ]; then
# As above, due to some timezones returning 'invalid date' for midnight
# on certain dates (eg America/Sao_Paulo), if date returns with error
# return 0.
return 0
fi
delta=$(($now-$stamp))
# intervall is in days,
interval=$(($interval*60*60*24))
#echo "stampfile: $1"
#echo "interval=$interval, now=$now, stamp=$stamp, delta=$delta"
if [ $delta -ge $interval ]; then
return 0
fi
return 1
}
update_stamp()
{
stamp="$1"
touch $stamp
}
# we check here if autoclean was enough sizewise
check_size_constraints()
{
# min-age in days
MaxAge=0
MinAge=2
MaxSize=0
CacheDir="var/cache/apt"
CacheArchive="archives/"
eval $(apt-config shell MaxAge APT::Archives::MaxAge)
eval $(apt-config shell MinAge APT::Archives::MinAge)
eval $(apt-config shell MaxSize APT::Archives::MaxSize)
eval $(apt-config shell Dir Dir)
eval $(apt-config shell CacheDir Dir::Cache)
eval $(apt-config shell CacheArchive Dir::Cache::archives)
# sanity check
if [ -z "$CacheDir" -o -z "$CacheArchive" ]; then
echo "empty Dir::Cache or Dir::Cache::archives, exiting"
exit
fi
Cache="${Dir%/}/${CacheDir%/}/${CacheArchive%/}/"
# check age
if [ ! $MaxAge -eq 0 ] && [ ! $MinAge -eq 0 ]; then
find $Cache -name "*.deb" \( -mtime +$MaxAge -and -ctime +$MaxAge \) -and -not \( -mtime -$MinAge -or -ctime -$MinAge \) -print0 | xargs -r -0 rm -f
elif [ ! $MaxAge -eq 0 ]; then
find $Cache -name "*.deb" -ctime +$MaxAge -and -mtime +$MaxAge -print0 | xargs -r -0 rm -f
fi
# check size
if [ ! $MaxSize -eq 0 ]; then
# maxSize is in MB
MaxSize=$(($MaxSize*1024))
#get current time
now=$(date --date=$(date --iso-8601) +%s)
MinAge=$(($MinAge*24*60*60))
# reverse-sort by mtime
for file in $(ls -rt $Cache/*.deb 2>/dev/null); do
du=$(du -s $Cache)
size=${du%%/*}
# check if the cache is small enough
if [ $size -lt $MaxSize ]; then
break
fi
# check for MinAge of the file
if [ ! $MinAge -eq 0 ]; then
# check both ctime and mtime
mtime=$(stat -c %Y $file)
ctime=$(stat -c %Z $file)
if [ $mtime -gt $ctime ]; then
delta=$(($now-$mtime))
else
delta=$(($now-$ctime))
fi
#echo "$file ($delta), $MinAge"
if [ $delta -le $MinAge ]; then
#echo "Skiping $file (delta=$delta)"
break
fi
fi
# delete oldest file
rm -f $file
done
fi
}
# sleep for a random interval of time (default 30min)
# (some code taken from cron-apt, thanks)
random_sleep()
{
RandomSleep=1800
eval $(apt-config shell RandomSleep APT::Periodic::RandomSleep)
if [ $RandomSleep -eq 0 ]; then
return
fi
if [ -z "$RANDOM" ] ; then
# A fix for shells that do not have this bash feature.
RANDOM=$(dd if=/dev/urandom count=1 2> /dev/null | cksum | cut -c"1-5")
fi
TIME=$(($RANDOM % $RandomSleep))
sleep $TIME
}
# main
if ! which apt-config >/dev/null; then
exit 0
fi
UpdateInterval=0
DownloadUpgradeableInterval=0
eval $(apt-config shell UpdateInterval APT::Periodic::Update-Package-Lists DownloadUpgradeableInterval APT::Periodic::Download-Upgradeable-Packages)
AutocleanInterval=$DownloadUpgradeableInterval
eval $(apt-config shell AutocleanInterval APT::Periodic::AutocleanInterval)
UnattendedUpgradeInterval=0
eval $(apt-config shell UnattendedUpgradeInterval APT::Periodic::Unattended-Upgrade)
# check if we actually have to do anything
if [ $UpdateInterval -eq 0 ] &&
[ $DownloadUpgradeableInterval -eq 0 ] &&
[ $UnattendedUpgradeInterval -eq 0 ] &&
[ $AutocleanInterval -eq 0 ]; then
exit 0
fi
# laptop check, on_ac_power returns:
# 0 (true) System is on mains power
# 1 (false) System is not on mains power
# 255 (false) Power status could not be determined
# Desktop systems always return 255 it seems
if which on_ac_power >/dev/null; then
on_ac_power
if [ $? -eq 1 ]; then
exit 0
fi
fi
# sleep random amount of time to avoid hitting the
# mirrors at the same time
random_sleep
# check if we can access the cache
if ! apt-get check -q -q 2>/dev/null; then
# wait random amount of time before retrying
random_sleep
# check again
if ! apt-get check -q -q 2>/dev/null; then
echo "$0: could not lock the APT cache while performing daily cron job. "
echo "Is another package manager working?"
exit 1
fi
fi
UPDATE_STAMP=/var/lib/apt/periodic/update-stamp
if check_stamp $UPDATE_STAMP $UpdateInterval; then
if apt-get -qq update 2>/dev/null; then
if which dbus-send >/dev/null && pidof dbus-daemon >/dev/null; then
dbus-send --system / app.apt.dbus.updated boolean:true
fi
update_stamp $UPDATE_STAMP
fi
fi
DOWNLOAD_UPGRADEABLE_STAMP=/var/lib/apt/periodic/download-upgradeable-stamp
if check_stamp $DOWNLOAD_UPGRADEABLE_STAMP $DownloadUpgradeableInterval; then
apt-get -qq -d dist-upgrade 2>/dev/null
update_stamp $DOWNLOAD_UPGRADEABLE_STAMP
fi
UPGRADE_STAMP=/var/lib/apt/periodic/upgrade-stamp
if check_stamp $UPGRADE_STAMP $UnattendedUpgradeInterval; then
unattended-upgrade
update_stamp $UPGRADE_STAMP
fi
AUTOCLEAN_STAMP=/var/lib/apt/periodic/autoclean-stamp
if check_stamp $AUTOCLEAN_STAMP $AutocleanInterval; then
apt-get -qq autoclean
update_stamp $AUTOCLEAN_STAMP
fi
# check cache size
check_size_constraints
|