File: check-support-status.in

package info (click to toggle)
debian-security-support 1%3A13%2B2025.07.16
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 420 kB
  • sloc: perl: 790; sh: 442; makefile: 107
file content (357 lines) | stat: -rwxr-xr-x 11,090 bytes parent folder | download
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
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
#!/bin/sh

#%# Copyright (C) 2014-2017 Christoph Biedl <debian.axhn@manchmal.in-ulm.de>
#%# License: GPL-2.0-only

set -e

. gettext.sh
export TEXTDOMAIN=debian-security-support

VERSION='[% VERSION %]'

# Oldest Debian version included in debian-security-support
DEB_LOWEST_VER_ID=10
# Version ID for next Debian stable
DEB_NEXT_VER_ID=14

if [ -z "$DEBIAN_VERSION" ] ; then
    DEBIAN_VERSION="$(cat /etc/debian_version | grep '[0-9.]' | cut -d. -f1)"
    [ "$DEBIAN_VERSION" ] || DEBIAN_VERSION="$DEB_NEXT_VER_ID"
fi

if [ "$DEBIAN_VERSION" -lt "$DEB_LOWEST_VER_ID" ] || [ "$DEBIAN_VERSION" -gt "$DEB_NEXT_VER_ID" ] ; then
    >&2 printf "%s: " "$NAME"
    >&2 eval_gettext "Warning: unknown DEBIAN_VERSION \$DEBIAN_VERSION. Valid values are from \$DEB_LOWEST_VER_ID to \$DEB_NEXT_VER_ID, inclusive."
    >&2 echo
fi

LIST=[% LIST %]
NOHEADING=
STATUSDB_FILE=
EXCEPT=
TYPE=

NAME="$(basename "$0")"

TODAY="$(date +"%Y%m%d")"

TEMP=$( \
    getopt \
    --options h,V \
    --long help,list:,no-heading,semaphore:,status-db:,except:,type:,version,Version \
    -n "$NAME" \
    -- "$@"
)

FOLD="fold -s -w 72"

usage()
{
gettext "Usage: $NAME [OPTION]
Options:
  -h, --help                    display this help and exit
  --list FILE                   database of packages under specific support conditions
  --no-heading                  skips printing headlines
  --status-db FILE              database about already reported packages
  --except PACKAGES             exempt given binary packages (comma-separated list)
  --type SECURITY_SUPPORT_TYPE  earlyend, ended or limited
  -V, --version                 display version and exit"; echo
}

if [ $? != 0 ] ; then
    >&2 printf "%s: " "$NAME"
    >&2 gettext "Failed to parse the command line parameters"
    >&2 echo
    exit 1
fi

eval set -- "$TEMP"

while true ; do
    case "$1" in
        -V|--version|--Version)
            eval_gettext "\$NAME version \$VERSION"; echo
            exit 0
            ;;
        -h|--help)
            usage;
            exit 0
            ;;
        --list)
            LIST="$2"
            shift 2
            ;;
        --no-heading)
            NOHEADING='--no-heading'
            shift
            ;;
        --semaphore|--status-db)
            # --semaphore is supported for a transitional period
            STATUSDB_FILE="$2"
            shift 2
            ;;
        --except)
            EXCEPT="$2"
            case "$EXCEPT" in
                *:*)
                    >&2 printf "%s: " "$NAME"
                    >&2 gettext 'E: --except=<package name> does not allow :<arch> suffixes'
                    >&2 echo
                    exit 1
                    ;;
            esac
            shift 2
            ;;
        --type)
            TYPE="$2"
            shift 2
            ;;
        --)
            shift ;
            break
            ;;
        *)
            >&2 printf "%s: " "$NAME"
            >&2 gettext 'E: Internal error'
            >&2 echo
            exit 1
            ;;
    esac
done

case "$TYPE" in
'')
    REPORT="$($0 --type ended --list [% LIST %] --status-db "$STATUSDB_FILE" --except "$EXCEPT" $NOHEADING)"
    if [ -n "$REPORT" ]  ; then
        echo "$REPORT"
        echo
    fi
    REPORT="$($0 --type limited --list [% LIST %] --status-db "$STATUSDB_FILE" --except "$EXCEPT" $NOHEADING)"
    if [ -n "$REPORT" ] ; then
        echo "$REPORT"
        echo
    fi
    $0 --type earlyend --list [% LIST %] --status-db "$STATUSDB_FILE" --except "$EXCEPT" $NOHEADING
    exit 0
    ;;
earlyend|ended)
    STATUS=non-supported
    ;;
limited)
    STATUS=limited
    ;;
*)
    >&2 printf "%s: " "$NAME"
    >&2 eval_gettext "E: Unknown --type '\$TYPE'"
    >&2 echo
    exit 1
    ;;
esac

# exit silently if there's no list
if [ ! -f "$LIST" ] ; then
    exit 0
fi

TEMPDIR="$(mktemp --tmpdir --directory debian-security-support.XXXXX)"
trap "rm -rf '$TEMPDIR'" 0

# Get list of installed packages
INSTALLED_LIST="$TEMPDIR/installed"

LC_ALL=C [% DPKG_QUERY %] --show --showformat '${Status}\t${binary:Package}\t${Version}\t${source:Package}\n' |
[% AWK %] '($1=="install"){print}' |
[% AWK %] -F'\t' '{if($4==""){print $2"\t"$3"\t"$2}else{print $2"\t"$3"\t"$4}}' >"$INSTALLED_LIST"

# Create intersection
LEFT="$TEMPDIR/left"
INTERSECTION_LIST="$TEMPDIR/intersection"
[% AWK %] -F'\t' '{print $3}' "$INSTALLED_LIST" | LC_ALL=C sort -u >"$LEFT"
PATTERNS=$(grep "^[^#][^ ]* *$STATUS *" "$LIST" | [% AWK %] '{print $1}' | paste -sd'|')

# build a supported packages pattern
PATTERNS_SUPPORTED=$(grep "^[^#][^ ]* *supported *" "$LIST" | [% AWK %] '{print $1}' | paste -sd'|')

LC_ALL=C grep -P -x -e "$PATTERNS" "$LEFT" >"$INTERSECTION_LIST" || true
if [ ! -s "$INTERSECTION_LIST" ] ; then
    # nothing to do
    exit 0
fi

TD="$TEMPDIR/$TYPE"
mkdir -p "$TD"

cat "$INTERSECTION_LIST" | while read SRC_NAME ; do
    LINE=$(grep -vP '^(#|$)' "$LIST" | while read pattern rest ; do
            if echo $SRC_NAME | grep -q -P -x -e "$pattern" ; then
                echo "$pattern $rest"
                break
            fi
        done)
    IFS="$(printf '\nx')"
    IFS="${IFS%x}"
    case "$TYPE" in
        earlyend)
            TMP_WHEN="$(echo "$LINE" | [% AWK %] '{print $4}')"
            if [ $(date -d $TMP_WHEN +"%Y%m%d") -gt $TODAY ] ; then
                ALERT_WHEN=$TMP_WHEN
                ALERT_VERSION="$(echo "$LINE" | [% AWK %] '{print $3}')"
                ALERT_WHY="$(
                    echo "$LINE" |
                    [% AWK %] '{
                        $0 = substr ($0, index ($0, $4) + length ($4) + 1);
                        gsub (/^[ \t]+/,"");
                        print
                    }'
                )"
            else
                unset TMP_WHEN
            fi
            ;;
        ended)
            TMP_WHEN="$(echo "$LINE" | [% AWK %] '{print $4}')"
            if [ $(date -d $TMP_WHEN +"%Y%m%d") -le $TODAY ] ; then
                ALERT_VERSION="$(echo "$LINE" | [% AWK %] '{print $3}')"
                ALERT_WHEN=$TMP_WHEN
                ALERT_WHY="$(
                    echo "$LINE" |
                    [% AWK %] '{
                        $0 = substr ($0, index ($0, $4) + length ($4) + 1);
                        gsub (/^[ \t]+/,"");
                        print
                    }'
                )"
            else
                unset TMP_WHEN
            fi
            ;;
        limited)
            ALERT_VERSION=
            ALERT_WHEN=
            ALERT_WHY="$(
                echo "$LINE" |
                [% AWK %] '{
                    $0 = substr ($0, index ($0, $2) + length ($2) + 1);
                    gsub (/^[ \t]+/,"");
                    print
                }'
            )"
            ;;
    esac
    unset IFS

    [% AWK %] '($3=="'"$SRC_NAME"'"){print $1" "$2}' "$INSTALLED_LIST" | \
    while read BIN_NAME BIN_VERSION ; do
        # skip packages that were listed in --except
        case ",$EXCEPT," in
            *,"$BIN_NAME",*) # plain match (e.g., "binutils")
                continue
                ;;
            *,"${BIN_NAME%:*}",*) # match with arch suffix (e.g., "libbinutils:amd64")
                continue
                ;;
        esac

        # skip packages fully supported
        if echo $SRC_NAME | grep -q -P -x -e "$PATTERNS_SUPPORTED" ; then
            continue
        fi

        # for earlyend and ended, check packages actually affected (if TMP_WHEN not null)
        if [ -n "$TMP_WHEN" ] || [ "$TYPE" = limited ] ; then
            # need to alert, but check status db first
            TOKEN="$BIN_NAME/$BIN_VERSION"
            if [ "$STATUSDB_FILE" ] && [ -f "$STATUSDB_FILE" ]; then
                if grep -qFx "$TOKEN" "$STATUSDB_FILE" ; then
                    continue
                fi
            fi
            echo "$BIN_NAME $BIN_VERSION" >>"$TD/$SRC_NAME.bin"
            echo "$ALERT_VERSION" >"$TD/$SRC_NAME.version"
            echo "$ALERT_WHEN" >"$TD/$SRC_NAME.when"
            echo "$ALERT_WHY" >"$TD/$SRC_NAME.why"
            if [ "$STATUSDB_FILE" ] ; then
                # add to status db, remove any older entries
                if [ -f "$STATUSDB_FILE" ]; then
                    TEMPFILE="$(mktemp --tmpdir="$(dirname "$STATUSDB_FILE")")"
                    [% AWK %] -F/ '($1!="'"$BIN_NAME"'"){print}' \
                        <"$STATUSDB_FILE" >"$TEMPFILE"
                    mv "$TEMPFILE" "$STATUSDB_FILE"
                fi
                echo "$TOKEN" >>"$STATUSDB_FILE"
            fi  # maintain status db
        fi # package BIN_NAME's version is not supported
    done # read binary name and version for matching source name
done # each source package from intersection

if [ $(find "$TD" -type f | wc -l) -eq 0 ] ; then
    # nothing to do
    exit 0
fi

if [ -z "$NOHEADING" ] ; then
    case "$TYPE" in
        earlyend)
            gettext \
"Future end of support for one or more packages"
            echo; echo
            gettext \
"Unfortunately, it will be necessary to end security support for some packages before the end of the regular security maintenance life cycle." | $FOLD
            echo; echo
            gettext \
"The following packages found on this system are affected by this:" ; echo
            ;;
        ended)
            gettext \
"Ended security support for one or more packages"
            echo; echo
            gettext \
"Unfortunately, it has been necessary to end security support for some packages before the end of the regular security maintenance life cycle." | $FOLD
            echo; echo
            gettext \
"The following packages found on this system are affected by this:" ; echo
            ;;
        limited)
            gettext \
"Limited security support for one or more packages"
            echo; echo
            gettext \
"Unfortunately, it has been necessary to limit security support for some packages." | $FOLD
            echo; echo
            gettext \
"The following packages found on this system are affected by this:" ; echo
            ;;
    esac
fi
for f in $(find "$TD" -type f -name '*.bin' | sort) ; do
    SRC_NAME="$(basename "$f" | sed -e 's/\.bin$//')"
    ALERT_VERSION="$(cat "$TD/$SRC_NAME.version")"
    ALERT_WHEN="$(cat "$TD/$SRC_NAME.when")"
    ALERT_WHY="$(cat "$TD/$SRC_NAME.why")"
    echo
    case "$TYPE" in
        earlyend)
            eval_gettext "* Source:\$SRC_NAME, will end on \$ALERT_WHEN"; echo
            ;;
        ended)
            eval_gettext "* Source:\$SRC_NAME, ended on \$ALERT_WHEN at version \$ALERT_VERSION"; echo
            ;;
        limited)
            eval_gettext "* Source:\$SRC_NAME"; echo
            ;;
    esac
    if [ "$ALERT_WHY" ] ; then
        eval_gettext "  Details: \$ALERT_WHY"; echo
    fi
    if [ $(wc -l <"$f") -eq 1 ] ; then
        gettext "  Affected binary package:"; echo
    else
        gettext "  Affected binary packages:"; echo
    fi
    cat "$f" | while read BIN_NAME BIN_VERSION ; do
        eval_gettext "  - \$BIN_NAME (installed version: \$BIN_VERSION)"; echo
    done
done

exit 0