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