Documentation: Encourage documentation with code changes
[coreboot.git] / util / board_status / board_status.sh
blob2e93fe22fe1e5346b3c42db58687f128cda4f91f
1 #!/bin/sh
5 EXIT_SUCCESS=0
6 EXIT_FAILURE=1
8 # Stuff from command-line switches
9 COREBOOT_IMAGE="build/coreboot.rom"
10 REMOTE_HOST=""
11 REMOTE_PORT_OPTION=""
12 CLOBBER_OUTPUT=0
13 UPLOAD_RESULTS=0
14 SERIAL_PORT_SPEED=115200
16 # Used to specify whether a command should always be run locally or
17 # if command should be run remoteley when a remote host is specified.
18 LOCAL=0
19 REMOTE=1
20 FATAL=0
21 NONFATAL=1
23 # Used if cbmem is not in default $PATH, e.g. not installed or when using `sudo`
24 CBMEM_PATH=""
26 # Used if nvramtool is not in default $PATH, e.g. not installed or when using `sudo`
27 NVRAMTOOL_PATH=""
29 # test a command
31 # $1: 0 ($LOCAL) to run command locally,
32 # 1 ($REMOTE) to run remotely if remote host defined
33 # $2: command to test
34 # $3: 0 ($FATAL) Exit with an error if the command fails
35 # 1 ($NONFATAL) Don't exit on command test failure
36 test_cmd()
38 local rc
40 if [ -e "$2" ]; then
41 return
44 if [ "$1" -eq "$REMOTE" ] && [ -n "$REMOTE_HOST" ]; then
45 ssh $REMOTE_PORT_OPTION root@${REMOTE_HOST} command -v "$2" > /dev/null
46 rc=$?
47 else
48 command -v "$2" >/dev/null
49 rc=$?
52 if [ $rc -eq 0 ]; then
53 return 0
56 if [ "$3" = "1" ]; then
57 return 1
60 echo "$2 not found"
61 exit $EXIT_FAILURE
64 _cmd()
66 if [ -e "$2" ]; then
67 return $EXIT_FAILURE
70 if [ -n "$3" ]; then
71 pipe_location="${3}"
72 else
73 pipe_location="/dev/null"
76 if [ "$1" -eq "$REMOTE" ] && [ -n "$REMOTE_HOST" ]; then
77 ssh $REMOTE_PORT_OPTION "root@${REMOTE_HOST}" "$2" > "$pipe_location" 2>&1
78 else
79 $2 > "$pipe_location" 2>&1
82 return $?
85 # run a command
87 # $1: 0 ($LOCAL) to run command locally,
88 # 1 ($REMOTE) to run remotely if remote host defined
89 # $2: command
90 # $3: filename to direct output of command into
91 cmd()
93 _cmd $1 "$2" "$3"
95 if [ $? -eq 0 ]; then
96 return
99 echo "Failed to run \"$2\", aborting"
100 rm -f "$3" # don't leave an empty file
101 exit $EXIT_FAILURE
104 # run a command where failure is considered to be non-fatal
106 # $1: 0 ($LOCAL) to run command locally,
107 # 1 ($REMOTE) to run remotely if remote host defined
108 # $2: command
109 # $3: filename to direct output of command into
110 cmd_nonfatal()
112 _cmd $1 "$2" "$3"
114 if [ $? -eq 0 ]; then
115 return
118 echo "Failed to run \"$2\", ignoring"
119 rm -f "$3" # don't leave an empty file
122 # read from a serial port device
124 # $1: serial device to read from
125 # $2: serial port speed
126 # $3: filename to direct output of command into
127 get_serial_bootlog () {
129 local TTY=$1
130 local SPEED=$2
131 local FILENAME=$3
133 if [ ! -c "$TTY" ]; then
134 echo "$TTY is not a valid serial device"
135 exit $EXIT_FAILURE
138 # make the text more noticible
139 test_cmd $LOCAL "tput" $NONFATAL
140 tput_not_available=$?
141 if [ $tput_not_available -eq 0 ]; then
142 tput bold
143 tput setaf 10 # set bright green
146 echo
147 echo "Waiting to receive boot log from $TTY"
148 echo "Press [Enter] when the boot is complete."
149 echo
151 if [ $tput_not_available -eq 0 ]; then
152 tput sgr0
155 # set up the serial port
156 stty -F $TTY $SPEED cs8 -cstopb -parenb clocal
158 # read from the serial port - user must press enter when complete
159 test_cmd $LOCAL "tee"
160 while read LINE; do
161 echo "$LINE" | tee -a "$FILENAME"
162 done < "$SERIAL_DEVICE" &
163 PID=$!
165 read foo
166 kill "$PID" 2>/dev/null
168 echo "Finished reading boot log."
171 show_help() {
172 echo "Usage:
173 ${0} <option>
175 Options
176 -c, --cbmem
177 Path to cbmem on device under test (DUT).
178 -n, --nvramtool
179 Path to nvramtool on device under test (DUT).
180 -C, --clobber
181 Clobber temporary output when finished. Useful for debugging.
182 -h, --help
183 Show this message.
184 -i, --image <image>
185 Path to coreboot image (Default is $COREBOOT_IMAGE).
186 -r, --remote-host <host>
187 Obtain machine information from remote host (using ssh).
188 -s, --serial-device </dev/xxx>
189 Obtain boot log via serial device.
190 -S, --serial-speed <speed>
191 Set the port speed for the serial device (Default is $SERIAL_PORT_SPEED).
192 -u, --upload-results
193 Upload results to coreboot.org.
195 Long options:
196 --ssh-port <port>
197 Use a specific SSH port.
201 getopt -T
202 if [ $? -ne 4 ]; then
203 echo "GNU-compatible getopt(1) required."
204 exit $EXIT_FAILURE
207 LONGOPTS="cbmem:,clobber,help,image:,remote-host:,upload-results"
208 LONGOPTS="${LONGOPTS},serial-device:,serial-speed:"
209 LONGOPTS="${LONGOPTS},ssh-port:"
211 ARGS=$(getopt -o c:n:Chi:r:s:S:u -l "$LONGOPTS" -n "$0" -- "$@");
212 if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi
213 eval set -- "$ARGS"
214 while true ; do
215 case "$1" in
216 # generic options
217 -c|--cbmem)
218 shift
219 CBMEM_PATH="$1"
221 -n|--nvramtool)
222 shift
223 NVRAMTOOL_PATH="$1"
225 -C|--clobber)
226 CLOBBER_OUTPUT=1
228 -h|--help)
229 show_help
230 exit $EXIT_SUCCESS
232 -i|--image)
233 shift
234 COREBOOT_IMAGE="$1"
236 -r|--remote-host)
237 shift
238 REMOTE_HOST="$1"
240 -u|--upload-results)
241 UPLOAD_RESULTS=1
244 # serial port options
245 -s|--serial-device)
246 shift
247 SERIAL_DEVICE="$1"
249 -S|--serial-speed)
250 shift
251 SERIAL_PORT_SPEED="$1"
254 # ssh options
255 --ssh-port)
256 shift
257 REMOTE_PORT_OPTION="-p $1"
260 # error handling
262 shift
263 if [ -n "$*" ]; then
264 echo "Non-option parameters detected: '$*'"
265 exit $EXIT_FAILURE
267 break
270 echo "error processing options at '$1'"
271 exit $EXIT_FAILURE
272 esac
273 shift
274 done
276 grep -rH 'coreboot.org' .git/config >/dev/null 2>&1
277 if [ $? -ne 0 ]; then
278 echo "Script must be run from root of coreboot directory"
279 exit $EXIT_FAILURE
282 if [ ! -e "$COREBOOT_IMAGE" ]; then
283 echo "board_status needs $COREBOOT_IMAGE, but it does not exist."
284 echo "Use \"-i IMAGE_FILE\" to select a different image, or \"--help\" for more options."
285 exit $EXIT_FAILURE
288 # Results will be placed in a temporary location until we're ready to upload.
289 # If the user does not wish to upload, results will remain in /tmp.
290 tmpdir=$(mktemp -d --tmpdir coreboot_board_status.XXXXXXXX)
292 # Obtain coreboot config by running cbfstool on the ROM image. cbfstool may
293 # already exist in build/ or util/cbfstool/, but if not then we'll build it
294 # now and clean it when we're done.
295 cbfstool_cmd="build/cbfstool"
296 do_clean_cbfstool=0
297 if [ ! -x $cbfstool_cmd ]; then
298 cbfstool_cmd="util/cbfstool/cbfstool"
299 if [ -e $cbfstool_cmd ]; then
300 if test ! -x $cbfstool_cmd; then
301 echo "Cannot execute $cbfstool_cmd."
302 exit $EXIT_FAILURE
304 else
305 make -C util/cbfstool/
306 do_clean_cbfstool=1
309 test_cmd $LOCAL "$cbfstool_cmd"
311 tmpcfg=$(mktemp coreboot_config.XXXXXX)
312 echo "Extracting config.txt from $COREBOOT_IMAGE"
313 $cbfstool_cmd "$COREBOOT_IMAGE" extract -n config -f "${tmpdir}/config.txt" >/dev/null 2>&1
314 mv "${tmpdir}/config.txt" "${tmpdir}/config.short.txt"
315 cp "${tmpdir}/config.short.txt" "${tmpcfg}"
316 yes "" | make "DOTCONFIG=${tmpcfg}" oldconfig 2>/dev/null >/dev/null
317 mv "${tmpcfg}" "${tmpdir}/config.txt"
318 rm -f "${tmpcfg}.old"
319 $cbfstool_cmd "$COREBOOT_IMAGE" print > "${tmpdir}/cbfs.txt"
320 rom_contents=$($cbfstool_cmd "$COREBOOT_IMAGE" print 2>&1)
321 if [ -n "$(echo $rom_contents | grep payload_config)" ]; then
322 echo "Extracting payload_config from $COREBOOT_IMAGE"
323 $cbfstool_cmd "$COREBOOT_IMAGE" extract -n payload_config -f "${tmpdir}/payload_config.txt" >/dev/null 2>&1
325 if [ -n "$(echo $rom_contents | grep payload_version)" ]; then
326 echo "Extracting payload_version from $COREBOOT_IMAGE"
327 $cbfstool_cmd "$COREBOOT_IMAGE" extract -n payload_version -f "${tmpdir}/payload_version.txt" >/dev/null 2>&1
329 md5sum -b "$COREBOOT_IMAGE" > "${tmpdir}/rom_checksum.txt"
331 if test $do_clean_cbfstool -eq 1; then
332 make -C util/cbfstool clean
335 # Obtain board and revision info to form the directory structure:
336 # <vendor>/<board>/<revision>/<timestamp>
337 mainboard_dir="$(grep CONFIG_MAINBOARD_DIR "${tmpdir}/config.txt" | awk -F '"' '{ print $2 }')"
338 vendor=$(echo "$mainboard_dir" | awk -F '/' '{ print $1 }')
339 mainboard=$(echo "$mainboard_dir" | awk -F '/' '{ print $2 }')
341 getrevision="util/board_status/getrevision.sh"
342 test_cmd $LOCAL $getrevision
343 tagged_version=$($getrevision -T)
344 timestamp=$($getrevision -t)
346 results="${vendor}/${mainboard}/${tagged_version}/${timestamp}"
348 if [ -n "$(echo $tagged_version | grep dirty)" ]; then
349 echo "The repository is in a dirty state. Please see the output of"
350 echo "'git status' below."
351 git status
352 exit $EXIT_FAILURE
355 echo "Temporarily placing output in ${tmpdir}/${results}"
356 mkdir -p "${tmpdir}/${results}"
358 mv "${tmpdir}/config.txt" "${tmpdir}/${results}"
359 test -f "${tmpdir}/payload_config.txt" && mv "${tmpdir}/payload_config.txt" "${tmpdir}/${results}"
360 test -f "${tmpdir}/payload_version.txt" && mv "${tmpdir}/payload_version.txt" "${tmpdir}/${results}"
361 mv "${tmpdir}/config.short.txt" "${tmpdir}/${results}"
362 mv "${tmpdir}/cbfs.txt" "${tmpdir}/${results}"
363 mv "${tmpdir}/rom_checksum.txt" "${tmpdir}/${results}"
365 touch "${tmpdir}/${results}/revision.txt"
366 printf "Local revision: %s\n" "$($getrevision -l)" >> "${tmpdir}/${results}/revision.txt"
367 printf "Tagged revision: %s\n" "${tagged_version}" >> "${tmpdir}/${results}/revision.txt"
368 printf "Upstream revision: %s\n" "$($getrevision -u)" >> "${tmpdir}/${results}/revision.txt"
369 printf "Upstream URL: %s\n" "$($getrevision -U)" >> "${tmpdir}/${results}/revision.txt"
370 printf "Timestamp: %s\n" "$timestamp" >> "${tmpdir}/${results}/revision.txt"
372 if [ -n "$CBMEM_PATH" ]; then
373 cbmem_cmd="$CBMEM_PATH"
374 else
375 cbmem_cmd="cbmem"
378 cmos_enabled=0
379 if grep -q "CONFIG_USE_OPTION_TABLE=y" "${tmpdir}/${results}/config.short.txt" > /dev/null; then
380 cmos_enabled=1
383 if [ -n "$NVRAMTOOL_PATH" ]; then
384 nvramtool_cmd="$NVRAMTOOL_PATH"
385 else
386 nvramtool_cmd="nvramtool"
389 if [ -n "$SERIAL_DEVICE" ]; then
390 get_serial_bootlog "$SERIAL_DEVICE" "$SERIAL_PORT_SPEED" "${tmpdir}/${results}/coreboot_console.txt"
391 elif [ -n "$REMOTE_HOST" ]; then
392 echo "Verifying that CBMEM is available on remote device"
393 test_cmd $REMOTE "$cbmem_cmd"
394 echo "Getting coreboot boot log"
395 cmd $REMOTE "$cbmem_cmd -1" "${tmpdir}/${results}/coreboot_console.txt"
396 echo "Getting timestamp data"
397 cmd_nonfatal $REMOTE "$cbmem_cmd -t" "${tmpdir}/${results}/coreboot_timestamps.txt"
399 if [ "$cmos_enabled" -eq 1 ]; then
400 echo "Verifying that nvramtool is available on remote device"
401 test_cmd $REMOTE "$nvramtool_cmd"
402 echo "Getting all CMOS values"
403 cmd $REMOTE "$nvramtool_cmd -a" "${tmpdir}/${results}/cmos_values.txt"
406 echo "Getting remote dmesg"
407 cmd $REMOTE dmesg "${tmpdir}/${results}/kernel_log.txt"
408 else
409 echo "Verifying that CBMEM is available"
410 if [ $(id -u) -ne 0 ]; then
411 command -v "$cbmem_cmd" >/dev/null
412 if [ $? -ne 0 ]; then
413 echo "Failed to run $cbmem_cmd. Check \$PATH or" \
414 "use -c to specify path to cbmem binary."
415 exit $EXIT_FAILURE
416 else
417 cbmem_cmd="sudo $cbmem_cmd"
419 else
420 test_cmd $LOCAL "$cbmem_cmd"
423 echo "Getting coreboot boot log"
424 cmd $LOCAL "$cbmem_cmd -1" "${tmpdir}/${results}/coreboot_console.txt"
425 if [ $(grep -- -dirty "${tmpdir}/${results}/coreboot_console.txt") ]; then
426 echo "coreboot or the payload are built from a source tree in a" \
427 "dirty state, making it hard to reproduce the result. Please" \
428 "check in your source tree with 'git status'."
429 exit $EXIT_FAILURE
432 echo "Getting timestamp data"
433 cmd_nonfatal $LOCAL "$cbmem_cmd -t" "${tmpdir}/${results}/coreboot_timestamps.txt"
435 if [ "$cmos_enabled" -eq 1 ]; then
436 echo "Verifying that nvramtool is available"
437 if [ $(id -u) -ne 0 ]; then
438 command -v "$nvramtool_cmd" >/dev/null
439 if [ $? -ne 0 ]; then
440 echo "Failed to run $nvramtool_cmd. Check \$PATH or" \
441 "use -n to specify path to nvramtool binary."
442 exit $EXIT_FAILURE
443 else
444 nvramtool_cmd="sudo $nvramtool_cmd"
446 else
447 test_cmd $LOCAL "$nvramtool_cmd"
450 echo "Getting all CMOS values"
451 cmd $LOCAL "$nvramtool_cmd -a" "${tmpdir}/${results}/cmos_values.txt"
454 echo "Getting local dmesg"
455 cmd $LOCAL "sudo dmesg" "${tmpdir}/${results}/kernel_log.txt"
459 # Finish up.
461 coreboot_dir=$(pwd)
462 if [ $UPLOAD_RESULTS -eq 1 ]; then
463 # extract username from ssh://<username>@review.coreboot.org/blah
464 bsrepo=$(git config --get remote.origin.url | sed "s,\(.*\)/coreboot,\1/board-status,")
466 cd "util/board_status/"
467 if [ ! -e "board-status" ]; then
468 # FIXME: the board-status directory might get big over time.
469 # Is there a way we can push the results without fetching the
470 # whole repo?
471 git clone "$bsrepo"
472 if [ $? -ne 0 ]; then
473 echo "Error cloning board-status repo, aborting."
474 exit $EXIT_FAILURE
478 cd "board-status"
480 echo "Checking for duplicate results"
481 # get any updates to board-status
482 git pull
484 echo "${tagged_version}" | grep dirty >/dev/null 2>&1
485 clean_version=$?
486 existing_results=$(git ls-files "${mainboard_dir}/${tagged_version}")
488 # reject duplicate results of non-dirty versions
489 if [ "${clean_version}" -eq 1 ] && [ -n "${existing_results}" ] ; then
490 echo "Result is a duplicate, aborting"
491 exit $EXIT_FAILURE
494 echo "Copying results to $(pwd)/${results}"
496 # Note: Result directory should be unique due to the timestamp.
497 cp -R "${tmpdir}/${vendor}" .
499 echo "Uploading results"
500 git add "${vendor}"
501 git commit -a -m "${mainboard_dir}/${tagged_version}/${timestamp}"
502 count=0
503 until git push origin master || test $count -eq 3; do
504 git pull --rebase
505 count=$((count + 1))
506 done
508 # Results have been uploaded so it's pointless to keep the
509 # temporary files around.
510 rm -rf "${tmpdir}"
511 if test $count -eq 3; then
512 echo "Error uploading to board-status repo, aborting."
513 exit $EXIT_FAILURE
516 cd "$coreboot_dir"
518 if [ $CLOBBER_OUTPUT -eq 1 ]; then
519 rm -rf "${tmpdir}"
520 else
521 if [ $UPLOAD_RESULTS -eq 1 ]; then
522 echo
523 echo "output files are in $(dirname $0)/board-status/${mainboard_dir}/${tagged_version}/${timestamp}"
524 else
525 echo
526 echo "output files are in ${tmpdir}/${results}"
530 exit $EXIT_SUCCESS