summaryrefslogtreecommitdiff
path: root/debian/apt.cron.daily
blob: 5c5ca88c79e8d4fb31740638ae350dec203a240d (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
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