@@ -28,6 +28,7 @@ if [ "$1" = "--help" ]; then
2828 echo " --force-xen-upgrade force major Xen upgrade even if some qubes are running"
2929 echo " --console does nothing; ignored for backward compatibility"
3030 echo " --show-output does nothing; ignored for backward compatibility"
31+ echo " --silent do not print anything to stdout"
3132 echo " --preserve-terminal does nothing; ignored for backward compatibility"
3233 echo " --skip-boot-check does not check if /boot & /boot/efi should be mounted"
3334 echo " --switch-audio-server-to=(pulseaudio|pipewire) switch audio daemon to pipewire or pulseaudio"
@@ -46,6 +47,7 @@ YUM_OPTS=()
4647UPDATEVM_OPTS=()
4748QVMTEMPLATE_OPTS=()
4849GUI=
50+ PROGRESS_REPORTING=
4951CHECK_ONLY=
5052CLEAN=
5153TEMPLATE=
@@ -79,6 +81,12 @@ while [ $# -gt 0 ]; do
7981 --show-output)
8082 # ignore
8183 ;;
84+ --silent)
85+ exec > /dev/null
86+ ;;
87+ --just-print-progress)
88+ PROGRESS_REPORTING=1
89+ ;;
8290 --check-only)
8391 CHECK_ONLY=1
8492 UPDATEVM_OPTS+=( " $1 " )
@@ -310,40 +318,111 @@ qvm-run --nogui -q -- "$UPDATEVM" "rm -rf -- '$dom0_updates_dir/etc' '$dom0_upda
310318 exit " $status "
311319}
312320
313- CMD= " /usr/lib/qubes/qubes-download-dom0-updates.sh --doit --nogui"
321+ QVMRUN_OPTS=(--quiet --filter-escape-chars --nogui --pass-io)
314322
315- # We avoid using bash’s own facilities for this, as they produce $'\n'-style
316- # strings in certain cases. These are not portable, whereas the string produced
317- # by the following is.
318- for i in " ${UPDATEVM_OPTS[@]} " ; do CMD+=" '${i// \' / \'\\\'\' } '" ; done
323+ progress_agent_version=" 4.3"
319324
320- QVMRUN_OPTS=(--quiet --filter-escape-chars --nogui --pass-io)
321- if [[ -t 1 ]] && [[ -t 2 ]]; then
322- # Use ‘script’ to emulate a TTY, so that we get status bars and other
323- # progress output. Since stdout and stderr are both terminals, qvm-run
324- # will automatically sanitize them, but we explicitly tell it to anyway
325- # as a precaution.
326- #
327- # We MUST NOT use ‘exec script’ here. That causes ‘script’ to
328- # inherit the child processes of the shell. ‘script’ mishandles
329- # this and enters an infinite loop.
330- CMD=" script --quiet --return --command '${CMD// \' / \'\\\'\' } ' /dev/null"
325+ get_base_vm () {
326+ # Resolve base VM (TemplateVM or StandaloneVM)
327+ local vm=" $1 "
328+ while true ; do
329+ # If it's a TemplateVM or StandaloneVM, stop
330+ if qvm-check --template " $vm " & > /dev/null || qvm-check --standalone " $vm " & > /dev/null; then
331+ echo " $vm "
332+ return
333+ fi
334+ # Try to get its template
335+ vm=$( qvm-prefs " $vm " template 2> /dev/null) || return 1
336+ done
337+ }
338+ version_check () {
339+ # Compare version numbers (e.g., 4.2 < 4.3)
340+ awk ' BEGIN {exit !(ARGV[1] < ARGV[2])}' " $1 " " $2 "
341+ }
342+ base_vm=$( get_base_vm " $UPDATEVM " )
343+ OLD_VERSION=0
344+ if [ -n " $base_vm " ]; then
345+ agent_version=$( qvm-features " $base_vm " qubes-agent-version 2> /dev/null)
346+
347+ if [ -n " $agent_version " ] && version_check " $agent_version " " $progress_agent_version " ; then
348+ OLD_VERSION=1
349+ fi
331350fi
332351
333- qvm-run " ${QVMRUN_OPTS[@]} " -- " $UPDATEVM " " $CMD " < /dev/null
334352
335- RETCODE=$?
336- if [[ " $REMOTE_ONLY " = ' 1' ]] || [ " $RETCODE " -ne 0 ]; then
353+ if [ " $PROGRESS_REPORTING " == " 1" ] && [ " $OLD_VERSION " == " 0" ]; then
354+ CMD=" /usr/lib/qubes/qubes-download-dom0-updates-init.sh"
355+ qvm-run " ${QVMRUN_OPTS[@]} " -- " $UPDATEVM " " $CMD " || exit 1
356+
357+ update_agent_log=" /var/log/qubes/qubes-update"
358+ qvm-run --nogui -q -u root -- " $UPDATEVM " " user=\$ (qubesdb-read /default-user) && chown -R -- \"\$ user:qubes\" '$update_agent_log '" || exit 1
359+
360+ # "--no-cleanup" is needed since fakeroot cannot remove entrypoint
361+ qubes-vm-update --force-update --targets " $UPDATEVM " --signal-no-updates --just-print-progress --display-name dom0 --download-only --no-cleanup --show-output --log=INFO ; RETCODE=$?
362+ if [ " ${RETCODE-0} " -eq 100 ]; then
363+ echo " $( hostname) :out: Nothing to do."
364+ echo " $( hostname) done no_updates" >&2
365+ exit 100
366+ fi
367+ if [ " ${RETCODE-0} " -ne 0 ]; then
368+ echo " $( hostname) done error" >&2
369+ exit " $RETCODE "
370+ fi
371+
372+ # qubes-vm-update leaves the downloaded packages with root ownership
373+ qvm-run --nogui -q -u root -- " $UPDATEVM " " user=\$ (qubesdb-read /default-user) && chown -R -- \"\$ user:qubes\" '$dom0_updates_dir '" || exit 1
374+
375+ CMD=" /usr/lib/qubes/qubes-download-dom0-updates-finish.sh"
376+ qvm-run " ${QVMRUN_OPTS[@]} " -- " $UPDATEVM " " $CMD " || exit 1
377+ else
378+ if [ " $PROGRESS_REPORTING " == " 1" ] && [ " $OLD_VERSION " == " 1" ]; then
379+ echo " $( hostname) :out: Progress reporting requires updateVM based on a template with Qubes 4.3 packages."
380+ fi
381+ CMD=" /usr/lib/qubes/qubes-download-dom0-updates.sh --doit --nogui"
382+
383+ # We avoid using bash’s own facilities for this, as they produce $'\n'-style
384+ # strings in certain cases. These are not portable, whereas the string produced
385+ # by the following is.
386+ for i in " ${UPDATEVM_OPTS[@]} " ; do CMD+=" '${i// \' / \'\\\'\' } '" ; done
387+
388+ if [[ -t 1 ]] && [[ -t 2 ]]; then
389+ # Use ‘script’ to emulate a TTY, so that we get status bars and other
390+ # progress output. Since stdout and stderr are both terminals, qvm-run
391+ # will automatically sanitize them, but we explicitly tell it to anyway
392+ # as a precaution.
393+ #
394+ # We MUST NOT use ‘exec script’ here. That causes ‘script’ to
395+ # inherit the child processes of the shell. ‘script’ mishandles
396+ # this and enters an infinite loop.
397+ CMD=" script --quiet --return --command '${CMD// \' / \'\\\'\' } ' /dev/null"
398+ fi
399+ if [ " $PROGRESS_REPORTING " == " 1" ]; then
400+ qvm-run " ${QVMRUN_OPTS[@]} " -- " $UPDATEVM " " $CMD " < /dev/null | sed " s/^/$( hostname) :out: /" ; RETCODE=$?
401+ # "consume" the last empty line
402+ echo " "
403+ else
404+ qvm-run " ${QVMRUN_OPTS[@]} " -- " $UPDATEVM " " $CMD " < /dev/null ; RETCODE=$?
405+ fi
406+ fi
407+
408+ if [ " $PROGRESS_REPORTING " == " 1" ] && [ " $OLD_VERSION " == " 1" ]; then
409+ echo " $( hostname) updating 50.0" >&2
410+ if [ " ${RETCODE-0} " -ne 0 ]; then
411+ echo " $( hostname) done error" >&2
412+ exit " $RETCODE "
413+ fi
414+ fi
415+ if [[ " $REMOTE_ONLY " = ' 1' ]] || [ " ${RETCODE-0} " -ne 0 ]; then
337416 if [ " $CHECK_ONLY " = ' 1' ]; then
338- if [ " $RETCODE " -eq 100 ]; then
417+ if [ " ${ RETCODE-0} " -eq 100 ]; then
339418 echo " There are dom0 updates available" >&2
340- elif [ " $RETCODE " -eq 0 ]; then
419+ elif [ " ${ RETCODE-0} " -eq 0 ]; then
341420 echo " No dom0 updates available" >&2
342421 else
343422 echo " Failed to check for dom0 updates" >&2
344423 fi
345424 fi
346- exit $ RETCODE
425+ exit " ${ RETCODE-0} "
347426fi
348427# Wait for download completed
349428while pidof -x qubes-receive-updates > /dev/null; do sleep 0.5; done
@@ -401,6 +480,9 @@ elif [ -f /var/lib/qubes/updates/repodata/repomd.xml ]; then
401480 # refresh packagekit metadata, GUI utilities use it
402481 pkcon refresh force
403482 $guiapp
483+ elif [ " $PROGRESS_REPORTING " == 1 ]; then
484+ # report progress to the user
485+ qubes-vm-update --no-refresh --targets dom0 --force-update --log=DEBUG --just-print-progress --show-output ; RETCODE=$?
404486 else
405487 dnf check-update ||
406488 if [ $? -eq 100 ]; then # Run dnf with options
@@ -416,9 +498,8 @@ elif [ -f /var/lib/qubes/updates/repodata/repomd.xml ]; then
416498 fi
417499 fi
418500else
419- if ! qvm-features dom0 updates-available ' ' 2 > /dev/null; then
501+ qvm-features dom0 updates-available ' ' > /dev/null 2>&1 ||
420502 echo " *** WARNING: cannot set feature 'updates-available'" >&2
421- fi
422503 echo " No updates available" >&2
423504 if [ " $GUI " == " 1" ]; then
424505 if [ " $KDE_FULL_SESSION " ]; then
0 commit comments