From 01a33ab0913d439150065ac23644c4f140ff8917 Mon Sep 17 00:00:00 2001 From: Casper Date: Mon, 23 Dec 2024 17:13:45 -0700 Subject: added qmenu! --- qmenu/qmenu_vm/f_notes | 23 +++++++ qmenu/qmenu_vm/f_screenshot | 18 +++++ qmenu/qmenu_vm/fq_keyboard | 12 ++++ qmenu/qmenu_vm/fq_pm | 75 +++++++++++++++++++++ qmenu/qmenu_vm/fqubes_logs | 16 +++++ qmenu/qmenu_vm/fqubes_prefs | 109 ++++++++++++++++++++++++++++++ qmenu/qmenu_vm/fqvm_appmenus | 64 ++++++++++++++++++ qmenu/qmenu_vm/fqvm_clone | 39 +++++++++++ qmenu/qmenu_vm/fqvm_create | 77 +++++++++++++++++++++ qmenu/qmenu_vm/fqvm_device | 70 +++++++++++++++++++ qmenu/qmenu_vm/fqvm_firewall | 81 ++++++++++++++++++++++ qmenu/qmenu_vm/fqvm_pci | 70 +++++++++++++++++++ qmenu/qmenu_vm/fqvm_prefs | 155 +++++++++++++++++++++++++++++++++++++++++++ qmenu/qmenu_vm/fqvm_remove | 18 +++++ qmenu/qmenu_vm/fqvm_run | 14 ++++ qmenu/qmenu_vm/fqvm_service | 39 +++++++++++ qmenu/qmenu_vm/fqvm_tags | 19 ++++++ qmenu/qmenu_vm/fqvm_volume | 26 ++++++++ 18 files changed, 925 insertions(+) create mode 100644 qmenu/qmenu_vm/f_notes create mode 100644 qmenu/qmenu_vm/f_screenshot create mode 100644 qmenu/qmenu_vm/fq_keyboard create mode 100644 qmenu/qmenu_vm/fq_pm create mode 100644 qmenu/qmenu_vm/fqubes_logs create mode 100644 qmenu/qmenu_vm/fqubes_prefs create mode 100644 qmenu/qmenu_vm/fqvm_appmenus create mode 100644 qmenu/qmenu_vm/fqvm_clone create mode 100644 qmenu/qmenu_vm/fqvm_create create mode 100644 qmenu/qmenu_vm/fqvm_device create mode 100644 qmenu/qmenu_vm/fqvm_firewall create mode 100644 qmenu/qmenu_vm/fqvm_pci create mode 100644 qmenu/qmenu_vm/fqvm_prefs create mode 100644 qmenu/qmenu_vm/fqvm_remove create mode 100644 qmenu/qmenu_vm/fqvm_run create mode 100644 qmenu/qmenu_vm/fqvm_service create mode 100644 qmenu/qmenu_vm/fqvm_tags create mode 100644 qmenu/qmenu_vm/fqvm_volume (limited to 'qmenu/qmenu_vm') diff --git a/qmenu/qmenu_vm/f_notes b/qmenu/qmenu_vm/f_notes new file mode 100644 index 0000000..ef93abd --- /dev/null +++ b/qmenu/qmenu_vm/f_notes @@ -0,0 +1,23 @@ +if [ "$(qvm-prefs "$qube" klass)" = DispVM ]; then + + notes=/tmp/."$qube".dispnotes +else + mkdir -p "$HOME"/.local/share/qubes-notes + notes="$HOME/.local/share/qubes-notes/$qube" +fi + +touch "$notes" + +note=$(dmenu-unlinked -l 25 -p "$qube:" < "$notes") + +while [ -n "$note" ]; do + + if grep -q "^$note\$" "$notes"; then + + sed -i "/^$note$/d" "$notes" + else + echo "$(date +%Y-%m-%d\ %H:%M) $note" >> "$notes" + fi + + note=$(dmenu-unlinked -l 25 -p "$qube:" < "$notes") +done diff --git a/qmenu/qmenu_vm/f_screenshot b/qmenu/qmenu_vm/f_screenshot new file mode 100644 index 0000000..cac22bc --- /dev/null +++ b/qmenu/qmenu_vm/f_screenshot @@ -0,0 +1,18 @@ +err="qmenu-vm - Error: Failed to take a screenshot! Please make sure that 'scrot' is installed inside $qube." + +target=$(printf 'Focused window\nAll visible windows' | dmenu-unlinked -l 2 -i -p "$qube:" | cut -f1 -d\ ) + +if [ "$target" = Focused ]; then + + if [ "$(xprop -id "$(xdotool getwindowfocus)" _QUBES_VMNAME | cut -d\" -f2)" = "$qube" ]; then + + (qvm-run -q "$qube" 'scrot -q 100 -u $HOME/Pictures/screenshot' || notify-send -u normal "$err")& + else + echo 'Go back...' | dmenu-unlinked -p "Warning: Unable to take a screenshot. Please focus a window belonging to $qube." > /dev/null 2>&1 + fi + +elif [ "$target" = All ]; then + + (qvm-run -q "$qube" 'scrot -q 100 $HOME/Pictures/screenshot' || notify-send -u normal "$err")& +fi + diff --git a/qmenu/qmenu_vm/fq_keyboard b/qmenu/qmenu_vm/fq_keyboard new file mode 100644 index 0000000..7a5c6e8 --- /dev/null +++ b/qmenu/qmenu_vm/fq_keyboard @@ -0,0 +1,12 @@ +LAYOUT=$(ls /usr/share/X11/xkb/symbols | dmenu-unlinked -l 50 -p "$qube:") && + +if [ -n "$LAYOUT" ]; then + + [ -d /usr/share/X11/xkb/symbols/"$LAYOUT" ] && LAYOUT="$LAYOUT/"$(ls /usr/share/X11/xkb/symbols/"$LAYOUT" | dmenu-unlinked -l 50 -p "$qube:") + + $(qvm-run -q "$qube" "setxkbmap $LAYOUT" || notify-send -u normal "Error: Failed to set keyboard layout to '$LAYOUT' in $qube! Please check if the selected layout is missing inside the qube itself.")& + + # 'qmenu-vm' does not get informed about the available layouts by the vm itself, + # so it is possible that the selected layout is missing inside the vm. + # However, getting the info from the vm itself would pose an unneccesary high risk. +fi diff --git a/qmenu/qmenu_vm/fq_pm b/qmenu/qmenu_vm/fq_pm new file mode 100644 index 0000000..313a6b0 --- /dev/null +++ b/qmenu/qmenu_vm/fq_pm @@ -0,0 +1,75 @@ +qubes=$(qvm-ls --no-spinner --all --exclude=dom0 -O name,label,template,netvm,default_dispvm,kernel | dmenu-unlinked -l 50 | cut -f1 -d\ ) + +if [ -n "$qubes" ]; then + + property=$(printf 'Default_DispVM\nKernel\nLabel\nTemplate\nNetVM' | dmenu-unlinked -i -l 5 -p "Select the property you wish to change:" | awk '{print tolower($0)}') + + if [ -n "$property" ]; then + + case $property in + + default_dispvm) + + if [ -z "$LIST_DISPTEMP" ]; then + + # [mediocre] Look up disposable templates in a very slow way because qvm-ls does not offer a flag for them + for n in $(qvm-ls --raw-data -O NAME,FLAGS | grep '|a.....-.$' | cut -d '|' -f1); do + + qvm-prefs "$n" template_for_dispvms | grep -q True && + + LIST_DISPTEMP="$LIST_DISPTEMP\n$n" + done + fi + + value=$(printf "(Default)\n(None)$LIST_DISPTEMP" | dmenu-unlinked -l 50 -p "Select default dispvm:") + + if [ "$value" = '(None)' ]; then value=None + elif [ "$value" = '(Default)' ]; then value=--default; fi;; + + kernel) + + value=$(echo --default | dmenu-unlinked -p "Enter kernel:");; + + label) + + value=$(printf 'Purple\nBlue\nGray\nGreen\nYellow\nOrange\nRed\nBlack' | dmenu-unlinked -i -l 8 -p "Select label:" | awk '{print tolower($0)}');; + + template) + + get_list template + + value=$(printf "(Default)\n$list" | dmenu-unlinked -l 50 -p "Select template:") + + [ "$value" = '(Default)' ] && value=--default;; + + netvm) + + get_list netvm + + value=$(printf "(Default)\n(None)\n$list" | dmenu-unlinked -l 50 -p "Select netvm:") + + if [ "$value" = '(None)' ]; then value=None + elif [ "$value" = '(Default)' ]; then value=--default; fi;; + + *) + esac + + if [ -n "$value" ]; then + + if nyprompt "Do you want to change the $property of all selected qubes to $value?"; then + + for qube in $qubes; do + + if [ "$property" = label ] || [ "$property" = template ] && qvm-check -q --running "$qube"; then + + echo Proceed... | dmenu-unlinked -p "Warning: Unable to change $property of $qube because it is not shut down." > /dev/null 2>&1 + else + qvm-prefs "$qube" "$property" "$value" || + + echo Proceed... | dmenu-unlinked -p "Error: Failed to set $property of $qube to '$value'!" > /dev/null 2>&1 + fi + done + fi + fi + fi +fi diff --git a/qmenu/qmenu_vm/fqubes_logs b/qmenu/qmenu_vm/fqubes_logs new file mode 100644 index 0000000..37fd6c8 --- /dev/null +++ b/qmenu/qmenu_vm/fqubes_logs @@ -0,0 +1,16 @@ +if [ "$qube" = dom0 ]; then + + logs=/var/log/xen/console/hypervisor.log +else + logs="/var/log/xen/console/guest-$qube.log\n/var/log/xen/console/guest-$qube-dm.log\n/var/log/qubes/guid.$qube.log\n/var/log/qubes/qrexec.$qube.log" +fi + +entry=1 + +while [ -n "$entry" ]; do + + if entry=$(printf "$logs" | dmenu-unlinked -i -l 4 -p "$qube:"); then + + qubes-log-viewer "$entry" + fi +done diff --git a/qmenu/qmenu_vm/fqubes_prefs b/qmenu/qmenu_vm/fqubes_prefs new file mode 100644 index 0000000..2570225 --- /dev/null +++ b/qmenu/qmenu_vm/fqubes_prefs @@ -0,0 +1,109 @@ +property=1 + +while [ -n "$property" ]; do + + property=$(qubes-prefs | dmenu-unlinked -l 16 -p "Global preferences:" | cut -f1 -d\ ) + + case $property in + + check_updates_vm) + + value=$(printf 'False\nTrue' | dmenu-unlinked -i -p "Should the system periodically check for domU updates?");; + + clockvm) + + get_list netvm + + value=$(printf "(None)\n$list" | dmenu-unlinked -l 50 -p "Select ClockVM:");; + + default_dispvm) + + if [ -z "$LIST_DISPTEMP" ]; then + + # [mediocre] Look up disposable templates in a very slow way because qvm-ls does not offer a flag for them + for n in $(qvm-ls --raw-data -O NAME,FLAGS | grep '|a.....-.$' | cut -d '|' -f1); do + + qvm-prefs "$n" template_for_dispvms | grep -q True && + + LIST_DISPTEMP="$LIST_DISPTEMP\n$n" + done + fi + + value=$(printf "(None)$LIST_DISPTEMP" | dmenu-unlinked -l 50 -p "Select default dispvm:");; + + default_kernel) + + value=$(echo '(None)' | dmenu-unlinked -l 2 -p "Enter default kernel:") && + + nyprompt "Set default kernel to $value?" || unset value;; + + default_netvm) + + get_list netvm + + value=$(printf "(None)\n$list" | dmenu-unlinked -l 50 -p "Select default netvm:");; + + default_pool) + + value=$(qvm-pool --list | sed '1d' | dmenu-unlinked -i -l 30 -p "Select default storage pool:" | cut -f1 -d\ );; + + default_pool_kernel) + + value=$(qvm-pool --list | sed '1d' | dmenu-unlinked -i -l 30 -p "Select default storage pool for kernel volumes:" | cut -f1 -d\ );; + + default_pool_private) + + value=$(qvm-pool --list | sed '1d' | dmenu-unlinked -i -l 30 -p "Select default storage pool for private volumes:" | cut -f1 -d\ );; + + default_pool_root) + + value=$(qvm-pool --list | sed '1d' | dmenu-unlinked -i -l 30 -p "Select default storage pool for root volumes:" | cut -f1 -d\ );; + + default_pool_volatile) + + value=$(qvm-pool --list | sed '1d' | dmenu-unlinked -i -l 30 -p "Select default storage pool for volatile volumes:" | cut -f1 -d\ );; + + default_qrexec_timeout) + + value=$(qubes-prefs default_qrexec_timeout | dmenu-unlinked -p "Enter the time in seconds, after which qrexec connection attempts are deemed a failure:");; + + default_shutdown_timeout) + + value=$(qubes-prefs default_shutdown_timeout | dmenu-unlinked -p "Enter the default time in seconds for qube shutdowns to complete:");; + + default_template) + + get_list template + + value=$(printf "(None)\n$list" | dmenu-unlinked -l 50 -p "Select default template:");; + + management_dispvm) + + get_list mgmt_disptemp + + value=$(printf "(None)\n$list" | dmenu-unlinked -l 50 -p "Select management dispvm:");; + + stats_interval) + + value=$(: | dmenu-unlinked -p "Enter interval in seconds for qube stats reporting:");; + + updatevm) + + get_list netvm + + value=$(printf "(None)\n$list" | dmenu-unlinked -l 50 -p "Select UpdateVM for dom0:");; + + *) + esac + + if [ -n "$value" ]; then + + [ "$value" = '(None)' ] && value='' + + qubes-prefs "$property" "$value" || + + echo Go back... | dmenu-unlinked -p "Error: Failed to set $property to '$value'!" > /dev/null 2>&1 + + unset value + fi +done diff --git a/qmenu/qmenu_vm/fqvm_appmenus b/qmenu/qmenu_vm/fqvm_appmenus new file mode 100644 index 0000000..4d3fe46 --- /dev/null +++ b/qmenu/qmenu_vm/fqvm_appmenus @@ -0,0 +1,64 @@ +option=1 + +while [ -n "$option" ]; do + + option=$(printf 'Available\nSelected\nRefresh' | dmenu-unlinked -i -l 3 -p "$qube:") + + if [ "$option" = Available ]; then + + applications=1 + + while [ -n "$applications" ]; do + + applications=$(qvm-appmenus --get-available --i-understand-format-is-unstable "$qube" | grep -v "$(qvm-appmenus --get-whitelist --i-understand-format-is-unstable "$qube")" | dmenu-unlinked -l 50 -p "$qube:" | cut -f1 -d\ ) + + if [ -n "$applications" ]; then + + # Check validity of input to prevent whitelisted-appmenus.list + # from being filled with garbage. + qvm-appmenus --get-available --i-understand-format-is-unstable "$qube" | cut -f1 -d\ | grep -q "^$applications$" && + + printf "\n$applications" >> "$HOME"/.local/share/qubes-appmenus/"$qube"/whitelisted-appmenus.list + + applications_modified=1 + fi + done + + elif [ "$option" = Selected ]; then + + applications=1 + + while [ -n "$applications" ]; do + + applications=$(qvm-appmenus --get-available --i-understand-format-is-unstable "$qube" | grep "$(qvm-appmenus --get-whitelist --i-understand-format-is-unstable "$qube")" | dmenu-unlinked -l 50 -p "$qube:" | cut -f1 -d\ ) + + if [ -n "$applications" ]; then + + for application in $applications; do + + # Look up linenumber above $application in + # whitelisted-appmenus.list to delete if it is garbage whitespace. + whitespace=$(grep -n1 "^$application$" < "$HOME"/.local/share/qubes-appmenus/"$qube"/whitelisted-appmenus.list | sed '1q;d' | cut -d- -f1) + + sed -i "${whitespace}{/^$/d;}" "$HOME"/.local/share/qubes-appmenus/"$qube"/whitelisted-appmenus.list + sed -i "/$application/d" "$HOME"/.local/share/qubes-appmenus/"$qube"/whitelisted-appmenus.list + + applications_modified=1 + done + fi + done + + elif [ "$option" = Refresh ]; then + + qvm-appmenus -q --force --update "$qube" + fi + + # Only update qvm-appmenus down here, *after* the user + # has quit the application selection to improve speed and reduce unnecessary updates. + if [ -n "$applications_modified" ]; then + + qvm-appmenus -q --update "$qube" + + unset applications_modified + fi +done diff --git a/qmenu/qmenu_vm/fqvm_clone b/qmenu/qmenu_vm/fqvm_clone new file mode 100644 index 0000000..d31b297 --- /dev/null +++ b/qmenu/qmenu_vm/fqvm_clone @@ -0,0 +1,39 @@ +clone_name=$(: | dmenu-unlinked -p "Enter the name for the clone of $qube:") && + + option=1 + + while [ -n "$option" ]; do + + option=$(printf 'Create the clone\nAdvanced options' | dmenu-unlinked -i -l 2 -p "$qube:" | cut -f1 -d\ ) + + if [ "$option" = Advanced ]; then + + option_adv=1 + + while [ -n "$option_adv" ]; do + + option_adv=$(printf 'Class\nPool' | dmenu-unlinked -i -l 2 -p "$clone_name($qube):") + + if [ "$option_adv" = Class ]; then + + class=$(printf 'AppVM\nDispVM\nStandaloneVM\nTemplateVM' | dmenu-unlinked -i -l 4 -p "Choose a class for $clone_name:") && + + class="-C $class" + + elif [ "$option_adv" = Pool ]; then + + pool=$(qvm-pool --list | sed '1d' | dmenu-unlinked -i -l 10 -p "Select a pool for $clone_name:" | cut -f1 -d\ ) && + + pool="-P $pool" + fi + done + + elif [ "$option" = Create ]; then + + unset option + + cp -n "$HOME/.local/share/qubes-notes/$qube" "$HOME/.local/share/qubes-notes/$clone_name" + + qvm-clone $class $pool "$qube" "$clone_name"& + fi + done diff --git a/qmenu/qmenu_vm/fqvm_create b/qmenu/qmenu_vm/fqvm_create new file mode 100644 index 0000000..b1990da --- /dev/null +++ b/qmenu/qmenu_vm/fqvm_create @@ -0,0 +1,77 @@ +name=$(: | dmenu-unlinked -p "Enter the name for the new qube:") && + + label=$(printf 'Red\nOrange\nYellow\nGreen\nGray\nBlue\nPurple\nBlack' | dmenu-unlinked -i -l 8 -p "Select label for $name:" | awk '{print tolower($0)}') + + if [ -n "$label" ]; then + + QUBEARGS="-l $label" + + class=$(printf 'AppVM\nStandaloneVM\nTemplateVM' | dmenu-unlinked -i -l 4 -p "Choose a class for $name:") + + QUBEARGS="$QUBEARGS -C $class" + + get_list template + + if [ "$class" = 'AppVM' ]; then + + template=$(printf "(Default)\n$list" | dmenu-unlinked -l 50 -p "Select template for $name:") + + [ "$template" = '(Default)' ] && unset template + + else + template=$(printf "(None)\n$list" | dmenu-unlinked -l 50 -p "Select template that $name will be copied from:") + + [ "$template" = '(None)' ] && unset template + fi + + [ -n "$template" ] && QUBEARGS="$QUBEARGS -t $template" + + get_list netvm + + netvm=$(printf "(Default)\n(None)\n$list" | dmenu-unlinked -l 50 -p "Select netvm for $name:") + + if [ "$netvm" = '(Default)' ]; then netvm=--default + elif [ "$netvm" = '(None)' ]; then unset netvm + fi + + QUBEARGS="$QUBEARGS --prop netvm=$netvm" + + provides_network=$(printf 'No\nYes' | dmenu-unlinked -i -p "Should $name provide networking for other qubes?") + + if [ "$provides_network" = Yes ]; then + + QUBEARGS="$QUBEARGS --prop provides_network=true" + fi + + option=1 + + while [ -n "$option" ]; do + + option=$(printf 'Create the new qube\nAdvanced options' | dmenu-unlinked -i -l 2 -p "dom0:" | cut -f1 -d\ ) + + if [ "$option" = Advanced ]; then + + option_adv=$(printf Pool | dmenu-unlinked -l 1 -p "$name:") + + if [ "$option_adv" = Pool ]; then + + pool=$(qvm-pool --list | sed '1d' | dmenu-unlinked -i -l 10 -p "Select a pool for $name:" | cut -f1 -d\ ) + + [ -n "$pool" ] && pool="-P $pool" + fi + + elif [ "$option" = Create ]; then + + qvm-create $QUBEARGS $pool "$name" + + if [ "$class" = 'StandaloneVM' ] && [ -z "$template" ]; then + + qvm-prefs "$name" kernel '' + qvm-prefs "$name" virt_mode hvm + qvm-prefs "$name" maxmem 0 + fi + + unset option + fi + done + fi diff --git a/qmenu/qmenu_vm/fqvm_device b/qmenu/qmenu_vm/fqvm_device new file mode 100644 index 0000000..a66d6df --- /dev/null +++ b/qmenu/qmenu_vm/fqvm_device @@ -0,0 +1,70 @@ +if ! qvm-check -q --running "$qube"; then + + echo Go back... | dmenu-unlinked -p "$qube needs to be running, in order to attach $(echo "$chosefrom" | cut -f1 -d\ | awk '{print tolower($0)}') devices to it." > /dev/null 2>&1 +else + case $chosefrom in + + Audio*) device_type='device mic';; + + Block*) device_type=block;; + + USB*) device_type=usb + esac + + devices_list=$(qvm-$device_type) + + device=1 + + while [ -n "$device" ]; do + + device=$(echo "$devices_list" | dmenu-unlinked -l 16 -p "$qube:") + + if [ -n "$device" ] && [ "$(echo "$device" | wc -l)" -eq 1 ]; then + + device_id=$(echo "$device" | cut -f1 -d\ ) + + if [ "$device_type" = block ]; then + + device_name=$(echo "$device" | awk '{print $2,$3}') + holds_qube=$(echo "$device" | awk '{print $4}') + else + device_name=$(echo "$device" | awk '{print $2}') + holds_qube=$(echo "$device" | awk '{print $3}') + fi + + if [ -z "$holds_qube" ]; then + + if nyprompt "Attach '$device_name' to $qube?"; then + + unset device + + qvm-$device_type attach -q "$qube" "$device_id" || + + echo Go back... | dmenu-unlinked -p "Error: Failed to attach device!" > /dev/null 2>&1 + fi + + elif [ "$holds_qube" = "$qube" ]; then + + if nyprompt "Detach '$device_name' from $qube?"; then + + unset device + + qvm-$device_type detach -q "$holds_qube" "$device_id" || + + echo Go back... | dmenu-unlinked -p "Error: Failed to detach device!" > /dev/null 2>&1 + fi + else + if nyprompt "Detach '$device_name' from $holds_qube and attach it to $qube?"; then + + unset device + + qvm-$device_type detach -q "$holds_qube" "$device_id" && + + qvm-$device_type attach -q "$qube" "$device_id" || + + echo Go back... | dmenu-unlinked -p "Error: Failed to handle device!" > /dev/null 2>&1 + fi + fi + fi + done +fi diff --git a/qmenu/qmenu_vm/fqvm_firewall b/qmenu/qmenu_vm/fqvm_firewall new file mode 100644 index 0000000..357ff28 --- /dev/null +++ b/qmenu/qmenu_vm/fqvm_firewall @@ -0,0 +1,81 @@ +rulenumber=1 + +while [ -n "$rulenumber" ]; do + + rulenumber=$(qvm-firewall "$qube" list | dmenu-unlinked -l 50 -p "$qube:" | cut -f1 -d\ ) + + if [ "$(echo "$rulenumber" | wc -w)" -eq 1 ]; then + + # This will equal "NO" if the user selects the top row, + # instead of any existing rule. + if [ "$rulenumber" != NO ]; then + + option=$(printf "Add new rule above rule $rulenumber\nRemove rule $rulenumber" | dmenu-unlinked -i -l 2 -p "$qube:" | cut -f1 -d\ ) + else + option=Add + fi + + if [ "$option" = Remove ]; then + + nyprompt "Remove rule $rulenumber?" && + + qvm-firewall "$qube" del --rule-no "$rulenumber" + + elif [ "$option" = Add ]; then + + [ -n "$RULEARGS" ] && unset RULEARGS + + action=$(printf 'Accept\nDrop' | dmenu-unlinked -i -l 2 -p "Select action for the new firewall rule:" | awk '{print tolower($0)}') + + if [ -n "$action" ]; then + + # Prompt the user to escape matches they want to leave empty. Leaving a match empty by pressing will prevent the rule from being created. + echo Continue... | dmenu-unlinked -p 'You will now be prompted to select the matches for the new rule. Please skip matches that you want to leave empty by escaping with or .' > /dev/null 2>&1 + + RULEARGS="$action" + + specialtarget=$(: | dmenu-unlinked -p "ACTION=$RULEARGS ") && + + RULEARGS="$RULEARGS SPECIALTARGET=$specialtarget" + + dsthost=$(: | dmenu-unlinked -p "ACTION=$RULEARGS ") && + + RULEARGS="$RULEARGS DSTHOST=$dsthost" + + proto=$(printf 'tcp\nudp\nicmp' | dmenu-unlinked -l 3 -p "ACTION=$RULEARGS ") && + + RULEARGS="$RULEARGS PROTO=$proto" + + if [ "$proto" = tcp ] || [ "$proto" = udp ]; then + + dstports=$(: | dmenu-unlinked -p "ACTION=$RULEARGS ") && + + RULEARGS="$RULEARGS DSTPORTS=$dstports" + + elif [ "$proto" = icmp ]; then + + icmptype=$(: | dmenu-unlinked -p "ACTION=$RULEARGS ") && + + RULEARGS="$RULEARGS ICMPTYPE=$icmptype" + fi + + comment=$(: | dmenu-unlinked -p "ACTION=$RULEARGS ") && + + RULEARGS="$RULEARGS COMMENT=$comment" + + if nyprompt "Add the following rule to $qube? {{ ACTION=$RULEARGS }}"; then + + [ -n "$beforerule" ] && unset beforerule + + [ "$rulenumber" != NO ] && beforerule=$(echo --before "$rulenumber") + + RULEARGS=$(echo "$RULEARGS" | awk '{print tolower($0)}') + + qvm-firewall "$qube" add $beforerule $RULEARGS || + + echo Go back... | dmenu-unlinked -p 'Error: Failed to add firewall rule! See 'qvm-firewall --help' for more information.' > /dev/null 2>&1 + fi + fi + fi + fi +done diff --git a/qmenu/qmenu_vm/fqvm_pci b/qmenu/qmenu_vm/fqvm_pci new file mode 100644 index 0000000..c71d055 --- /dev/null +++ b/qmenu/qmenu_vm/fqvm_pci @@ -0,0 +1,70 @@ +if qvm-check -q --running "$qube"; then + + echo Go back... | dmenu-unlinked -p "$qube needs to be powered off, in order to attach or detach PCI devices." > /dev/null 2>&1 +else + list_pci=$(qvm-pci) + + qvm-prefs "$qube" maxmem | grep -q ^0 || + + answer=$(printf 'Continue anyways\nDisable dynamic memory balancing' | dmenu-unlinked -l 2 -i -p "Dynamic memory balancing is enabled in $qube, some devices might not work!" | cut -f1 -d\ ) + + [ "$answer" = Disable ] && qvm-prefs "$qube" maxmem 0 + + qvm-prefs "$qube" virt_mode | grep -q pvh && + + answer=$(printf 'Continue anyways\nChange to another virtualisation mode' | dmenu-unlinked -l 2 -i -p "$qube is using PVH for its virtualisation mode, which does not support PCI passthrough!" | cut -f1 -d\ ) + + if [ "$answer" = Change ]; then + + virtmode=$(printf 'HVM\nPV' | dmenu-unlinked -l 2 -i -p "Select virtualisation mode for $qube:") && + + qvm-prefs "$qube" virt_mode "$virtmode" + fi + + device=1 + + while [ -n "$device" ]; do + + device=$(echo "$list_pci" | dmenu-unlinked -l 30 -p "$qube:") + + if [ -n "$device" ] && [ "$(echo "$device" | wc -l)" -eq 1 ]; then + + device_src=$(echo "$device" | cut -f1 -d\ | sed 's/:.*//') + device_bdf=$(echo "$device" | cut -f1 -d\ | sed 's/.*://') + + if echo "$device" | grep -q " $qube$\\| $qube (no-strict-reset=True)$\\| $qube (permissive=True)$"; then + + if nyprompt "Detach \"$device_bdf\" from $qube?"; then + + qvm-pci detach "$qube" "$device_src":"$device_bdf" || + + echo Go back... | dmenu-unlinked -p "Error: Failed to detach \"$device_bdf\" from $qube!" > /dev/null 2>&1 + + list_pci=$(qvm-pci) + fi + else + if nyprompt "Attach \"$device_bdf\" to $qube?"; then + + # Check if there is more than one function + # that belongs to the same device. + bdf_count=$(echo "$list_pci" | cut -f1 -d\ | grep -c $(echo "$device_bdf" | sed 's/\..*//')) + + if [ "$bdf_count" -gt 1 ]; then + + [ -n "$pci_option" ] && unset pci_option + + answer=$(printf 'No, attach without this option\nYes' | dmenu-unlinked -i -p "\"$device_bdf\" is most likely to be attached with the option 'no-strict-reset' enabled. Do not enable this option if you are unaware of the security implications! Do you want to attach \"$device_bdf\" with the option 'no-strict-reset' set to true?") + + [ "$answer" = Yes ] && pci_option='-o no-strict-reset=True' + fi + + qvm-pci attach --persistent $pci_option "$qube" "$device_src:$device_bdf" || + + echo Go back... | dmenu-unlinked -p "Error: Failed to attach '$device_bdf' to $qube!" > /dev/null 2>&1 + + list_pci=$(qvm-pci) + fi + fi + fi + done +fi diff --git a/qmenu/qmenu_vm/fqvm_prefs b/qmenu/qmenu_vm/fqvm_prefs new file mode 100644 index 0000000..0609923 --- /dev/null +++ b/qmenu/qmenu_vm/fqvm_prefs @@ -0,0 +1,155 @@ +property=1 + +while [ -n "$property" ]; do + + property=$(qvm-prefs "$qube" | dmenu-unlinked -l 45 -p "$qube:" | cut -f1 -d\ ) + + if [ -n "$property" ]; then + + case $property in + + autostart) + + value=$(printf 'False\nTrue' | dmenu-unlinked -i -p "Set autostart of $qube to:");; + + debug) + + value=$(printf 'False\nTrue' | dmenu-unlinked -i -p "Set debug mode of $qube to:");; + + default_dispvm) + + if [ -z "$LIST_DISPTEMP" ]; then + + # [mediocre] Look up disposable templates in a very slow way because qvm-ls does not offer a flag for them + for n in $(qvm-ls --raw-data -O NAME,FLAGS | grep '|a.....-.$' | cut -d '|' -f1); do + + qvm-prefs "$n" template_for_dispvms | grep -q True && + + LIST_DISPTEMP="$LIST_DISPTEMP\n$n" + done + fi + + value=$(printf "(Default)\n(None)$LIST_DISPTEMP" | dmenu-unlinked -l 50 -p "Select default dispvm for $qube:");; + + default_user) + + value=$(echo --default | dmenu-unlinked -p "Enter the name of the default user for $qube:");; + + include_in_backups) + + value=$(printf 'False\nTrue' | dmenu-unlinked -i -p "Include $qube in backups?");; + + kernel) + + value=$(printf "(Default)\n(None)" | dmenu-unlinked -l 2 -p "Enter the kernel to be used by $qube:");; + + kernelopts) + + value=$(echo --default | dmenu-unlinked -p "Enter the kernel options for $qube:") && + + nyprompt "Set kernel options for $qube to \"$value\"?" || unset value;; + + label) + + if qvm-check -q --running "$qube"; then + + echo Go back... | dmenu-unlinked -p "$qube needs to be powered off, in order to change its label." > /dev/null 2>&1 + else + value=$(printf 'Purple\nBlue\nGray\nGreen\nYellow\nOrange\nRed\nBlack' | dmenu-unlinked -i -l 8 -p "Select label for $qube:" | awk '{print tolower($0)}') + fi;; + + mac) + + value=$(echo --default | dmenu-unlinked -p "Enter the MAC address for $qube:") && + + nyprompt "Set MAC address of $qube to $value?" || unset value;; + + maxmem) + + value=$(echo --default | dmenu-unlinked -p "Enter the maximum amount of memory in MB to be allocated to $qube. Setting it to 0 will disable dynamic memory balancing.") && + + if nyprompt "Set maximum memory of $qube to $value MB?"; then + + # For linux qubes, initial memory can not be less than one tenth of maxmem + # so we will automatically set the minimum allowed value. + # Users can still overwrite this manually via fqvm_prefs - memory. + + minmem=$(( $value / 10 )) + + [ "$(qvm-prefs $qube memory)" -lt "$minmem" ] && qvm-prefs "$qube" memory "$minmem" + else + unset value + fi;; + + memory) + + value=$(echo --default | dmenu-unlinked -p "Enter the amount of initial memory in MB to be allocated to $qube:") && + + nyprompt "Set initial memory of $qube to $value MB?" || unset value;; + + netvm) + + get_list netvm + + value=$(printf "(Default)\n(None)\n$list" | dmenu-unlinked -l 50 -p "Select netvm for $qube:");; + + provides_network) + + value=$(printf 'False\nTrue' | dmenu-unlinked -i -p "Should $qube provide networking to other qubes?");; + + qrexec_timeout) + + value=$(echo --default | dmenu-unlinked -p "Enter the time in seconds, after which qrexec connection attempts are deemed a failure for $qube:") && + + nyprompt "Set qrexec timeout for $qube to $value seconds?" || unset value;; + + shutdown_timeout) + + value=$(echo --default | dmenu-unlinked -p "Enter the time in seconds to wait for shutdown, after which $qube may be forcefully powered off:") && + + nyprompt "Set shutdown timeout for $qube to $value seconds?" || unset value;; + + template) + + if qvm-check -q --running "$qube"; then + + echo Go back... | dmenu-unlinked -p "$qube needs to be powered off, in order to change its template." > /dev/null 2>&1 + else + get_list template + + value=$(printf "(Default)\n$list" | dmenu-unlinked -l 50 -p "Select template for $qube:") && + + (sleep 2 && qvm-appmenus -q --update "$qube"&) + fi;; + + template_for_dispvms) + + value=$(printf 'False\nTrue' | dmenu-unlinked -i -p "Should $qube be used as a template for disposable qubes?");; + + vcpus) + + value=$(echo --default | dmenu-unlinked -p "Enter the number of CPU cores that should be made available to $qube:") && + + nyprompt "Set number of CPU cores available to $qube to $value?" || unset value;; + + virt_mode) + + value=$(printf 'PVH\nHVM\nPV' | dmenu-unlinked -i -l 3 -p "Select virtualisation mode for $qube:");; + + *) + esac + + if [ -n "$value" ]; then + + if [ "$value" = '(None)' ]; then value='' + elif [ "$value" = '(Default)' ]; then value=--default + fi + + qvm-prefs "$qube" "$property" "$value" || + + echo Go back... | dmenu-unlinked -p "Error: Failed to set $property to '$value'!" > /dev/null 2>&1 + + unset value + fi + fi +done diff --git a/qmenu/qmenu_vm/fqvm_remove b/qmenu/qmenu_vm/fqvm_remove new file mode 100644 index 0000000..91ff8dd --- /dev/null +++ b/qmenu/qmenu_vm/fqvm_remove @@ -0,0 +1,18 @@ +if qvm-check -q --running "$qube"; then + + echo Go back... | dmenu-unlinked -p "$qube needs to be powered off, in order to be removed." > /dev/null 2>&1 +else + confirmation=$(: | dmenu-unlinked -p "Enter the name of the qube '$qube' in order to remove it:") + + if [ "$qube" = "$confirmation" ]; then + + if nyprompt "Are you sure you want to remove '$qube' permanently?"; then + + unset chosefrom + + rm -f "$HOME/.local/share/qubes-notes/$qube" + + $(qvm-remove -f "$qube" || notify-send -u normal "Error: Failed to remove "$qube"!")& + fi + fi +fi diff --git a/qmenu/qmenu_vm/fqvm_run b/qmenu/qmenu_vm/fqvm_run new file mode 100644 index 0000000..18db4f3 --- /dev/null +++ b/qmenu/qmenu_vm/fqvm_run @@ -0,0 +1,14 @@ +if user=$(printf 'Default user\nRoot' | dmenu-unlinked -i -l 2 -p "Run commands as:"); then + + [ "$user" = Root ] && as_root='-u root' && user=# || user=$ + + commandtr=1 + + while [ -n "$commandtr" ]; do + + if commandtr=$(: | dmenu-unlinked -p "[@$qube]$user"); then + + qvm-run -q $as_root "$qube" "$commandtr"& + fi + done +fi diff --git a/qmenu/qmenu_vm/fqvm_service b/qmenu/qmenu_vm/fqvm_service new file mode 100644 index 0000000..cc8baaa --- /dev/null +++ b/qmenu/qmenu_vm/fqvm_service @@ -0,0 +1,39 @@ +services=1 + +while [ -n "$services" ]; do + + services=$(qvm-service "$qube" --list | dmenu-unlinked -l 32 -p "$qube:" | cut -f1 -d\ ) + + if [ -n "$services" ]; then + + for service in $services; do + + qvm-service "$qube" --list | grep -q "^$service " && + + unset='\nUnset' + + value=$(printf "Disable\nEnable$unset" | dmenu-unlinked -l 3 -i -p "Select value for '$service':") + + if [ "$value" = Disable ]; then + + qvm-service "$qube" "$service" off || + + echo Go back... | dmenu-unlinked -p "Error: Failed to deactivate '$service'!" > /dev/null 2>&1 + + elif [ "$value" = Enable ]; then + + qvm-service "$qube" "$service" on || + + echo Go back... | dmenu-unlinked -p "Error: Failed to activate '$service'!" > /dev/null 2>&1 + + elif [ "$value" = Unset ]; then + + qvm-service "$qube" "$service" --unset || + + echo Go back... | dmenu-unlinked -p "Error: Failed to unset '$service'!" > /dev/null 2>&1 + fi + + [ -n "$unset" ] && unset unset + done + fi +done diff --git a/qmenu/qmenu_vm/fqvm_tags b/qmenu/qmenu_vm/fqvm_tags new file mode 100644 index 0000000..6c6ee6f --- /dev/null +++ b/qmenu/qmenu_vm/fqvm_tags @@ -0,0 +1,19 @@ +tags=1 + +while [ -n "$tags" ]; do + + tags=$(qvm-tags "$qube" list | dmenu-unlinked -l 15 -p "$qube:" | cut -f1 -d\ ) + + if [ -n "$tags" ]; then + + for tag in $tags; do + + if qvm-tags "$qube" list | grep -q "^$tag$"; then + + nyprompt "Remove tag '$tag' from $qube?" && qvm-tags "$qube" del "$tag" + else + qvm-tags "$qube" add "$tag" + fi + done + fi +done diff --git a/qmenu/qmenu_vm/fqvm_volume b/qmenu/qmenu_vm/fqvm_volume new file mode 100644 index 0000000..8b762e0 --- /dev/null +++ b/qmenu/qmenu_vm/fqvm_volume @@ -0,0 +1,26 @@ +qube_class=$(qvm-ls --raw-data -O flags "$qube" | cut -c 1) + +if [ "$qube_class" = t ] || [ "$qube_class" = s ] || [ "$qube_class" = S ]; then + + volume=$(printf 'Root\nPrivate' | dmenu-unlinked -l 2 -i -p "$qube:" | awk '{print tolower($0)}') +else + volume=private +fi + +if [ -n "$volume" ]; then + + current_storage=$(( $(qvm-volume info "$qube:$volume" size) / 1048576 )) + + mebibyte=$(echo "$current_storage" | dmenu-unlinked -p "Enter the maximum size of $volume storage in MiB to be allocated to $qube:") && + + if [ "$mebibyte" -gt "$current_storage" ]; then + + byte=$(( mebibyte * 1048576 )) + + nyprompt "Increase the maximum $volume storage size of $qube from $current_storage MiB to $mebibyte MiB?" && + + (qvm-volume extend "$qube:$volume" "$byte"&) + else + echo Go back... | dmenu-unlinked -p "Warning: Unable to decrease the maximum $volume storage!" > /dev/null 2>&1 + fi +fi -- cgit v1.2.3