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