xref: /openbmc/qemu/scripts/coverity-scan/run-coverity-scan (revision 9c263d07fd80d18dcee99b74335505779d150db1)
1#!/bin/sh -e
2
3# Upload a created tarball to Coverity Scan, as per
4# https://scan.coverity.com/projects/qemu/builds/new
5
6# This work is licensed under the terms of the GNU GPL version 2,
7# or (at your option) any later version.
8# See the COPYING file in the top-level directory.
9#
10# Copyright (c) 2017-2020 Linaro Limited
11# Written by Peter Maydell
12
13# Note that this script will automatically download and
14# run the (closed-source) coverity build tools, so don't
15# use it if you don't trust them!
16
17# This script assumes that you're running it from a QEMU source
18# tree, and that tree is a fresh clean one, because we do an in-tree
19# build. (This is necessary so that the filenames that the Coverity
20# Scan server sees are relative paths that match up with the component
21# regular expressions it uses; an out-of-tree build won't work for this.)
22# The host machine should have as many of QEMU's dependencies
23# installed as possible, for maximum coverity coverage.
24
25# To do an upload you need to be a maintainer in the Coverity online
26# service, and you will need to know the "Coverity token", which is a
27# secret 8 digit hex string. You can find that from the web UI in the
28# project settings, if you have maintainer access there.
29
30# Command line options:
31#   --dry-run : run the tools, but don't actually do the upload
32#   --update-tools-only : update the cached copy of the tools, but don't run them
33#   --tokenfile : file to read Coverity token from
34#   --version ver : specify version being analyzed (default: ask git)
35#   --description desc : specify description of this version (default: ask git)
36#   --srcdir : QEMU source tree to analyze (default: current working dir)
37#   --results-tarball : path to copy the results tarball to (default: don't
38#                       copy it anywhere, just upload it)
39#
40# User-specifiable environment variables:
41#  COVERITY_TOKEN -- Coverity token
42#  COVERITY_EMAIL -- the email address to use for uploads (default:
43#                    looks at your git user.email config)
44#  COVERITY_BUILD_CMD -- make command (default: 'make -jN' where N is
45#                    number of CPUs as determined by 'nproc')
46#  COVERITY_TOOL_BASE -- set to directory to put coverity tools
47#                        (default: /tmp/coverity-tools)
48#
49# You must specify the token, either by environment variable or by
50# putting it in a file and using --tokenfile. Everything else has
51# a reasonable default if this is run from a git tree.
52
53check_upload_permissions() {
54    # Check whether we can do an upload to the server; will exit the script
55    # with status 1 if the check failed (usually a bad token);
56    # will exit the script with status 0 if the check indicated that we
57    # can't upload yet (ie we are at quota)
58    # Assumes that PROJTOKEN, PROJNAME and DRYRUN have been initialized.
59
60    echo "Checking upload permissions..."
61
62    if ! up_perm="$(wget https://scan.coverity.com/api/upload_permitted --post-data "token=$PROJTOKEN&project=$PROJNAME" -q -O -)"; then
63        echo "Coverity Scan API access denied: bad token?"
64        exit 1
65    fi
66
67    # Really up_perm is a JSON response with either
68    # {upload_permitted:true} or {next_upload_permitted_at:<date>}
69    # We do some hacky string parsing instead of properly parsing it.
70    case "$up_perm" in
71        *upload_permitted*true*)
72            echo "Coverity Scan: upload permitted"
73            ;;
74        *next_upload_permitted_at*)
75            if [ "$DRYRUN" = yes ]; then
76                echo "Coverity Scan: upload quota reached, continuing dry run"
77            else
78                echo "Coverity Scan: upload quota reached; stopping here"
79                # Exit success as this isn't a build error.
80                exit 0
81            fi
82            ;;
83        *)
84            echo "Coverity Scan upload check: unexpected result $up_perm"
85            exit 1
86            ;;
87    esac
88}
89
90
91update_coverity_tools () {
92    # Check for whether we need to download the Coverity tools
93    # (either because we don't have a copy, or because it's out of date)
94    # Assumes that COVERITY_TOOL_BASE, PROJTOKEN and PROJNAME are set.
95
96    mkdir -p "$COVERITY_TOOL_BASE"
97    cd "$COVERITY_TOOL_BASE"
98
99    echo "Checking for new version of coverity build tools..."
100    wget https://scan.coverity.com/download/linux64 --post-data "token=$PROJTOKEN&project=$PROJNAME&md5=1" -O coverity_tool.md5.new
101
102    if ! cmp -s coverity_tool.md5 coverity_tool.md5.new; then
103        # out of date md5 or no md5: download new build tool
104        # blow away the old build tool
105        echo "Downloading coverity build tools..."
106        rm -rf coverity_tool coverity_tool.tgz
107        wget https://scan.coverity.com/download/linux64 --post-data "token=$PROJTOKEN&project=$PROJNAME" -O coverity_tool.tgz
108        if ! (cat coverity_tool.md5.new; echo "  coverity_tool.tgz") | md5sum -c --status; then
109            echo "Downloaded tarball didn't match md5sum!"
110            exit 1
111        fi
112        # extract the new one, keeping it corralled in a 'coverity_tool' directory
113        echo "Unpacking coverity build tools..."
114        mkdir -p coverity_tool
115        cd coverity_tool
116        tar xf ../coverity_tool.tgz
117        cd ..
118        mv coverity_tool.md5.new coverity_tool.md5
119    fi
120
121    rm -f coverity_tool.md5.new
122}
123
124
125# Check user-provided environment variables and arguments
126DRYRUN=no
127UPDATE_ONLY=no
128
129while [ "$#" -ge 1 ]; do
130    case "$1" in
131        --dry-run)
132            shift
133            DRYRUN=yes
134            ;;
135        --update-tools-only)
136            shift
137            UPDATE_ONLY=yes
138            ;;
139        --version)
140            shift
141            if [ $# -eq 0 ]; then
142                echo "--version needs an argument"
143                exit 1
144            fi
145            VERSION="$1"
146            shift
147            ;;
148        --description)
149            shift
150            if [ $# -eq 0 ]; then
151                echo "--description needs an argument"
152                exit 1
153            fi
154            DESCRIPTION="$1"
155            shift
156            ;;
157        --tokenfile)
158            shift
159            if [ $# -eq 0 ]; then
160                echo "--tokenfile needs an argument"
161                exit 1
162            fi
163            COVERITY_TOKEN="$(cat "$1")"
164            shift
165            ;;
166        --srcdir)
167            shift
168            if [ $# -eq 0 ]; then
169                echo "--srcdir needs an argument"
170                exit 1
171            fi
172            SRCDIR="$1"
173            shift
174            ;;
175        --results-tarball)
176            shift
177            if [ $# -eq 0 ]; then
178                echo "--results-tarball needs an argument"
179                exit 1
180            fi
181            RESULTSTARBALL="$1"
182            shift
183            ;;
184        *)
185            echo "Unexpected argument '$1'"
186            exit 1
187            ;;
188    esac
189done
190
191if [ -z "$COVERITY_TOKEN" ]; then
192    echo "COVERITY_TOKEN environment variable not set"
193    exit 1
194fi
195
196if [ -z "$COVERITY_BUILD_CMD" ]; then
197    NPROC=$(nproc)
198    COVERITY_BUILD_CMD="make -j$NPROC"
199    echo "COVERITY_BUILD_CMD: using default '$COVERITY_BUILD_CMD'"
200fi
201
202if [ -z "$COVERITY_TOOL_BASE" ]; then
203    echo "COVERITY_TOOL_BASE: using default /tmp/coverity-tools"
204    COVERITY_TOOL_BASE=/tmp/coverity-tools
205fi
206
207if [ -z "$SRCDIR" ]; then
208    SRCDIR="$PWD"
209fi
210
211PROJTOKEN="$COVERITY_TOKEN"
212PROJNAME=QEMU
213TARBALL=cov-int.tar.xz
214
215
216if [ "$UPDATE_ONLY" = yes ]; then
217    # Just do the tools update; we don't need to check whether
218    # we are in a source tree or have upload rights for this,
219    # so do it before some of the command line and source tree checks.
220    update_coverity_tools
221    exit 0
222fi
223
224cd "$SRCDIR"
225
226echo "Checking this is a QEMU source tree..."
227if ! [ -e "$SRCDIR/VERSION" ]; then
228    echo "Not in a QEMU source tree?"
229    exit 1
230fi
231
232# Fill in defaults used by the non-update-only process
233if [ -z "$VERSION" ]; then
234    VERSION="$(git describe --always HEAD)"
235fi
236
237if [ -z "$DESCRIPTION" ]; then
238    DESCRIPTION="$(git rev-parse HEAD)"
239fi
240
241if [ -z "$COVERITY_EMAIL" ]; then
242    COVERITY_EMAIL="$(git config user.email)"
243fi
244
245check_upload_permissions
246
247update_coverity_tools
248
249TOOLBIN="$(cd "$COVERITY_TOOL_BASE" && echo $PWD/coverity_tool/cov-analysis-*/bin)"
250
251if ! test -x "$TOOLBIN/cov-build"; then
252    echo "Couldn't find cov-build in the coverity build-tool directory??"
253    exit 1
254fi
255
256export PATH="$TOOLBIN:$PATH"
257
258cd "$SRCDIR"
259
260echo "Doing make distclean..."
261make distclean
262
263echo "Configuring..."
264# We configure with a fixed set of enables here to ensure that we don't
265# accidentally reduce the scope of the analysis by doing the build on
266# the system that's missing a dependency that we need to build part of
267# the codebase.
268./configure --disable-modules --enable-sdl --enable-gtk \
269    --enable-opengl --enable-vte --enable-gnutls \
270    --enable-nettle --enable-curses --enable-curl \
271    --audio-drv-list=oss,alsa,sdl,pa --enable-virtfs \
272    --enable-vnc --enable-vnc-sasl --enable-vnc-jpeg --enable-vnc-png \
273    --enable-xen --enable-brlapi \
274    --enable-linux-aio --enable-attr \
275    --enable-cap-ng --enable-trace-backends=log --enable-spice --enable-rbd \
276    --enable-xfsctl --enable-libusb --enable-usb-redir \
277    --enable-libiscsi --enable-libnfs --enable-seccomp \
278    --enable-tpm --enable-libssh --enable-lzo --enable-snappy --enable-bzip2 \
279    --enable-numa --enable-rdma --enable-smartcard --enable-virglrenderer \
280    --enable-mpath --enable-libxml2 --enable-glusterfs \
281    --enable-virtfs --enable-zstd
282
283echo "Making libqemustub.a..."
284make libqemustub.a
285
286echo "Running cov-build..."
287rm -rf cov-int
288mkdir cov-int
289cov-build --dir cov-int $COVERITY_BUILD_CMD
290
291echo "Creating results tarball..."
292tar cvf - cov-int | xz > "$TARBALL"
293
294if [ ! -z "$RESULTSTARBALL" ]; then
295    echo "Copying results tarball to $RESULTSTARBALL..."
296    cp "$TARBALL" "$RESULTSTARBALL"
297fi
298
299echo "Uploading results tarball..."
300
301if [ "$DRYRUN" = yes ]; then
302    echo "Dry run only, not uploading $TARBALL"
303    exit 0
304fi
305
306curl --form token="$PROJTOKEN" --form email="$COVERITY_EMAIL" \
307     --form file=@"$TARBALL" --form version="$VERSION" \
308     --form description="$DESCRIPTION" \
309     https://scan.coverity.com/builds?project="$PROJNAME"
310
311echo "Done."
312