1
|
#!/bin/bash
|
2
|
|
3
|
# $Id: email_updates.sh 87 2014-10-13 19:34:00Z deoren $
|
4
|
# $HeadURL: file:///var/www/svn/whyaskwhy.org/projects/email_updates/trunk/email_updates.sh $
|
5
|
|
6
|
# Purpose:
|
7
|
# This script is intended to be run once daily to report any patches
|
8
|
# available for the OS. If a particular patch has been reported previously
|
9
|
# the goal is to NOT report it again (TODO: unless requested via FLAG).
|
10
|
|
11
|
# Compatiblity notes:
|
12
|
# * This script needs to be compatible with:
|
13
|
# "GNU bash, version 3.2.25(1)-release (x86_64-redhat-linux-gnu)"
|
14
|
# as that is the oldest version of Bash that I'll be using this script with.
|
15
|
# * Tested on RHELv5.x, CentOSv5.x & CentOSv6.x; basic update and LOCKSS repos
|
16
|
|
17
|
# References:
|
18
|
#
|
19
|
# * http://projects.whyaskwhy.org/projects/email-updates/wiki/Custom_Settings
|
20
|
#
|
21
|
# * http://quickies.andreaolivato.net/post/133473114/using-sqlite3-in-bash
|
22
|
# * The Definitive Guide to SQLite, 2e
|
23
|
# * http://www.thegeekstuff.com/2010/06/bash-array-tutorial/
|
24
|
# * http://stackoverflow.com/questions/5431909/bash-functions-return-boolean-to-be-used-in-if
|
25
|
# * http://mywiki.wooledge.org/BashPitfalls
|
26
|
# * http://stackoverflow.com/questions/1063347/passing-arrays-as-parameters-in-bash
|
27
|
|
28
|
|
29
|
#########################
|
30
|
# Settings
|
31
|
#########################
|
32
|
|
33
|
# Custom file that allows overriding all predefined settings
|
34
|
# http://projects.whyaskwhy.org/projects/email-updates/wiki/Custom_Settings
|
35
|
OVERRIDES_FILE="/etc/whyaskwhy.org/email_updates.conf"
|
36
|
|
37
|
# Not a bad idea to run with this enabled for a while after big changes
|
38
|
# and have cron deliver the output to you for verification
|
39
|
DEBUG_ON=1
|
40
|
|
41
|
# Usually not needed
|
42
|
VERBOSE_DEBUG_ON=0
|
43
|
|
44
|
# Useful for testing where we don't want to bang on upstream servers too much
|
45
|
SKIP_UPSTREAM_SYNC=0
|
46
|
|
47
|
# Used to determine whether up2date, yum or apt-get should be used to
|
48
|
# calculate the available updates
|
49
|
MATCH_RHEL4='Red Hat Enterprise Linux.*4'
|
50
|
MATCH_RHEL5='Red Hat Enterprise Linux.*5'
|
51
|
MATCH_UBUNTU='Ubuntu'
|
52
|
MATCH_CENTOS='CentOS'
|
53
|
|
54
|
# Used when providing host info via email (if enabled)
|
55
|
MATCH_IFCONFIG_FULL='^\s+inet addr:[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+'
|
56
|
MATCH_IFCONFIG_IPS_ONLY='[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+'
|
57
|
|
58
|
# Mash the contents into a single string - not creating an array via ()
|
59
|
RELEASE_INFO=$(cat /etc/*release)
|
60
|
|
61
|
# Let's not rely on a crontab to be configured properly. Instead, let's go
|
62
|
# ahead and append to what's already set with the most important entries.
|
63
|
# PATH lookups are short-circuited on first match anyway, so lookup times
|
64
|
# should be trivial.
|
65
|
PATH="${PATH}:/usr/sbin:/usr/bin:/sbin:/bin"
|
66
|
|
67
|
# Redmine tags
|
68
|
EMAIL_TAG_PROJECT="server-support"
|
69
|
EMAIL_TAG_CATEGORY="Patch"
|
70
|
EMAIL_TAG_STATUS="Assigned"
|
71
|
|
72
|
# Set this to a valid email address if you want to have this
|
73
|
# report appear to come from that address.
|
74
|
EMAIL_SENDER=""
|
75
|
|
76
|
# Where should the email containing the list of updates go?
|
77
|
EMAIL_DEST="updates-notification@example.org"
|
78
|
|
79
|
# Should we include the IP Address and full hostname of the system sending
|
80
|
# the email? This could be useful if this script is deployed on a system
|
81
|
# that is being prepped to replace another one (i.e., same hostname).
|
82
|
EMAIL_INCLUDE_HOST_INFO="1"
|
83
|
|
84
|
|
85
|
TEMP_FILE="/tmp/updates_list_$$.tmp"
|
86
|
TODAY=$(date "+%B %d %Y")
|
87
|
|
88
|
# Schema for database:
|
89
|
DB_STRUCTURE="CREATE TABLE reported_updates (id INTEGER PRIMARY KEY, package TEXT, time TIMESTAMP NOT NULL DEFAULT (datetime('now','localtime')));"
|
90
|
|
91
|
# In which field in the database is patch information stored?
|
92
|
DB_PATCH_FIELD=2
|
93
|
|
94
|
DB_FILE="/var/cache/email_updates/reported_updates.db"
|
95
|
|
96
|
# FIXME: Create Bash function instead of using external dirname tool?
|
97
|
DB_FILE_DIR=$(dirname ${DB_FILE})
|
98
|
|
99
|
# Anything required for this script to run properly
|
100
|
DEPENDENCIES=(
|
101
|
|
102
|
sqlite3
|
103
|
mailx
|
104
|
|
105
|
)
|
106
|
|
107
|
#------------------------------
|
108
|
# Internal Field Separator
|
109
|
#------------------------------
|
110
|
# Backup of IFS
|
111
|
# FIXME: Needed for anything?
|
112
|
OIFS=${IFS}
|
113
|
|
114
|
# Set to newlines only so spaces won't trigger a new array entry and so loops
|
115
|
# will only consider items separated by newlines to be the next in the loop
|
116
|
IFS=$'\n'
|
117
|
|
118
|
|
119
|
|
120
|
# Allow overriding any of the predefined settings above
|
121
|
# http://projects.whyaskwhy.org/projects/email-updates/wiki/Custom_Settings
|
122
|
#
|
123
|
# FIXME: Verify permissions first before importing file
|
124
|
#
|
125
|
if [ -f ${OVERRIDES_FILE} ]; then
|
126
|
. ${OVERRIDES_FILE}
|
127
|
fi
|
128
|
|
129
|
|
130
|
#########################
|
131
|
# Functions
|
132
|
#########################
|
133
|
|
134
|
verify_dependencies() {
|
135
|
|
136
|
# Verify that all dependencies are present
|
137
|
# sqlite3, mail|mailx, ?
|
138
|
if [[ "${DEBUG_ON}" -ne 0 ]]; then
|
139
|
echo -e '\n\n************************'
|
140
|
echo "Dependency checks"
|
141
|
echo -e '************************'
|
142
|
fi
|
143
|
|
144
|
for dependency in ${DEPENDENCIES[@]}
|
145
|
do
|
146
|
# Debug output
|
147
|
#echo "$(which ${dependency}) ${dependency}"
|
148
|
|
149
|
# Try to locate the dependency within the path. If found, compare
|
150
|
# the basename of the dependency against the full path. If there
|
151
|
# is a match, consider the required dependency present on the system
|
152
|
if [[ "$(which ${dependency})" =~ "${dependency}" ]]; then
|
153
|
if [[ "${DEBUG_ON}" -ne 0 ]]; then
|
154
|
echo "[I] ${dependency} found."
|
155
|
fi
|
156
|
else
|
157
|
echo "[!] ${dependency} missing. Please install then try again."
|
158
|
exit 1
|
159
|
fi
|
160
|
|
161
|
done
|
162
|
|
163
|
}
|
164
|
|
165
|
|
166
|
initialize_db() {
|
167
|
|
168
|
if [[ "${DEBUG_ON}" -ne 0 ]]; then
|
169
|
echo -e '\n\n************************'
|
170
|
echo "Initializing Database"
|
171
|
echo -e '************************'
|
172
|
fi
|
173
|
|
174
|
# Check if cache dir already exists
|
175
|
if [[ ! -d ${DB_FILE_DIR} ]]; then
|
176
|
if [[ "${DEBUG_ON}" -ne 0 ]]; then
|
177
|
echo "[I] Creating ${DB_FILE_DIR}"
|
178
|
fi
|
179
|
mkdir ${DB_FILE_DIR}
|
180
|
fi
|
181
|
|
182
|
# Check if database already exists
|
183
|
if [[ -f ${DB_FILE} ]]; then
|
184
|
if [[ "${DEBUG_ON}" -ne 0 ]]; then
|
185
|
echo "[I] ${DB_FILE} already exists, leaving it be."
|
186
|
fi
|
187
|
return 0
|
188
|
else
|
189
|
# if not, create it
|
190
|
if [[ "${DEBUG_ON}" -ne 0 ]]; then
|
191
|
echo "[I] Creating ${DB_FILE}"
|
192
|
fi
|
193
|
sqlite3 ${DB_FILE} ${DB_STRUCTURE}
|
194
|
fi
|
195
|
|
196
|
}
|
197
|
|
198
|
# http://stackoverflow.com/a/2990533
|
199
|
# Used to print to the screen from within functions that rely on returning data
|
200
|
# to a variable via stdout
|
201
|
echoerr() { echo -e "$@" 1>&2; }
|
202
|
|
203
|
sanitize_string () {
|
204
|
|
205
|
# This process removes extraneous spaces from update strings in order to
|
206
|
# change lines like these:
|
207
|
#
|
208
|
# xorg-x11-server-Xnest.i386 1.1.1-48.91.el5_8.2 update
|
209
|
# libxml2-dev [2.7.6.dfsg-1ubuntu1.9] (2.7.6.dfsg-1ubuntu1.10 Ubuntu:10.04/lucid-updates) []
|
210
|
#
|
211
|
# into lines like these:
|
212
|
# xorg-x11-server-Xnest.i386-1.1.1-48.91.el5_8.2
|
213
|
# libxml2-dev-2.7.6.dfsg-1ubuntu1.9
|
214
|
#
|
215
|
# It does this by:
|
216
|
# ------------------------------------------------------------------------
|
217
|
# #1) Filtering out lines that do not include numbers (they're not kept)
|
218
|
# #2) Replacing instances of multiple spaces with only one instance
|
219
|
# #3) Using a single space as a delimiter, grab fields 1 and 2
|
220
|
# #4) Replace any of '[', ']', '(', ')' or a leading spaces with nothing
|
221
|
# #5) Replace the first space encountered with a '-' character
|
222
|
# ------------------------------------------------------------------------
|
223
|
|
224
|
if $(echo "${1}" | grep -qE '[0-9]'); then
|
225
|
echo "${1}" \
|
226
|
| grep -Ev '^[[:blank:]]{1,}$' \
|
227
|
| tr -s ' ' \
|
228
|
| cut -d' ' -f1,2 \
|
229
|
| sed -r 's/([][(\)]|^\s)//g' \
|
230
|
| sed -r 's/ /-/'
|
231
|
fi
|
232
|
|
233
|
}
|
234
|
|
235
|
is_patch_already_reported() {
|
236
|
|
237
|
# $1 should equal the quoted patch that we're checking
|
238
|
# By this point it should have already been cleaned by sanitize_string()
|
239
|
patch_to_check="${1}"
|
240
|
|
241
|
if [[ "${DEBUG_ON}" -ne 0 ]]; then
|
242
|
echoerr "\n[I] Checking \"$1\" against previously reported updates ..."
|
243
|
fi
|
244
|
|
245
|
# Rely on the sanitized string having fields separated by spaces so we can
|
246
|
# grab the first field (no version info) and use that as a search term
|
247
|
package_prefix=$(echo ${1} | cut -d' ' -f 1)
|
248
|
|
249
|
sql_query_match_first_field="SELECT * FROM reported_updates WHERE package LIKE '${package_prefix}%' ORDER BY time DESC"
|
250
|
|
251
|
previously_reported_updates=($(sqlite3 "${DB_FILE}" "${sql_query_match_first_field}" | cut -d '|' -f 2))
|
252
|
|
253
|
for previously_reported_update in ${previously_reported_updates[@]}
|
254
|
do
|
255
|
if [[ "${VERBOSE_DEBUG_ON}" -ne 0 ]]; then
|
256
|
echoerr "[I] SQL QUERY MATCH:" $previously_reported_update
|
257
|
fi
|
258
|
|
259
|
# Assume that old database entries may need multiple spaces
|
260
|
# stripped from strings so we can accurately compare them
|
261
|
stripped_prev_reported_update=$(sanitize_string ${previously_reported_update})
|
262
|
|
263
|
# See if the selected patch has already been reported
|
264
|
if [[ "${stripped_prev_reported_update}" == "${patch_to_check}" ]]; then
|
265
|
# Report a match, and exit loop
|
266
|
return 0
|
267
|
fi
|
268
|
done
|
269
|
|
270
|
# If we get this far, report no match
|
271
|
return 1
|
272
|
}
|
273
|
|
274
|
|
275
|
print_patch_arrays() {
|
276
|
|
277
|
# This function is useful for getting debug output "on demand"
|
278
|
# when the global debug option is disabled
|
279
|
|
280
|
#NOTE: Relies on global variables
|
281
|
|
282
|
echo -e '\n\n***************************************************'
|
283
|
#echo "${#UNREPORTED_UPDATES[@]} unreported update(s) are available"
|
284
|
echo "UNREPORTED UPDATES"
|
285
|
echo -e '***************************************************\n'
|
286
|
echo -e " ${#UNREPORTED_UPDATES[@]} unreported update(s) are available\n"
|
287
|
|
288
|
for unreported_update in "${UNREPORTED_UPDATES[@]}"
|
289
|
do
|
290
|
echo " * ${unreported_update}"
|
291
|
done
|
292
|
|
293
|
echo -e '\n***************************************************'
|
294
|
#echo "${#SKIPPED_UPDATES[@]} skipped update(s) are available"
|
295
|
echo "SKIPPED UPDATES"
|
296
|
echo -e '***************************************************\n'
|
297
|
echo -e " ${#SKIPPED_UPDATES[@]} skipped update(s) are available\n"
|
298
|
|
299
|
for skipped_update in "${SKIPPED_UPDATES[@]}"
|
300
|
do
|
301
|
echo " * ${skipped_update}"
|
302
|
done
|
303
|
|
304
|
}
|
305
|
|
306
|
|
307
|
email_report() {
|
308
|
|
309
|
# $@ is ALL arguments to this function, i.e., the unreported patches
|
310
|
updates=(${@})
|
311
|
|
312
|
# Use $1 array function argument
|
313
|
NUMBER_OF_UPDATES="${#updates[@]}"
|
314
|
EMAIL_SUBJECT="${HOSTNAME}: ${NUMBER_OF_UPDATES} update(s) are available"
|
315
|
|
316
|
# Write updates to the temp file
|
317
|
for update in "${updates[@]}"
|
318
|
do
|
319
|
echo "${update}" >> ${TEMP_FILE}
|
320
|
done
|
321
|
|
322
|
echo " " >> ${TEMP_FILE}
|
323
|
|
324
|
# Tag report with Redmine compliant keywords
|
325
|
# http://www.redmine.org/projects/redmine/wiki/RedmineReceivingEmails
|
326
|
echo "Project: ${EMAIL_TAG_PROJECT}" >> ${TEMP_FILE}
|
327
|
echo "Category: ${EMAIL_TAG_CATEGORY}" >> ${TEMP_FILE}
|
328
|
echo "Status: ${EMAIL_TAG_STATUS}" >> ${TEMP_FILE}
|
329
|
|
330
|
# If we're to include host specific info ...
|
331
|
if [[ "${EMAIL_INCLUDE_HOST_INFO}" -ne 0 ]]; then
|
332
|
|
333
|
echo -e "\nHostname: $(hostname -f)" >> ${TEMP_FILE}
|
334
|
echo -e "\nIP Address(es):\n----------------------------------" >> ${TEMP_FILE}
|
335
|
# FIXME: This is ugly, but works on RHEL5 and newer
|
336
|
echo $(ifconfig | grep -Po "${MATCH_IFCONFIG_FULL}" | grep -v '127.0.0' | grep -Po "${MATCH_IFCONFIG_IPS_ONLY}") >> ${TEMP_FILE}
|
337
|
|
338
|
fi
|
339
|
|
340
|
# Send the report via email
|
341
|
# If user chose to masquerade this email as a specific user, set the value
|
342
|
if [[ ! -z ${EMAIL_SENDER} ]]; then
|
343
|
mail -s "${EMAIL_SUBJECT}" --append=FROM:${EMAIL_SENDER} ${EMAIL_DEST} < ${TEMP_FILE}
|
344
|
else
|
345
|
# otherwise, just use whatever user account this script runs as
|
346
|
# (which is usually root)
|
347
|
mail -s "${EMAIL_SUBJECT}" ${EMAIL_DEST} < ${TEMP_FILE}
|
348
|
fi
|
349
|
|
350
|
}
|
351
|
|
352
|
|
353
|
record_reported_patches() {
|
354
|
|
355
|
# $@ is ALL arguments to this function, i.e., the unreported patches
|
356
|
updates=(${@})
|
357
|
|
358
|
# Add reported patches to the database
|
359
|
|
360
|
for update in "${updates[@]}"
|
361
|
do
|
362
|
sqlite3 ${DB_FILE} "INSERT INTO reported_updates (package) VALUES (\"${update}\");"
|
363
|
done
|
364
|
|
365
|
}
|
366
|
|
367
|
|
368
|
sync_packages_list () {
|
369
|
|
370
|
# Update index of available packages for the OS
|
371
|
|
372
|
THIS_DISTRO=$(detect_supported_distros)
|
373
|
|
374
|
case "${THIS_DISTRO}" in
|
375
|
up2date )
|
376
|
# FIXME: There isn't a "run from cache" option to use later on that
|
377
|
# I am aware of, so we'll just do a single run later
|
378
|
:
|
379
|
;;
|
380
|
apt )
|
381
|
# Skip upstream sync unless running in production mode
|
382
|
if [[ "${SKIP_UPSTREAM_SYNC}" -eq 0 ]]; then
|
383
|
apt-get update > /dev/null
|
384
|
fi
|
385
|
;;
|
386
|
yum )
|
387
|
# Skip upstream sync unless running in production mode
|
388
|
if [[ "${SKIP_UPSTREAM_SYNC}" -eq 0 ]]; then
|
389
|
|
390
|
# Fixes #120
|
391
|
#
|
392
|
# Toss stdout, but only toss the one RHEL status message from
|
393
|
# stderr that just mentions the system is receiving updates
|
394
|
# from Red Hat Subscription Management
|
395
|
yum check-update 2> >(grep -v 'This system is receiving') \
|
396
|
> /dev/null
|
397
|
|
398
|
fi
|
399
|
;;
|
400
|
esac
|
401
|
|
402
|
}
|
403
|
|
404
|
|
405
|
detect_supported_distros () {
|
406
|
|
407
|
if [[ "${RELEASE_INFO}" =~ ${MATCH_RHEL4} ]]; then
|
408
|
echo "up2date"
|
409
|
fi
|
410
|
|
411
|
if [[ "${RELEASE_INFO}" =~ ${MATCH_RHEL5} ]]; then
|
412
|
echo "yum"
|
413
|
fi
|
414
|
|
415
|
if [[ "${RELEASE_INFO}" =~ ${MATCH_CENTOS} ]]; then
|
416
|
echo "yum"
|
417
|
fi
|
418
|
|
419
|
if [[ "${RELEASE_INFO}" =~ ${MATCH_UBUNTU} ]]; then
|
420
|
echo "apt"
|
421
|
fi
|
422
|
|
423
|
}
|
424
|
|
425
|
|
426
|
calculate_updates_via_up2date() {
|
427
|
|
428
|
local -a RAW_UPDATES_ARRAY
|
429
|
|
430
|
# Capture output in array so we can clean and return it
|
431
|
RAW_UPDATES_ARRAY=($(up2date --list | grep -i -E -w "${UP2DATE_MATCH_ON}"))
|
432
|
|
433
|
for update in "${RAW_UPDATES_ARRAY[@]}"
|
434
|
do
|
435
|
# Return cleaned up string
|
436
|
echo $(sanitize_string ${update})
|
437
|
done
|
438
|
|
439
|
}
|
440
|
|
441
|
|
442
|
calculate_updates_via_yum() {
|
443
|
|
444
|
declare -a YUM_CHECKUPDATE_OUTPUT
|
445
|
|
446
|
# Capturing output in array so we can more easily filter out what we're not
|
447
|
# interested in considering an "update". Don't toss lines without a number
|
448
|
# yet; sanitize_string() handles that. We need "Obsoleting Packages"
|
449
|
# in place as a cut-off marker. We're also tossing (see #120)
|
450
|
# the one RHEL status message from stderr that just mentions the system
|
451
|
# is receiving updates from Red Hat Subscription Management
|
452
|
YUM_CHECKUPDATE_OUTPUT=(
|
453
|
$(yum check-update 2> >(grep -v 'This system is receiving'))
|
454
|
)
|
455
|
|
456
|
for line in "${YUM_CHECKUPDATE_OUTPUT[@]}"
|
457
|
do
|
458
|
# If we've gotten this far it means we have passed all available
|
459
|
# updates and yum is telling us what old packages it will remove
|
460
|
if [[ "${line}" =~ "Obsoleting Packages" ]]; then
|
461
|
if [[ "${DEBUG_ON}" -ne 0 ]]; then
|
462
|
echoerr "Hit marker, breaking loop"
|
463
|
fi
|
464
|
|
465
|
break
|
466
|
else
|
467
|
echo $(sanitize_string ${line})
|
468
|
fi
|
469
|
done
|
470
|
|
471
|
}
|
472
|
|
473
|
|
474
|
calculate_updates_via_apt() {
|
475
|
local -a RAW_UPDATES_ARRAY
|
476
|
|
477
|
# Capture output in array so we can clean and return it
|
478
|
# Using the follwing syntax mainly as a reminder that it's available
|
479
|
RAW_UPDATES_ARRAY=($(apt-get dist-upgrade -s | grep 'Conf' | cut -c 6-))
|
480
|
|
481
|
for update in "${RAW_UPDATES_ARRAY[@]}"
|
482
|
do
|
483
|
# Return cleaned up string
|
484
|
echo $(sanitize_string ${update})
|
485
|
done
|
486
|
|
487
|
}
|
488
|
|
489
|
|
490
|
calculate_updates_available () {
|
491
|
|
492
|
THIS_DISTRO=$(detect_supported_distros)
|
493
|
|
494
|
case "${THIS_DISTRO}" in
|
495
|
up2date ) calculate_updates_via_up2date
|
496
|
;;
|
497
|
apt ) calculate_updates_via_apt
|
498
|
;;
|
499
|
yum ) calculate_updates_via_yum
|
500
|
;;
|
501
|
esac
|
502
|
|
503
|
|
504
|
}
|
505
|
|
506
|
|
507
|
#############################
|
508
|
# Setup
|
509
|
#############################
|
510
|
|
511
|
# Make sure we have sqlite3, mailx and other necessary tools installed
|
512
|
verify_dependencies
|
513
|
|
514
|
# Create SQLite DB if it doesn't already exist
|
515
|
initialize_db
|
516
|
|
517
|
|
518
|
if [[ "${DEBUG_ON}" -ne 0 ]]; then
|
519
|
echo -e '\n\n************************'
|
520
|
echo "Checking for updates ..."
|
521
|
echo -e '************************'
|
522
|
fi
|
523
|
|
524
|
# Run apt-get update, yum check-update or other applicable commands
|
525
|
# to synchronize this systems local packages list with upstream server
|
526
|
# so we can determine which patches/updates need to be installed
|
527
|
sync_packages_list
|
528
|
|
529
|
|
530
|
|
531
|
#############################
|
532
|
# Main Code
|
533
|
#############################
|
534
|
|
535
|
|
536
|
# Create an array containing all updates, one per array member
|
537
|
AVAILABLE_UPDATES=($(calculate_updates_available))
|
538
|
|
539
|
|
540
|
# If updates are available ...
|
541
|
if [[ ${#AVAILABLE_UPDATES[@]} -gt 0 ]]; then
|
542
|
|
543
|
declare -a UNREPORTED_UPDATES SKIPPED_UPDATES
|
544
|
|
545
|
for update in "${AVAILABLE_UPDATES[@]}"
|
546
|
do
|
547
|
# Check to see if the patch has been previously reported
|
548
|
if $(is_patch_already_reported ${update}); then
|
549
|
|
550
|
# Skip the update, but log it for troubleshooting purposes
|
551
|
SKIPPED_UPDATES=("${SKIPPED_UPDATES[@]}" "${update}")
|
552
|
|
553
|
if [[ "${VERBOSE_DEBUG_ON}" -ne 0 ]]; then
|
554
|
echo "[SKIP] ${update}"
|
555
|
fi
|
556
|
|
557
|
else
|
558
|
# Add the update to an array to be reported
|
559
|
# FIXME: There is a bug here that results in a duplicate item
|
560
|
UNREPORTED_UPDATES=("${UNREPORTED_UPDATES[@]}" "${update}")
|
561
|
|
562
|
if [[ "${VERBOSE_DEBUG_ON}" -ne 0 ]]; then
|
563
|
echo "[INCL] ${update}"
|
564
|
fi
|
565
|
fi
|
566
|
done
|
567
|
|
568
|
# Only print out the list of unreported and skipped updates if we're in
|
569
|
# debug mode.
|
570
|
if [[ "${DEBUG_ON}" -ne 0 ]]; then
|
571
|
print_patch_arrays
|
572
|
fi
|
573
|
|
574
|
# If we're not in debug mode, send an email
|
575
|
if [[ "${DEBUG_ON}" -eq 0 ]]; then
|
576
|
# If there are no updates, DON'T send an email
|
577
|
if [[ ! ${#UNREPORTED_UPDATES[@]} -gt 0 ]]; then
|
578
|
:
|
579
|
else
|
580
|
# There ARE updates, so send the email
|
581
|
email_report "${UNREPORTED_UPDATES[@]}"
|
582
|
fi
|
583
|
fi
|
584
|
|
585
|
record_reported_patches "${UNREPORTED_UPDATES[@]}"
|
586
|
|
587
|
else
|
588
|
|
589
|
if [[ "${DEBUG_ON}" -ne 0 ]]; then
|
590
|
echo -e '\n\n************************'
|
591
|
echo "No updates found"
|
592
|
echo -e '************************'
|
593
|
fi
|
594
|
|
595
|
# The "do nothing" operator in case DEBUG_ON is off
|
596
|
# FIXME: Needed?
|
597
|
:
|
598
|
|
599
|
fi
|